OpenTelemetry
Send traces and logs from any OpenTelemetry SDK or collector without the OpenPerf SDK.
OpenPerf accepts OTLP over HTTP, so any OpenTelemetry SDK or the Collector can send to it. Use this for languages the SDK doesn’t cover, or an app that already uses OpenTelemetry.
| Signal | Path |
|---|---|
| Traces | /v1/traces |
| Logs | /v1/logs |
Metrics and gRPC are not accepted. Bodies are protobuf (application/x-protobuf) or JSON (application/json), plain or gzip.
Connect
Copy the DSN from the project settings, under Connection. Its token, opf_…, authenticates the requests. The Endpoint shown there is the intake address with /v1 already added.
With the standard environment variables:
OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.example.com"
OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer%20opf_…"
OTEL_METRICS_EXPORTER="none"
OTEL_SERVICE_NAME="checkout"
OTEL_RESOURCE_ATTRIBUTES="deployment.environment.name=production,service.version=1.4.2"
OTEL_EXPORTER_OTLP_ENDPOINT takes the address without /v1; the SDK adds /v1/traces and /v1/logs. Per-signal variables such as OTEL_EXPORTER_OTLP_TRACES_ENDPOINT take the full URL.
A client that can’t set headers can pass the token as ?key=opf_… instead.
Browser exporters work too. The intake answers CORS preflights, and Allowed origins in the project settings limits which sites may send. Empty accepts any origin; requests from an unlisted origin get 403.
Send a request
curl https://ingest.example.com/v1/logs \
-H "Authorization: Bearer opf_…" \
-H "Content-Type: application/json" \
-d '{
"resourceLogs": [{
"resource": { "attributes": [
{ "key": "service.name", "value": { "stringValue": "checkout" } }
] },
"scopeLogs": [{ "logRecords": [{
"severityNumber": 17,
"body": { "stringValue": "Payment failed" },
"attributes": [
{ "key": "exception.type", "value": { "stringValue": "PaymentError" } }
]
}] }]
}]
}'
The log shows under Logs and, because it carries exception.type, as an error under Errors.
Attributes OpenPerf reads
Resource attributes:
| Attribute | Used for |
|---|---|
service.name |
The service. unknown when missing. |
deployment.environment.name |
The environment. deployment.environment also works. default when missing. |
service.version |
The release. Needed for source maps and release health. |
vcs.ref.head.revision |
The commit the code was built from. |
telemetry.sdk.language |
webjs, set by OpenTelemetry’s web SDK, marks the data as coming from a browser. |
Span and log attributes:
| Attribute | Used for |
|---|---|
exception.type, exception.message, exception.stacktrace |
The error’s type, message and stack. |
openperf.error.fingerprint |
Groups all errors with the same value together. |
user.id, user.email, user.name |
The user. |
http.route |
Names server transactions, such as GET /users/:id. |
Errors
An error is created from:
- a span event named
exception, whichrecordExceptionadds. Its level iserror. - a log record with
exception.typeorexception.stacktrace. Its level follows the log severity:fatal,error, orwarnfor anything lower.
Errors with a similar type and stack join the same group. Set openperf.error.fingerprint to group them yourself.
Transactions
Root spans, server spans and consumer spans count as transactions in Performance. In the browser, the documentLoad span of the document load instrumentation counts as a page load.
Responses
| Status | Meaning |
|---|---|
200 |
Accepted. Spans without a valid trace or span ID are dropped and counted in partialSuccess. |
400 |
The body isn’t valid OTLP. |
401 |
Unknown token. |
403 |
The browser origin isn’t in Allowed origins. |
413 |
The body is too large. The limit is 10 MB unless your operator changed it. |
415 |
Unsupported content type or encoding. |
429 |
Rate limited, too many invalid tokens, or the intake is busy. Retry after Retry-After seconds. |
503 |
The intake is unavailable. Retry after Retry-After seconds. |
A body identical to one sent in the last 15 minutes is answered with 200 and dropped, so retries are safe.