docmind-ai / monitor.py
Ryanfafa's picture
Upload monitor.py
9e50d20 verified
"""
monitor.py
Lightweight monitoring logger for DocMind AI.
Logs every query, retrieval, LLM response, latency, and errors
to a local JSONL file readable from HuggingFace Logs tab.
"""
import json
import time
import os
from datetime import datetime, timezone
LOG_FILE = "/tmp/docmind_logs.jsonl"
def log_query(
question: str,
answer: str,
sources: list,
latency_ms: float,
model_used: str = "",
chunk_count: int = 0,
error: str = "",
):
"""Log a single query event."""
entry = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"event": "query",
"question": question[:200], # truncate for log size
"answer_len": len(answer),
"sources": sources,
"latency_ms": round(latency_ms, 1),
"model": model_used,
"chunk_count": chunk_count,
"error": error,
"success": not bool(error),
}
_write(entry)
_print_summary(entry)
def log_ingestion(filename: str, chunk_count: int, latency_ms: float, error: str = ""):
"""Log a document ingestion event."""
entry = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"event": "ingestion",
"filename": filename,
"chunk_count": chunk_count,
"latency_ms": round(latency_ms, 1),
"error": error,
"success": not bool(error),
}
_write(entry)
_print_summary(entry)
def log_startup():
"""Log app startup."""
entry = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"event": "startup",
"message": "DocMind AI started",
}
_write(entry)
print("[DocMind] App started at {}".format(entry["timestamp"]))
def get_stats() -> dict:
"""Read log file and compute summary stats."""
if not os.path.exists(LOG_FILE):
return {
"total_queries": 0,
"success_rate": 0.0,
"avg_latency_ms": 0.0,
"total_ingestions": 0,
"errors": [],
}
queries = []
ingestions = []
errors = []
with open(LOG_FILE, "r") as f:
for line in f:
try:
entry = json.loads(line.strip())
if entry["event"] == "query":
queries.append(entry)
if entry.get("error"):
errors.append(entry)
elif entry["event"] == "ingestion":
ingestions.append(entry)
except Exception:
continue
success_count = sum(1 for q in queries if q.get("success"))
latencies = [q["latency_ms"] for q in queries if q.get("latency_ms")]
return {
"total_queries": len(queries),
"success_rate": round(success_count / len(queries) * 100, 1) if queries else 0.0,
"avg_latency_ms": round(sum(latencies) / len(latencies), 1) if latencies else 0.0,
"min_latency_ms": round(min(latencies), 1) if latencies else 0.0,
"max_latency_ms": round(max(latencies), 1) if latencies else 0.0,
"total_ingestions": len(ingestions),
"total_errors": len(errors),
"recent_errors": [e.get("error", "") for e in errors[-3:]],
}
def _write(entry: dict):
try:
with open(LOG_FILE, "a") as f:
f.write(json.dumps(entry) + "\n")
except Exception as e:
print("[DocMind Monitor] Failed to write log: {}".format(e))
def _print_summary(entry: dict):
"""Print to stdout so it shows in HuggingFace Logs tab."""
if entry["event"] == "query":
status = "OK" if entry["success"] else "ERROR"
print("[DocMind][{}] Q: '{}...' | Latency: {}ms | Model: {} | AnswerLen: {}".format(
status,
entry["question"][:50],
entry["latency_ms"],
entry.get("model", "unknown"),
entry["answer_len"],
))
elif entry["event"] == "ingestion":
print("[DocMind][INGEST] File: {} | Chunks: {} | Latency: {}ms".format(
entry["filename"],
entry["chunk_count"],
entry["latency_ms"],
))