Skip to content

Log Event Reference ​

Applies to: SWAO v1.4.0+
Related issues: #3284 (shared LLM provider request helper), #3221, #3225, #3222

SWAO writes structured events to two NDJSON log files inside the workspace:

ScopeFile
Portfolio<workspace>/wsp/logs/portfolio-events-<YYYY-MM>.ndjson
App<workspace>/apps/<app-id>/wsp/logs/app-events-<YYYY-MM>.ndjson

Each line is one JSON object with ts (ISO 8601 UTC), level (debug, info, warn, error, enhancement), scope (portfolio or app), code (dotted event code), message, an optional context object and, for app scope, app_id (packages/@swao/core/src/log.ts). Events at warn and error are also printed on the terminal. Files rotate monthly.

Event context never contains prompt text, request bodies, image bytes, API keys or tokens (CLAUDE.md section 5.7). URL userinfo is stripped at write time.


1. LLM provider events ​

Every LLM call, for every provider and every call kind, runs through one shared request helper (packages/@swao/module-llm-providers/src/llm-request.ts, requestLlmWithRetry). It applies one retry policy, one attempt count, an idle watchdog and the provider-level concurrency limiter, and it writes the same event set for each provider.

1.1 Event codes ​

The code is provider.llm.<provider>.<event>, where <provider> is one of:

<provider>DriverCall kinds
anthropicanthropic.ts (also gateway protocol anthropic-messages)text, vision, tools
openaiopenai.tstext, vision
ollamaollama.ts (also gateway protocol ollama)text, vision
open-llm-provideropen-llm-provider.ts (also gateway protocol openai-chat)text, vision, tools
bedrockbedrock.ts (gateway protocol bedrock, AWS SDK)text
EventLevelWhenContext fields
attemptinfoAn attempt is sent (after a concurrency slot was granted)common fields, endpoint, prompt_chars, idle_timeout_ms, queued_ms; tools: iteration, max_iterations, tool_count
waitinginfo, or warn when no data arrived for 60 s on a streaming response or in the body phaseEvery 60 s while an attempt is outstandingcommon fields, phase (headers or body), elapsed_ms, ms_since_data, bytes_received, idle_timeout_ms, streaming
timeoutwarnThe idle or total limit ended the attempt; the request is aborted and retriedcommon fields, phase, limit (idle or total), limit_ms, elapsed_ms, bytes_received
http-errorwarn when transient or re-sent at once; error when final (open-llm-provider: warn, #1896)A non-2xx responsecommon fields, http_status, reason, latency_ms, body_excerpt (API error body, max 500 characters, PII fields removed for open-llm-provider), transient, retry_now; Anthropic: temperature_deprecated; open-llm: token_refreshed
retrywarnBefore the back-off sleep of the next attemptcommon fields, attempt (the attempt that failed), next_attempt, reason, delay_ms
okinfoThe attempt succeededcommon fields, http_status, latency_ms, tokens_in, tokens_out, cost_usd; open-llm: tokens_reasoning, content_source; Anthropic tools: stop_reason
errorerrorA non-retryable, non-HTTP failure (for example a missing response field)common fields, reason (non_retryable), error_name, error_message (max 300 characters), latency_ms
connectivity-failureerrorEvery attempt failed; the call throws a connectivity error and the pass degrades or fails over (#1703)provider, model, kind, image_count (vision), max_attempts, reason, last_error (max 300 characters)

Common fields: provider, model, kind (text, vision or tools), image_count (vision only), attempt, max_attempts.

Every message counts attempts the same way: attempt N/6. A retry line reads attempt 1/6 failed (...), retrying in 3s as attempt 2/6.

reason values: bad_request, auth, not_found, request_timeout, payload_too_large, rate_limited, overloaded, server_error, client_error (HTTP statuses), timeout_idle_headers, timeout_idle_body, timeout_total_headers, timeout_total_body (watchdog), network_or_malformed_response (network failure or a malformed or truncated response), non_retryable.

1.2 Portfolio and app scope ​

Every event above is written to the portfolio log. When the call runs in an app context (an assessment of one app), the same event with the same code and context is also written to that app's log. The app copy of a final http-error uses level warn. The app copy is not printed on the terminal a second time.

1.3 Other provider events ​

CodeLevelMeaningSource
provider.llm.anthropic.temperature-retryinfoThe model rejected the temperature field; the request is re-sent without it (no attempt consumed)anthropic.ts
provider.llm.anthropic.tool-resultinfoAn MCP tool returned a result in a chat tool loop (tool, raw_chars, scrubbed_chars)anthropic.ts
provider.llm.open-llm-provider.empty-responsewarnThe response carried neither content nor reasoning_content (completion_tokens, hint); portfolio and app scopeopen-llm-provider.ts
provider.open-llm.initinfoOpenLlmProvider built (model, hasProxy, tlsSkip)open-llm-provider.ts
provider.llm.egress.redactedinfoPre-LLM redaction replaced content before egress (counts only)egress-redaction.ts
provider.llm.unknownerrorUnknown legacy provider typefactory.ts
provider.llm.max-concurrency-invalidwarnproviders.llm.max_concurrency is not an integer from 1 to 64; the default appliesfactory.ts
provider.llm.leg-failoverwarnThe primary provider failed with a connectivity error; the secondary provider takes overpackages/swao/src/commands/assess.ts
provider.llm.gateway.model-not-in-cataloguewarnConfigured model is not in the connector catalogue (advisory)gateway/resolve.ts
provider.llm.gateway.token-command-executed, .token-command-failedinfo, warnConnector auth.token_command ran (the token is never logged)gateway/resolve.ts
provider.llm.gateway.tls-reject-unauthorized-disabled, .tls-ca-bundle-not-foundwarnConnector TLS overridesgateway/resolve.ts
provider.llm.gateway.alias-*warnModel alias resolution (alias-resolved, alias-no-match, alias-no-discovery, alias-discovery-failed, alias-batch-model)gateway/alias-resolver.ts

Paths without a package are under packages/@swao/module-llm-providers/src/.

1.4 Codes replaced in v1.4.0 (#3284) ​

Old codeNew code
provider.bedrock.retryprovider.llm.bedrock.retry (plus the full event set)
provider.llm.anthropic.tool-call-attemptprovider.llm.anthropic.attempt with kind: tools and iteration
provider.llm.gateway.ok (app scope)provider.llm.open-llm-provider.ok (portfolio and app scope)
provider.llm.gateway.http-error (app scope)provider.llm.open-llm-provider.http-error
provider.llm.gateway.empty-response (app scope)provider.llm.open-llm-provider.empty-response

2. Timeouts, retries and concurrency ​

SettingDefaultMeaning
Attempts per call6One initial attempt and up to 5 retries for every provider and call kind. Back-off 3, 6, 12, 24, 48 s. The health-check live ping uses 4 attempts so it answers within its 35 s ceiling.
Transient HTTP statuses408, 429, 5xx (including 529)Retried with back-off. Other statuses fail at once.
SWAO_LLM_IDLE_TIMEOUT_MS120000Per-attempt idle timeout in ms: the wait for response headers and every gap between body chunks. SWAO_ANTHROPIC_IDLE_TIMEOUT_MS is still accepted as an alias; the provider-neutral name wins when both are set.
Non-streaming headers floor300000OpenAI, Ollama, open-LLM, Bedrock and tool calls do not stream, so no data arrives until the model has finished. Their headers phase uses the larger of the idle timeout and 300 s.
Total cap per attempt600000Hard limit for one attempt, headers and body together.
providers.llm.max_concurrency4Maximum LLM requests in flight per endpoint (provider and endpoint origin), shared by all passes of the process. Integer from 1 to 64. Set it in the workspace .swao.yml.
Connector max_concurrencynoneA gateway connector file may set its own limit. It applies when .swao.yml sets none.
yaml
# .swao.yml
providers:
  llm:
    max_concurrency: 2        # client gateway allows two parallel requests
    primary:
      connector: my-gateway

Pass 11 (compliance) sends its batch prompts concurrently and sizes its fan-out from the same limit. A request waiting for a slot is not counted against the idle timeout; the wait is reported as queued_ms on the attempt event.


3. Other event families ​

Codes and meaning, sourced from code. Paths are under swao/packages/.

FamilyCodesMeaningSource
swao.run.*start, complete, abortedOne assessment run of an app: start and end. complete carries status (complete, partial, failed or aborted, as in run-status.json) and exit_code on every exit path, including gate exits (--fail-on) and errors (#3283); aborted is emitted for SIGINT, SIGTERM and uncaught exceptions onlyswao/src/commands/assess.ts, run-lifecycle.ts
assessment.*pass.start, pass.complete, pass.connectivity-failure, pass.provider-error, pass.invalid-llm-response, pass.fatal, heartbeatPer-pass lifecycle of the assess engine, LLM failures per pass, periodic heartbeatswao/src/commands/assess.ts
assess.post_run.*<step>.start, <step>.complete, <step>.failedTimed post-pass steps (file_counts, run_manifest, run_context, scope_coverage, portfolio_summary, plan_derivation, findings, pii_scrub, assessment_counter, run_retention); complete (level info, status: ok) and failed (level warn, status: error, plus error) carry duration_ms. A step logs one or the other, never both. A failed step is non-fatal; assessment_counter.failed also prints one operator warning and the run is not counted (one write attempt, no retry, so no double count) (#3440). The LLM Assessment and landing-zone catalogue flows have no post-run timer: there assessment_counter.failed is logged alone, without .start (expected, not an anomaly)swao/src/commands/post-run-timing.ts
assess.pass.*challenge.start/.skip/.complete, challenge-lz.start/.skip/.complete, sbom.external-inputs-foundChallenge passes and SBOM inputsswao/src/commands/assess.ts, @swao/module-app-assessment/src/passes/pass-05-sbom.ts
assess.app.*, assess.lz.*start, pass.start, pass.complete, complete, select.confirmed, provider.selected, region.selected, frameworks.selectedTUI assessment screens@swao/module-app-assessment/src/tui/assess/
assess.preflight.*llm.ping.ok, llm.ping.failTUI LLM preflight ping@swao/module-app-assessment/src/tui/assess/shared/PreflightLlmPhase.tsx
lz.assessment.*start, target.resolved, provider.start, provider.complete, provider.errorLanding zone assessment per provider and region targetswao/src/commands/assess.ts, lz-run-lifecycle.ts, lz-target-config.ts
lz.catalogue.*update.startLZ catalogue update@swao/module-landing-zone/src/commands/lz-premium.ts
dynamic.*start, complete, skip, error, playwright-absent, vision.start/.complete/.skipped/.cloud/.baseline/.baseline.errorDynamic analysis (Pass 10) and screenshot vision analysisswao/src/commands/assess.ts
ctx.pass.*ceiling-risk, truncation-detected, json-parse-errorContext pass (Pass 04) output limits@swao/module-app-assessment/src/passes/pass-04-ctx.ts
pass.iac.*, pass.malware.*scanner.start/.complete/.skipped, tools.missingIaC scanner and malware tools@swao/module-app-assessment/src/passes/
provider.vcs.*clone-start, clone-okSource repository cloneswao/src/commands/assess.ts
llm-assessment.*, leg.*, swao.llm.run.*start, refused, pass.start, pass.complete; leg.start/.heartbeat/.stall/.error/.complete; run.start, run.completeLLM Assessment (model comparison) orchestration and legsswao/src/commands/assess.ts, @swao/module-llm-assessment/src/orchestrator.ts
health-check.*start, probe.start, probe.complete, lz-catalogue-provenanceswao health-check probes@swao/module-health-check/src/commands/health-check.ts
report.generate.*start, ok, complete, errorswao reportswao/src/commands/report.ts
publish.*start, ok, complete, error, editor.start/.stop, template.exportHTML publication@swao/module-html-report/src/
export.*start, complete, errorPower BI export@swao/module-powerbi/src/export.ts
ingest.*start, complete, errorContext ingestionswao/src/commands/ingest.ts
credential.*stored, deleted, store.error, export, importCredential store (names only, never values)@swao/core/src/credential-store.ts, swao/src/commands/credential.ts
licence.*load, activate, remove, expired, invalid, upgrade_request, *.error, state.corruptLicence lifecycle and tier gates. state.corrupt (level error, portfolio scope): the licence state file (assessment counter, fingerprint) is not valid JSON or not the expected shape; it is not reset, its bytes are kept as <state>.corrupt-<hash> and the command stops with recovery guidance (#3440)swao/src/commands/license.ts, swao/src/lib/license-gate-error.ts, swao/src/tui/screens/LicenseScreen.tsx, @swao/core/src/license-guard.ts
wizard.*, setup.*, wsp.setup.*, playwright.check.*step.complete, llm.configured, credentials.llm.ping.ok/.fail, health-check.start/.complete/.empty, abort, ...Setup wizard stepsswao/src/tui/screens/SetupWizard.tsx, swao/src/tui/screens/wizard/steps/
support.bundle.*start, createdswao support-bundleswao/src/commands/support-bundle.ts
swao.log.file-largewarnA log file passed the size threshold@swao/core/src/log.ts

4. Reading the logs ​

bash
# All provider events of today's runs, newest last
grep '"code":"provider.llm.' wsp/logs/portfolio-events-2026-10.ndjson | tail -50

# Calls that waited for a concurrency slot
grep '"code":"provider.llm.[a-z-]*.attempt"' wsp/logs/portfolio-events-2026-10.ndjson | grep -v '"queued_ms":0'

swao support-bundle collects both log scopes for a support case.