Skip to content

The v1 docs follow nauthera-server's main branch and its 0.x releases on the way to 1.0, so fields and APIs can still change.

v1

Observability: Metrics, Alerts and Tracing

Docs version v1 (main)Nauthera is pre-1.0, in a design-partner programUpdated

Metrics

Prometheus metrics are served on the admin listener (:9090/metrics by default; see metrics.enabled and metrics.path). They are never served on the public port. Besides its own metrics, the endpoint serves the Go runtime (go_*), process (process_*) and database connection-pool (go_sql_*, with db_name="nauthera") metrics. The server's own metrics have the nauthera_ prefix:

MetricTypeWhat it tells you
nauthera_http_requests_totalcounterPublic HTTP requests by route (the operation), method and status
nauthera_http_request_duration_secondshistogramPublic HTTP latency
nauthera_http_in_flight_requestsgaugeRequests being served now
nauthera_http_cache_totalcounterPer-operation response-cache hits and misses
nauthera_grpc_handled_totalcounterAdminService calls by method and code
nauthera_grpc_handling_secondshistogramAdminService latency
nauthera_grpc_in_flight_requestsgaugeAdminService calls in flight
nauthera_cache_operations_totalcounterRedis cache operations
nauthera_cache_operation_secondshistogramRedis cache latency
nauthera_dependency_upgaugeWhether the database or cache is answering: 0 while its outage window is open
nauthera_rate_limit_degradedgauge1 while the shared rate limiter cannot answer and this replica limits on its own counter instead, which loosens every limit by up to the replica count
nauthera_auth_logins_totalcounterPassword sign-in attempts by result (success, invalid, locked, throttled, unavailable). A success means the password was right; a second factor may still follow.
nauthera_auth_account_lockouts_totalcounterSoft locks applied, re-locks included
nauthera_auth_password_screens_totalcounterNew passwords screened, by outcome (accepted, too_short, too_long, common, breached, unavailable, unchecked)
nauthera_audit_events_totalcounterAudit events recorded, by category and outcome
nauthera_audit_events_dropped_totalcounterAudit events dropped because their queue was full, by lane
nauthera_audit_buffer_depth, nauthera_audit_buffer_capacitygaugeAudit queue depth and size, by lane (priority, buffered)
nauthera_audit_flushes_total, nauthera_audit_flush_duration_secondscounter, histogramAudit batch writes
nauthera_audit_partitions_missinggaugeAudit partitions not attached, for this month (current) and the coming ones (upcoming)
nauthera_audit_export_lag_secondsgaugeHow long the oldest record an audit exporter has yet to deliver has been stored
nauthera_audit_exported_records_totalcounterRecords offered to an audit exporter, by exporter and result
nauthera_backchannel_logout_deliveries_totalcounterBack-channel logout deliveries by outcome; anything but success leaves a relying party's session alive
nauthera_mail_deliveries_totalcounterOutbound email delivery attempts by result (sent, retried, failed)
nauthera_threat_signals_totalcounterAudit records a threat signal counts, by signal, category and organization
nauthera_threat_threshold_per_hourgaugeThe rate per hour at which each signal reads elevated or critical (level)
nauthera_tls_certificate_expiration_timestamp_secondsgaugeWhen the certificate a listener (http, grpc) serves expires. The http listener's is read at startup; the grpc listener's is updated whenever a renewed certificate is loaded.
nauthera_build_infogaugeVersion, commit and Go version

Threat signals

Every attack signal of the dashboard's threat page is exported too. nauthera_threat_signals_total counts each audit record a signal counts as the replica records it, once the audit policy has kept it, labelled with the signal, its category and the organization's ID (empty for a platform record). Because it counts as records are written, it sees what the audit level records, as the page does, and each replica counts its own records. nauthera_threat_threshold_per_hour publishes the built-in elevated and critical rates for each signal, so an alert compares against the same thresholds the page shows. Unlike nauthera_audit_events_total, the threat counter carries the organization, so it can tell which tenant is under attack; it never carries an actor or an address.

The operator's metrics

The Kubernetes operator serves its metrics over TLS on :8443, only to callers the API server authorizes for GET /metrics (operator.metrics.readers in the chart). Beside controller-runtime's own, it publishes:

MetricLabelsWhat it tells you
nauthera_operator_reconciles_totalkind, reason, causeReconcile outcomes by the reason left on the resource (Registered, Refused, Unreachable, Drifted, …) and, for a refusal, the server's cause
nauthera_operator_server_calls_totalcall, codeCalls on the server's control plane, by gRPC code
nauthera_operator_server_call_duration_secondscallLatency of those calls
nauthera_operator_resourceskind, phaseResources managed, by phase

See Operator.

Alerting

With the Helm chart, metrics.serviceMonitor creates a ServiceMonitor and metrics.prometheusRule.enabled renders the server's alerting rules as a PrometheusRule; both are off by default and need the Prometheus Operator CRDs. The rules come in groups that can be switched off one by one under metrics.prometheusRule.rules:

GroupWhat it alerts on
availabilityNo replica answers a scrape, restarts, file descriptors
errors5xx responses burning the error budget of availabilityObjective (99.9%), fast and slow
latencyThe protocol endpoints' p99 above 1s
dependenciesA database or cache outage window, a saturated connection pool, failing cache operations
auditDropped audit events, failing audit writes, a backed-up queue, missing partitions, failing or lagging exporters
securitySign-in failure and lockout spikes, a high share of 429s
threatsOne organization's rate per hour of a threat signal, over the last hour, reaching its critical rate (NautheraThreatSignalCritical) or its elevated rate (NautheraThreatSignalElevated)
logoutFailing back-channel logout deliveries
controlPlaneAdminService errors, and a caller it keeps refusing
certificatesA served certificate expiring within 7 or 2 days
kubernetesNo available replica (reads kube-state-metrics)
operatorNo operator replica answers a scrape, resources in phase Error, the control plane not answering the operator. Rendered only with operator.enabled and the operator's ServiceMonitor (or operatorSelector).

Leave out single alerts under disabled, and tune an alert's severity, for and threshold under alerts. The threat alerts take their thresholds from nauthera_threat_threshold_per_hour and have a window (1h) instead; by default the critical one fires after 5m and the elevated one, below the critical rate, after 15m. Every alert has a firing and a silent test case in the chart. See Installation; the chart README lists every alert and its default.

Every alert carries a runbook_url annotation to its runbook: what it means, who is affected, how to diagnose it, what to do and when to escalate. metrics.prometheusRule.runbookUrl (default https://nauthera.io/runbooks/alerts) sets the base; point it at your own wiki to link <runbookUrl>/<alert name> there, or set it empty to leave the annotation out. nauthera-server runbook alerts <name> prints the runbook of the running version offline.

Tracing

OpenTelemetry tracing is opt-in and exports over OTLP/gRPC:

tracing:
  enabled: true
  endpoint: tempo:4317
  insecure: true          # no TLS to the collector
  sample_ratio: 1.0       # head-based sampling, 0.0–1.0
  environment: production # deployment.environment resource attribute

The public HTTP handler, the gRPC server, database queries, cache calls, SMTP delivery and back-channel logout deliveries are instrumented.

Logs

Structured logs come from zap, as logging.format: json (the default) or console. Each request's own log line (http_request, or grpc_call for the AdminService) carries its request_id, and, when tracing is on, trace_id and span_id, so you can go from a request to its trace. An http_request line also carries client_kind, what kind of software the User-Agent claims sent the request (browser, ai_agent, crawler, automation, library or unknown), and, for anything but a browser, client_agent, the product it names, such as ClaudeBot or curl. Both are a claim the sender makes; the audit log labels its records the same way. Other lines logged while serving it carry them only when they are logged through the request's logger. DSNs, driver errors and secrets are logged on the server and never returned to clients.

Health

ProbePath / mechanism
LivenessGET /healthz on :9090
ReadinessGET /readyz on :9090. Fails while the database is unavailable and during shutdown.
StartupGET /startupz on :9090
gRPCgrpc.health.v1 shares the AdminService listener on :9091, which takes mTLS or, without TLS, listens on loopback only, so the kubelet's native gRPC probe cannot reach it. Probe the admin port's HTTP endpoints above instead.
Inside the imagenauthera-server healthcheck --url http://127.0.0.1:9090/readyz exits 0 or 1

The Redis cache and the audit pipeline are checked as soft dependencies: if either is down, the server reports degraded, but the replica is not taken out of service.

Dashboards

The Docker Compose stack in the repository provisions Grafana with:

  • a server overview dashboard (/d/nauthera-overview) on Prometheus: HTTP and gRPC request rates and latency, requests in flight, the database pool and cache, goroutines and memory, and the build,
  • an audit-log explorer (/d/nauthera-audit) that reads audit_events from PostgreSQL and opens a record's trace in Tempo when the request was sampled, and
  • a threats dashboard (/d/nauthera-threats) on Prometheus: how many organization and signal pairs are elevated or critical now, every signal counted in the last hour against its thresholds, with a link from the organization to the audit-log explorer, and the signals over time by signal, category and organization.

Tempo is provisioned as a separate datasource: search traces in Explore. Nothing links a metric to its trace. The server attaches trace_id exemplars to its HTTP and gRPC latency histograms when the trace is sampled, but /metrics does not serve the OpenMetrics format, so a Prometheus with default scrape settings, like this one, receives none.

Prometheus in the same stack loads deploy/compose/alerts.yml, the Helm chart's alerting rules rendered for the compose stack.