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.
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
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:
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
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.
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:443so 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.
