// OpenTelemetry bootstrap: sends traces, metrics and logs to the LGTM // stack's OTLP/HTTP collector at http://localhost:4318. Must be required // before any other module so auto-instrumentation can patch http/express/pg. const { NodeSDK } = require('@opentelemetry/sdk-node') const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node') const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http') const { OTLPMetricExporter } = require('@opentelemetry/exporter-metrics-otlp-http') const { OTLPLogExporter } = require('@opentelemetry/exporter-logs-otlp-http') const { PeriodicExportingMetricReader } = require('@opentelemetry/sdk-metrics') const { BatchLogRecordProcessor } = require('@opentelemetry/sdk-logs') const { resourceFromAttributes } = require('@opentelemetry/resources') const { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } = require('@opentelemetry/semantic-conventions') const { logs } = require('@opentelemetry/api-logs') const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4318' const resource = resourceFromAttributes({ [ATTR_SERVICE_NAME]: 'hn-reader-api', [ATTR_SERVICE_VERSION]: '1.0.0', }) const sdk = new NodeSDK({ resource, traceExporter: new OTLPTraceExporter({ url: `${endpoint}/v1/traces` }), metricReader: new PeriodicExportingMetricReader({ exporter: new OTLPMetricExporter({ url: `${endpoint}/v1/metrics` }), exportIntervalMillis: 15000, }), logRecordProcessors: [ new BatchLogRecordProcessor(new OTLPLogExporter({ url: `${endpoint}/v1/logs` })), ], instrumentations: [ getNodeAutoInstrumentations({ '@opentelemetry/instrumentation-fs': { enabled: false }, }), ], }) sdk.start() process.on('SIGTERM', () => sdk.shutdown().finally(() => process.exit(0))) const otelLogger = logs.getLogger('hn-reader-api') // Small structured logger: prints to stdout (captured by journald) and // emits an OTLP log record so logs show up alongside traces in Grafana. function log(severity, message, attributes = {}) { const line = `[${severity}] ${message} ${Object.keys(attributes).length ? JSON.stringify(attributes) : ''}` if (severity === 'ERROR') console.error(line) else console.log(line) otelLogger.emit({ severityText: severity, body: message, attributes, }) } module.exports = { log }