ontreDeveloper documentation

Ontre API / OpenTelemetry

Send OpenTelemetry to Ontre

If your services already use OpenTelemetry, point an exporter at Ontre. You keep your SDKs and Collector. Ontre reads incoming requests and named business events, and turns them into the events it measures.

OTLP/HTTPBinary ProtobufTraces and logsToken header

All requests go to https://api.ontre.app. The OTLP path comes from the connection’s postTo field.

Overview

An admin creates an OpenTelemetry connection for a project and chooses its environment, such as production. Your exporter sends traces and logs to that connection’s URL with the connection token in a header. Ontre returns 200 once the batch is stored.

Ontre does not store full traces or log lines. From traces it keeps one event per incoming request or handled message. From logs it keeps only named events that carry an ID. Everything else is skipped.

Ontre accepts traces and logs only, over HTTP with binary Protobuf. Metrics, JSON encoding and gRPC are not supported.

Set up a connection

01Create an OpenTelemetry connectionAn admin creates it for one project and one environment.
02Store the tokenThe token is shown once. Keep it in your secrets store or Collector config.
03Point your exporter at OntreSet the endpoint, protocol and token header, then deploy.

Project admins create the connection with POST /api/v1/projects/{projectId}/connections:

Create requestJSON
{
  "displayName": "Checkout production",
  "kind": "otlp",
  "environment": "production"
}
Response · 201JSON
{
  "id": "0190a0b0-6c1e-7a2b-9f3d-5e4c3b2a1908",
  "displayName": "Checkout production",
  "token": "8f3c0c1e9b7a4d2f8e6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706",
  "postTo": "/otlp/0190a0b0-6c1e-7a2b-9f3d-5e4c3b2a1908",
  "signingKey": "NOT_REQUIRED"
}

The environment cannot be changed later. Use one connection per environment: a staging connection and a production connection, for example. No signing key is needed; the token authenticates every request.

Ontre stores only a hash of the token and cannot show it again. If you lose it, create a new connection.

Endpoint and headers

POSThttps://api.ontre.app/otlp/{connectionId}/v1/traces
POSThttps://api.ontre.app/otlp/{connectionId}/v1/logs

Most exporters take a base URL and add /v1/traces and /v1/logs themselves. Use https://api.ontre.app/otlp/{connectionId} as that base. When you configure a single signal’s URL directly, include the full path.

HeaderValue
X-Ontre-TokenThe connection token from setup.
Content-Typeapplication/x-protobuf. OpenTelemetry exporters set this when the protocol is http/protobuf.
Content-EncodingOptional. gzip or omitted.

Every resource must set service.name. If it also sets deployment.environment.name, the value must match the connection’s environment.

Traces

Ontre keeps server spans, one per incoming request, and consumer spans, one per handled message. Internal, client and producer spans are skipped. Each kept span becomes one event named after its operation and outcome.

SpanOperation nameExample event
HTTP serverMethod and http.routePOST /charge error
Consumermessaging.destination.template or messaging.destination.nameprocess orders ok
Other serverThe span nameProcessRefund unknown

HTTP server spans need http.route, the route template such as /orders/{id}. A raw path like /orders/88231 would create a new operation for every order, so spans without a route are rejected. Span and destination names that contain IDs or URLs are rejected for the same reason. Temporary queues are rejected.

Outcome

Span statusHTTP statusOutcome
ERRORAny or noneerror
OK or unset5xxerror
OK or unset2xx or 3xxok
OK or unset4xxunknown
OKNoneok
UnsetNoneunknown

ok means the request was not a server failure. It does not mean a payment settled or an order completed. To measure business outcomes, send log events.

The event time is the span’s end time.

Sampling changes the numbers. Counts and rates from traces describe the spans you export. If you sample, especially with tail or error-biased sampling, rates in Ontre will not match your real traffic. Export server and consumer spans unsampled to an Ontre pipeline when you want accurate rates.

Log events

Use log events for business moments such as an order being placed or a payment captured. Ontre keeps a log record when it has an event name and an ID. Ordinary log lines are skipped.

FieldRequiredMeaning
Event nameYesThe log record’s event_name field, or an event.name attribute. For example order.placed. At most 128 characters, and no IDs in the name.
event.idYesAn attribute unique for that service and event name, such as the order ID. Ontre uses it to store retried events once. A named event without it is rejected.
TimestampNoThe record’s time, then its observed time, then the time Ontre received it.

The same ID can appear on different event names. order.placed and order.paid for order ord_88f2 are two events.

Configuration examples

Set ONTRE_OTLP_ENDPOINT to https://api.ontre.app plus the returned postTo path, and ONTRE_TOKEN to the connection token. Send only traces and logs to Ontre.

environment otel-collector.yaml telemetry.mjs telemetry.py
# Works with any OpenTelemetry SDK that reads the standard variables
OTEL_SERVICE_NAME=checkout-api
OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=production
OTEL_EXPORTER_OTLP_ENDPOINT=https://api.ontre.app/otlp/{connectionId}
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_HEADERS=X-Ontre-Token=YOUR_TOKEN
OTEL_TRACES_EXPORTER=otlp
OTEL_LOGS_EXPORTER=otlp
OTEL_METRICS_EXPORTER=none
exporters:
  otlphttp/ontre:
    endpoint: ${env:ONTRE_OTLP_ENDPOINT}   # https://api.ontre.app/otlp/{connectionId}
    encoding: proto
    compression: gzip
    headers:
      X-Ontre-Token: ${env:ONTRE_TOKEN}

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp/ontre]
    logs:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp/ontre]
    # Do not add otlphttp/ontre to a metrics pipeline
// npm i @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-proto \
//   @opentelemetry/exporter-logs-otlp-proto @opentelemetry/sdk-logs @opentelemetry/api-logs
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-proto';
import { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';
import { logs } from '@opentelemetry/api-logs';

const endpoint = process.env.ONTRE_OTLP_ENDPOINT;
const headers = { 'X-Ontre-Token': process.env.ONTRE_TOKEN };

const sdk = new NodeSDK({
  serviceName: 'checkout-api',
  // Signal URLs set in code need the full path
  traceExporter: new OTLPTraceExporter({ url: endpoint + '/v1/traces', headers }),
  logRecordProcessors: [new BatchLogRecordProcessor(
    new OTLPLogExporter({ url: endpoint + '/v1/logs', headers }))]
});
sdk.start();

// A business event: named, with an ID
logs.getLogger('checkout').emit({
  body: 'order placed',
  attributes: { 'event.name': 'order.placed', 'event.id': 'ord_88f2' }
});
# pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
import logging
import os

from opentelemetry import trace
from opentelemetry._logs import set_logger_provider
from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

endpoint = os.environ["ONTRE_OTLP_ENDPOINT"]
headers = {"X-Ontre-Token": os.environ["ONTRE_TOKEN"]}
resource = Resource.create({
    "service.name": "checkout-api",
    "deployment.environment.name": "production",
})

# Signal URLs set in code need the full path
tracer_provider = TracerProvider(resource=resource)
tracer_provider.add_span_processor(BatchSpanProcessor(
    OTLPSpanExporter(endpoint=endpoint + "/v1/traces", headers=headers)))
trace.set_tracer_provider(tracer_provider)

logger_provider = LoggerProvider(resource=resource)
logger_provider.add_log_record_processor(BatchLogRecordProcessor(
    OTLPLogExporter(endpoint=endpoint + "/v1/logs", headers=headers)))
set_logger_provider(logger_provider)

log = logging.getLogger("checkout")
log.addHandler(LoggingHandler(logger_provider=logger_provider))
log.setLevel(logging.INFO)

# A business event: named, with an ID
log.info("order placed", extra={"event.name": "order.placed", "event.id": "ord_88f2"})

Instrumentation libraries for your web framework create the server spans. Make sure they record http.route.

What Ontre keeps

Ontre keeps only the fields below. Request and response bodies, log message bodies, user attributes and all other span attributes are discarded when the batch arrives and never stored.

FromAttributes kept
Resourceservice.name, service.namespace, service.version, deployment.environment.name, cloud.region
Server and consumer spanshttp.route, http.request.method, http.response.status_code, error.type, the trace ID, the operation and the outcome
Log eventsThe event name, event.id and error.type

Events from different services or namespaces stay separate. Events are kept for 30 days.

Responses and retries

Ontre answers as the OTLP specification describes, so standard exporters handle retries correctly. Error responses carry a Protobuf status message with a short reason.

StatusMeaningWhat to do
200Stored. If some records were rejected, partial_success gives the count and the reasons.Nothing, unless records were rejected. Fix those at the source; resending them will not help.
400The body is not a valid OTLP Protobuf request.Check the protocol is http/protobuf.
401Unknown or disabled connection, or a wrong token.Check the URL and the X-Ontre-Token header.
403The connection is paused.Ask an admin to activate it. Data sent while paused is not stored.
413Over 5 MiB, or over 1,000 spans or log records.Send smaller batches.
415Not application/x-protobuf, or an encoding other than gzip.Use http/protobuf and gzip or no compression.
501Metrics sent to /v1/metrics.Turn off metrics export to Ontre.
429, 503Temporarily unable to accept data. Nothing from the request was stored.Your exporter retries automatically, using Retry-After when present.

Why records are rejected

  • The resource has no service.name, or its environment differs from the connection’s.
  • A span has an invalid trace or span ID, no end time, or ends before it starts.
  • An HTTP server span has no http.route, or an operation or event name looks like it contains an ID or a URL.
  • A named log event has no event.id.
  • A timestamp is more than five minutes in the future or more than 30 days old.
  • A new operation or event name is over the connection’s name limit.

Retries are safe. Ontre stores each span once, by trace and span ID, and each log event once, by service, event name and event.id.

Limits

LimitValue
Request size5 MiB, before and after decompression
Records per request1,000 spans or log records
Operations per connection300 distinct operations, counted per service
Event names per connection100 distinct log event names, counted per service
Event ageUp to 30 days old, and no more than five minutes in the future

Names already accepted always continue to work. Once a limit is reached, records with new names are rejected and reported in partial_success. If your services need more, contact Ontre support.

Connection lifecycle

An admin can pause or resume an OpenTelemetry connection through authenticated endpoints:

POST/api/v1/projects/{projectId}/connections/{connectionId}/suspend
POST/api/v1/projects/{projectId}/connections/{connectionId}/activate

Both return 204 on success. GET /api/v1/projects/{projectId}/connections lists each connection’s status, environment and postTo path. Disabling a connection stops its token from working.

Paused connections refuse data. Requests to a paused connection return 403. Exporters do not retry a 403, so telemetry sent while paused is lost. It is not replayed after activation.