Repository navigation
feat(filters): Logs Ingestion API for the time token tracker (2.7.0) - #191
Conversation
…188) Microsoft deprecated the HTTP Data Collector API the tracker sends through (support ended 2026-09-14). The tracker now also sends through the Azure Monitor Logs Ingestion API (data collection rule, Microsoft Entra ID token from a client secret, a managed identity or AKS workload identity) without new dependencies. The Data Collector request stays byte-identical as the fallback for existing configurations and logs a one-time deprecation warning. - 10 new valves with environment defaults, LOG_ANALYTICS_LOG_TYPE gets one too; LOG_ANALYTICS_INGESTION_API selects auto, logs_ingestion, data_collector or both - tokens cached per identity (one request per key, refreshed before expiry, a still-valid token outlives a failed refresh, 30 s back-off); the client secret is decrypted only for the token request and secrets and tokens are redacted from error texts - one actionable log line per failed record, no retries - docs: DCR templates for an in-place table migration and a side-by-side table, identity and role setup, sovereign clouds, troubleshooting - e2e: token, DCR and managed identity routes in mock_la.py, a PROBE_ENV hook in the probe pipe, the filters.ingest group (34 checks) and two spec checks +semver: minor Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Token errors of the App Service / Container Apps token service
({statusCode, message, correlationId}) were logged as "400 error - "
without a reason; they now show the message, the correlation ID and a
LOG_ANALYTICS_CLIENT_ID hint. Every field of a token error is redacted
before it is cut, so no fragment of a secret survives the truncation.
An empty LOG_ANALYTICS_LOG_TYPE variable counts as unset again, as in
2.6.2, instead of sending an empty Log-Type.
The e2e suite now kills the mutants the review found surviving:
second revocation, late 401, reuse before half the token lifetime,
a usable token inside the back-off, the back-off after 20 s, an
http:// authority, scope and tenant in the cache key, the DCR ID hint
once per value, auto with only the auth mode, both with one side
incomplete, redaction at the cut points, and the tracker's DEBUG
output (captured through the probe pipe's new PROBE_LOG hook). The
once-per-process warning checks no longer pass on a reused container
when the warning is never logged. The setup guide's troubleshooting
table covers the missing log lines.
+semver: none
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CodeQL flags the secret_ok/assertion_ok values in the mock's log line as clear-text logging of sensitive data. The HTTP status in the same line already shows whether the credentials were accepted. +semver: none Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Converted to draft: per maintainer decision this becomes Time Token Tracker 3.0.0 with the Logs Ingestion API only. The HTTP Data Collector path and its valves are removed; users who need it stay on 2.6.2. The rework is in progress; the description will be updated when it is ready. |
|
Update: the 3.0.0 rework was stopped before any code change. This PR stays 2.7.0, backward compatible: Microsoft ended support for the HTTP Data Collector API but ingestion still works and no shutdown date is announced, and the |
Brings in Azure AI Foundry 3.0.0 (#195): pipeline-side Azure AI Search, mocks/mock_search.py on 127.0.0.1:9106 and the azure rag group. Conflicts: README.md and docs/testing.md keep both sides (counts table: azure 198 from main, filters 101 from this branch). The azure docs, pipeline and suite conflicted only through the criss-cross merge base; this branch never changed them, so main's version is taken. +semver: none Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mocks/mock_search.py (serve_all.py, Azure AI Foundry 3.0.0) listens on 127.0.0.1:9106 from the container start, so mock_la.py could not open its App Service / IMDS listeners there and the filters suite could not start its Log Analytics mock. mock_la.py now serves managed identity on 127.0.0.1:9107 and 127.0.0.2:9107; the filters suite, serve_all.py, harness/config.py and docs/testing.md say so. +semver: none Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ngest group Since Azure AI Foundry 3.0.0, run.sh starts the container with IDENTITY_ENDPOINT / IDENTITY_HEADER (App Service managed identity from mocks/mock_search.py, azure rag group). The filters ingest group removed every managed identity variable from the server process at its end, so an azure suite after it (`run.sh filters azure`, or --reuse) lost its managed identity. The group now restores the container's own values, which the driver reads from its environment; the probe pipe's comment no longer claims that the container sets none of them. +semver: none Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Measured on the merged branch (v0.11.4-slim, normal and strict known mode): 463 checks, 462 PASS / 1 KNOWN, 1000 s for all suites (filters 259 s with the ingest group); v0.11.3-slim gives the same azure and filters counts. README.md said "about 300 checks in 7-10 minutes" again since 87eb6fb, which undid 6d6d3ee; it now says about 500 checks in 15-20 minutes. +semver: none Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…/gemini-native-tool-calling Brings Time Token Tracker 2.7.0 with the Logs Ingestion API (#191), merged with main 4b80e24, and its filters suite (mock_la.py with the managed identity endpoints on 127.0.0.1/127.0.0.2:9107). config.py keeps search 9106 with #191's comment on 9105/9107 next to tools 9111 and MCP 9112. docs/testing.md keeps the native tool calling section, takes #191's filters row, PROBE_ENV / PROBE_LOG, mock_la setup and output file rows, and combines the counts (filters 101, total 531); the layout lists :9106, :9111, :9112 and mock_la's :443, :9105, :9107. +semver: none Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ogs Ingestion API Measured on the merged tree (main 4b80e24 + #191 + #193): 531 checks, 530 PASS / 1 KNOWN on v0.11.4-slim (normal and strict known mode) and on v0.11.3-slim, about 19 minutes per full run. The sample output, the timing paragraph, the counts header and the meta-test row (57 PASS / 370 FAIL / 0 KNOWN with main's files) now say so. +semver: none Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Problem
time_token_tracker.pysends one record per response through the HTTP Data Collector API (workspace shared key). Microsoft ended support for it on September 14, 2026. Ingestion still works with TLS 1.2+, but the API gets no fixes and does not work with Azure Monitor Private Link (AMPLS). The replacement is the Logs Ingestion API: it is based on a data collection rule (DCR) and authenticates with a Microsoft Entra ID token.Change (Time Token Tracker 2.6.2 → 2.7.0)
New mode valve
LOG_ANALYTICS_INGESTION_API:auto(default) |logs_ingestion|data_collector|both.auto, records go to the Logs Ingestion API once its settings are complete. Otherwise they go through the Data Collector API exactly as in 2.6.2: same request, signature and headers, plus a one-time deprecation warning.bothwrites each record to both APIs for a side-by-side migration. One failing side does not stop the other.New valves, all with environment-variable defaults:
LOG_ANALYTICS_DCR_ENDPOINT,LOG_ANALYTICS_DCR_IMMUTABLE_ID,LOG_ANALYTICS_DCR_STREAM_NAME(derived fromLOG_ANALYTICS_LOG_TYPEwhen empty);LOG_ANALYTICS_AUTH_MODE,LOG_ANALYTICS_TENANT_ID,LOG_ANALYTICS_CLIENT_ID;LOG_ANALYTICS_CLIENT_SECRET(EncryptedStr, password input);LOG_ANALYTICS_AUTHORITY_HOSTandLOG_ANALYTICS_INGESTION_SCOPE, for sovereign clouds.No valve is renamed or removed.
LOG_ANALYTICS_LOG_TYPEcan now also be set by environment variable; an empty variable counts as unset.Tokens need no extra packages (aiohttp only):
IDENTITY_ENDPOINT) and on VMs (IMDS);Tokens are cached per identity and refreshed before they expire. Concurrent records share one token request, and a failed refresh keeps using the still-valid token. After a failed token request, or after repeated 401s with fresh tokens, new token requests pause for 30 s. The authority and the endpoint must use https.
Sending:
Secrets: the client secret is decrypted only for the token request. The secret and the token never appear in logs, status events or error texts. Token errors are redacted before they are cut.
Docs (
docs/setup-azure-log-analytics.md):getschema;OpenWebuiMetrics_CLin place, with a DCR whosetransformKqlkeeps the existing suffixed columns, so Power BI and saved queries keep working. Migration is irreversible; this is called out;README and the docstring are updated as well.
E2E (filters suite, 57 → 101 checks):
mock_la.pynow emulates the token endpoint, the managed-identity endpoints and the DCR ingestion endpoint (Bearer check, URI, body, 204, error injection).ingestgroup covers mode selection, the fallback,both, token caching and refresh, the back-off, managed identity, every HTTP error, slow or hanging endpoints, and no secrets in the logs. That last check also covers DEBUG output, which the probe pipe now captures.Verification
Merging main (#195, Azure 3.0.0) needed two test-harness changes: the managed-identity mock moved from port 9106 to 9107, because 9106 is now the Azure AI Search mock, and the
ingestgroup gives the container itsIDENTITY_ENDPOINT/IDENTITY_HEADERback when it ends, so a later azure suite in the same container keeps its managed identity. The filter itself is unchanged.--strict-known--strict-knowninfomaniak-name-prefix, no fix yet)--strict-knowninfomaniak-name-prefix), 463 checks--strict-knownE2E_MOCK_FAULT=500)Before the code was written, the API facts were checked against Microsoft Learn, the azure-rest-api-specs and the SDK sources, and a critic reviewed the spec.
Three reviews followed (API and docs, security and compatibility, mutation testing). All 18 findings were fixed, 7 of them major.
Not verified against a real Azure tenant
x-ms-error-codevalues;OpenWebuiMetrics_CLreally has (_gvs_s,timestamp_t). The docs tell users to check withgetschemabefore writing the DCR;Closes #188
🤖 Generated with Claude Code