TriFrost

TriFrost Docs

Learn and build with confidence, from a first project with workers to global scale on bare metal.

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 and maxBufferSize 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

Resources

Loved the read? Share it with others