Ryanfafa commited on
Commit
9e50d20
·
verified ·
1 Parent(s): ce4796a

Upload monitor.py

Browse files
Files changed (1) hide show
  1. monitor.py +136 -0
monitor.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ monitor.py
3
+ Lightweight monitoring logger for DocMind AI.
4
+ Logs every query, retrieval, LLM response, latency, and errors
5
+ to a local JSONL file readable from HuggingFace Logs tab.
6
+ """
7
+
8
+ import json
9
+ import time
10
+ import os
11
+ from datetime import datetime, timezone
12
+
13
+
14
+ LOG_FILE = "/tmp/docmind_logs.jsonl"
15
+
16
+
17
+ def log_query(
18
+ question: str,
19
+ answer: str,
20
+ sources: list,
21
+ latency_ms: float,
22
+ model_used: str = "",
23
+ chunk_count: int = 0,
24
+ error: str = "",
25
+ ):
26
+ """Log a single query event."""
27
+ entry = {
28
+ "timestamp": datetime.now(timezone.utc).isoformat(),
29
+ "event": "query",
30
+ "question": question[:200], # truncate for log size
31
+ "answer_len": len(answer),
32
+ "sources": sources,
33
+ "latency_ms": round(latency_ms, 1),
34
+ "model": model_used,
35
+ "chunk_count": chunk_count,
36
+ "error": error,
37
+ "success": not bool(error),
38
+ }
39
+ _write(entry)
40
+ _print_summary(entry)
41
+
42
+
43
+ def log_ingestion(filename: str, chunk_count: int, latency_ms: float, error: str = ""):
44
+ """Log a document ingestion event."""
45
+ entry = {
46
+ "timestamp": datetime.now(timezone.utc).isoformat(),
47
+ "event": "ingestion",
48
+ "filename": filename,
49
+ "chunk_count": chunk_count,
50
+ "latency_ms": round(latency_ms, 1),
51
+ "error": error,
52
+ "success": not bool(error),
53
+ }
54
+ _write(entry)
55
+ _print_summary(entry)
56
+
57
+
58
+ def log_startup():
59
+ """Log app startup."""
60
+ entry = {
61
+ "timestamp": datetime.now(timezone.utc).isoformat(),
62
+ "event": "startup",
63
+ "message": "DocMind AI started",
64
+ }
65
+ _write(entry)
66
+ print("[DocMind] App started at {}".format(entry["timestamp"]))
67
+
68
+
69
+ def get_stats() -> dict:
70
+ """Read log file and compute summary stats."""
71
+ if not os.path.exists(LOG_FILE):
72
+ return {
73
+ "total_queries": 0,
74
+ "success_rate": 0.0,
75
+ "avg_latency_ms": 0.0,
76
+ "total_ingestions": 0,
77
+ "errors": [],
78
+ }
79
+
80
+ queries = []
81
+ ingestions = []
82
+ errors = []
83
+
84
+ with open(LOG_FILE, "r") as f:
85
+ for line in f:
86
+ try:
87
+ entry = json.loads(line.strip())
88
+ if entry["event"] == "query":
89
+ queries.append(entry)
90
+ if entry.get("error"):
91
+ errors.append(entry)
92
+ elif entry["event"] == "ingestion":
93
+ ingestions.append(entry)
94
+ except Exception:
95
+ continue
96
+
97
+ success_count = sum(1 for q in queries if q.get("success"))
98
+ latencies = [q["latency_ms"] for q in queries if q.get("latency_ms")]
99
+
100
+ return {
101
+ "total_queries": len(queries),
102
+ "success_rate": round(success_count / len(queries) * 100, 1) if queries else 0.0,
103
+ "avg_latency_ms": round(sum(latencies) / len(latencies), 1) if latencies else 0.0,
104
+ "min_latency_ms": round(min(latencies), 1) if latencies else 0.0,
105
+ "max_latency_ms": round(max(latencies), 1) if latencies else 0.0,
106
+ "total_ingestions": len(ingestions),
107
+ "total_errors": len(errors),
108
+ "recent_errors": [e.get("error", "") for e in errors[-3:]],
109
+ }
110
+
111
+
112
+ def _write(entry: dict):
113
+ try:
114
+ with open(LOG_FILE, "a") as f:
115
+ f.write(json.dumps(entry) + "\n")
116
+ except Exception as e:
117
+ print("[DocMind Monitor] Failed to write log: {}".format(e))
118
+
119
+
120
+ def _print_summary(entry: dict):
121
+ """Print to stdout so it shows in HuggingFace Logs tab."""
122
+ if entry["event"] == "query":
123
+ status = "OK" if entry["success"] else "ERROR"
124
+ print("[DocMind][{}] Q: '{}...' | Latency: {}ms | Model: {} | AnswerLen: {}".format(
125
+ status,
126
+ entry["question"][:50],
127
+ entry["latency_ms"],
128
+ entry.get("model", "unknown"),
129
+ entry["answer_len"],
130
+ ))
131
+ elif entry["event"] == "ingestion":
132
+ print("[DocMind][INGEST] File: {} | Chunks: {} | Latency: {}ms".format(
133
+ entry["filename"],
134
+ entry["chunk_count"],
135
+ entry["latency_ms"],
136
+ ))