> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bronto.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Ingest OpenTelemetry data into Bronto

> Instrument any application to send logs and distributed traces to Bronto using the OpenTelemetry SDK and Collector, with OTLP over HTTP or gRPC and no code rewrites.

The pages in this section show you how to instrument your application with the OpenTelemetry SDK to send **logs and traces** to Bronto over OTLP/HTTP. Both signals are co-equal: logs are bridged from your existing logging framework — no log statement rewrites needed — and traces are emitted via a tracer provider.

<Tip>
  Want to see Bronto with real data before instrumenting your own app? [Try Bronto with the OpenTelemetry Demo](/getting-started/otel-demo) — spin up a sample microservices app and route its logs and traces into Bronto in minutes.
</Tip>

<Tip>
  Calling an LLM (OpenAI, Anthropic, Amazon Bedrock, etc.)? Every language page below also has a **GenAI semantic conventions** section covering `gen_ai.*` spans — auto-instrumentation where it exists, manual spans where it doesn't, and the experimental prompt/response capture flags. See [LLM Observability](/ai-features/llm-observability) for how Bronto surfaces that data.
</Tip>

## Choose your language

<CardGroup cols="3">
  <Card title="Python" href="/opentelemetry/python">
    <div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
      <img src="https://datadog-docs.imgix.net/images/integrations_logos/python.png?auto=format&fit=max&w=200" alt="Python" style={{height: "64px", width: "auto", objectFit: "contain", maxWidth: "100%", backgroundColor: "white"}} nozoom />
    </div>
  </Card>

  <Card title=".NET" href="/opentelemetry/dotnet">
    <div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
      <img src="https://datadog-docs.imgix.net/images/integrations_logos/dotnet.png?auto=format&fit=max&w=200" alt=".NET" style={{height: "64px", width: "auto", objectFit: "contain", maxWidth: "100%", backgroundColor: "white"}} nozoom />
    </div>
  </Card>

  <Card title="Java" href="/opentelemetry/java">
    <div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
      <img src="https://datadog-docs.imgix.net/images/integrations_logos/java.png?auto=format&fit=max&w=200" alt="Java" style={{height: "64px", width: "auto", objectFit: "contain", maxWidth: "100%", backgroundColor: "white"}} nozoom />
    </div>
  </Card>

  <Card title="Kotlin" href="/opentelemetry/kotlin">
    <div style={{display: "flex", justifyContent: "center", alignItems: "center", minHeight: "64px"}}>
      <img src="https://mintcdn.com/bronto/mPmcNraAV0CURsWG/images/languages/kotlin.svg?fit=max&auto=format&n=mPmcNraAV0CURsWG&q=85&s=1f75b424d48b6a642a953d05e7d75cd6" alt="Kotlin" style={{height: "48px", width: "auto", objectFit: "contain", maxWidth: "100%", backgroundColor: "white"}} nozoom width="174" height="48" data-path="images/languages/kotlin.svg" />
    </div>
  </Card>

  <Card title="Node.js / JavaScript" href="/opentelemetry/nodejs">
    <div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
      <img src="https://datadog-docs.imgix.net/images/integrations_logos/nodejs.png?auto=format&fit=max&w=200" alt="Node.js" style={{height: "64px", width: "auto", objectFit: "contain", maxWidth: "100%", backgroundColor: "white"}} nozoom />
    </div>
  </Card>

  <Card title="Go" href="/opentelemetry/go">
    <div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
      <img src="https://datadog-docs.imgix.net/images/integrations_logos/golang.png?auto=format&fit=max&w=200" alt="Go" style={{height: "64px", width: "auto", objectFit: "contain", maxWidth: "100%", backgroundColor: "white"}} nozoom />
    </div>
  </Card>

  <Card title="Ruby" href="/opentelemetry/ruby">
    <div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
      <img src="https://datadog-docs.imgix.net/images/integrations_logos/ruby.png?auto=format&fit=max&w=200" alt="Ruby" style={{height: "64px", width: "auto", objectFit: "contain", maxWidth: "100%", backgroundColor: "white"}} nozoom />
    </div>
  </Card>

  <Card title="PHP" href="/opentelemetry/php">
    <div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
      <img src="https://datadog-docs.imgix.net/images/integrations_logos/php.png?auto=format&fit=max&w=200" alt="PHP" style={{height: "64px", width: "auto", objectFit: "contain", maxWidth: "100%", backgroundColor: "white"}} nozoom />
    </div>
  </Card>

  <Card title="Erlang / Elixir" href="/opentelemetry/erlang-elixir">
    <div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
      <img src="https://datadog-docs.imgix.net/images/integrations_logos/erlang.png?auto=format&fit=max&w=200" alt="Erlang / Elixir" style={{height: "64px", width: "auto", objectFit: "contain", maxWidth: "100%", backgroundColor: "white"}} nozoom />
    </div>
  </Card>

  <Card title="Rust" href="/opentelemetry/rust">
    <div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
      <img src="https://datadog-docs.imgix.net/images/integrations_logos/rust.png?auto=format&fit=max&w=200" alt="Rust" style={{height: "64px", width: "auto", objectFit: "contain", maxWidth: "100%", backgroundColor: "white"}} nozoom />
    </div>
  </Card>

  <Card title="C++" href="/opentelemetry/cpp">
    <div style={{display: "flex", justifyContent: "center", alignItems: "center"}}>
      <img src="https://datadog-docs.imgix.net/images/integrations_logos/cpp.png?auto=format&fit=max&w=200" alt="C++" style={{height: "64px", width: "auto", objectFit: "contain", maxWidth: "100%", backgroundColor: "white"}} nozoom />
    </div>
  </Card>

  <Card title="Swift" href="/opentelemetry/swift">
    <div style={{display: "flex", justifyContent: "center", alignItems: "center", minHeight: "64px"}}>
      <img src="https://mintcdn.com/bronto/mPmcNraAV0CURsWG/images/languages/swift.svg?fit=max&auto=format&n=mPmcNraAV0CURsWG&q=85&s=cc95602c40a850f5b2fbf410aa6c424d" alt="Swift" style={{height: "48px", width: "auto", objectFit: "contain", maxWidth: "100%", backgroundColor: "white"}} nozoom width="191" height="59" data-path="images/languages/swift.svg" />
    </div>
  </Card>
</CardGroup>

## How OTel logging works

OpenTelemetry provides a **Log Bridge API**. You attach an OTel handler or appender to your existing logging framework — Logback, Python's `logging`, `ILogger`, Winston, and so on. Every log record your application emits passes through the bridge, which enriches it with structured metadata and forwards it to the OTel exporter.

**Nothing in your application code changes.** `logger.info()`, `log.warn()`, `console.log()` — all of these keep working exactly as before.

### What the bridge adds

Here is the same log event before and after the bridge:

<CodeGroup>
  ```text Before — plain log output theme={"dark"}
  Payment failed for user 123
  ```

  ```json After — OTel log record exported to Bronto theme={"dark"}
  {
    "timestamp": "2024-11-14T10:32:05.123456789Z",
    "severity": "ERROR",
    "body": "Payment failed for user 123",
    "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
    "span_id": "00f067aa0ba902b7",
    "resource": {
      "service.name": "payments-api",
      "service.namespace": "checkout",
      "deployment.environment": "production"
    },
    "attributes": {
      "user.id": "123",
      "exception.type": "PaymentGatewayError",
      "exception.message": "Card declined: insufficient funds"
    }
  }
  ```
</CodeGroup>

The `trace_id` and `span_id` were injected automatically because this log was emitted inside a traced request. The `service.name` and `service.namespace` were set once at application startup and are now attached to every log record — no per-statement boilerplate.

## Why it's worth adopting

**Automatic trace correlation**

When a log is emitted inside a traced request, the active `trace_id` and `span_id` are injected automatically — no manual MDC propagation or context threading needed. In Bronto, `trace_id` is a queryable field. Click it to jump from a log line directly to the corresponding trace.

**Structured by default**

Every OTel log record follows a defined schema: `timestamp`, `severity`, `body`, `attributes`, `resource`, and `instrumentation_scope`. Not "structured if you remembered to configure JSON output" — structured unconditionally, in a format Bronto understands natively.

**Service identity is automatic**

`service.name` and `service.namespace` are Resource attributes — set once at SDK initialisation, then attached to every log record that process emits. You do not add them to individual log statements. In Bronto, they map directly to Dataset and Collection with no extra configuration.

**Semantic conventions**

OTel defines standard attribute names across all languages: `http.request.method`, `exception.type`, `db.system`, `user.id`, and hundreds more. When all your services use the same attribute names, your Bronto queries work identically regardless of which language or framework emitted the log.

**One pipeline for logs, traces, and metrics**

Logs, traces, and metrics all flow through the same OTel SDK and exporter. One endpoint URL, one API key, one exporter configuration. Adding traces later (Phase 2) means extending existing setup — not wiring a new pipeline.

**Vendor portability**

OTLP is an open standard. Switching your observability backend requires changing one endpoint URL, not rewriting instrumentation.

**Zero code churn**

Adoption is a configuration change, not a refactor. Existing log statements are untouched.

## How OTel concepts map to Bronto

| OTel concept             | Bronto concept    | How it's set                      |
| ------------------------ | ----------------- | --------------------------------- |
| `service.name`           | Dataset           | Resource attribute at SDK init    |
| `service.namespace`      | Collection        | Resource attribute at SDK init    |
| `trace_id` / `span_id`   | Queryable fields  | Automatic when tracing is active  |
| `severity`               | Log level         | Mapped from OTel `SeverityNumber` |
| `attributes`             | Searchable fields | Any key/value on the log record   |
| `deployment.environment` | Searchable field  | Resource attribute at SDK init    |

No Bronto-specific SDK attributes are needed. Standard OTel Resource attributes are sufficient.

### Endpoints

| Region | Logs                                     | Traces                                     |
| ------ | ---------------------------------------- | ------------------------------------------ |
| EU     | `https://ingestion.eu.bronto.io/v1/logs` | `https://ingestion.eu.bronto.io/v1/traces` |
| US     | `https://ingestion.us.bronto.io/v1/logs` | `https://ingestion.us.bronto.io/v1/traces` |

All requests require the header `x-bronto-api-key: <YOUR_API_KEY>`. See [API Keys](/Account-Management/API-Keys) for how to create one.

## Two ways to get data into Bronto

### Via OTel Collector (recommended)

Your application exports to a local OTel Collector process, which batches, filters, and forwards to Bronto. The Collector can enrich attributes, route signals to multiple destinations, and apply sampling rules before data leaves your infrastructure.

**Best for:** multi-service environments, existing Collector infrastructure, or pipelines that need transformation or fan-out before ingestion.

<Tip>
  See [Connect Open Telemetry to Bronto](/agent-setup/open-telemetry) for Collector setup.
</Tip>

### Direct export

The OTel SDK inside your application exports logs and traces directly to Bronto over OTLP/HTTP. No additional components required.

**Best for:** new projects, simple architectures, or teams that want the least possible operational overhead.
