petter2025 commited on
Commit
8299ce4
·
verified ·
1 Parent(s): 0f7833b

Upload folder using huggingface_hub

Browse files
app/core/usage_tracker.py CHANGED
@@ -621,6 +621,40 @@ class UsageTracker:
621
  self._mark_idempotent_key_used(idempotency_key)
622
  return True, None
623
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
624
  # --------------------------------------------------------------------------
625
  # Legacy interface (kept for compatibility)
626
  # --------------------------------------------------------------------------
 
621
  self._mark_idempotent_key_used(idempotency_key)
622
  return True, None
623
 
624
+ def _insert_audit_log(self, record: UsageRecord) -> None:
625
+ """Insert a standalone usage_log row for a call whose quota was
626
+ already consumed at request time (see consume_quota_and_log) --
627
+ used by routes_governance.py's background tasks to record the
628
+ response body once it's known, under a distinct endpoint suffix
629
+ (e.g. ".../response"). Best-effort and logged, not raised, for the
630
+ same reason _record_pg_monthly_count is: this runs after the
631
+ response has already been sent to the caller, so it must not
632
+ surface as a request failure -- a background task exception here
633
+ is otherwise swallowed silently. `record.tier` is None at both real
634
+ call sites (tier only matters for quota consumption, already done
635
+ by the earlier consume_quota_and_log call for the same request),
636
+ but usage_log.tier is NOT NULL, so an absent tier is recorded as
637
+ "unknown" rather than raising or silently guessing a real tier."""
638
+ tier_value = record.tier.value if record.tier else "unknown"
639
+ try:
640
+ with self._get_conn() as conn:
641
+ conn.execute(
642
+ """INSERT INTO usage_log
643
+ (api_key, tier, timestamp, endpoint, request_body, response, error,
644
+ processing_ms, idempotency_key)
645
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""",
646
+ (record.api_key, tier_value, record.timestamp, record.endpoint,
647
+ json.dumps(record.request_body) if record.request_body else None,
648
+ json.dumps(record.response) if record.response else None,
649
+ record.error, record.processing_ms, None)
650
+ )
651
+ conn.commit()
652
+ except Exception:
653
+ logger.error(
654
+ "Failed to insert audit log for api_key=%s endpoint=%s",
655
+ record.api_key, record.endpoint, exc_info=True,
656
+ )
657
+
658
  # --------------------------------------------------------------------------
659
  # Legacy interface (kept for compatibility)
660
  # --------------------------------------------------------------------------
tests/test_usage_tracker.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import os
2
 
3
  import psycopg2
@@ -149,3 +150,30 @@ def test_increment_usage_sync_succeeds_even_if_postgres_mirror_fails(tracker, mo
149
  result = tracker.increment_usage_sync(record)
150
  assert result is True
151
  assert tracker.get_remaining_quota("mirror-fail-key", Tier.FREE) == 999
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
  import os
3
 
4
  import psycopg2
 
150
  result = tracker.increment_usage_sync(record)
151
  assert result is True
152
  assert tracker.get_remaining_quota("mirror-fail-key", Tier.FREE) == 999
153
+
154
+
155
+ def test_insert_audit_log_writes_response_row(tracker):
156
+ """routes_governance.py schedules current_tracker._insert_audit_log as
157
+ a background task (background_tasks.add_task) to record the response
158
+ body once it's known, at app/api/routes_governance.py:407 and :738 --
159
+ always with tier=None, since quota was already consumed by an earlier
160
+ consume_quota_and_log call for the same request. The real UsageTracker
161
+ had no such method (only tests/conftest.py's MockTracker did), so every
162
+ real call raised AttributeError inside the background task (arf-api-002)."""
163
+ record = UsageRecord(
164
+ api_key="audit-log-key",
165
+ tier=None,
166
+ timestamp=time.time(),
167
+ endpoint="/api/v1/intents/evaluate/response",
168
+ request_body=None,
169
+ response={"recommended_action": "approve"},
170
+ processing_ms=12.5,
171
+ )
172
+
173
+ tracker._insert_audit_log(record)
174
+
175
+ logs = tracker.get_audit_logs("audit-log-key", limit=10)
176
+ assert len(logs) == 1
177
+ assert logs[0]["endpoint"] == "/api/v1/intents/evaluate/response"
178
+ assert logs[0]["tier"] == "unknown"
179
+ assert json.loads(logs[0]["response"]) == {"recommended_action": "approve"}