Logs
Every audit event acl records reaches the collector as one OpenTelemetry log record. The exporter batches and sends records from its own worker, over OTLP HTTP/protobuf or gRPC, using the OpenTelemetry C++ SDK. acl's decision path never waits on the network.
The record
- Severity.
- INFO for an allowed event.
- WARN for a refusal.
- ERROR when the source of the decision failed rather than the principal: a
source_errororpolicy_error, or a policy or keys event.
- Body.
<kind> <allowed|denied>followed by: <reason>. A refusal's reason is a fixed sentence, so it never contains a claim value or statement text. For an execution profile the body is the profile as one JSON document (Traces). - Trace context. Taken from the statement's
traceparentwhen it parses. A malformed value sets nothing. - Resource.
service.namecomes fromacl_otel_service_name, defaultduckdb-acl;service.instance.idis the node's id (acl'sacl_node_id);acl_otel_resource_attributesaddsk=vpairs.
Attributes. Every field is an acl.* attribute, present only when the event carries it:
- the event:
acl.kind,acl.statement,acl.verdict,acl.reason_code,acl.reason,acl.detail; - where and who:
acl.door,acl.session,acl.subject,acl.issuer; acl.rolesandacl.objectsas JSON arrays. A list is cut at whole elements, and the last element says how many did not fit;- the trace:
acl.correlation_id; - measurements:
acl.rewrite_us,acl.duration_us,acl.rows; acl.level,acl.seq,acl.node;- for a profile:
acl.decision_seqandacl.exec.*.
A record never carries rows, statement text or keys. It carries claim values only when the operator names the claim.
Claims
A claim's value leaves the node only when its name is listed:
SET GLOBAL acl_otel_claim_attributes = 'tenant,department'; -- as acl.claim.tenant, acl.claim.department
You can list at most sixteen names, and each value is cut at 256 bytes.
What was lost
Every drop is counted, never silent. acl_otel_status() separates the causes:
- the queue was full;
- no exporter was configured;
- the backend refused the export, with the error the SDK gave (
last_error).
The SDK's HTTP exporter reports success even when its client failed, so an error the SDK logged during an export is treated as the failure. Export failures are never retried after a restart.