1
+ /**
2
+ * OpenTelemetry Configuration for Lowcoder Application
3
+ *
4
+ * This file sets up OpenTelemetry auto-instrumentation for traces and metrics.
5
+ *
6
+ * How to use:
7
+ * 1. Save this file as `otel-config.js` in your application's root directory.
8
+ * 2. Ensure you have the necessary OpenTelemetry packages installed:
9
+ * @opentelemetry /sdk-node
10
+ * @opentelemetry /api
11
+ * @opentelemetry /exporter-trace-otlp-http (or -grpc)
12
+ * @opentelemetry /exporter-metrics-otlp-http (or -grpc)
13
+ * @opentelemetry /resources
14
+ * @opentelemetry /semantic-conventions
15
+ * @opentelemetry /auto-instrumentations-node (CRITICAL for auto-instrumentation)
16
+ *
17
+ * Install @opentelemetry/auto-instrumentations-node if you haven't:
18
+ * `npm install @opentelemetry/auto-instrumentations-node`
19
+ * or
20
+ * `yarn add @opentelemetry/auto-instrumentations-node`
21
+ *
22
+ * 3. Start your application using the `-r` flag to preload this configuration:
23
+ * `export NODE_OPTIONS="-r ./otel-config.js"`
24
+ *
25
+ * Environment Variables for Configuration:
26
+ * - OTEL_EXPORTER_OTLP_ENDPOINT: Base URL for OTLP HTTP exporters (e.g., http://localhost:4318).
27
+ * If not set, defaults to http://localhost:4318.
28
+ * - OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: Specific URL for OTLP HTTP traces exporter (e.g., http://localhost:4318/v1/traces).
29
+ * - OTEL_EXPORTER_OTLP_METRICS_ENDPOINT: Specific URL for OTLP HTTP metrics exporter (e.g., http://localhost:4318/v1/metrics).
30
+ * - OTEL_SERVICE_NAME: Name of your service (e.g., 'node-service'). Defaults to 'unknown_service:nodejs'.
31
+ * - OTEL_LOG_LEVEL: Set OpenTelemetry diagnostic logging level (e.g., 'debug', 'info', 'warn', 'error').
32
+ * - OTEL_EXPORTER_PROTOCOL: 'http/protobuf' (default) or 'grpc'.
33
+ */
34
+
35
+ const process = require ( 'process' ) ;
36
+ const { NodeSDK } = require ( '@opentelemetry/sdk-node' ) ;
37
+ const { OTLPTraceExporter : OTLPTraceExporterHttp } = require ( '@opentelemetry/exporter-trace-otlp-http' ) ;
38
+ const { OTLPTraceExporter : OTLPTraceExporterGrpc } = require ( '@opentelemetry/exporter-trace-otlp-grpc' ) ;
39
+ const { OTLPMetricExporter : OTLPMetricExporterHttp } = require ( '@opentelemetry/exporter-metrics-otlp-http' ) ;
40
+ const { OTLPMetricExporter : OTLPMetricExporterGrpc } = require ( '@opentelemetry/exporter-metrics-otlp-grpc' ) ;
41
+ const { BatchSpanProcessor } = require ( '@opentelemetry/sdk-trace-node' ) ; // Using BatchSpanProcessor for better performance
42
+ const { PeriodicExportingMetricReader } = require ( '@opentelemetry/sdk-metrics' ) ;
43
+ const { Resource } = require ( '@opentelemetry/resources' ) ;
44
+ const { SemanticResourceAttributes } = require ( '@opentelemetry/semantic-conventions' ) ;
45
+ const { getNodeAutoInstrumentations } = require ( '@opentelemetry/auto-instrumentations-node' ) ;
46
+ const { DiagConsoleLogger, DiagLogLevel, diag } = require ( '@opentelemetry/api' ) ;
47
+
48
+ // --- Configuration ---
49
+ const SERVICE_NAME = process . env . OTEL_SERVICE_NAME || 'lowcoder-node-service' ;
50
+ const OTLP_EXPORTER_PROTOCOL = process . env . OTEL_EXPORTER_PROTOCOL || 'http/protobuf' ; // 'http/protobuf' or 'grpc'
51
+
52
+ const DEFAULT_OTLP_HTTP_ENDPOINT = 'http://localhost:4318' ;
53
+ const DEFAULT_OTLP_GRPC_ENDPOINT = 'http://localhost:4317' ;
54
+
55
+ const OTLP_ENDPOINT = process . env . OTEL_EXPORTER_OTLP_ENDPOINT ||
56
+ ( OTLP_EXPORTER_PROTOCOL === 'grpc' ? DEFAULT_OTLP_GRPC_ENDPOINT : DEFAULT_OTLP_HTTP_ENDPOINT ) ;
57
+
58
+ const TRACES_ENDPOINT = process . env . OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||
59
+ ( OTLP_EXPORTER_PROTOCOL === 'grpc' ? OTLP_ENDPOINT : `${ OTLP_ENDPOINT } /v1/traces` ) ;
60
+ const METRICS_ENDPOINT = process . env . OTEL_EXPORTER_OTLP_METRICS_ENDPOINT ||
61
+ ( OTLP_EXPORTER_PROTOCOL === 'grpc' ? OTLP_ENDPOINT : `${ OTLP_ENDPOINT } /v1/metrics` ) ;
62
+
63
+ // Optional: Set OpenTelemetry diagnostic logging level
64
+ const otelLogLevel = process . env . OTEL_LOG_LEVEL ?. toUpperCase ( ) ;
65
+ if ( otelLogLevel && DiagLogLevel [ otelLogLevel ] ) {
66
+ diag . setLogger ( new DiagConsoleLogger ( ) , DiagLogLevel [ otelLogLevel ] ) ;
67
+ } else {
68
+ diag . setLogger ( new DiagConsoleLogger ( ) , DiagLogLevel . INFO ) ; // Default to INFO
69
+ }
70
+
71
+ diag . info ( `OpenTelemetry SDK configured for service: ${ SERVICE_NAME } ` ) ;
72
+ diag . info ( `Using OTLP protocol: ${ OTLP_EXPORTER_PROTOCOL } ` ) ;
73
+ diag . info ( `Traces Exporter Endpoint: ${ TRACES_ENDPOINT } ` ) ;
74
+ diag . info ( `Metrics Exporter Endpoint: ${ METRICS_ENDPOINT } ` ) ;
75
+
76
+ // --- Resource Definition ---
77
+ const resource = Resource . default ( ) . merge (
78
+ new Resource ( {
79
+ [ SemanticResourceAttributes . SERVICE_NAME ] : SERVICE_NAME ,
80
+ // [SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0', // Optional
81
+ } )
82
+ ) ;
83
+
84
+ // --- Exporter Configuration ---
85
+ let traceExporter ;
86
+ let metricExporter ;
87
+
88
+ if ( OTLP_EXPORTER_PROTOCOL === 'grpc' ) {
89
+ diag . info ( 'Using gRPC Exporters' ) ;
90
+ traceExporter = new OTLPTraceExporterGrpc ( { url : TRACES_ENDPOINT } ) ;
91
+ metricExporter = new OTLPMetricExporterGrpc ( { url : METRICS_ENDPOINT } ) ;
92
+ } else {
93
+ diag . info ( 'Using HTTP/protobuf Exporters' ) ;
94
+ traceExporter = new OTLPTraceExporterHttp ( { url : TRACES_ENDPOINT } ) ;
95
+ metricExporter = new OTLPMetricExporterHttp ( { url : METRICS_ENDPOINT } ) ;
96
+ }
97
+
98
+ // --- SDK Initialization ---
99
+ const sdk = new NodeSDK ( {
100
+ resource : resource ,
101
+ traceExporter : traceExporter ,
102
+ spanProcessor : new BatchSpanProcessor ( traceExporter ) , // Recommended for most cases
103
+ metricReader : new PeriodicExportingMetricReader ( {
104
+ exporter : metricExporter ,
105
+ exportIntervalMillis : 10000 , // Export metrics every 10 seconds
106
+ } ) ,
107
+ instrumentations : [
108
+ getNodeAutoInstrumentations ( {
109
+ // Configuration for specific instrumentations can be added here if needed
110
+ // Example:
111
+ // '@opentelemetry/instrumentation-http': {
112
+ // applyCustomAttributesOnSpan: (span, request, response) => {
113
+ // span.setAttribute('custom.attribute', 'value');
114
+ // },
115
+ // },
116
+ } ) ,
117
+ ] ,
118
+ } ) ;
119
+
120
+ // --- Start SDK and Graceful Shutdown ---
121
+ try {
122
+ sdk . start ( ) ;
123
+ diag . info ( 'OpenTelemetry SDK started successfully for traces and metrics.' ) ;
124
+ } catch ( error ) {
125
+ diag . error ( 'Error starting OpenTelemetry SDK:' , error ) ;
126
+ process . exit ( 1 ) ;
127
+ }
128
+
129
+ // Graceful shutdown
130
+ const shutdown = ( ) => {
131
+ diag . info ( 'Shutting down OpenTelemetry SDK...' ) ;
132
+ sdk . shutdown ( )
133
+ . then ( ( ) => diag . info ( 'OpenTelemetry SDK shut down successfully.' ) )
134
+ . catch ( error => diag . error ( 'Error shutting down OpenTelemetry SDK:' , error ) )
135
+ . finally ( ( ) => process . exit ( 0 ) ) ;
136
+ } ;
137
+
138
+ process . on ( 'SIGTERM' , shutdown ) ;
139
+ process . on ( 'SIGINT' , shutdown ) ;
0 commit comments