Dillon Sellars
06/10/2025, 1:16 AMimport { LoggerProvider, BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
import { OpenTelemetryTransportV3 } from '@opentelemetry/winston-transport';
import { resourceFromAttributes } from '@opentelemetry/resources';
import winston from 'winston';
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
import { logs } from '@opentelemetry/api-logs';
import {
OTEL_EXPORTER_ACCESS_TOKEN,
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
OTEL_SERVICE_NAME,
} from '../bootstrapConfig';
console.log(`*** OTLP logging is configured. Endpoint: '${OTEL_EXPORTER_OTLP_LOGS_ENDPOINT}'`);
// Create the OTLP exporter with proper authentication
const logExporter = new OTLPLogExporter({
url: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT,
headers: {
'signoz-access-token': OTEL_EXPORTER_ACCESS_TOKEN,
},
});
// Create and configure the LoggerProvider
const provider = new LoggerProvider({
resource: resourceFromAttributes({
[ATTR_SERVICE_NAME]: 'winston-logger',
[ATTR_SERVICE_VERSION]: '1.0.0',
'deployment.environment': process.env.NODE_ENV || 'development',
}),
});
// Connect the exporter to the provider
provider.addLogRecordProcessor(new BatchLogRecordProcessor(logExporter));
// Set the provider as the global logger provider
logs.setGlobalLoggerProvider(provider);
// Now the OpenTelemetryTransportV3 will use the global provider
const transports: winston.transport[] = [
new winston.transports.Console(),
new OpenTelemetryTransportV3(),
];
export const logger = winston.createLogger({
level: 'debug',
transports,
format: winston.format.combine(
winston.format.timestamp(),
winston.format.errors({
stack: true,
}),
winston.format.metadata(),
winston.format.json()
),
defaultMeta: {
service: 'winston-logger',
environment: process.env.NODE_ENV || 'development',
},
});
full error:
{
"stack": "OTLPExporterError: Unauthorized\n at IncomingMessage.<anonymous> (/Users/nhoize/vortex/vortex/node_modules/.pnpm/@opentelemetry+otlp-exporter-base@0.202.0_@opentelemetry+api@1.9.0/node_modules/@opentelemetry/otlp-exporter-base/src/transport/http-transport-utils.ts:75:23)\n at <anonymous> (/Users/nhoize/vortex/vortex/node_modules/.pnpm/@opentelemetry+context-async-hooks@2.0.1_@opentelemetry+api@1.9.0/node_modules/@opentelemetry/context-async-hooks/src/AbstractAsyncHooksContextManager.ts:75:49)\n at AsyncLocalStorage.run (node:internal/async_local_storage/async_hooks:80:14)\n at AsyncLocalStorageContextManager.with (/Users/nhoize/vortex/vortex/node_modules/.pnpm/@opentelemetry+context-async-hooks@2.0.1_@opentelemetry+api@1.9.0/node_modules/@opentelemetry/context-async-hooks/src/AsyncLocalStorageContextManager.ts:40:36)\n at IncomingMessage.contextWrapper (/Users/nhoize/vortex/vortex/node_modules/.pnpm/@opentelemetry+context-async-hooks@2.0.1_@opentelemetry+api@1.9.0/node_modules/@opentelemetry/context-async-hooks/src/AbstractAsyncHooksContextManager.ts:75:26)\n at IncomingMessage.emit (node:events:530:35)\n at endReadableNT (node:internal/streams/readable:1698:12)\n at process.processTicksAndRejections (node:internal/process/task_queues:90:21)",
"message": "Unauthorized",
"code": "401",
"name": "OTLPExporterError",
"data": "Unauthorized\n"
}