OpenTelemetry (OTLP) Endpoint

GoodLogs exposes a native OTLP/HTTP trace receiver, so any OpenTelemetry SDK or Collector can ship spans to GoodLogs without code changes — just an exporter config.

Protocol support today

SignalHTTP/JSONHTTP/ProtogRPC
Traces⏳ deferred
Logs⏳ deferred
Metrics

Pick http/json or http/protobuf — both go to the same endpoint. gRPC OTLP (:4317) is not supported; switch your Collector exporter to otlphttp for now.

Endpoint

bash
POST https://api.goodlogs.io/v1/traces
Authorization: Bearer <PROJECT_SECRET_KEY>
Content-Type: application/json
  • Region routing: hit your project's regional host (e.g. https://eu.api.goodlogs.io/v1/traces) for lowest latency. The global api.goodlogs.io host transparently forwards.
  • Auth: any project API key with the ingest:write scope. Same keys you already use for the native envelope endpoint — find them in Project Settings → API Keys.
  • Body cap: 10 MB per request. Batch and retry in your Collector.

The response is JSON:

json
{ "accepted_spans": 42, "rejected_spans": 0 }

Spans missing traceId or spanId are counted in rejected_spans but never fail the whole batch — this matches Collector retry semantics.

OpenTelemetry Collector

Add a goodlogs exporter under exporters: in your Collector config:

yaml
exporters:
  otlphttp/goodlogs:
    endpoint: https://eu.api.goodlogs.io
    encoding: json
    headers:
      Authorization: "Bearer ${env:GOODLOGS_SECRET_KEY}"

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp/goodlogs]

The Collector appends /v1/traces to the endpoint automatically.

SDK (no Collector)

If you're exporting straight from an OTel SDK, point it at the same endpoint:

bash
export OTEL_EXPORTER_OTLP_PROTOCOL=http/json
export OTEL_EXPORTER_OTLP_ENDPOINT=https://eu.api.goodlogs.io
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer $GOODLOGS_SECRET_KEY"
export OTEL_SERVICE_NAME=checkout-api
export OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production,service.version=v3.1.0

That's it — every span you emit becomes queryable in the explorer:

lua
from:spans op:http.server status:error | groupby http.route

How OTLP maps to the GoodLogs span model

OTLP fieldGoodLogs column / behaviour
resource.attributes["service.name"]service
resource.attributes["deployment.environment"]environment
resource.attributes["service.version"]release
span.kind = SERVER + http.* attrsop = http.server
span.kind = CLIENT + http.* attrsop = http.client
db.system presentop = db.query + typed db_system
messaging.system + kind=CONSUMERop = queue.consume
attributes["http.method"]http_method
attributes["http.route"]http_route
attributes["http.status_code"]http_status_code
status.code = OK (1)status = ok
status.code = ERROR (2)status = error
status.code = UNSET (0)status = ok
events[]events[] with ts / name / attributes
Everything elseattributes JSON blob

startTimeUnixNano / endTimeUnixNano are accepted as either strings (per the OTLP spec) or numbers — most SDKs send strings.

See also