Telemetry
Configure OpenTelemetry tracing and structured logging for observability.
Telemetry
HypLab uses OpenTelemetry for distributed tracing and Pino for structured logging. All telemetry is opt-in -- it is disabled by default and can be enabled via environment variables.
Overview
| Component | Technology | Purpose |
|---|---|---|
| Backend tracing | OpenTelemetry + OTLP | Distributed trace export |
| Backend logging | Pino | Structured log output |
| Frontend tracing | OpenTelemetry + OTLP | Browser-side trace export |
| Trace viewer | Jaeger | View and search traces |
| Metrics (optional) | Prometheus + Grafana | Dashboards and alerting |
Environment variables
Backend
| Variable | Default | Description |
|---|---|---|
TELEMETRY_ENABLED | false | Enable OpenTelemetry tracing |
OTEL_EXPORTER_OTLP_ENDPOINT | http://localhost:4318/v1/traces | OTLP HTTP endpoint |
OTEL_SERVICE_NAME | api | Service name in traces |
OTEL_SERVICE_VERSION | 0.1.0 | Service version in traces |
LOG_LEVEL | debug (dev) / info (prod) | Log level: error, warn, info, debug |
Frontend
| Variable | Default | Description |
|---|---|---|
NEXT_PUBLIC_TELEMETRY_ENABLED | false | Enable frontend tracing |
NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT | -- | OTLP HTTP endpoint (required if enabled) |
NEXT_PUBLIC_OTEL_SERVICE_NAME | app | Service name in traces |
Disabling telemetry
To completely disable telemetry (the default for open-source deployments):
Backend (api/.env):
TELEMETRY_ENABLED=false
LOG_LEVEL=infoFrontend (app/.env.local):
NEXT_PUBLIC_TELEMETRY_ENABLED=falseEnabling telemetry
Step 1: Enable in environment variables
# Backend
TELEMETRY_ENABLED=true
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318/v1/traces
# Frontend
NEXT_PUBLIC_TELEMETRY_ENABLED=true
NEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318Step 2: View traces
The Docker setup includes the OpenTelemetry Collector and Jaeger automatically. Access Jaeger at:
http://localhost:16686What is instrumented
Backend (when enabled):
- All Express.js HTTP requests and responses
- Outbound HTTP requests
- Structured logging (Pino logs are always active, independent of tracing)
Frontend (when enabled):
- All
fetchAPI requests - All
XMLHttpRequestrequests
Observability stack (optional)
For metrics dashboards, enable the Prometheus + Grafana stack:
make observability
# or
docker compose -f docker/docker-compose.yml --profile observability up -d prometheus grafanaAccess:
- Grafana: http://localhost:3001 (login: admin/admin)
- Prometheus: http://localhost:9090
Note: The /metrics endpoint is not yet implemented in the backend. Prometheus is configured and ready for when it is.
Logging
Structured logging with Pino
Backend logging is always active (independent of telemetry). Pino produces:
- Development: Pretty-printed, colorized log output.
- Production: JSON format for log aggregation tools.
Log levels: error, warn, info, debug
Filtered requests: Health checks (/health) and CORS preflight (OPTIONS) requests are not logged to reduce noise.
Best practices
// Good: structured logging with context
logger.info({ userId, action: 'create_person' }, 'Person created')
logger.error({ error, personId }, 'Failed to create person')
// Avoid: unstructured strings
console.log('Person created') // Don't do thisTroubleshooting
Traces not appearing in Jaeger
- Check that
otel-collectorandjaegercontainers are running:docker compose -f docker/docker-compose.yml ps - Verify
TELEMETRY_ENABLED=trueis set. - Check collector logs:
docker compose -f docker/docker-compose.yml logs otel-collector
Frontend telemetry not working
- Verify
NEXT_PUBLIC_TELEMETRY_ENABLED=trueandNEXT_PUBLIC_OTEL_EXPORTER_OTLP_ENDPOINTare set. - Check browser console for OpenTelemetry initialization messages.
- Verify CORS is configured in the collector for your frontend origin.
Next: Docker Production -- deploy HypLab to production.