UNPKG

otel-agent-nodejs14

Version:

OpenTelemetry agent for Node.js 14+ applications with distributed tracing and metrics

171 lines (157 loc) 5.79 kB
"use strict"; // NÃO use o register automático - vamos controlar manualmente // require("@opentelemetry/auto-instrumentations-node/register"); // REMOVER ESTA LINHA const { NodeSDK } = require("@opentelemetry/sdk-node"); const { getNodeAutoInstrumentations } = require("@opentelemetry/auto-instrumentations-node"); const { OTLPTraceExporter } = require("@opentelemetry/exporter-trace-otlp-proto"); const { OTLPMetricExporter } = require("@opentelemetry/exporter-metrics-otlp-proto"); const { PeriodicExportingMetricReader } = require("@opentelemetry/sdk-metrics"); const { BatchSpanProcessor } = require("@opentelemetry/sdk-trace-base"); const { GraphQLInstrumentation } = require("@opentelemetry/instrumentation-graphql"); const { diag, DiagConsoleLogger, DiagLogLevel } = require("@opentelemetry/api"); const { Resource } = require("@opentelemetry/resources"); const { SemanticResourceAttributes } = require("@opentelemetry/semantic-conventions"); // Configurar diagnóstico se necessário if (process.env.OTEL_DIAGNOSTIC_LOGS === "true") { diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG); } // Configurar Resource com informações do serviço const resource = Resource.default().merge( new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: process.env.OTEL_SERVICE_NAME || "nodejs-app", [SemanticResourceAttributes.SERVICE_VERSION]: process.env.SERVICE_VERSION || "1.0.0", }) ); // Configurar Trace Exporter const traceExporter = new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT || "http://otel-collector:4318/v1/traces", headers: {}, }); // Configurar Span Processor const spanProcessor = new BatchSpanProcessor(traceExporter); // Configurar Metric Exporter const metricExporter = new OTLPMetricExporter({ url: process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT || "http://otel-collector:4318/v1/metrics", headers: {}, }); // Configurar Metric Reader const metricReader = new PeriodicExportingMetricReader({ exporter: metricExporter, exportIntervalMillis: Number(process.env.OTEL_METRIC_EXPORT_INTERVAL) || 60000, exportTimeoutMillis: Number(process.env.OTEL_METRIC_EXPORT_TIMEOUT) || 30000, }); // Configurar Instrumentações const instrumentations = [ getNodeAutoInstrumentations({ // Desabilitar fs para evitar overhead "@opentelemetry/instrumentation-fs": { enabled: false, }, // Configuração customizada para HTTP "@opentelemetry/instrumentation-http": { enabled: true, requestHook: (span, req) => { span.setAttribute("http.method", req.method); span.setAttribute("http.url", req.url); if (req.headers?.["user-agent"]) { span.setAttribute("http.user_agent", req.headers["user-agent"]); } if (req.socket?.remoteAddress) { span.setAttribute("http.client_ip", req.socket.remoteAddress); } }, responseHook: (span, res) => { span.setAttribute("http.status_code", res.statusCode); }, }, // Express habilitado "@opentelemetry/instrumentation-express": { enabled: true, }, // Redis habilitado "@opentelemetry/instrumentation-redis": { enabled: true, }, // MongoDB habilitado "@opentelemetry/instrumentation-mongodb": { enabled: true, }, // MySQL habilitado "@opentelemetry/instrumentation-mysql": { enabled: true, }, // PostgreSQL habilitado "@opentelemetry/instrumentation-pg": { enabled: true, }, }), // GraphQL como instrumentação separada new GraphQLInstrumentation({ mergeItems: true, depth: 5, allowValues: true, requestHook: (span, info) => { if (info.operationName) { span.setAttribute("graphql.operation.name", info.operationName); } if (info.operation?.operation) { span.setAttribute("graphql.operation.type", info.operation.operation); } }, responseHook: (span, result) => { if (result?.errors) { span.setStatus({ code: 2, message: "GraphQL Error" }); span.setAttribute("graphql.errors", JSON.stringify(result.errors)); } }, }), ]; // Inicializar SDK const sdk = new NodeSDK({ resource, spanProcessor, metricReader, // Passar como propriedade direta, não como array instrumentations, }); // Função de inicialização com melhor tratamento de erro async function startSDK() { try { await sdk.start(); console.log("[otel-agent] OpenTelemetry SDK iniciado com sucesso"); console.log(`[otel-agent] Service Name: ${process.env.OTEL_SERVICE_NAME || "nodejs-app"}`); console.log(`[otel-agent] Traces Endpoint: ${process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT || "http://otel-collector:4318/v1/traces"}`); console.log(`[otel-agent] Metrics Endpoint: ${process.env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT || "http://otel-collector:4318/v1/metrics"}`); } catch (err) { console.error("[otel-agent] Falha ao iniciar SDK:", err); // Não encerrar o processo, deixar a aplicação continuar } } // Iniciar SDK startSDK(); // Graceful shutdown process.on("SIGTERM", () => { console.log("[otel-agent] SIGTERM recebido, iniciando shutdown..."); sdk .shutdown() .then(() => { console.log("[otel-agent] SDK shutdown completo"); process.exit(0); }) .catch((err) => { console.error("[otel-agent] Erro no shutdown:", err); process.exit(1); }); }); process.on("SIGINT", () => { console.log("[otel-agent] SIGINT recebido, iniciando shutdown..."); sdk .shutdown() .then(() => { console.log("[otel-agent] SDK shutdown completo"); process.exit(0); }) .catch((err) => { console.error("[otel-agent] Erro no shutdown:", err); process.exit(1); }); });