---
title: OpenTelemetry logs in New Relic
source: https://docs.newrelic.com/docs/opentelemetry/best-practices/opentelemetry-best-practices-logs
---

This documentation focuses on how New Relic processes OpenTelemetry logs received through its dedicated OTLP endpoint.

There are two typical workflows for sending OpenTelemetry logs to New Relic:

-   [Direct to Collector](https://opentelemetry.io/docs/specs/otel/logs/#direct-to-collector):

    -   Applications can send logs directly to the New Relic OTLP endpoint.
    -   Refer to the relevant [OpenTelemetry language documentation](https://opentelemetry.io/docs/languages/) for specific implementation details, and [OpenTelemetry APM monitoring](https://docs.newrelic.com/docs/opentelemetry/get-started/apm-monitoring/opentelemetry-apm-intro/) for details on monitoring services with New Relic.

-   [Via file or `stdout`](https://opentelemetry.io/docs/specs/otel/logs/#via-file-or-stdout-logs):
    -   This method involves scraping application logs written to files or standard output (`stdout`).
    -   The OpenTelemetry Collector is typically used for this task. Scraped logs are then forwarded to the New Relic OTLP endpoint.
    -   In-depth configuration information can be found in the following OpenTelemetry resources:
        -   [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/)
        -   [Filelog receiver with kubernetes](https://opentelemetry.io/docs/kubernetes/collector/components/#filelog-receiver)
        -   [A practical example demonstrating this workflow for Java applications using Log4j2](https://github.com/newrelic/newrelic-opentelemetry-examples/tree/main/other-examples/java/logs-in-context-log4j2)

Regardless of the chosen collection method, successful integration requires configuring your log source to export logs to this endpoint. Make sure to review the [endpoint configuration requirements](https://docs.newrelic.com/docs/opentelemetry/best-practices/opentelemetry-otlp/#configure-endpoint-port-protocol) before proceeding.

## OTLP log record mapping [#otlp-log-mapping]

New Relic maps OTLP log records to the `Log` data type. The table below describes how fields from the [`LogRecord` proto message](https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/logs/v1/logs.proto) are mapped to New Relic `Log`:

| OTLP `logs.proto` field                     | New Relic `Log` field                                     |
| ------------------------------------------- | --------------------------------------------------------- |
| `ResourceLogs.Resource.attributes`          | Each key/value is an attribute on the `Log` field **[1]** |
| `ScopeLogs.InstrumentationScope.name`       | `otel.library.name`                                       |
| `ScopeLogs.InstrumentationScope.version`    | `otel.library.version`                                    |
| `ScopeLogs.InstrumentationScope.attributes` | Each key/value is an attribute on the `Log` field **[1]** |
| `LogRecord.time_unix_nanos`                 | `timestamp` **[2]**                                       |
| `LogRecord.severity_number`                 | `severity.number`                                         |
| `LogRecord.severity_text`                   | `severity.text`                                           |
| `LogRecord.body`                            | `message`, and possibly parsed attributes **[3]**         |
| `LogRecord.attributes`                      | Each key/value is an attribute on the `Log` field **[1]** |
| `LogRecord.dropped_attribute_count`         | `otel.dropped_attributes_count`                           |
| `LogRecord.flags`                           | `w3c.flags` (integer)                                     |
| `LogRecord.trace_id`                        | `trace.id`                                                |
| `LogRecord.span_id`                         | `span.id`                                                 |

### Table footnotes [#otlp-mapping-notes]

**[1]** In case of conflict in resource attributes, scope attributes, log record attributes, top level log record fields, and parsed attributes from the `LogRecord.body` **[3]**, the order of precedent (highest to lowest) is: parsed attributes from `LogRecord.body` -> top level `LogRecord.*` fields > `LogRecord.attributes` > `ScopeLogs.InstrumentationScope.attributes` > `ResourceLogs.Resource.attributes`.

See [OTLP attribute types](https://docs.newrelic.com/docs/opentelemetry/best-practices/opentelemetry-otlp/#otlp-attribute-types) for details on New Relic OTLP endpoint supported attribute types and [OTLP attribute limits](https://docs.newrelic.com/docs/opentelemetry/best-practices/opentelemetry-otlp/#attribute-limits) for details on validation performed on attributes.

**[2]** If `LogRecord.time_unix_nanos` is not present, `timestamp` is set to the time New Relic received the data.

**[3]** [Log parsing](https://docs.newrelic.com/docs/logs/ui-data/parsing/) is applied to the `LogRecord.body` to attempt to extract attributes from:

-   Plain log text: The string value will be set as the `message` attribute.
-   Stringified JSON: If a log is formatted as JSON but sent as a plain text string, the key-value pairs will become attributes of the resulting log. For more details, refer to the [JSON parsing](https://docs.newrelic.com/docs/logs/log-api/introduction-log-api/#message-attribute-parsin) documentation. This is particularly useful when collecting logs from files or `stdout`. In this case, it's common to have no resource attributes associated with the log record (required for [APM service correlation](#service-correlation)) and no value for `LogRecord.trace_id` / `LogRecord.span_id` (required for [trace correlation](#trace-correlation)). [Logs in context](https://docs.newrelic.com/docs/logs/logs-context/get-started-logs-context/) will function as intended if the required fields can be successfully parsed.
-   Map structure: If the data is formatted as a map according to the [OTLP spec](https://opentelemetry.io/docs/specs/otel/logs/data-model/#type-mapstring-any), it will be parsed and flattened into attributes, similar to JSON parsing. For more details, refer to the [JSON parsing](https://docs.newrelic.com/docs/logs/log-api/introduction-log-api/#message-attribute-parsin) documentation.

## Correlation with OpenTelemetry APM service [#service-correlation]

Log are correlated with a service entity if they include the [required attributes](https://docs.newrelic.com/docs/opentelemetry/best-practices/opentelemetry-best-practices-resources/#required-attributes). Typically, these come from the log's resource attributes, such as `ResourceLogs.Resource.attributes`, but they can also be parsed from the `LogRecord.body` as described in [footnote #3 of OTLP mapping](#otlp-mapping-notes).

To view a service's logs, navigate to the [Logs page](https://docs.newrelic.com/docs/logs/ui-data/use-logs-ui/) for that service.

## Correlation with traces [#trace-correlation]

Logs are correlated with a trace if `trace.id` and `span.id` attributes can be resolved. Typically, these come from `LogRecord.trace_id` and `LogRecord.span_id` fields, but can also be parsed from the `LogRecord.body` as described in footnote 3 of [OTLP mapping](#otlp-mapping-notes).

To view logs recorded in the context of a particular trace, you have two options:

-   Navigate to the **Logs** tab within the [trace details page](https://docs.newrelic.com/docs/distributed-tracing/ui-data/trace-details/#view-your-logs).
-   Navigate to the [Logs page](https://docs.newrelic.com/docs/logs/ui-data/use-logs-ui/) for a service and click on a log to open log details. If it's associated with a trace, you'll be able to navigate from **Log details** to **Trace details**.

## Logs as New Relic Custom Events [#custom-events]

OpenTelemetry defines an [Event](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#events) as a `LogRecord` with a non-empty [EventName](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#field-eventname). [Custom Events](https://docs.newrelic.com/docs/data-apis/custom-data/custom-events/report-custom-event-data/) are a core signal in the New Relic platform. However, despite using the same name, OpenTelemetry Events and New Relic Custom Events are not identical concepts:

-   OpenTelemetry `EventName`s do not share the same format or [semantics](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/events.md) as Custom Event types. OpenTelemetry Event names are fully qualified with a namespace and follow lower snake case, e.g. `com.acme.my_event`. Custom Event types are pascal case, e.g. `MyEvent`.
-   OpenTelemetry Events can be thought of as an enhanced structured log. Like structured logs, their data is encoded in key-value pairs rather than free form text. In addition, the `EventName` acts as an unambiguous signal of the class / type of event which occurred. Custom Events are treated as an entirely new event type, accessible via NRQL with `SELECT * FROM MyEvent`.

Because of these differences, OpenTelemetry Events are ingested as New Relic `Logs` since most of the time, OpenTelemetry Events are closer in similarity to New Relic `Logs` than New Relic Custom Events.

However, you can explicitly signal that an OpenTelemetry `LogRecord` should be ingested as a Custom Event by adding an entry to `LogRecord.attributes` following the form: `newrelic.event.type=<EventType>`.

For example, a `LogRecord` with attribute `newrelic.event.type=MyEvent` will be ingested as a Custom Event with `type=MyEvent`, and accessible via NRQL with: `SELECT * FROM MyEvent`.
