feat(sofiia-console): add structured json logging for chat ops
Made-with: Cursor
This commit is contained in:
88
tests/test_sofiia_structured_logging.py
Normal file
88
tests/test_sofiia_structured_logging.py
Normal file
@@ -0,0 +1,88 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
|
||||
def _create_chat(client, agent_id: str, node_id: str, ref: str) -> str:
|
||||
r = client.post(
|
||||
"/api/chats",
|
||||
json={
|
||||
"agent_id": agent_id,
|
||||
"node_id": node_id,
|
||||
"source": "web",
|
||||
"external_chat_ref": ref,
|
||||
},
|
||||
)
|
||||
assert r.status_code == 200, r.text
|
||||
return r.json()["chat"]["chat_id"]
|
||||
|
||||
|
||||
def _event_messages(caplog, event: str):
|
||||
out = []
|
||||
for rec in caplog.records:
|
||||
try:
|
||||
payload = json.loads(rec.getMessage())
|
||||
except Exception:
|
||||
continue
|
||||
if payload.get("event") == event:
|
||||
out.append(payload)
|
||||
return out
|
||||
|
||||
|
||||
def test_structured_logging_send_and_replay(sofiia_client, sofiia_module, monkeypatch, caplog):
|
||||
def _router_url(node_id: str) -> str:
|
||||
return {"NODA1": "http://noda1-router.test", "NODA2": "http://noda2-router.test"}.get(node_id, "")
|
||||
|
||||
async def _fake_infer(base_url, agent_id, text, **kwargs):
|
||||
return {"response": "ok-structured", "backend": "fake", "model": "fake-model"}
|
||||
|
||||
monkeypatch.setattr(sofiia_module, "get_router_url", _router_url)
|
||||
monkeypatch.setattr(sofiia_module, "infer", _fake_infer)
|
||||
|
||||
chat_id = _create_chat(sofiia_client, "sofiia", "NODA1", "log-send")
|
||||
headers = {"Idempotency-Key": "idem-log-1", "X-Request-Id": "req-123"}
|
||||
|
||||
with caplog.at_level(logging.INFO, logger="sofiia"):
|
||||
r1 = sofiia_client.post(f"/api/chats/{chat_id}/send", json={"text": "hello"}, headers=headers)
|
||||
r2 = sofiia_client.post(f"/api/chats/{chat_id}/send", json={"text": "hello"}, headers=headers)
|
||||
|
||||
assert r1.status_code == 200, r1.text
|
||||
assert r2.status_code == 200, r2.text
|
||||
assert r2.json().get("idempotency", {}).get("replayed") is True
|
||||
|
||||
send_events = _event_messages(caplog, "chat.send")
|
||||
replay_events = _event_messages(caplog, "chat.send.replay")
|
||||
ok_events = _event_messages(caplog, "chat.send.ok")
|
||||
|
||||
assert send_events, "Expected chat.send structured log"
|
||||
assert replay_events, "Expected chat.send.replay structured log"
|
||||
assert ok_events, "Expected chat.send.ok structured log"
|
||||
|
||||
first_send = send_events[0]
|
||||
assert first_send["chat_id"] == chat_id
|
||||
assert first_send["node_id"] == "NODA1"
|
||||
assert first_send["event"] == "chat.send"
|
||||
assert first_send["request_id"] == "req-123"
|
||||
assert "idempotency_key_hash" in first_send
|
||||
|
||||
replay = replay_events[0]
|
||||
assert replay["chat_id"] == chat_id
|
||||
assert replay["status"] == "ok"
|
||||
assert replay["replayed"] is True
|
||||
|
||||
|
||||
def test_structured_logging_pagination_events(sofiia_client, caplog):
|
||||
with caplog.at_level(logging.INFO, logger="sofiia"):
|
||||
r = sofiia_client.get("/api/chats?nodes=NODA1,NODA2&limit=5")
|
||||
|
||||
assert r.status_code == 200, r.text
|
||||
list_events = _event_messages(caplog, "chat.list")
|
||||
assert list_events, "Expected chat.list structured log"
|
||||
|
||||
entry = list_events[0]
|
||||
assert entry["event"] == "chat.list"
|
||||
assert entry["limit"] == 5
|
||||
assert "cursor_present" in entry
|
||||
assert "has_more" in entry
|
||||
assert entry["status"] == "ok"
|
||||
Reference in New Issue
Block a user