---
title: "OTLP: OpenTelemetry Protocol format considerations | Grafana Cloud documentation"
description: "Understand format considerations when sending data to Grafana Cloud via OpenTelemetry OTLP Protocol."
---

> For a curated documentation index, see [llms.txt](/llms.txt). For the complete documentation index, see [llms-full.txt](/llms-full.txt).

# OTLP: OpenTelemetry Protocol format considerations

OpenTelemetry doesn’t specify a data storage approach and leaves it to the observability backend to implement. Grafana Cloud converts metrics, logs, and traces sent to the Grafana Cloud OTLP endpoint to be compatible with Grafana databases.

The Grafana Cloud OTLP endpoint supports ingestion of signals in the [OTLP/HTTP with binary protocol buffer encoding](https://opentelemetry.io/docs/specs/otlp/#binary-protobuf-encoding) with either no compression or `gzip` compression. It also supports ingestion of [JSON protocol buffer encoding](https://opentelemetry.io/docs/specs/otlp/#json-protobuf-encoding), ideally only for low-traffic testing cases. Signals should not be sent via JSON in bulk when binary protocol buffer support is available.

## Metrics

Grafana Cloud stores metrics in [Mimir](/oss/mimir/), a [Prometheus](https://prometheus.io/) compatible database, and maps OpenTelemetry metrics following the [official specification for OTLP Metric points to Prometheus](https://opentelemetry.io/docs/reference/specification/compatibility/prometheus_and_openmetrics/#otlp-metric-points-to-prometheus).

### Exponential histograms

Grafana Cloud accepts [OpenTelemetry exponential histograms](https://opentelemetry.io/docs/specs/otel/metrics/data-model/#exponentialhistogram) by default. Grafana Cloud converts OpenTelemetry exponential histograms into Prometheus native histograms following the [official specifications for exponential histograms](https://opentelemetry.io/docs/specs/otel/compatibility/prometheus_and_openmetrics/#exponential-histograms).

> Note
> 
> Native histograms have a different pricing structure compared to other float samples. For more information, consult [Understand your Grafana Cloud Metrics invoice](/docs/grafana-cloud/cost-management-and-billing/manage-invoices/understand-your-invoice/metrics-invoice/#prometheus-native-histograms).

### Metric and label name conversion

Prometheus metric and label names need to adhere to the regular expression `[a-zA-Z_:][a-zA-Z0-9_:]*` which contains alphanumeric, underscore, and colon characters. Grafana converts fullstops `.` and dashes `-` in OpenTelemetry metric or label names to underscores `_` to store them in Prometheus.

**Example:**

If you sent the following OTLP data:

JSON ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```json
requests.duration{http.response.status_code=500, http.route="/api/orders"}
```

Grafana converts it for Prometheus storage:

JSON ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```json
requests_duration{http_response_status_code="500", http_route="/api/orders"}
```

### Resource attributes added to `target_info` metric

Grafana Cloud follows the [OpenTelemetry specification](https://opentelemetry.io/docs/specs/otel/compatibility/prometheus_and_openmetrics/#resource-attributes-1) when it converts resource attributes to labels and into the `target_info` metric.

Grafana Cloud adds resource attributes as labels to the `target_info` metric, except for `service.instance.id`, `service.name`, and `service.namespace` resource attributes:

- `service.namespace/service.name` added to the `job` label. If `service.namespace` is empty, only `service.name` is added to the `job` label
- `service.instance.id` added to the `instance` label

> Note
> 
> [Contact support](mailto:support@grafana.com) if you would like to keep `service.instance.id`, `service.name`, and `service.namespace` in the `target_info` metric in addition to converting them into `job` and `instance` labels.

To retrieve the resource attributes for a metric use the `on(job, instance)` operator to join the metric with the `target_info` metric, for example use the following Prometheus query to get the `service.version` attribute for a `requests_total` metric:

PromQL ![Copy code to clipboard](/media/images/icons/icon-copy-small-2.svg) Copy

```promql
requests_total * on(job, instance) group_left(service_version) target_info
```

### Work with default OpenTelemetry labels

OpenTelemetry metrics use resource attributes to describe the set of characteristics associated with a given resource, or entity, producing telemetry data. For example, a host resource might have multiple attributes, including an ID, an image, and a type.

Grafana Cloud automatically promotes the following OTel resource attributes to labels, with periods (`.`) replaced by underscores (`_`):

- `service.instance.id`
- `service.name`
- `service.namespace`
- `service.version`
- `cloud.availability_zone`
- `cloud.region`
- `container.name`
- `deployment.environment`
- `deployment.environment.name`
- `k8s.cluster.name`
- `k8s.container.name`
- `k8s.cronjob.name`
- `k8s.daemonset.name`
- `k8s.deployment.name`
- `k8s.job.name`
- `k8s.namespace.name`
- `k8s.pod.name`
- `k8s.replicaset.name`
- `k8s.statefulset.name`

> Note
> 
> To disable this option or to update this list, contact Grafana Labs Support.

Mimir stores additional OTel resource attributes in a separate series called `target_info`, which you can query using a join query or the Prometheus `info()` function. Refer to [Functions](https://prometheus.io/docs/prometheus/latest/querying/functions/) in the Prometheus documentation for more information.

To learn more about OpenTelemetry resource attributes, refer to [Resources](https://opentelemetry.io/docs/languages/js/resources/) in the OpenTelemetry documentation.

#### Promote OpenTelemetry labels

You can configure Mimir to promote metrics labels, for example `service.instance.id`, `service.name`, `service.namespace`, or any other resource attribute to labels.

> Note
> 
> The `-distributor.otel-promote-resource-attributes` option is an experimental feature in Grafana Mimir.

To configure Mimir to promote metrics labels, refer to the Mimir documentation on how to [work with default OpenTelemetry labels](/docs/mimir/next/configure/configure-otel-collector/#work-with-default-opentelemetry-labels).

For example usage, refer to the [practical guide to data collection with OpenTelemetry and Prometheus blog post](/blog/2023/07/20/a-practical-guide-to-data-collection-with-opentelemetry-and-prometheus/).

### Suffixes added to metric names

By default Prometheus adds suffixes to metric names to comply with the [Prometheus metric types name conventions](https://prometheus.io/docs/concepts/metric_types/). Grafana Cloud follows the [official specification for OTLP Metric points to Prometheus](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.33.0/specification/compatibility/prometheus_and_openmetrics.md#otlp-metric-points-to-prometheus).

The suffix generation procedure is as follows:

1. Split the OTel unit into two parts, before and after any `/` character.
2. Add `_<UNIT>` to the suffix if the metric name doesn’t contain the first unit part.
3. Add `_per_<UNIT>` to the suffix if there’s a second unit part and the metric name doesn’t contain it.
4. Add `_total` to the suffix if the OTel metric type is a monotonic sum.
5. Add `ratio` to the suffix if the OTel metric type is gauge and the unit is `1`.

> Note
> 
> We recommend you keep the default Prometheus metric name suffix generation enabled. If you need it disabled [contact support](mailto:support@grafana.com).

**Example:**

Grafana Cloud converts the OpenTelemetry monotonic sum `system.io` with unit `By` into the Prometheus name `system_io_bytes_total`, and `_bytes_total` is the generated suffix.

### Metrics ingestion limits

Expand table

| Limit                                                                  | Value      | When you exceed the limit                                       |
|------------------------------------------------------------------------|------------|-----------------------------------------------------------------|
| The maximum length of a metric name.                                   | 2048 bytes | Names that exceed the limit cause an ingestion exception.       |
| The maximum number of resource attributes.                             | 40         | Grafana Cloud drops limits above resource attribute limit.      |
| The maximum number of metric attributes.                               | 40         | Grafana Cloud drops limits above metric attribute limit.        |
| The maximum length for resource attribute and metric attribute names.  | 2048 bytes | Names that exceed the limit cause an ingestion exception.       |
| The maximum length for resource attribute and metric attribute values. | 2048 bytes | Grafana Cloud truncates attribute values that exceed the limit. |

When you send batch metrics, Grafana Cloud ingests only the metrics that don’t exceed limits and returns exceptions for the metrics that exceed limits. The exception is attribute values, which instead get truncated when they exceed the limit.

## Logs

Grafana Cloud converts OpenTelemetry logs and stores them in the Loki 3 format to leverage structured metadata and labels.

The conversion process is as follows:

Expand table

| OpenTelemetry log record field                                                                                 | Loki field                                                                                                                                                                                                                                                                                                      |
|----------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`Timestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-timestamp)                       | `timestamp`                                                                                                                                                                                                                                                                                                     |
| [`ObservedTimestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-observedtimestamp)       | `metadata[observed_timestamp]`                                                                                                                                                                                                                                                                                  |
| [`TraceId`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-traceid)                           | `metadata[trace_id]`                                                                                                                                                                                                                                                                                            |
| [`SpanId`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-spanid)                             | `metadata[span_id]`                                                                                                                                                                                                                                                                                             |
| [`TraceFlags`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-traceflags)                     | `metadata[flags]`                                                                                                                                                                                                                                                                                               |
| [`SeverityText`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitytext)                 | `metadata[severity_text]`, the `detected_level` label is available                                                                                                                                                                                                                                              |
| [`SeverityNumber`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber)             | `metadata[severity_number]`                                                                                                                                                                                                                                                                                     |
| [`Body`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)                                 | The Loki log message. `__line__`in LogQL functions, for example `line_format`.                                                                                                                                                                                                                                  |
| [`InstrumentationScope`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-instrumentationscope) | `metadata[scope_name]`                                                                                                                                                                                                                                                                                          |
| [`Attributes`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-attributes)                     | `metadata[xyz]` where `xyz` is the `_` version of the OpenTelemetry attribute name, for example the OpenTelemetry attribute `thread.name` converted to `thread_name` Loki metadata.                                                                                                                             |
| [`Resource`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-resource)                         | Loki promotes certain resource attributes to Loki labels and persists others as Loki message metadata. Refer to [Loki OTel format considerations](/docs/loki/latest/send-data/otel/#format-considerations) for a list of specific resource attributes that get promoted and relevant formatting considerations. |

> Tip
> 
> To configure the resource attributes that Loki promotes as labels you can use the [Grafana Cloud self-serve API](/docs/grafana-cloud/send-data/logs/config-self-serve/#otlp-label-mappings).

### Logs ingestion limits

Expand table

| Limit                                                                                             | Value                                                 | When you exceed the limit                                        |
|---------------------------------------------------------------------------------------------------|-------------------------------------------------------|------------------------------------------------------------------|
| The maximum length of a log line.                                                                 | 256 kilobytes                                         | Log lines that exceed the limit cause an ingestion exception.    |
| The maximum number of resource attributes promoted to Loki labels.                                | 15                                                    | Log messages that exceed the limit cause an ingestion exception. |
| The maximum number of resource attributes and logs attributes stored in Loki structured metadata. | 128 attributes and for an overall max of 64 kilobytes | Log messages that exceed the limit cause an ingestion exception. |
| The maximum length of a resource attribute value when promoted to Loki labels.                    | 2048 bytes                                            | Values that exceed the limit cause an ingestion exception.       |

When you send batch logs, Loki ingests only the logs that don’t exceed limits and returns exceptions for the logs that exceed limits.

### Loki versions before v3

Before Loki 3 introduced structured metadata, Loki converted OpenTelemetry logs in the [Alloy `otelcol.exporter.loki` component](/docs/grafana-cloud/send-data/alloy/reference/components/otelcol/otelcol.exporter.loki/) or in the [OpenTelemetry Collector Loki Exporter](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/exporter/lokiexporter/README.md) and stored them as JSON in the message of log lines.

Expand table

| OpenTelemetry log record field                                                                                 | Loki field                                                                                                                                                                                                                                                                                                                            |
|----------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`Timestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-timestamp)                       | `timestamp`                                                                                                                                                                                                                                                                                                                           |
| [`ObservedTimestamp`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-observedtimestamp)       | Not available.                                                                                                                                                                                                                                                                                                                        |
| [`TraceId`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-traceid)                           | `traceid` field of the Loki JSON log message.                                                                                                                                                                                                                                                                                         |
| [`SpanId`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-spanid)                             | `spanid` field of the Loki JSON log message.                                                                                                                                                                                                                                                                                          |
| [`TraceFlags`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-traceflags)                     | Not available                                                                                                                                                                                                                                                                                                                         |
| [`SeverityText`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitytext)                 | Simultaneously mapped to the `severity` field of the JSON log message and the `level` and `detected_level` label fields of the Loki log record.                                                                                                                                                                                       |
| [`SeverityNumber`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber)             | Not available.                                                                                                                                                                                                                                                                                                                        |
| [`Body`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-body)                                 | `body` field of the Loki JSON log message.                                                                                                                                                                                                                                                                                            |
| [`InstrumentationScope`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-instrumentationscope) | `instrumentation_scope_name` field of the JSON log message.                                                                                                                                                                                                                                                                           |
| [`Attributes`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-attributes)                     | JSON fields of the Loki log message                                                                                                                                                                                                                                                                                                   |
| [`Resource`](https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-resource)                         | Loki stores resource attributes as JSON fields of the Loki log message with the prefix `resources_`, for example `resources_k8s_namespace_name`, and promotes `service.name`, `service.namespace`, and `service.instance.id` to labels as follows `job=[${service.namespace}/]${service.name}` and `instance=${service.instance.id}`. |
|                                                                                                                | Loki adds a static label `exporter=OTLP`.                                                                                                                                                                                                                                                                                             |

To promote more resource attributes and log attributes to Loki labels, use the hints `loki.resource.labels` and `loki.attribute.labels` as detailed in the [OpenTelemetry Collector Loki Exporter documentation](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/lokiexporter) and the [Alloy `otelcol.exporter.loki` component documentation](/docs/grafana-cloud/send-data/alloy/reference/components/otelcol/otelcol.exporter.loki/).

## Traces

### Traces limits

Expand table

| Limit                                                               | Value                                                                     | When you exceed the limit                                                                    |
|---------------------------------------------------------------------|---------------------------------------------------------------------------|----------------------------------------------------------------------------------------------|
| The maximum volume of traces.                                       | 5 megabytes (MB) per trace, ingest rate of 15 MB/s and bursts of 20 MB/s. | Spans that exceed the limit cause an ingestion exception.                                    |
| The maximum number of resource attributes.                          | Limits are on the size of the traces.                                     |                                                                                              |
| The maximum number of span attributes.                              | Limits are on the size of the traces.                                     |                                                                                              |
| The maximum length of resource attribute and span attribute names.  | 1024 bytes                                                                | Grafana Cloud truncates attribute names that exceed the limit.                               |
| The maximum length of resource attribute and span attribute values. | 2048 bytes                                                                | Grafana Cloud truncates attribute names that exceed the limit.                               |
| The maximum size of spans in a batch.                               | Limits are on the size of the traces and the volume of bytes per second   | Grafana Cloud rejects spans that exceed the trace size limit and throws a partial exception. |
