-
Notifications
You must be signed in to change notification settings - Fork 28
/
Copy pathmc_log.py
executable file
·112 lines (103 loc) · 3.59 KB
/
mc_log.py
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/usr/bin/env python3
"""
Post Minecraft Java Edition server logs running in service to webhooks (Discord and
Rocket Chat).
"""
import argparse
import os
import pathlib
import re
import select
import signal
import subprocess
import sys
import requests
import systemd.journal
def send(msg: str):
"""
:param msg: Message to send to URLs in webhook files
"""
if DISCORD_FILE.is_file():
for url in DISCORD_FILE.read_text(encoding="utf-8").split(os.linesep)[:-1]:
try:
requests.post(
url,
json={"content": msg},
timeout=60,
)
except requests.exceptions.RequestException as err:
print(type(err), flush=True)
if ROCKET_FILE.is_file():
for url in ROCKET_FILE.read_text(encoding="utf-8").split(os.linesep)[:-1]:
try:
requests.post(
url,
json={"text": msg},
timeout=60,
)
except requests.exceptions.RequestException as err:
print(type(err), flush=True)
PARSER = argparse.ArgumentParser(
description=(
"Post Minecraft Java Edition server logs running in service to webhooks "
+ "(Discord and Rocket Chat)."
),
epilog="Logs include server start/stop and player connect/disconnect/kick.",
)
PARSER.add_argument("SERVICE", type=str, help="systemd service")
ARGS = PARSER.parse_args()
SERVICE = ARGS.SERVICE
# Trim off SERVICE after last .service
if SERVICE.endswith(".service"):
SERVICE = SERVICE[: -len(".service")]
if subprocess.run(
["systemctl", "is-active", "-q", "--", SERVICE], check=False
).returncode:
sys.exit(f"Service {SERVICE} not active")
# Trim off SERVICE before last @
INSTANCE = SERVICE.split("@")[-1]
DISCORD_FILE = pathlib.Path(pathlib.Path.home(), ".mc_log", f"{INSTANCE}_discord.txt")
if DISCORD_FILE.is_file():
DISCORD_FILE.chmod(0o600)
ROCKET_FILE = pathlib.Path(pathlib.Path.home(), ".mc_log", f"{INSTANCE}_rocket.txt")
if ROCKET_FILE.is_file():
ROCKET_FILE.chmod(0o600)
send(f"Server {SERVICE} starting")
journal = systemd.journal.Reader()
journal.add_match(_SYSTEMD_UNIT=SERVICE + ".service")
journal.seek_tail()
journal.get_previous()
poll = select.poll()
poll.register(journal, journal.get_events())
signal.signal(signal.SIGTERM, lambda signalnum, currentframe: sys.exit())
try:
# Follow log for unit SERVICE
while poll.poll():
journal.process()
for entry in journal:
line = entry["MESSAGE"]
# Filter out chat
if re.search("<.+>", line):
continue
connect = re.search("([^: ][^:]*) joined the game", line)
if connect:
# Gamertags can have spaces if they're not leading/trailing/consecutive
player = connect.group(1)
send(f"{player} connected to {SERVICE}")
continue
disconnect = re.search("([^: ][^:]*) left the game", line)
if disconnect:
player = disconnect.group(1)
send(f"{player} disconnected from {SERVICE}")
continue
kick = re.search("Kicked ([^:]+): (.*)", line)
if kick:
player = kick.group(1)
reason = kick.group(2)
# Trim off leading space from reason
if reason.startswith(" "):
reason = reason[1:]
send(f"{player} was kicked from {SERVICE} because {reason}")
continue
finally:
send(f"Server {SERVICE} stopping")