Repository navigation
Expand file tree
/
Copy pathconsole_tee.py
More file actions
67 lines (63 loc) · 2.87 KB
/
Copy pathconsole_tee.py
File metadata and controls
67 lines (63 loc) · 2.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
"""Preserve raw output while recording the first received output timestamp."""
import datetime
import os
import time
from pathlib import Path
import sys
import admin_logs
def copy_output(source, target, destination, tracker=None, player_tracker=None):
first = True
tail = b''
_, _, rotation_size = admin_logs.limits()
last_cleanup = time.monotonic()
with target.open('wb', buffering=0) as log:
while chunk := source.read1(65536):
if log.tell() and log.tell() + len(chunk) > rotation_size:
# The stream remains open for the whole process; replace its fd
# after moving the completed segment into console history.
admin_logs.rotate(target)
with target.open('wb', buffering=0) as fresh:
os.dup2(fresh.fileno(), log.fileno())
first = True
if time.monotonic() - last_cleanup >= 60:
admin_logs.prune(target.parent)
last_cleanup = time.monotonic()
if first:
target.with_name(target.name + '.first').write_text(
datetime.datetime.now(datetime.timezone.utc).isoformat())
first = False
log.write(chunk)
if player_tracker is not None:
player_tracker.feed(chunk)
if tracker is not None:
combined = tail + chunk
if b'\nServer started\n' in b'\n' + combined.replace(b'\r\n', b'\n'):
try:
tracker.start()
except (OSError, ValueError) as error:
print(f'[ADMIN] World uptime tracking unavailable: {error}', file=sys.stderr, flush=True)
tracker = None
tail = combined[-128:]
# Explicit nanoseconds avoid coarse filesystem write times appearing
# earlier than the first-output marker for very short runs.
written = time.time_ns()
os.utime(target, ns=(written, written))
destination.write(chunk)
destination.flush()
if __name__ == '__main__':
from admin_player_history import VisitTracker
from admin_world_time import SessionTracker
name = os.environ.get('TMOD_WORLDNAME')
custom = os.environ.get('TMOD_USECONFIGFILE', 'No').lower() in ('yes', 'true', '1')
tracker = SessionTracker(name) if name and not custom else None
player_tracker = VisitTracker(sys.argv[2]) if len(sys.argv) > 2 else None
try:
copy_output(sys.stdin.buffer, Path(sys.argv[1]), sys.stdout.buffer, tracker, player_tracker)
finally:
if tracker:
tracker.finish()
if player_tracker:
try:
player_tracker.finish()
except OSError as error:
print(f'[ADMIN] Player history session could not close: {error}', file=sys.stderr, flush=True)