Skip to main content

LogRecord fields

The internal representation of a log line. Every binding exposes a typed LogRecord dataclass with the fields below; wire serialisation lives in separate functions (see Wire formats).

Field table

FieldTypeOptionalDefaultSet byMeaning
time_unix_nanoint (uint64)notime.time_ns() at emitproducerEmit timestamp, nanoseconds since Unix epoch (OTel TimeUnixNano).
severity_numberintnocallerOTel severity 1-24.
severity_textstrnoderived from severity_numberbindingOne of six canonical strings (TRACE, DEBUG, INFO, WARN, ERROR, FATAL).
bodyValuenocallerPrimary message — string or structured (map/array/scalar).
attributesdict[str, Value]yes{}caller + bindingPer-record key-value context. Redaction applies before fan-out.
instrumentation_scopeInstrumentationScope?yesnullbindingLogger self-descriptor (name, version). Set when Logger.get(name, version) is used.
resourceResource?yesnullbindingProcess/service/host attributes. Inherited from the root logger after configure(resource_attributes=...).
trace_idbytes(16)?yesnullbindingW3C Trace Context — 16 random bytes. Filled from the OTel context if a span is active.
span_idbytes(8)?yesnullbindingW3C Trace Context — 8 random bytes. Same source as trace_id.
trace_flagsint (uint8)no0bindingW3C flags (sampled bit, etc.). 0 = not-sampled.
observed_time_unix_nanoint? (uint64)yesnullsink (on ingest)Ingest timestamp at the sink. Producer leaves null; sink fills it before wire serialisation (per spec §1).

The Value type

Value is a recursive sum type used for body and attribute values. Concrete shape:

Value = str | int | float | bool | null | dict[str, Value] | list[Value]

The same shape backs ConfigTree in config-spec §1; consumers may reuse a single language-level type to represent both. Values are JSON-serialisable (the Value set is exactly the JSON value set).

InstrumentationScope

Self-descriptor for the logger that emitted the record:

FieldTypeMeaning
namestrLogger name (matches Logger.get(name) argument).
versionstr?Semantic version, set by Logger.get(name, version).
attributesdict[str, Value]Optional scope-level attributes.

For records emitted by a plugin, the scope is recommended to match the plugin's id and version from its PluginManifest (see dagstack/plugin-system-spec).

Resource

Process-level attributes shared across every logger in the process:

FieldTypeMeaning
attributesdict[str, Value]OTel Resource attributes — service.name, service.version, service.instance.id, deployment.environment, host.name, process.pid, telemetry.sdk.{name,version,language}, etc.

A binding detects Resource attributes through:

  1. OTel autodetect (OTEL_RESOURCE_ATTRIBUTES env var, OTel Resource Detectors).
  2. Explicit config from the logging.resource.* section.
  3. Merge: env-detected ∪ config-supplied (config wins).

Field ownership

Per spec §1 ownership rules:

  • Caller sets severity_number, body, optional attributes. The caller never sets time_unix_nano directly; the binding fills it at emit.
  • Binding fills time_unix_nano, severity_text, instrumentation_scope, resource, trace_id, span_id, trace_flags, plus any attributes injected via Baggage propagation.
  • Sink fills observed_time_unix_nano if the producer left it null. Doing so guarantees that wire output always carries an ingest timestamp.

Wire encoding overview

The same field set serialises to three wire formats with format-specific encoding rules. See Wire formats for the full table; a short version:

FieldOTLP protobufOTel JSONdagstack JSON-lines
time_unix_nanofixed64string-decimalint (Canonical JSON allows int64)
trace_idbytes(16)lowercase 32-hexlowercase 32-hex
span_idbytes(8)lowercase 16-hexlowercase 16-hex
severity_numberintintint
severity_textstringstringstring
Casing(binary)camelCasesnake_case

See also