securenow 3.0.6 → 3.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/tracing.js +64 -64
package/package.json
CHANGED
package/tracing.js
CHANGED
|
@@ -4,16 +4,18 @@
|
|
|
4
4
|
* Preload with: NODE_OPTIONS="-r securenow/register"
|
|
5
5
|
*
|
|
6
6
|
* Env:
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* SECURENOW_DISABLE_INSTRUMENTATIONS="@opentelemetry/instrumentation-mongodb,@opentelemetry/instrumentation-redis"
|
|
7
|
+
* SECURENOW_APPID=logical-name # or OTEL_SERVICE_NAME=logical-name
|
|
8
|
+
* SECURENOW_NO_UUID=1 # one service.name across all workers
|
|
9
|
+
* SECURENOW_INSTANCE=http://host:4318 # OTLP/HTTP base (default http://46.62.173.237:4318)
|
|
10
|
+
* OTEL_EXPORTER_OTLP_ENDPOINT=... # alternative base
|
|
11
|
+
* OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=... # full traces URL
|
|
12
|
+
* OTEL_EXPORTER_OTLP_HEADERS="k=v,k2=v2"
|
|
13
|
+
* SECURENOW_DISABLE_INSTRUMENTATIONS="pkg1,pkg2"
|
|
15
14
|
* OTEL_LOG_LEVEL=info|debug
|
|
16
|
-
* SECURENOW_TEST_SPAN=1
|
|
15
|
+
* SECURENOW_TEST_SPAN=1
|
|
16
|
+
*
|
|
17
|
+
* Safety:
|
|
18
|
+
* SECURENOW_STRICT=1 -> if no appid/name is provided in cluster, exit(1) so PM2 restarts the worker
|
|
17
19
|
*/
|
|
18
20
|
|
|
19
21
|
const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api');
|
|
@@ -24,111 +26,109 @@ const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventi
|
|
|
24
26
|
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
|
|
25
27
|
const { v4: uuidv4 } = require('uuid');
|
|
26
28
|
|
|
27
|
-
// -------------------- helpers --------------------
|
|
28
29
|
const env = k => process.env[k] ?? process.env[k.toUpperCase()] ?? process.env[k.toLowerCase()];
|
|
29
|
-
const parseHeaders =
|
|
30
|
-
const out = {};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
if (!s) continue;
|
|
35
|
-
const i = s.indexOf('=');
|
|
36
|
-
if (i === -1) continue;
|
|
30
|
+
const parseHeaders = str => {
|
|
31
|
+
const out = {}; if (!str) return out;
|
|
32
|
+
for (const raw of String(str).split(',')) {
|
|
33
|
+
const s = raw.trim(); if (!s) continue;
|
|
34
|
+
const i = s.indexOf('='); if (i === -1) continue;
|
|
37
35
|
out[s.slice(0, i).trim().toLowerCase()] = s.slice(i + 1).trim();
|
|
38
36
|
}
|
|
39
37
|
return out;
|
|
40
38
|
};
|
|
41
39
|
|
|
42
|
-
//
|
|
40
|
+
// -------- diagnostics --------
|
|
43
41
|
(() => {
|
|
44
42
|
const L = (env('OTEL_LOG_LEVEL') || '').toLowerCase();
|
|
45
|
-
const level =
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
L === 'error' ? DiagLogLevel.ERROR : DiagLogLevel.NONE;
|
|
43
|
+
const level = L === 'debug' ? DiagLogLevel.DEBUG :
|
|
44
|
+
L === 'info' ? DiagLogLevel.INFO :
|
|
45
|
+
L === 'warn' ? DiagLogLevel.WARN :
|
|
46
|
+
L === 'error' ? DiagLogLevel.ERROR : DiagLogLevel.NONE;
|
|
50
47
|
diag.setLogger(new DiagConsoleLogger(), level);
|
|
51
|
-
console.log('[securenow] preload loaded pid
|
|
48
|
+
console.log('[securenow] preload loaded pid=%d', process.pid);
|
|
52
49
|
})();
|
|
53
50
|
|
|
54
|
-
//
|
|
51
|
+
// -------- endpoints --------
|
|
55
52
|
const endpointBase = (env('SECURENOW_INSTANCE') || env('OTEL_EXPORTER_OTLP_ENDPOINT') || 'http://46.62.173.237:4318').replace(/\/$/, '');
|
|
56
53
|
const tracesUrl = env('OTEL_EXPORTER_OTLP_TRACES_ENDPOINT') || `${endpointBase}/v1/traces`;
|
|
57
54
|
const headers = parseHeaders(env('OTEL_EXPORTER_OTLP_HEADERS'));
|
|
58
55
|
|
|
59
|
-
//
|
|
60
|
-
const rawBase =
|
|
61
|
-
(env('OTEL_SERVICE_NAME') || env('SECURENOW_APPID') || '').trim().replace(/^['"]|['"]$/g, '');
|
|
56
|
+
// -------- naming rules --------
|
|
57
|
+
const rawBase = (env('OTEL_SERVICE_NAME') || env('SECURENOW_APPID') || '').trim().replace(/^['"]|['"]$/g, '');
|
|
62
58
|
const baseName = rawBase || null;
|
|
59
|
+
const noUuid = String(env('SECURENOW_NO_UUID')) === '1' || String(env('SECURENOW_NO_UUID')).toLowerCase() === 'true';
|
|
60
|
+
const strict = String(env('SECURENOW_STRICT')) === '1' || String(env('SECURENOW_STRICT')).toLowerCase() === 'true';
|
|
61
|
+
const inPm2Cluster = !!(process.env.NODE_APP_INSTANCE || process.env.pm_id);
|
|
62
|
+
|
|
63
|
+
// Fail fast in cluster if base is missing (no more "free" names)
|
|
64
|
+
if (!baseName && inPm2Cluster && strict) {
|
|
65
|
+
console.error('[securenow] FATAL: SECURENOW_APPID/OTEL_SERVICE_NAME missing in cluster (pid=%d). Exiting due to SECURENOW_STRICT=1.', process.pid);
|
|
66
|
+
// small delay so the log flushes
|
|
67
|
+
setTimeout(() => process.exit(1), 10);
|
|
68
|
+
}
|
|
63
69
|
|
|
64
|
-
//
|
|
65
|
-
const noUuid = String(env('SECURENOW_NO_UUID')) === '1' || String(env('SECURENOW_NO_UUID')).toLowerCase() === 'true';
|
|
66
|
-
|
|
70
|
+
// service.name
|
|
67
71
|
let serviceName;
|
|
68
72
|
if (baseName) {
|
|
69
73
|
serviceName = noUuid ? baseName : `${baseName}-${uuidv4()}`;
|
|
70
74
|
} else {
|
|
71
|
-
//
|
|
75
|
+
// last-resort fallback (only if STRlCT is off). You can rename this to make it obvious in monitoring.
|
|
72
76
|
serviceName = `securenow-free-${uuidv4()}`;
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
//
|
|
76
|
-
const instancePrefix
|
|
79
|
+
// service.instance.id = <appid-or-fallback>-<uuid> (unique per worker)
|
|
80
|
+
const instancePrefix = baseName || 'securenow';
|
|
77
81
|
const serviceInstanceId = `${instancePrefix}-${uuidv4()}`;
|
|
78
82
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.
|
|
84
|
-
.
|
|
85
|
-
.
|
|
83
|
+
// Loud line per worker to prove what was used
|
|
84
|
+
console.log('[securenow] pid=%d SECURENOW_APPID=%s OTEL_SERVICE_NAME=%s SECURENOW_NO_UUID=%s SECURENOW_STRICT=%s → service.name=%s instance.id=%s',
|
|
85
|
+
process.pid,
|
|
86
|
+
JSON.stringify(env('SECURENOW_APPID')),
|
|
87
|
+
JSON.stringify(env('OTEL_SERVICE_NAME')),
|
|
88
|
+
JSON.stringify(env('SECURENOW_NO_UUID')),
|
|
89
|
+
JSON.stringify(env('SECURENOW_STRICT')),
|
|
90
|
+
serviceName,
|
|
91
|
+
serviceInstanceId
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// -------- instrumentations --------
|
|
86
95
|
const disabledMap = {};
|
|
87
|
-
for (const
|
|
96
|
+
for (const n of (env('SECURENOW_DISABLE_INSTRUMENTATIONS') || '').split(',').map(s => s.trim()).filter(Boolean)) {
|
|
97
|
+
disabledMap[n] = { enabled: false };
|
|
98
|
+
}
|
|
88
99
|
|
|
89
|
-
//
|
|
100
|
+
// -------- SDK --------
|
|
90
101
|
const traceExporter = new OTLPTraceExporter({ url: tracesUrl, headers });
|
|
91
|
-
|
|
92
102
|
const sdk = new NodeSDK({
|
|
93
103
|
traceExporter,
|
|
94
104
|
instrumentations: getNodeAutoInstrumentations({ ...disabledMap }),
|
|
95
105
|
resource: new Resource({
|
|
96
106
|
[SemanticResourceAttributes.SERVICE_NAME]: serviceName,
|
|
97
107
|
[SemanticResourceAttributes.SERVICE_INSTANCE_ID]: serviceInstanceId,
|
|
98
|
-
[SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: env('NODE_ENV') || '
|
|
108
|
+
[SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: env('NODE_ENV') || 'production',
|
|
99
109
|
[SemanticResourceAttributes.SERVICE_VERSION]: process.env.npm_package_version || undefined,
|
|
100
110
|
}),
|
|
101
111
|
});
|
|
102
112
|
|
|
103
|
-
//
|
|
113
|
+
// -------- start / shutdown (sync/async safe) --------
|
|
104
114
|
(async () => {
|
|
105
115
|
try {
|
|
106
116
|
await Promise.resolve(sdk.start?.());
|
|
107
|
-
console.log('[securenow] OTel SDK started →', tracesUrl);
|
|
108
|
-
|
|
117
|
+
console.log('[securenow] OTel SDK started → %s', tracesUrl);
|
|
109
118
|
if (String(env('SECURENOW_TEST_SPAN')) === '1') {
|
|
110
119
|
const api = require('@opentelemetry/api');
|
|
111
120
|
const tracer = api.trace.getTracer('securenow-smoke');
|
|
112
|
-
const span = tracer.startSpan('securenow.startup.smoke');
|
|
113
|
-
span.setAttribute('securenow.test', true);
|
|
114
|
-
span.end();
|
|
115
|
-
console.log('[securenow] emitted startup smoke span');
|
|
121
|
+
const span = tracer.startSpan('securenow.startup.smoke'); span.end();
|
|
116
122
|
}
|
|
117
|
-
} catch (
|
|
118
|
-
console.error('[securenow] OTel start failed:',
|
|
123
|
+
} catch (e) {
|
|
124
|
+
console.error('[securenow] OTel start failed:', e && e.stack || e);
|
|
119
125
|
}
|
|
120
126
|
})();
|
|
121
127
|
|
|
122
|
-
// -------------------- graceful shutdown --------------------
|
|
123
128
|
async function safeShutdown(sig) {
|
|
124
|
-
try {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
} catch (err) {
|
|
128
|
-
console.error('[securenow] Tracing shutdown error:', err);
|
|
129
|
-
} finally {
|
|
130
|
-
process.exit(0);
|
|
131
|
-
}
|
|
129
|
+
try { await Promise.resolve(sdk.shutdown?.()); console.log(`[securenow] Tracing terminated on ${sig}`); }
|
|
130
|
+
catch (e) { console.error('[securenow] Tracing shutdown error:', e); }
|
|
131
|
+
finally { process.exit(0); }
|
|
132
132
|
}
|
|
133
133
|
process.on('SIGINT', () => safeShutdown('SIGINT'));
|
|
134
134
|
process.on('SIGTERM', () => safeShutdown('SIGTERM'));
|