vk_hackathon/logserver/server.py
q 6a25927813 Add in-process TCP log streaming to 185.33.228.73:9999 + logserver receiver
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 16:09:35 +03:00

107 lines
2.9 KiB
Python

#!/usr/bin/env python3
"""
TCP log server — receives JSON-line logs from index-service and search-service.
Usage:
python3 server.py # listen on 0.0.0.0:9999
python3 server.py --port 9999
python3 server.py --save logs.jsonl # also save to file
"""
import argparse
import json
import logging
import socketserver
import sys
import threading
from datetime import datetime
COLORS = {
"DEBUG": "\033[36m",
"INFO": "\033[0m",
"WARNING": "\033[33m",
"ERROR": "\033[31m",
"CRITICAL": "\033[35m",
}
RESET = "\033[0m"
SERVICE_COLOR = {
"index-service": "\033[34m", # blue
"search-service": "\033[32m", # green
}
_save_file = None
_save_lock = threading.Lock()
def _format(entry: dict) -> str:
ts = entry.get("ts", "")[:23].replace("T", " ")
level = entry.get("level", "INFO")
service = entry.get("service", "?")
msg = entry.get("msg", "")
lc = COLORS.get(level, "")
sc = SERVICE_COLOR.get(service, "\033[0m")
return f"{ts} {sc}{service:<15}{RESET} {lc}{level:<8}{RESET} {msg}"
def _handle_line(raw: str) -> None:
raw = raw.strip()
if not raw:
return
try:
entry = json.loads(raw)
except json.JSONDecodeError:
entry = {"ts": datetime.utcnow().isoformat(), "level": "INFO", "service": "?", "msg": raw}
print(_format(entry), flush=True)
if _save_file:
with _save_lock:
_save_file.write(raw + "\n")
_save_file.flush()
class _Handler(socketserver.StreamRequestHandler):
def handle(self) -> None:
addr = self.client_address[0]
print(f"\033[90m[+] connected: {addr}{RESET}", flush=True)
try:
for raw_bytes in self.rfile:
try:
_handle_line(raw_bytes.decode("utf-8", errors="replace"))
except Exception:
pass
except Exception:
pass
print(f"\033[90m[-] disconnected: {addr}{RESET}", flush=True)
def main() -> None:
global _save_file
parser = argparse.ArgumentParser(description="TCP JSON-line log receiver")
parser.add_argument("--host", default="0.0.0.0")
parser.add_argument("--port", type=int, default=9999)
parser.add_argument("--save", metavar="FILE", help="Also save raw JSON lines to this file")
args = parser.parse_args()
if args.save:
_save_file = open(args.save, "a", encoding="utf-8")
print(f"Saving logs to {args.save}", flush=True)
server = socketserver.ThreadingTCPServer((args.host, args.port), _Handler)
server.allow_reuse_address = True
print(f"Listening on {args.host}:{args.port} ...\n", flush=True)
try:
server.serve_forever()
except KeyboardInterrupt:
print("\nStopped.")
finally:
server.server_close()
if _save_file:
_save_file.close()
if __name__ == "__main__":
main()