Files
hn-reader/server/otel.js
T
privatecloud builder c57606cd90
CI / build (push) Successful in 58s
Fix OTLP log export: BatchLogRecordProcessor takes an options object
sdk-logs 0.221 changed the constructor to {exporter, ...} instead of a
bare exporter argument; passing the exporter directly silently left
this._exporter undefined, so every log export failed inside
suppressed error handling and no logs ever reached the collector.
2026-07-25 12:30:06 +00:00

60 lines
2.3 KiB
JavaScript

// 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({ exporter: 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 }