Otel.SDK.Logs.LogRecord (otel v0.2.0)

Copy Markdown View Source

SDK-side ReadWriteLogRecord (logs/sdk.md §ReadWriteLogRecord L298-L319 + §ReadableLogRecord L277-L296).

Spec L294-L296 explicitly suggests "a new interface or (immutable) value type" separate from the API LogRecord — this module is that type. Constructed inside Otel.SDK.Logs.Logger.build_log_record/3 from the caller-supplied Otel.API.Logs.LogRecord plus context- and state-derived fields, then flowed unchanged through every registered processor and exporter.

Fields beyond Otel.API.Logs.LogRecord

FieldSourceSpec
trace_id, span_id, trace_flagsresolved Otel.API.Ctx.t() at emit timeL285-L287 "trace context fields MUST be populated from / the resolved Context (either the explicitly passed Context or the / current Context)"
scopeOtel.API.InstrumentationScope of the originating LoggerL281 "Instrumentation Scope (implicitly) associated with the LogRecord"
resourceOtel.SDK.Resource of the LoggerProviderL282-L283 "Resource information (implicitly) associated"
dropped_attributes_countsize delta after LogRecordLimits applicationL289-L292 "Counts for attributes due to collection limits MUST be available for exporters"

The exception sidecar from Otel.API.Logs.LogRecord is not present — it is consumed by apply_exception_attributes/1 before this struct is constructed and surfaces as exception.type / exception.message attributes per trace/exceptions.md §Attributes.

Why a separate struct from Otel.API.Logs.LogRecord

Two reasons (code-conventions.md §Layer independence):

  1. The API struct is the application's expression of what to log — 8 fields covering proto3-defined LogRecord plus the project's exception sidecar. Adding SDK-state fields like scope / resource to it would push SDK concerns into the API surface.
  2. Spec L294-L296 prescribes the separation directly.

References

  • OTel Logs SDK §ReadableLogRecord: opentelemetry-specification/specification/logs/sdk.md L277-L296
  • OTel Logs SDK §ReadWriteLogRecord: same file L298-L319
  • OTLP proto LogRecord: opentelemetry-proto/opentelemetry/proto/logs/v1/logs.proto L136-L226

Summary

Types

t()

A LogRecord ready for processor/exporter consumption — the spec's ReadWriteLogRecord shape filled in by Otel.SDK.Logs.Logger.build_log_record/3.

Types

primitive()

@type primitive() ::
  String.t() | {:bytes, binary()} | boolean() | integer() | float() | nil

primitive_any()

@type primitive_any() ::
  primitive() | [primitive_any()] | %{required(String.t()) => primitive_any()}

t()

@type t() :: %Otel.SDK.Logs.LogRecord{
  attributes: %{required(String.t()) => primitive_any()},
  body: primitive_any(),
  dropped_attributes_count: non_neg_integer(),
  event_name: String.t(),
  observed_timestamp: non_neg_integer(),
  resource: Otel.SDK.Resource.t(),
  scope: Otel.API.InstrumentationScope.t(),
  severity_number: Otel.API.Logs.severity_number(),
  severity_text: Otel.API.Logs.severity_level(),
  span_id: Otel.API.Trace.SpanId.t(),
  timestamp: non_neg_integer(),
  trace_flags: Otel.API.Trace.SpanContext.trace_flags(),
  trace_id: Otel.API.Trace.TraceId.t()
}

A LogRecord ready for processor/exporter consumption — the spec's ReadWriteLogRecord shape filled in by Otel.SDK.Logs.Logger.build_log_record/3.

All defaults are proto3 zero values for the Otel.API.Logs.LogRecord-mirrored fields; scope and resource default to their respective empty structs so the spec MUST in logs/sdk.md L281-L283 — "It MUST also be able to access the Instrumentation Scope and Resource information ... associated with the LogRecord" — holds on every record without needing nil-guards in processors and exporters.