Skip to content

Commit 6b2001f

Browse files
author
Connell, Joseph
committed
Added Node Service Otel-Auto Instrumentation
1 parent 624d1a9 commit 6b2001f

File tree

6 files changed

+210
-4
lines changed

6 files changed

+210
-4
lines changed

deploy/docker/.dockerignore

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Node.js dependencies
2+
node_modules
3+
npm-debug.log
4+
yarn-error.log
5+
6+
# Logs
7+
logs
8+
*.log
9+
10+
# Build artifacts
11+
dist
12+
build
13+
*.tsbuildinfo
14+
15+
# Environment files
16+
.env
17+
.env.local
18+
.env.*.local
19+
20+
# IDE and editor files
21+
.vscode/
22+
.idea/
23+
*.swp
24+
25+
# OS files
26+
.DS_Store
27+
Thumbs.db
28+
29+
# Docker-related files
30+
.dockerignore
31+
Dockerfile*
32+
33+
# Temporary files
34+
tmp/
35+
temp/
36+
*.tmp
37+
*.temp
38+
39+
# Test files
40+
coverage/
41+
*.test.js
42+
*.spec.js
43+
*.test.ts
44+
*.spec.ts
45+
jest.config.js

deploy/docker/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,10 @@ WORKDIR /lowcoder/node-service/app/
7878
RUN yarn --immutable
7979
RUN yarn build
8080

81-
# Copy startup script
81+
# Copy startup script and OpenTelemetry config
8282
COPY deploy/docker/node-service/entrypoint.sh /lowcoder/node-service/entrypoint.sh
8383
COPY deploy/docker/node-service/init.sh /lowcoder/node-service/init.sh
84+
COPY deploy/docker/node-service/otel-config.js /lowcoder/node-service/otel-config.js
8485
RUN chmod +x /lowcoder/node-service/*.sh
8586

8687
##

deploy/docker/docker-compose-multi-otel.yaml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,9 @@ services:
103103

104104
# OpenTelemetry Related Settings
105105
# OTEL_JAVAAGENT_ENABLED: "false"
106-
OTEL_RESOURCE_ATTRIBUTES: "service.name=lowcoder-api-service,service.version=2.6.5,deployment.environment=production"
106+
OTEL_RESOURCE_ATTRIBUTES: "deployment.environment=production"
107107
OTEL_SERVICE_NAME: "lowcoder-api-service"
108+
OTEL_SERVICE_VERSION: "2.6.5"
108109
OTEL_EXPORTER_OTLP_PROTOCOL: "grpc"
109110
OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-lgtm:4317"
110111
OTEL_TRACES_EXPORTER: "otlp"
@@ -143,6 +144,23 @@ services:
143144
LOWCODER_PUID: "9001"
144145
LOWCODER_PGID: "9001"
145146
LOWCODER_API_SERVICE_URL: "http://lowcoder-api-service:8080"
147+
148+
##
149+
# OpenTelemetry Related Settings
150+
#
151+
# Uncomment OTEL_NODE_ENABLED_INSTRUMENTATIONS
152+
# to disable OpenTelemetry Node agent
153+
##
154+
# OTEL_NODE_ENABLED_INSTRUMENTATIONS=""
155+
OTEL_RESOURCE_ATTRIBUTES: "deployment.environment=production"
156+
OTEL_SERVICE_NAME: "lowcoder-node-service"
157+
OTEL_SERVICE_VERSION: "2.6.5"
158+
OTEL_EXPORTER_OTLP_PROTOCOL: "grpc"
159+
OTEL_EXPORTER_OTLP_ENDPOINT: "http://otel-lgtm:4317"
160+
OTEL_TRACES_EXPORTER: "otlp"
161+
OTEL_METRICS_EXPORTER: "otlp"
162+
OTEL_LOGS_EXPORTER: "otlp"
163+
146164
restart: unless-stopped
147165
depends_on:
148166
lowcoder-api-service:
@@ -153,7 +171,7 @@ services:
153171
interval: 3s
154172
timeout: 5s
155173
retries: 10
156-
174+
157175
##
158176
## Start Lowcoder web frontend
159177
##

deploy/docker/node-service/entrypoint.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,7 @@ if [ "$(id -u)" -eq 0 ]; then
2323
fi
2424
echo
2525

26+
# Require OpenTelemetry configuration
27+
export NODE_OPTIONS="-r ./otel-config.js"
28+
2629
exec $GOSU yarn start
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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);

server/node-service/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
22

33
# dependencies
4-
/node_modules
4+
/node_modules/**
55
/packages/*/node_modules
66
/packages/*/dist
77
/packages/*/tsdoc-metadata.json

0 commit comments

Comments
 (0)