Logger: OtelHttp
The OtelHttpExporter sends structured logs and spans to an OpenTelemetry-compatible collector via HTTP. Itβs TriFrostβs production-grade exporter when you want real observability, including distributed tracing, performance timelines, and full-context logs.
It supports:
- OTLP-over-HTTP export of logs and spans
- Batch buffering, retry with backoff, and payload scrubbing
- Compatible with tools like: SigNoz, Uptrace, Grafana Tempo, ...
The TriFrost website for example uses a combination of JsonExporter for Cloudflare observability and OTEL through UpTrace.
π₯ Import and Use
import {App, OtelHttpExporter} from '@trifrost/core';
new App({
...
tracing: {
exporters: ({env}) => [
new OtelHttpExporter({
logEndpoint: env.OTEL_LOGS,
spanEndpoint: env.OTEL_SPANS,
headers: {
Authorization: `Bearer ${env.OTEL_TOKEN}`
}
}),
],
},
...
})Note: π‘ By default, logs and spans are flushed at the end of each request β you do not need to manually call
flush().
βοΈ Available Options
logEndpoint: string
OTEL collector HTTP endpoint for logs.spanEndpoint: string
Optional. If not provided,logEndpointis reused for spans.headers:Record<string, string>
Optional headers to include in every OTLP request. (usually for authorization purposes)maxBatchSize: number
How many logs/spans to batch before flushing.
default:20maxBufferSize: number
Maximum retained buffer size if transport fails.
default:10 000maxRetries: number
Number of retries for failed deliveries.
default:3omit: TriFrostLogScramblerValue[]
Fields to redact before export.
default:OMIT_PRESETS.default
π See Scrambling Hygiene for how redaction works
π What gets sent?
Logs -> OTEL resourceLogs
Each ctx.logger.log(...) call is sent as an OTLP log record:
{
"timeUnixNano": 1717689600000000000,
"severityText": "INFO",
"body": {"stringValue": "User logged in"},
"attributes": [
{"key": "trace_id", "value": {"stringValue": "abc..."}},
{"key": "ctx.userId", "value": {"stringValue": "123"}},
{"key": "data.status", "value": {"stringValue": "success"}}
]
}Spans -> OTEL resourceSpans
Spans created via ctx.logger.span(...), decorators, or middleware tracing are serialized as full OTLP spans:
{
"name": "fetchUser",
"traceId": "...",
"spanId": "...",
"startTimeUnixNano": 1717689600000000000,
"endTimeUnixNano": 1717689600123456000,
"attributes": [
{"key": "db.query", "value": {"stringValue": "SELECT * FROM users WHERE ..."}}
]
}Retry and Buffering
- Batches are retried up to
maxRetriestimes on network failure - Retries use jittered exponential backoff
- If all retries fail, logs/spans are requeued if within buffer limit, otherwise they're dropped to prevent memory pressure
Note: Failed sends log a console warning β you may wish to hook this in production.
Examples
Minimal
new OtelHttpExporter({
logEndpoint: 'https://collector.mycompany.com/v1/logs'
});With custom headers
new OtelHttpExporter({
logEndpoint: 'https://otel.example.com/v1/logs',
headers: {
'X-Project-ID': 'abc123',
'Authorization': `Bearer ${process.env.OTEL_TOKEN}`
}
});Custom retry/batch settings
new OtelHttpExporter({
logEndpoint: 'https://myotel/logs',
maxBatchSize: 50,
maxBufferSize: 5000,
maxRetries: 5
});SigNoz (EU Region)
new OtelHttpExporter({
logEndpoint: 'https://ingest.eu.signoz.cloud/v1/logs',
spanEndpoint: 'https://ingest.eu.signoz.cloud/v1/traces',
headers: {
'signoz-access-token': env.SIGNOZ_API_TOKEN
}
});Note: You'll find this token in your SigNoz project settings under API Tokens. Make sure you match the ingest region (
eu,us, etc).
π See SigNoz OTEL Setup for more info
Uptrace
new OtelHttpExporter({
logEndpoint: 'https://otlp.uptrace.dev/v1/logs',
spanEndpoint: 'https://otlp.uptrace.dev/v1/traces',
headers: {
'uptrace-dsn': env.UPTRACE_DSN
}
});Note: The
uptrace-dsnis a secure connection string from your Uptrace project β it contains project ID, token, and endpoint info.
π See Uptrace DSN Guide for more info
Best Practices
- β Use in production when full tracing and telemetry are required
- β
Tune
maxBatchSizeandmaxBufferSizebased on expected traffic - β
Set meaningful redaction via
omit - π‘ You can use this exporter in tandem with other exporters such as JsonExporter
- π‘ Want to go fancy? Make use of TriFrost's isDevMode function to refine between dev and prod
- β Donβt rely on it for logs in CI β prefer Console/Json exporters