OTEL Field Mapping
How OpenTelemetry Protocol fields map to Berserk columns for traces, logs, and metrics
Berserk converts OTLP data into rows with the following conventions:
- Field names use
snake_case - Timestamps are stored as
DateTime(nanoseconds since epoch) - Durations are stored as
Timespan(100-nanosecond ticks) - IDs (trace, span) are hex-encoded strings
- Attribute keys are stored as-is (e.g.,
"http.method"stays as a flat key underattributes). Dotted-path shortcuts let you also access them asattributes.http.method. - Empty/default fields are omitted to save space
Common Structures
Resource
resource: {
attributes: {
"service.name": "my-service",
"host.name": "host-1"
},
dropped_attributes_count: 5 // only if > 0
}Scope
scope: {
name: "opentelemetry-java",
version: "1.25.0",
attributes: { // only if non-empty
"custom.attr": "value"
}
}Attributes
All attributes (span, log, event, link) store keys as flat strings:
attributes: {
"http.method": "GET",
"http.status_code": 200
}Accessible via both attributes.['http.method'] (bracket notation) and attributes.http.method (dotted shortcut).
Traces (Spans)
Each OTLP span becomes one row.
| OTEL Field | Berserk Field | Type | Notes |
|---|---|---|---|
start_time_unix_nano | start_time | DateTime | Span start timestamp |
end_time_unix_nano | end_time | DateTime | Span end timestamp |
end_time_unix_nano | $time | DateTime | Primary timestamp (copy of end_time) |
| (computed) | $time_ingest | DateTime | Ingestion timestamp |
| (computed) | duration | Timespan | (end_time - start_time) / 100 |
trace_id | trace_id | String | Hex-encoded |
span_id | span_id | String | Hex-encoded |
parent_span_id | parent_span_id | String | Hex-encoded, omitted if empty |
name | name | String | |
kind | kind | String | INTERNAL, SERVER, CLIENT, PRODUCER, CONSUMER |
trace_state | trace_state | String | W3C trace state |
status | status | Propertybag | {code: "OK"/"ERROR"/"UNSET", message: "..."} |
flags (bit 0) | sampled | Boolean | Only if sampled flag is set |
flags (bits 1-31) | flags | Long | Only if uninterpreted bits remain |
attributes | attributes | Propertybag | Flat keys |
resource | resource | Propertybag | See Resource structure |
scope | scope | Propertybag | See Scope structure |
events | events | Array | See Events below |
links | links | Array | See Links below |
dropped_*_count | dropped_*_count | Long | Only if > 0 |
Events
Each event in the events array is a propertybag with time, name, attributes, and optional dropped_attributes_count.
Links
Each link in the links array is a propertybag with trace_id, span_id, optional trace_state, sampled, is_remote, flags, attributes, and optional dropped_attributes_count.
Example
{
"$time": datetime(2024-01-15T10:30:00.150000000Z),
"start_time": datetime(2024-01-15T10:30:00.000000000Z),
"end_time": datetime(2024-01-15T10:30:00.150000000Z),
"$time_ingest": datetime(2024-01-15T10:31:00.000000000Z),
"trace_id": "0af7651916cd43dd8448eb211c80319c",
"span_id": "b7ad6b7169203331",
"parent_span_id": "00f067aa0ba902b7",
"name": "GET /api/users",
"kind": "SERVER",
"duration": timespan(150ms),
"status": { "code": "OK" },
"attributes": {
"http.method": "GET",
"http.status_code": 200
},
"resource": {
"attributes": {
"service.name": "user-service"
}
}
}Logs
Each OTLP log record becomes one row.
| OTEL Field | Berserk Field | Type | Notes |
|---|---|---|---|
time_unix_nano | $time | DateTime | Falls back to current time if 0 |
observed_time_unix_nano | observed_time | DateTime | |
| (computed) | $time_ingest | DateTime | Ingestion timestamp |
trace_id | trace_id | String | Hex-encoded, for log-trace correlation |
span_id | span_id | String | Hex-encoded |
severity_number | severity_number | Long | 1-24 per OTEL spec |
severity_text | severity_text | String | INFO, ERROR, etc. |
body | body | Dynamic | String, object, or array |
flags (bit 0) | sampled | Boolean | Only if sampled flag is set |
flags (bits 1-31) | flags | Long | Only if uninterpreted bits remain |
attributes | attributes | Propertybag | Flat keys |
resource | resource | Propertybag | See Resource structure |
scope | scope | Propertybag | See Scope structure |
dropped_attributes_count | dropped_attributes_count | Long | Only if > 0 |
Example
{
"$time": datetime(2024-01-15T10:30:00.000000000Z),
"$time_ingest": datetime(2024-01-15T10:31:00.000000000Z),
"severity_number": 9,
"severity_text": "INFO",
"body": "User login successful",
"trace_id": "0af7651916cd43dd8448eb211c80319c",
"attributes": {
"user.id": "12345"
},
"resource": {
"attributes": {
"service.name": "auth-service"
}
}
}Metrics
Each OTLP metric data point becomes one row. The structure varies by metric type.
Common Fields
| OTEL Field | Berserk Field | Type | Notes |
|---|---|---|---|
time_unix_nano | $time | DateTime | Data point timestamp |
| (computed) | $time_ingest | DateTime | Ingestion timestamp |
start_time_unix_nano | start_time | DateTime | Aggregation window start |
| (multiple) | metric | Propertybag | {name, type, description, unit} |
attributes | attributes | Propertybag | Flat keys, data point attributes |
resource | resource | Propertybag | See Resource structure |
scope | scope | Propertybag | See Scope structure |
flags (bit 0) | no_recorded_value | Boolean | Only if no_recorded_value flag is set |
Gauge / Sum
Single value field (int or double). Sum also includes aggregation_temporality and is_monotonic.
Histogram
Fields: count, sum, min, max, bucket_counts, explicit_bounds, aggregation_temporality.
Exponential Histogram
Fields: count, sum, min, max, scale, zero_count, positive (offset + bucket_counts), negative (offset + bucket_counts), aggregation_temporality.
Summary
Fields: count, sum, quantile_values (array of {quantile, value}).
Omitted Fields
The following OTEL fields are intentionally not stored:
- Schema URLs at all levels (not needed for storage)
InstrumentationScope.dropped_attributes_count(low value)- Metric exemplars (high cardinality; can be added if needed)
Link.flagsare decomposed intosampled,is_remote, and remainingflags