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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/tracing.js +64 -64
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "securenow",
3
- "version": "3.0.6",
3
+ "version": "3.0.8",
4
4
  "type": "commonjs",
5
5
  "main": "register.js",
6
6
  "exports": { ".": "./register.js", "./register": "./register.js", "./tracing": "./tracing.js" },
package/tracing.js CHANGED
@@ -4,16 +4,18 @@
4
4
  * Preload with: NODE_OPTIONS="-r securenow/register"
5
5
  *
6
6
  * Env:
7
- * SECURENOW_INSTANCE=http://host:4318
8
- * OTEL_EXPORTER_OTLP_ENDPOINT=...
9
- * OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=...
10
- * OTEL_EXPORTER_OTLP_HEADERS="authorization=Bearer abc123,foo=bar"
11
- * OTEL_SERVICE_NAME=logical-name
12
- * SECURENOW_APPID=logical-name
13
- * SECURENOW_NO_UUID=1 # one service.name across all workers
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 # emit a smoke test span on startup
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 = (str) => {
30
- const out = {};
31
- if (!str) return out;
32
- for (const raw of str.split(',')) {
33
- const s = raw.trim();
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
- // -------------------- diagnostics --------------------
40
+ // -------- diagnostics --------
43
41
  (() => {
44
42
  const L = (env('OTEL_LOG_LEVEL') || '').toLowerCase();
45
- const level =
46
- L === 'debug' ? DiagLogLevel.DEBUG :
47
- L === 'info' ? DiagLogLevel.INFO :
48
- L === 'warn' ? DiagLogLevel.WARN :
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=', process.pid);
48
+ console.log('[securenow] preload loaded pid=%d', process.pid);
52
49
  })();
53
50
 
54
- // -------------------- endpoints --------------------
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
- // -------------------- naming rules --------------------
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
- // SECURENOW_NO_UUID=1 -> keep one service.name for all workers (baseName), but unique instance ids
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
- // No provided name: safe fallback, unique per process
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
- // Always make a unique instance id (appID + uuid if available; else “securenow” + uuid)
76
- const instancePrefix = baseName || 'securenow';
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
- console.log('[securenow] resolved names →', { serviceName, serviceInstanceId });
80
-
81
- // -------------------- instrumentations --------------------
82
- const disabledList = (env('SECURENOW_DISABLE_INSTRUMENTATIONS') || '')
83
- .split(',')
84
- .map(s => s.trim())
85
- .filter(Boolean);
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 name of disabledList) disabledMap[name] = { enabled: false };
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
- // -------------------- SDK --------------------
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') || 'development',
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
- // -------------------- start (sync/async safe) --------------------
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 (err) {
118
- console.error('[securenow] OTel start failed:', err && err.stack || err);
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
- await Promise.resolve(sdk.shutdown?.());
126
- console.log(`[securenow] Tracing terminated on ${sig}`);
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'));