OpenTelemetry (OTLP)

Point any OpenTelemetry gRPC trace exporter at Neatlogs and your spans are ingested — no Neatlogs SDK required.

Neatlogs speaks OTLP (the OpenTelemetry Protocol) over gRPC, so you can send traces without installing a Neatlogs SDK. Point any OpenTelemetry trace exporter from an OpenTelemetry Collector, an instrumentation library like OpenLLMetry or a framework that emits the OpenTelemetry GenAI semantic conventions.

Note

Prefer a Neatlogs SDK when one exists for your language (Python, TypeScript, Go) — it auto-instruments providers and adds the @span decorator. OTLP is for everything else.


Endpoint

Note

gRPC endpoint: ingest.neatlogs.com:443


Authentication

Authenticate with your project key — the same key you pass to init() — sent as x-api-key in the gRPC metadata:

Warning

Use the x-api-key metadata key — not an Authorization: Bearer token.


Getting started

Configure a standard OpenTelemetry gRPC trace exporter with the Neatlogs endpoint and your x-api-key, then register it on your tracer provider.

import os
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

exporter = OTLPSpanExporter(
    endpoint="ingest.neatlogs.com:443",
    headers=(("x-api-key", os.environ["NEATLOGS_API_KEY"]),),
)

provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)

# Spans are batched — flush before your program exits, or they're lost.
provider.shutdown()
import { Metadata } from '@grpc/grpc-js';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';

const metadata = new Metadata();
metadata.set('x-api-key', process.env.NEATLOGS_API_KEY!);

const exporter = new OTLPTraceExporter({
  url: 'https://ingest.neatlogs.com',
  metadata,
});

const provider = new NodeTracerProvider({
  spanProcessors: [new BatchSpanProcessor(exporter)],
});
provider.register();

// Spans are batched — flush before your process exits, or they're lost.
await provider.shutdown();
import (
	"context"
	"crypto/tls"
	"log"
	"os"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	"google.golang.org/grpc/credentials"
)

exporter, err := otlptracegrpc.New(context.Background(),
	otlptracegrpc.WithEndpoint("ingest.neatlogs.com:443"),
	otlptracegrpc.WithHeaders(map[string]string{
		"x-api-key": os.Getenv("NEATLOGS_API_KEY"),
	}),
	otlptracegrpc.WithTLSCredentials(credentials.NewTLS(&tls.Config{})),
)
if err != nil {
	log.Fatal(err)
}

provider := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter))
otel.SetTracerProvider(provider)

// Spans are batched — flush before your program exits, or they're lost.
defer provider.Shutdown(context.Background())

Already running an OpenTelemetry app? Point it at Neatlogs without touching code via the standard environment variables:

export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://ingest.neatlogs.com
export OTEL_EXPORTER_OTLP_TRACES_HEADERS=x-api-key=<your-project-key>

Troubleshooting

Warning

Flush before your process exits. The exporter batches spans, so a short-lived script or a serverless handler can exit before the batch is sent — and those spans are silently dropped. Call provider.shutdown() (Python / TypeScript) or provider.Shutdown(ctx) (Go) before the process ends. Long-running services flush on their own interval; they only need this on graceful shutdown.

Warning

Export hangs or fails with DEADLINE_EXCEEDED? If the connection stalls before any span arrives, it's almost always client-side gRPC DNS resolution failing in a restricted network — a minimal container, a CI runner or behind a corporate proxy. Force the system resolver:

  • Python and other gRPC C-core exporters: set GRPC_DNS_RESOLVER=native.
  • Go: use the endpoint passthrough:///ingest.neatlogs.com:443 so the host is passed to the dialer verbatim.

See also

  • HTTP Trace Injection — a dependency-free JSON receiver, no OpenTelemetry required.
  • Go SDK — a native OTLP-based SDK that wraps the exporter setup above.
  • Span Kinds — the span taxonomy Neatlogs maps OTLP spans into.

On this page

Ask Neatlogs AI

Answers from the docs

How can I help?

Ask anything about instrumenting, tracing, or the Neatlogs dashboard.