OpenTelemetry supports attributes at different levels in an OpenTelemetry log request, such as the resource level, scope level, and record level.
The Log ingestion API collects and attempts to automatically transform log data.
Each log record from the ingested batch is mapped to a single Dynatrace log record, which contains three special attributes: timestamp, loglevel, content, and a set of other key-value attributes. These properties are set based on keys present in the input object as follows.
Set based on the Timestamp field of the input log record. See the differences between data models in the Log ingestion API processing section below for more details.
Log events older than the Log Age limit are discarded. Timestamps more than 10 minutes ahead of the current time are replaced with the current time. See the Ingestion limits section for details.
The default value is the current timestamp.
Set based on the SeverityText field (first priority) or SeverityNumber field (secondnd priority) of the input log record. See the differences between data models in the section Log ingestion API processing below for more details.
The default value is NONE.
The content is set based on the Body field of the input log record.
If the Body field is not a string type, the value is stringified. In case of complex types, it is stringified as a JSON string. For kvlist_value type, see the differences between data models in the Log ingestion API processing section below for more details.
Contains all other attributes from the input record's attributes contained in the sections: Resource, InstrumentationScope, and Attributes.
The TraceID and SpanID attributes are mapped to the trace_id and span_id fields, and their values are converted to hexadecimal representation (e.g., 0xCAFEBABE).
Automatic attribute. The dt.auth.origin attribute is automatically added to every log record ingested via API. This attribute is the public part of the API key that the log source authorizes to connect to the generic log ingest API.
All attributes should preferably map to semantic attributes for Dynatrace to interpret them correctly.
Dynatrace supports OpenTelemetry data types as described in the sections below.
Scalar values are transformed as follows:
Logs on Grail with OpenPipeline custom processing (Dynatrace SaaS version 1.295+, Environment ActiveGate version 1.295+): All JSON data types (string, number, boolean, null) are supported. All attributes can be used in queries. Keys are case-sensitive.
Logs on Grail with OpenPipeline routed to Classic Pipeline: All attribute keys are lowercased and all attribute values are stringified. All attributes can be used in queries.
Log Monitoring Classic: All attribute keys are lowercased and all attribute values are stringified. Custom attributes and semantic attributes can generally be used in queries.
Byte arrays are converted to base64-encoded strings. For example, the following array
[0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64]
is transformed and ingested as aGVsbG8gd29yZA==.
Array attribute values are converted to arrays of a uniform type. The target type is chosen according to the following rules:
Map processing depends on the data model used. See Log ingestion API processing below for more details.
See Log Management and Analytics default limits and Log Monitoring default limits (Logs Classic) for the limits applied to ingested log requests, their attributes, and their attribute values.
There are two data models that identify how structured logs are processed by log ingestion endpoints: raw and flattened. The difference between the two is in how attributes with object/dictionary values are transformed.
If this configuration option is not specified, the default behavior depends on when your environment was created.
Escaping in output examples is for visualization purposes only. \" is billed as one character.
The raw data model transforms the content of structured logs as described in the sections below. All the following examples apply to Log ingestion API endpoints available on Environment ActiveGateand SaaS.
For the raw data model, the map attribute values are turned into a JSON string, and the array attribute values are turned into an array of the uniform type.
Input
Log ingestion API endpoint output
body: "Hello world!"Resource:- "any-attr-type-3": {"3" = "c"}Scope:- "any-attr-type-2": {"2" = "b"}Attributes:- "any-attr-type-1": {"1" = "a"}- "any-attr-type-4":[ "val1", 10, -123.456, false, 0x01020304 ]
“content”: "Hello world!""any-attr-type-1": "{\"1\": \"a\"}""any-attr-type-2": "{\"2\": \"b\"}""any-attr-type-3": "{\"3\": \"c\"}""any-attr-type-4":["val1", "10", "-123.456", "false", "AQIDBA=="]
KeyValue {key: "test"value: {kvlist_value: {values: [{key: "attribute"value: {kvlist_value: {values: [{ key: "one", value: { string_value: "value 1" } },{ key: "two", value: { string_value: "value 2" } }]}}}]}}}
"test": "{ \"attribute\": {\"one\": \"value 1\", \"two\": \"value 2\" } }"
In this case, the Body field of the input log record is converted to a JSON string.
Input
Log ingestion API endpoint output
Body:{"content" = "Hello World!","my-body-attr-1": "abc","my-body-nested-1": {"subkey": "val"},"@timestamp": "2025-06-01 13:01:02.123","loglevel": "INFO"}
"content": "{ \"content\" = \"Hello World!\",\"my-body-attr-1\": \"abc\",\"my-body-nested-1\": {\"subkey\": \"val\"},\"@timestamp\": \"2025-06-01 13:01:02.123\",\"loglevel\": \"INFO\"}"
In this case, the array in the body is stringified.
Input
Log ingestion API endpoint output
Body:[ "string-val", true, 12, 12.34, 0x6279746573 ]
"content": "[\"string-val\",true,12,12.34,\"Ynl0ZXM=\"]"...
In the raw data model, OTLP resource attributes and OTLP attributes are copied into Dynatrace top-level attributes, and the OTLP body is copied into the content.
Dynatrace prefixes duplicate attributes with an incrementing counter, for example overwritten1.myattribute. The counter value indicates how many times the attribute has been encountered as a duplicate. This avoids name collisions when attributes at different OTLP levels share the same name.
With the flattened data model, the content of structured logs is transformed as described in the sections below. All the following examples apply to Log ingestion API endpoints available on Environment ActiveGate and SaaS.
In this case, the map attribute values are flattened, i.e. replaced with keys concatenated using a dot (.) until a simple value is reached in the hierarchy, and the array attribute values are turned into a custom string.
Input
Log ingestion API endpoint output
body: "Hello world!"Resource:- "any-attr-type-3": {"3" = "c"}Scope:- "any-attr-type-2" : {"2" = "b"}Attributes:- "any-attr-type-1" : {"1" = "a"}- "any-attr-type-4" :[ "val1", 10, -123.456, false, 0x01020304 ]
“content”: "Hello world!""any-attr-type-1.1": "a""any-attr-type-2.2": "b""any-attr-type-3.3": "c""any-attr-type-4":["val1", 10, -123.456, false, "AQIDBA=="]
Flattening proceeds up to the maximum nesting level specified by the Nested objects limit. Structures nested deeper than this are replaced with the string value <truncated due to nesting limit>. See the Ingestion limits section for details.
In this case, the map attributes are merged with the log record.
Input
Log ingestion API endpoint output
Body:{"content" = "Hello World!","my-body-attr-1": "abc","my-body-nested-1": {"subkey": "val"},"@timestamp": "2025-06-01 13:01:02.123","loglevel": "INFO"}Attributes:- "any-attr-type-1" : "my-attr"
"content": "Hello world!""timestamp": "2025-06-01 13:01:02.123""loglevel": "INFO""any-attr-type-1": "my-attr""my-body-attr-1": "abc""my-body-nested-1.subkey": "val"
In this case, the array in the body is stringified.
Input
Log ingestion API endpoint output
Body:[ "string-val", true, 12, 12.34, 0x6279746573 ]
"content": "[\"string-val\",true,12,12.34,\"Ynl0ZXM=\"]"...
If the Body field is of kvlist_value type (a list of key-value pairs), the structure is processed in the same way as log record attributes, including flattening and conflict resolution.
Attributes found in Body may also be used for setting the timestamp, loglevel, and content attributes of the log record, as described below.
If the timestamp cannot be set based on the Timestamp field, the first of the following keys found in Body is used: timestamp, @timestamp, _timestamp, eventtime, date, published_date, syslog.timestamp, time, epochSecond, startTime, datetime, ts, timeMillis, @t.
Supported timestamp formats: UTC milliseconds, RFC3339, and RFC3164.
The default value is the current timestamp and the default timezone is UTC if it's missing in timestamp.
If the loglevel cannot be set based on the Severity field, the first of the following keys found in Body is used: loglevel, status, severity, level, syslog.severity.
The default value is NONE.
content is set based on the first of the following keys found in Body: content, message, payload, body, log, _raw (_raw is supported only in the raw data model).
If no content attribute is found among supported content keys, the content is set to an empty string.
When attributes are saved in a flattened fashion on the Dynatrace side, there may be name collisions if attributes on different levels share the same name. Dynatrace resolves this by prefixing duplicate attributes with overwritten[COUNTER].. The counter value indicates how many times the attribute name has been already encountered as a duplicate.
For example, if you have three attributes all named my.attribute on the resource, scope, and log levels:
my.attributeoverwritten1.my.attributeoverwritten2.my.attributeThe Log ingestion API additionally accepts log attributes through:
X-Dynatrace-AttrThese attributes are merged with those provided in the OpenTelemetry log request according to the rules described below.
Request URL
Resulting output
otlphttp:logs_endpoint: /api/v2/otlp/v1/logs?env=prod&env=blue&team=payments
Body: "Hello World!"
{"content": "Hello World!","env": ["prod", "blue"],"team": "payments"}
The API supports a special header for passing additional attributes:
otlphttp:endpoint: /api/v2/otlpheaders:X-Dynatrace-Attr: region=eu-central-1&team=core
Rules:
When attributes appear in multiple places, the Log ingestion API applies attribute precedence while still preserving body values for auditability. The attributes are applied in the following order:
When attributes from query parameters or the header override log request attributes:
overwrittenN.<attribute_key>.
Where N is an incrementing integer (1, 2, …) depending on how many log request-originating values had to be preserved. This ensures uniqueness, even when multiple conflicts occur.overwrittenN.* keys. Attributes overridden by higher-precedence sources do not generate overwritten copies.Request
Resulting output
otlphttp:logs_endpoint: /api/v2/otlp/v1/logs?team=frontend
Log Request:
Body: "Hello World!"Attributes:- "team": "backend"
{"content": "Hello World!","team": "frontend","overwritten1.team": "backend"}
Attributes provided through query parameters or headers are included in billing calculations.
For multi-value attributes, the attribute key contributes to billing only once, regardless of how many values are present.