Skip to main content

Telemetry Configuration

Complete configuration reference for logging, metrics, and tracing across AppServer and SDKs.

Overview

The telemetry system provides three pillars of observability:

  • Traces - Distributed request tracing with OpenTelemetry
  • Metrics - Performance and business metrics exported to Prometheus
  • Logs - Structured logging with trace correlation

All components export telemetry data to an OpenTelemetry Collector, which routes it to the appropriate backends (Tempo, Prometheus, Loki).

Environment Variables Reference

Common Variables (All Components)

VariableDefaultDescription
OTEL_EXPORTER_OTLP_ENDPOINThttp://otel-collector:4318OTLP HTTP endpoint
OTEL_SERVICE_NAMEvariesService identifier for telemetry
OTEL_SERVICE_VERSION-Service version string
LOG_LEVELinfoLog level: debug, info, warn, error

AppServer (Go) Variables

VariableDefaultDescription
APPSERVER_LOG_LEVELinfoLog level (overrides LOG_LEVEL)
APPSERVER_METRICS_ENABLEDtrueEnable Prometheus metrics export
APPSERVER_TRACING_ENABLEDtrueEnable distributed tracing
TELEMETRY_TRACES_ENABLEDtrueAlternative trace enable flag
TELEMETRY_METRICS_ENABLEDtrueAlternative metrics enable flag
TELEMETRY_LOGS_ENABLEDtrueEnable OTLP log export
OTEL_TRACES_SAMPLER_ARG1.0Sampling rate (0.0-1.0)
APPSERVER_ENVdevelopmentEnvironment name (used by config loader)
APP_ENVdevelopmentEnvironment name (used by telemetry default config)
OTEL_ENVIRONMENT-Environment name (alternative, checked by config loader)

SDK Variables

SDKs read configuration from environment variables with these defaults:

VariableNode.js DefaultDescription
OTEL_ENABLEDfalseMaster enable switch
OTEL_TRACES_ENABLEDfalseEnable trace export
OTEL_METRICS_ENABLEDfalseEnable metrics export
OTEL_LOGS_ENABLEDfalseEnable log export

AppServer (Go) Configuration

Configuration Struct

The Go telemetry package uses the Config struct:

type Config struct {
// ServiceName is the name of the service for telemetry
ServiceName string

// Enabled controls whether telemetry is active
Enabled bool

// OTLPEndpoint is the OTLP collector endpoint
OTLPEndpoint string

// TracesEnabled enables trace export
TracesEnabled bool

// MetricsEnabled enables metrics export
MetricsEnabled bool

// LogsEnabled enables log export (via OTLP logs)
LogsEnabled bool

// MetricsExportInterval is the interval for metrics export
MetricsExportInterval time.Duration

// LogLevel sets the minimum log level
LogLevel string

// Environment is the deployment environment
Environment string

// Version is the service version
Version string

// SamplingRate is the trace sampling rate (0.0 to 1.0)
SamplingRate float64

// ExtraAttributes are additional attributes for all telemetry
ExtraAttributes map[string]string
}

Initialization

import "github.com/easy-m/appserver/pkg/v2/telemetry"

func main() {
cfg := &telemetry.Config{
ServiceName: "my-service",
Enabled: true,
OTLPEndpoint: "http://otel-collector:4318",
TracesEnabled: true,
MetricsEnabled: true,
LogsEnabled: true,
LogLevel: "info",
SamplingRate: 1.0, // Sample all traces
}

if err := telemetry.Init(cfg); err != nil {
log.Fatal(err)
}
defer telemetry.Shutdown(context.Background())

// Application code...
}

Default Configuration

The DefaultConfig() function provides sensible defaults:

cfg := telemetry.DefaultConfig()
// Returns:
// - ServiceName: "unknown-service"
// - Enabled: true
// - OTLPEndpoint: from OTEL_EXPORTER_OTLP_ENDPOINT or "http://otel-collector:4318"
// - TracesEnabled: true
// - MetricsEnabled: true
// - LogsEnabled: true
// - MetricsExportInterval: 15s
// - LogLevel: from LOG_LEVEL or "info"
// - Environment: from APP_ENV or "development"
// - Version: "" (empty string)
// - SamplingRate: 1.0
// - ExtraAttributes: nil (no additional attributes)

Node.js SDK Configuration

Configuration Schema

The Node.js SDK uses Zod for configuration validation:

interface TelemetryConfig {
serviceName: string
enabled: boolean
otlpEndpoint?: string
logLevel?: 'debug' | 'info' | 'warn' | 'error'
metricsEnabled?: boolean
tracesEnabled?: boolean
logsEnabled?: boolean
metricsExportInterval?: number // milliseconds, default 15000
}

Initialization

import { initTelemetry, shutdownTelemetry } from '@appserver/telemetry'

await initTelemetry({
serviceName: 'my-node-app',
enabled: true,
otlpEndpoint: 'http://otel-collector:4318',
tracesEnabled: true,
metricsEnabled: true,
logsEnabled: true,
logLevel: 'info',
metricsExportInterval: 15000,
})

// On shutdown
await shutdownTelemetry()

Using the Logger

import { getLogger } from '@appserver/telemetry'

const logger = getLogger()

// Basic logging
logger.info('Server started')
logger.error('Connection failed')

// Structured logging with context
logger.info({ userId: '123', action: 'login' }, 'User logged in')

// Child loggers with bound context
const childLogger = logger.child({ requestId: 'abc-123' })
childLogger.info('Processing request') // Includes requestId in all logs

Using Metrics

import { getMetrics } from '@appserver/telemetry'

const metrics = getMetrics()

// Counter
const requestCounter = metrics.counter(
'http_requests_total',
'Total HTTP requests',
['method', 'path', 'status']
)
requestCounter.inc({ method: 'GET', path: '/api/users', status: '200' })

// Histogram
const latencyHistogram = metrics.histogram(
'http_request_duration_seconds',
'HTTP request latency',
['method', 'path'],
[0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5]
)
latencyHistogram.observe({ method: 'GET', path: '/api/users' }, 0.045)

// Gauge
const activeConnections = metrics.gauge(
'active_connections',
'Current active connections',
['type']
)
activeConnections.set({ type: 'websocket' }, 42)

Browser Telemetry Configuration

Configuration Interface

interface BrowserTracingConfig {
/** Service name for telemetry identification */
serviceName: string
/** Service version (default: "unknown") */
version?: string
/** OTLP collector endpoint */
otlpEndpoint: string
/** Enable or disable browser tracing (default: true) */
enabled?: boolean
/** URLs to propagate trace context to (default: all URLs via /.*/) */
propagateTraceHeaderCorsUrls?: (string | RegExp)[]
}

Note: By default, propagateTraceHeaderCorsUrls is set to /.*/ which propagates trace context headers to all URLs. You may want to restrict this in production to only your own API endpoints.

Initialization

import { initBrowserTracing, shutdownBrowserTracing } from '@appserver/telemetry/browser'

// Initialize tracing
initBrowserTracing({
serviceName: 'my-frontend-app',
version: '1.0.0',
otlpEndpoint: 'http://localhost:4318',
enabled: true,
// Propagate trace headers to these URLs
propagateTraceHeaderCorsUrls: [
/http:\/\/localhost:.*/,
/https:\/\/api\.example\.com\/.*/,
],
})

// On app unmount
await shutdownBrowserTracing()

Features

Browser telemetry automatically instruments:

  • Fetch API - All fetch requests create spans
  • XMLHttpRequest - XHR requests create spans
  • Trace Context Propagation - W3C Trace Context headers are added to requests

Getting Trace Information

import { getBrowserTraceId, getBrowserSpanId, isBrowserTracingInitialized } from '@appserver/telemetry/browser'

if (isBrowserTracingInitialized()) {
const traceId = getBrowserTraceId()
const spanId = getBrowserSpanId()
console.log(`Current trace: ${traceId}, span: ${spanId}`)
}

Sampling Configuration

Sampling Rate

The sampling rate controls what percentage of traces are recorded:

RateDescriptionUse Case
1.0Sample all tracesDevelopment, low-traffic
0.1Sample 10% of tracesMedium traffic production
0.01Sample 1% of tracesHigh traffic production

Parent-Based Sampling

When a request arrives with an existing trace context, the sampling decision is inherited from the parent span. This ensures complete traces are captured rather than partial ones.

Configuration Examples

Development - Sample everything:

OTEL_TRACES_SAMPLER_ARG=1.0

Production - Sample 10%:

OTEL_TRACES_SAMPLER_ARG=0.1

Service Naming Conventions

Use consistent service names across your deployment:

ServiceRecommended Name
AppServerappserver
Orchestratororchestrator
Node.js Appapp-{appname}
Browser Appshell or app-{appname}-frontend

Service names appear in:

  • Trace spans (service.name attribute)
  • Metrics labels
  • Log fields

Log Levels

LevelDescriptionWhen to Use
debugDetailed debugging informationDevelopment only
infoGeneral operational informationDefault for production
warnWarning conditionsIssues that don't stop operation
errorError conditionsFailures requiring attention

Log Level by Environment

Development:

LOG_LEVEL=debug

Production:

LOG_LEVEL=info

Metrics Export

Export Interval

Metrics are exported periodically to the OTLP collector:

  • Default: 15 seconds
  • Recommended range: 10-60 seconds
  • Trade-off: Shorter intervals = more resolution but higher overhead

Configuration

Go:

cfg.MetricsExportInterval = 15 * time.Second

Node.js:

{
metricsExportInterval: 15000 // milliseconds
}

Development vs Production Configuration

Development Configuration

# Enable all telemetry for debugging
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_SERVICE_NAME=appserver-dev
LOG_LEVEL=debug
OTEL_TRACES_SAMPLER_ARG=1.0
APPSERVER_METRICS_ENABLED=true
APPSERVER_TRACING_ENABLED=true

Production Configuration

# Optimized for production workloads
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
OTEL_SERVICE_NAME=appserver
LOG_LEVEL=info
OTEL_TRACES_SAMPLER_ARG=0.1
APPSERVER_METRICS_ENABLED=true
APPSERVER_TRACING_ENABLED=true
APPSERVER_ENV=production

Docker Compose Environment

When running with Docker Compose, telemetry is pre-configured:

services:
appserver:
environment:
OTEL_EXPORTER_OTLP_ENDPOINT: http://otel-collector:4318
OTEL_SERVICE_NAME: appserver
APPSERVER_LOG_LEVEL: debug

The OTEL Collector routes telemetry to:

  • Traces → Tempo
  • Metrics → Prometheus
  • Logs → Loki