Observability
Signal ownership
Section titled “Signal ownership”Operational signals explain failures; durable product records explain usage and security decisions. They have separate storage and retention boundaries.
flowchart TB
app["Kesita app · Node"] -->|"Azure Monitor exporter"| traces["Configured trace backend"]
core["Legal Core · Go"] -->|"OTLP / HTTP exporter"| collector["Configured OTLP endpoint"]
collector -->|"Deployment-managed delivery"| traces
app -->|"Structured JSON"| logs["Container stdout → log backend"]
core -->|"Structured JSON"| logs
app -->|"Usage, audit and security writes"| db[("Product PostgreSQL")]
db -->|"Authorized server-side queries"| admin["Admin usage and audit views"]
Trace export requires configuration; the diagram does not imply a collector or backend is provisioned. Structured logging remains enabled when trace export is disabled. Admin product views read durable records; a telemetry-reader adapter is still planned.
| Signal | Store | Purpose |
|---|---|---|
| HTTP traces, dependencies, exceptions | Configured telemetry backend; Azure Monitor / Application Insights is an Azure option | SRE debugging, latency, error grouping |
| Structured logs | Container stdout → configured log backend; Log Analytics on Azure | Correlated operational logs |
| LLM usage, estimated cost, latency | PostgreSQL llm_usage_event | Provider/model/profile receipts, detailed cache usage and versioned micro-USD estimates; invoice and commercial-credit reconciliation remain pending |
| Audit | PostgreSQL audit_log | Product audit records; tamper-evidence not verified |
| Security enforcement | PostgreSQL security_event | Recorded enforcement decisions; not proof of provisioned alert delivery |
Ephemeral telemetry must never be the billing or compliance source of truth.
Cloud-independent admin operations
Section titled “Cloud-independent admin operations”The data operations view at /operations/data on the admin host belongs to Kesita,
not Azure. It reads aggregate queue, lease, cleanup and accounting state through
a platform-admin-only database capability, and probes database, blob and Legal
Core availability. Observations carry timestamps and become stale after 60 seconds.
Product workers report process presence every 20 seconds, including when idle. The view counts workers observed in the last 90 seconds; graceful shutdown removes presence and crashed processes age out. This proves recent process contact, not successful job execution or provider health. Maintenance-paused processes do not connect to the database or report presence. Corpus-worker presence and indexing freshness are not yet included. Legal summaries must come through Legal Core, not direct SQL. Infrastructure cost ingestion is a separate optional integration.
Add a narrow telemetry-reader adapter only when latency/error summaries are needed. It owns provider credentials and queries; admin receives stable types, timestamps, and explicit unknown/stale states. Bound and cache reads, enforce platform-admin access, and link to the backend for full log/trace exploration.
OpenTelemetry makes instrumentation vendor-neutral, but supplies neither storage nor a standard read API. Keep export configuration in shared observability packages and deployment configuration. Do not build a general cloud abstraction or self-host a monitoring stack just for portability. External uptime checks and alert delivery must survive an outage of Kesita and its database.
Existing usage summaries, shared logging/tracing, health endpoints and the data
operations snapshot are implemented. The telemetry-reader adapter is not;
see Deployment for the runtime boundary.
Custom OTel/Prometheus RED metrics are not wired; slos.yaml is a specification,
not proof of provisioned alerts.
Standard resource attributes
Section titled “Standard resource attributes”service.name— deployable name (kesita-app,legal-core-api, …)service.version— git sha or package versiondeployment.environment—development|staging|productioncloud.provider— actual deployment provider, e.g.azure; omit locallycloud.region— actual deployment region, e.g.westeurope; omit locally
Correlation
Section titled “Correlation”sequenceDiagram
participant Client
participant App as Kesita app
participant Core as Legal Core
participant DB as Product PostgreSQL
Client->>App: HTTP request, optional x-request-id
Note over App: Honor or generate request ID
App->>Core: Internal HTTP, traceparent / tracestate
Note over App,Core: Trace context links service spans
Core-->>App: Service response
opt Operation records LLM usage
App->>DB: Usage event with active traceId / spanId
end
App-->>Client: HTTP response, x-request-id
The request ID identifies an ingress request; the trace ID links instrumented work across services. Persisted trace IDs help investigations, but the associated trace may be sampled out or expire before the product record.
- Ingress:
x-request-id(generated if absent) - Distributed trace: W3C
traceparent/tracestate - Domain records: optional
traceId/spanIdonLlmUsageEventand audit metadata - All outbound HTTP to internal services injects W3C
traceparent - Responses should echo
x-request-id
Privacy
Section titled “Privacy”Never in traces, logs, or metrics:
- Passwords, session tokens,
CRON_SECRET, provider API keys - Full legal document text, pratica content, email bodies
- LLM prompts and completions (default off; content capture requires explicit opt-in)
- Payment webhook payloads (when billing is enabled)
- Raw
Authorization/X-API-Keyheaders - Raw search queries beyond bounded hashes
Allowed with care:
- Opaque IDs:
userId,organizationId,job_id,traceId - Route templates:
/api/aix/assignments/:id/events, not raw URLs with tokens - Aggregated counts: tokens, latency ms, error types
- Hashed query fingerprints for abuse detection
Server-side APM is operational only. Product analytics, if added later, must be a separate opt-in pipeline with its own subprocessors entry.
Health
Section titled “Health”| Service | Port | Health |
|---|---|---|
kesita-app | 3000 | GET /api/health/live, /ready, /deep |
legal-core-api | 8080 | GET /v1/health/live, /v1/health/ready |
Disable trace export with KESITA_TELEMETRY_ENABLED=false (structured JSON logs stay on). Machine-readable SLOs live in slos.yaml.
Local development
Section titled “Local development”Use logger-only mode for ordinary local development. To inspect exported traces,
enable telemetry and configure the exporter supported by that service: Node uses
APPLICATIONINSIGHTS_CONNECTION_STRING; Go uses OTEL_EXPORTER_OTLP_ENDPOINT.
Setting an OTLP endpoint alone does not configure the current Node initializer.
See Configuration for authoritative environment templates
and Local development for lifecycle controls.
Packages
Section titled “Packages”@kesita/observability— Node/Next.js helperspackages/observability-go— Go OTel + slog