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,logEndpoint
is 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:20
maxBufferSize
: number
Maximum retained buffer size if transport fails.
default:10 000
maxRetries
: number
Number of retries for failed deliveries.
default:3
omit
: 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
maxRetries
times 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-dsn
is 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
maxBatchSize
andmaxBufferSize
based 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