Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions chelation_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ def __init__(
Initialize logger.

Args:
log_path: Path to log file (default: chelation_debug.jsonl)
log_path: Path to log file (default: chelation_events.jsonl)
console_level: Logging level for console output
file_level: (Unused - kept for backward compatibility)
"""
self.log_path = log_path or Path("chelation_debug.jsonl")
self.log_path = log_path or Path("chelation_events.jsonl")
self.start_time = time.time()
self.operation_stack = [] # Track nested operations

Expand Down
28 changes: 22 additions & 6 deletions dashboard_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -1154,12 +1154,9 @@ def filter_events(
# Generic event_type field filter
filtered = [e for e in filtered if e.get("event_type") == event_type]

# Sort by timestamp (most recent first)
filtered = sorted(
filtered,
key=lambda e: e.get("timestamp", 0),
reverse=True
)
# Sort by timestamp (most recent first). ISO strings and missing values
# must not be compared with each other as str and int.
filtered = sorted(filtered, key=_event_sort_value, reverse=True)

# Apply limit (0 means no rows; clamped above at _MAX_API_LIMIT)
if limit is not None:
Expand All @@ -1168,6 +1165,25 @@ def filter_events(
return filtered


def _event_sort_value(event: Dict[str, Any]) -> float:
"""Numeric sort key. Naive ISO datetimes are UTC. Missing values sort as 0."""
stamp = event.get("timestamp", None)
if isinstance(stamp, bool):
return 0.0
if isinstance(stamp, (int, float)):
return float(stamp)
if isinstance(stamp, str) and stamp:
text = stamp
if not (text.endswith("Z") or len(text) >= 6 and text[-6] in "+-" and text[-3] == ":"):
text = text + "Z"
try:
parsed = datetime.fromisoformat(text.replace("Z", "+00:00"))
except ValueError:
return 0.0
return parsed.timestamp()
return 0.0


def _first_present(payload: Dict[str, Any], keys: List[str]) -> Any:
for key in keys:
if key in payload:
Expand Down
31 changes: 31 additions & 0 deletions test_event_log_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Default event-log path and mixed timestamp sorting."""

import unittest
from pathlib import Path

import dashboard_server
from chelation_logger import ChelationLogger


class TestEventLogContract(unittest.TestCase):
def test_default_log_path_matches_dashboard_events_file(self):
logger = ChelationLogger(console_level="ERROR")
self.assertEqual(logger.log_path, Path("chelation_events.jsonl"))
self.assertEqual(dashboard_server.LOG_FILE_PATH, "chelation_events.jsonl")
explicit = ChelationLogger(log_path=Path("custom.jsonl"), console_level="ERROR")
self.assertEqual(explicit.log_path, Path("custom.jsonl"))

def test_filter_iso_timestamp_does_not_crash_when_timestamp_missing(self):
rows = [
{"timestamp": "2026-09-24T00:00:00", "query_snippet": "a"},
{"message": "no ts"},
]
result = dashboard_server.filter_events(rows)
self.assertEqual(len(result), 2)
self.assertEqual(result[0]["timestamp"], "2026-09-24T00:00:00")
self.assertEqual(result[0]["query_snippet"], "a")
self.assertEqual(result[1]["message"], "no ts")


if __name__ == "__main__":
unittest.main()
Loading