Remove logviewer, clean up docker-compose logging sections
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1f976cf297
commit
1104ed936c
3 changed files with 0 additions and 209 deletions
|
|
@ -44,15 +44,6 @@ services:
|
||||||
- qdrant
|
- qdrant
|
||||||
ports:
|
ports:
|
||||||
- "8001:8000"
|
- "8001:8000"
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: "20m"
|
|
||||||
max-file: "5"
|
|
||||||
tag: "index-service"
|
|
||||||
labels: "service"
|
|
||||||
labels:
|
|
||||||
- "service=index-service"
|
|
||||||
|
|
||||||
search:
|
search:
|
||||||
build:
|
build:
|
||||||
|
|
@ -64,12 +55,3 @@ services:
|
||||||
condition: service_completed_successfully
|
condition: service_completed_successfully
|
||||||
ports:
|
ports:
|
||||||
- "8002:8000"
|
- "8002:8000"
|
||||||
logging:
|
|
||||||
driver: json-file
|
|
||||||
options:
|
|
||||||
max-size: "20m"
|
|
||||||
max-file: "5"
|
|
||||||
tag: "search-service"
|
|
||||||
labels: "service"
|
|
||||||
labels:
|
|
||||||
- "service=search-service"
|
|
||||||
|
|
|
||||||
|
|
@ -1,179 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
CLI tool to query and analyze Docker logs from index-service and search-service.
|
|
||||||
|
|
||||||
Usage:
|
|
||||||
python3 analyze.py # tail both services, live
|
|
||||||
python3 analyze.py --service search # filter by service
|
|
||||||
python3 analyze.py --level ERROR # filter by log level
|
|
||||||
python3 analyze.py --grep "qdrant" # grep in log message
|
|
||||||
python3 analyze.py --last 100 # last N lines per service
|
|
||||||
python3 analyze.py --since 10m # since N minutes/hours ago (e.g. 10m, 2h)
|
|
||||||
python3 analyze.py --stats # show request count / error rate summary
|
|
||||||
"""
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
from datetime import datetime, timezone
|
|
||||||
|
|
||||||
SERVICES = {
|
|
||||||
"index": "hackaton-index-1",
|
|
||||||
"search": "hackaton-search-1",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def _run(cmd: list[str], **kwargs) -> subprocess.CompletedProcess:
|
|
||||||
return subprocess.run(cmd, capture_output=True, text=True, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def _detect_container_name(service: str) -> str:
|
|
||||||
"""Find the actual running container name for a service."""
|
|
||||||
candidates = [
|
|
||||||
f"hackaton-{service}-1",
|
|
||||||
f"hackaton_{service}_1",
|
|
||||||
f"{service}-1",
|
|
||||||
f"{service}_1",
|
|
||||||
]
|
|
||||||
result = _run(["docker", "ps", "--format", "{{.Names}}"])
|
|
||||||
running = result.stdout.splitlines()
|
|
||||||
for name in candidates:
|
|
||||||
if name in running:
|
|
||||||
return name
|
|
||||||
# fallback: try matching by label
|
|
||||||
result2 = _run(
|
|
||||||
["docker", "ps", "--filter", f"label=service={service}-service", "--format", "{{.Names}}"]
|
|
||||||
)
|
|
||||||
names = result2.stdout.strip().splitlines()
|
|
||||||
if names:
|
|
||||||
return names[0]
|
|
||||||
return candidates[0]
|
|
||||||
|
|
||||||
|
|
||||||
def _docker_logs(container: str, since: str | None, last: int) -> list[str]:
|
|
||||||
cmd = ["docker", "logs", "--timestamps"]
|
|
||||||
if since:
|
|
||||||
cmd += ["--since", since]
|
|
||||||
if last:
|
|
||||||
cmd += ["--tail", str(last)]
|
|
||||||
cmd.append(container)
|
|
||||||
result = _run(cmd)
|
|
||||||
lines = (result.stdout + result.stderr).splitlines()
|
|
||||||
return lines
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_line(raw: str) -> dict:
|
|
||||||
"""Try to extract structured fields from a log line."""
|
|
||||||
# Docker prepends an RFC3339 timestamp
|
|
||||||
ts_match = re.match(r"^(\d{4}-\d{2}-\d{2}T[\d:.+Z-]+)\s+(.*)", raw)
|
|
||||||
ts = ""
|
|
||||||
message = raw
|
|
||||||
if ts_match:
|
|
||||||
ts = ts_match.group(1)
|
|
||||||
message = ts_match.group(2)
|
|
||||||
|
|
||||||
level = "INFO"
|
|
||||||
for lvl in ("CRITICAL", "ERROR", "WARNING", "WARN", "INFO", "DEBUG"):
|
|
||||||
if lvl in message.upper():
|
|
||||||
level = lvl if lvl != "WARN" else "WARNING"
|
|
||||||
break
|
|
||||||
|
|
||||||
return {"ts": ts, "level": level, "message": message, "raw": raw}
|
|
||||||
|
|
||||||
|
|
||||||
def _color(level: str) -> str:
|
|
||||||
return {
|
|
||||||
"ERROR": "\033[31m",
|
|
||||||
"CRITICAL": "\033[35m",
|
|
||||||
"WARNING": "\033[33m",
|
|
||||||
"INFO": "\033[0m",
|
|
||||||
"DEBUG": "\033[36m",
|
|
||||||
}.get(level, "\033[0m")
|
|
||||||
|
|
||||||
|
|
||||||
RESET = "\033[0m"
|
|
||||||
|
|
||||||
|
|
||||||
def cmd_tail(args: argparse.Namespace) -> None:
|
|
||||||
services = [args.service] if args.service else list(SERVICES.keys())
|
|
||||||
for svc in services:
|
|
||||||
container = _detect_container_name(svc)
|
|
||||||
lines = _docker_logs(container, args.since, args.last)
|
|
||||||
print(f"\n{'='*60}")
|
|
||||||
print(f" {svc.upper()} SERVICE ({container})")
|
|
||||||
print(f"{'='*60}")
|
|
||||||
count = 0
|
|
||||||
for raw in lines:
|
|
||||||
parsed = _parse_line(raw)
|
|
||||||
if args.level and parsed["level"] != args.level.upper():
|
|
||||||
continue
|
|
||||||
if args.grep and args.grep.lower() not in parsed["message"].lower():
|
|
||||||
continue
|
|
||||||
color = _color(parsed["level"])
|
|
||||||
print(f"{color}{parsed['raw']}{RESET}")
|
|
||||||
count += 1
|
|
||||||
print(f" → {count} lines shown")
|
|
||||||
|
|
||||||
|
|
||||||
def cmd_stats(args: argparse.Namespace) -> None:
|
|
||||||
services = [args.service] if args.service else list(SERVICES.keys())
|
|
||||||
for svc in services:
|
|
||||||
container = _detect_container_name(svc)
|
|
||||||
lines = _docker_logs(container, args.since, args.last)
|
|
||||||
|
|
||||||
counts: dict[str, int] = {"ERROR": 0, "WARNING": 0, "INFO": 0, "DEBUG": 0, "CRITICAL": 0}
|
|
||||||
requests = 0
|
|
||||||
errors_5xx = 0
|
|
||||||
|
|
||||||
for raw in lines:
|
|
||||||
parsed = _parse_line(raw)
|
|
||||||
lvl = parsed["level"]
|
|
||||||
counts[lvl] = counts.get(lvl, 0) + 1
|
|
||||||
msg = parsed["message"]
|
|
||||||
if re.search(r'"(GET|POST|PUT|DELETE|PATCH)\s', msg):
|
|
||||||
requests += 1
|
|
||||||
if re.search(r'" 5\d\d ', msg):
|
|
||||||
errors_5xx += 1
|
|
||||||
|
|
||||||
print(f"\n{'='*50}")
|
|
||||||
print(f" STATS: {svc.upper()} SERVICE")
|
|
||||||
print(f"{'='*50}")
|
|
||||||
print(f" Total lines : {sum(counts.values())}")
|
|
||||||
print(f" HTTP requests: {requests}")
|
|
||||||
print(f" 5xx errors : {errors_5xx}")
|
|
||||||
print(f" ERROR lines : {counts['ERROR']}")
|
|
||||||
print(f" WARNING lines: {counts['WARNING']}")
|
|
||||||
print(f" INFO lines : {counts['INFO']}")
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="Analyze Docker logs for index-service and search-service",
|
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
||||||
epilog=__doc__,
|
|
||||||
)
|
|
||||||
parser.add_argument("--service", choices=list(SERVICES.keys()), help="Filter by service")
|
|
||||||
parser.add_argument("--level", help="Filter by log level (ERROR, WARNING, INFO, DEBUG)")
|
|
||||||
parser.add_argument("--grep", help="Substring filter on log message")
|
|
||||||
parser.add_argument("--last", type=int, default=200, help="Last N lines per service (default 200)")
|
|
||||||
parser.add_argument("--since", help="Show logs since duration (e.g. 10m, 2h, 30s)")
|
|
||||||
parser.add_argument("--stats", action="store_true", help="Show stats summary instead of log lines")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
try:
|
|
||||||
if args.stats:
|
|
||||||
cmd_stats(args)
|
|
||||||
else:
|
|
||||||
cmd_tail(args)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("\nInterrupted.")
|
|
||||||
except FileNotFoundError:
|
|
||||||
print("ERROR: docker not found in PATH", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
services:
|
|
||||||
dozzle:
|
|
||||||
image: amir20/dozzle:latest
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
||||||
ports:
|
|
||||||
- "9999:8080"
|
|
||||||
environment:
|
|
||||||
DOZZLE_FILTER: "label=service"
|
|
||||||
DOZZLE_LEVEL: info
|
|
||||||
DOZZLE_ENABLE_ACTIONS: "false"
|
|
||||||
restart: unless-stopped
|
|
||||||
Loading…
Reference in a new issue