@carecard/telemetry 3.40.0 → 3.44.0
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/README.md +11 -2
- package/index.d.ts +4 -1
- package/package.json +19 -19
- package/src/initializeServiceTelemetry.js +23 -6
- package/src/instrumentations.js +3 -24
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ explicit narrowing in all TypeScript-family files (`.ts`, `.tsx`, `.mts`,
|
|
|
33
33
|
## Install
|
|
34
34
|
|
|
35
35
|
```sh
|
|
36
|
-
npm install @carecard/telemetry@3.
|
|
36
|
+
npm install @carecard/telemetry@3.44.0 --save-exact
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## Bootstrap
|
|
@@ -50,7 +50,7 @@ const packageJson = require('./package.json');
|
|
|
50
50
|
const { createTelemetryShutdown, initializeServiceTelemetry } = require('@carecard/telemetry');
|
|
51
51
|
|
|
52
52
|
const telemetry = initializeServiceTelemetry({
|
|
53
|
-
serviceName: '
|
|
53
|
+
serviceName: 'worker',
|
|
54
54
|
serviceVersion: packageJson.version,
|
|
55
55
|
});
|
|
56
56
|
|
|
@@ -159,3 +159,12 @@ npm run lint
|
|
|
159
159
|
npm run format:check
|
|
160
160
|
npm audit --audit-level=high
|
|
161
161
|
```
|
|
162
|
+
|
|
163
|
+
## Caller-owned identity and exclusions
|
|
164
|
+
|
|
165
|
+
Service names are generic bounded operational identifiers. Set `serviceNamespace`
|
|
166
|
+
explicitly when needed. There is no built-in application naming rule, namespace,
|
|
167
|
+
health route list, or framework route exclusion. Supply `ignoreIncomingRequest`
|
|
168
|
+
with a boolean decision for the owning service or application. Outgoing exports
|
|
169
|
+
remain excluded to avoid telemetry recursion. Privacy sanitization and W3C
|
|
170
|
+
propagation remain technical package responsibilities.
|
package/index.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import type { IncomingMessage } from 'node:http';
|
|
1
2
|
export interface TelemetryRuntime {
|
|
2
3
|
forceFlush(): Promise<void>;
|
|
3
4
|
shutdown(): Promise<void>;
|
|
4
5
|
}
|
|
5
6
|
|
|
6
7
|
export interface ServiceTelemetryOptions {
|
|
7
|
-
serviceName:
|
|
8
|
+
serviceName: string;
|
|
8
9
|
serviceVersion: string;
|
|
10
|
+
serviceNamespace?: string;
|
|
11
|
+
ignoreIncomingRequest?: (request: IncomingMessage) => boolean;
|
|
9
12
|
}
|
|
10
13
|
|
|
11
14
|
export interface DurableTraceContextOptions {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carecard/telemetry",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.44.0",
|
|
4
4
|
"description": "Privacy-safe OpenTelemetry tracing for CareCard Node.js services",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"src"
|
|
20
20
|
],
|
|
21
21
|
"engines": {
|
|
22
|
-
"node": ">=24.
|
|
22
|
+
"node": ">=24.21.0 <25"
|
|
23
23
|
},
|
|
24
24
|
"sideEffects": true,
|
|
25
25
|
"repository": {
|
|
@@ -53,28 +53,28 @@
|
|
|
53
53
|
"license": "ISC",
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@opentelemetry/api": "1.9.1",
|
|
56
|
-
"@opentelemetry/context-async-hooks": "2.
|
|
57
|
-
"@opentelemetry/core": "2.
|
|
58
|
-
"@opentelemetry/exporter-trace-otlp-http": "0.
|
|
59
|
-
"@opentelemetry/instrumentation": "0.
|
|
60
|
-
"@opentelemetry/instrumentation-express": "0.
|
|
61
|
-
"@opentelemetry/instrumentation-http": "0.
|
|
62
|
-
"@opentelemetry/instrumentation-kafkajs": "0.
|
|
63
|
-
"@opentelemetry/instrumentation-pg": "0.
|
|
64
|
-
"@opentelemetry/instrumentation-undici": "0.
|
|
65
|
-
"@opentelemetry/resources": "2.
|
|
66
|
-
"@opentelemetry/sdk-trace-base": "2.
|
|
67
|
-
"@opentelemetry/sdk-trace-node": "2.
|
|
56
|
+
"@opentelemetry/context-async-hooks": "2.12.0",
|
|
57
|
+
"@opentelemetry/core": "2.12.0",
|
|
58
|
+
"@opentelemetry/exporter-trace-otlp-http": "0.223.0",
|
|
59
|
+
"@opentelemetry/instrumentation": "0.223.0",
|
|
60
|
+
"@opentelemetry/instrumentation-express": "0.71.0",
|
|
61
|
+
"@opentelemetry/instrumentation-http": "0.223.0",
|
|
62
|
+
"@opentelemetry/instrumentation-kafkajs": "0.32.0",
|
|
63
|
+
"@opentelemetry/instrumentation-pg": "0.75.0",
|
|
64
|
+
"@opentelemetry/instrumentation-undici": "0.33.0",
|
|
65
|
+
"@opentelemetry/resources": "2.12.0",
|
|
66
|
+
"@opentelemetry/sdk-trace-base": "2.12.0",
|
|
67
|
+
"@opentelemetry/sdk-trace-node": "2.12.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
-
"@eslint/js": "
|
|
71
|
-
"@types/node": "
|
|
72
|
-
"@typescript-eslint/parser": "8.71.
|
|
73
|
-
"eslint": "
|
|
70
|
+
"@eslint/js": "10.0.1",
|
|
71
|
+
"@types/node": "24.19.2",
|
|
72
|
+
"@typescript-eslint/parser": "8.71.1",
|
|
73
|
+
"eslint": "10.12.0",
|
|
74
74
|
"globals": "17.13.0",
|
|
75
75
|
"husky": "9.1.7",
|
|
76
76
|
"lint-staged": "17.6.0",
|
|
77
|
-
"prettier": "3.9.
|
|
77
|
+
"prettier": "3.9.10",
|
|
78
78
|
"typescript": "6.0.3"
|
|
79
79
|
},
|
|
80
80
|
"overrides": {
|
|
@@ -15,12 +15,26 @@ const { createTraceparentOnlyPropagator } = require('./traceparentOnlyPropagator
|
|
|
15
15
|
let activeRuntime;
|
|
16
16
|
const installedShutdownHandlers = new WeakSet();
|
|
17
17
|
|
|
18
|
-
// Pattern: Boundary Validation -
|
|
19
|
-
function validateServiceIdentity({
|
|
20
|
-
|
|
18
|
+
// Pattern: Boundary Validation - validates generic operational identity metadata.
|
|
19
|
+
function validateServiceIdentity({
|
|
20
|
+
serviceName,
|
|
21
|
+
serviceVersion,
|
|
22
|
+
serviceNamespace,
|
|
23
|
+
ignoreIncomingRequest,
|
|
24
|
+
}) {
|
|
25
|
+
const namePattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,254}$/;
|
|
21
26
|
const versionPattern = /^\d+\.\d+\.\d+(?:-[a-z0-9.-]+)?$/;
|
|
22
|
-
if (!namePattern.test(serviceName)) {
|
|
23
|
-
throw new Error('serviceName must
|
|
27
|
+
if (typeof serviceName !== 'string' || !namePattern.test(serviceName)) {
|
|
28
|
+
throw new Error('serviceName must be a bounded operational identifier');
|
|
29
|
+
}
|
|
30
|
+
if (
|
|
31
|
+
serviceNamespace !== undefined &&
|
|
32
|
+
(typeof serviceNamespace !== 'string' || !namePattern.test(serviceNamespace))
|
|
33
|
+
) {
|
|
34
|
+
throw new TypeError('serviceNamespace must be a bounded operational identifier');
|
|
35
|
+
}
|
|
36
|
+
if (ignoreIncomingRequest !== undefined && typeof ignoreIncomingRequest !== 'function') {
|
|
37
|
+
throw new TypeError('ignoreIncomingRequest must be a function');
|
|
24
38
|
}
|
|
25
39
|
if (!versionPattern.test(serviceVersion)) {
|
|
26
40
|
throw new Error('serviceVersion must be a semantic version');
|
|
@@ -37,7 +51,9 @@ function createNoopRuntime() {
|
|
|
37
51
|
function createResource(options) {
|
|
38
52
|
return resourceFromAttributes({
|
|
39
53
|
'service.name': options.serviceName,
|
|
40
|
-
|
|
54
|
+
...(options.serviceNamespace === undefined
|
|
55
|
+
? {}
|
|
56
|
+
: { 'service.namespace': options.serviceNamespace }),
|
|
41
57
|
'service.version': options.serviceVersion,
|
|
42
58
|
});
|
|
43
59
|
}
|
|
@@ -81,6 +97,7 @@ function startTelemetry(options, configuration) {
|
|
|
81
97
|
const instrumentations = registerServiceInstrumentations({
|
|
82
98
|
endpoint: configuration.endpoint,
|
|
83
99
|
tracerProvider: provider,
|
|
100
|
+
ignoreIncomingRequest: options.ignoreIncomingRequest,
|
|
84
101
|
});
|
|
85
102
|
return buildRuntime(provider, contextManager, instrumentations);
|
|
86
103
|
}
|
package/src/instrumentations.js
CHANGED
|
@@ -7,31 +7,11 @@ const { KafkaJsInstrumentation } = require('@opentelemetry/instrumentation-kafka
|
|
|
7
7
|
const { PgInstrumentation } = require('@opentelemetry/instrumentation-pg');
|
|
8
8
|
const { UndiciInstrumentation } = require('@opentelemetry/instrumentation-undici');
|
|
9
9
|
|
|
10
|
-
const IGNORED_REQUEST_PATHS = new Set([
|
|
11
|
-
'/api/health',
|
|
12
|
-
'/favicon.ico',
|
|
13
|
-
'/health',
|
|
14
|
-
'/health-check',
|
|
15
|
-
'/healthz',
|
|
16
|
-
'/metrics',
|
|
17
|
-
'/ready',
|
|
18
|
-
'/readyz',
|
|
19
|
-
]);
|
|
20
|
-
|
|
21
10
|
function requestPath(request) {
|
|
22
11
|
const rawPath = request.url || request.path || '/';
|
|
23
12
|
return String(rawPath).split('?')[0];
|
|
24
13
|
}
|
|
25
14
|
|
|
26
|
-
function isRoutineRequest(request) {
|
|
27
|
-
const path = requestPath(request);
|
|
28
|
-
return (
|
|
29
|
-
IGNORED_REQUEST_PATHS.has(path) ||
|
|
30
|
-
path.startsWith('/_next/image') ||
|
|
31
|
-
path.startsWith('/_next/static/')
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
15
|
// Pattern: Normalizer - produces the bracketed URL host form for DNS, IPv4, and IPv6 inputs.
|
|
36
16
|
function normalizeRequestHost(requestHost) {
|
|
37
17
|
const host = String(requestHost || '')
|
|
@@ -61,11 +41,11 @@ function isExporterRequest(request, endpoint) {
|
|
|
61
41
|
);
|
|
62
42
|
}
|
|
63
43
|
|
|
64
|
-
function createInstrumentations(endpointUrl) {
|
|
44
|
+
function createInstrumentations(endpointUrl, ignoreIncomingRequest) {
|
|
65
45
|
const endpoint = new URL(endpointUrl);
|
|
66
46
|
return [
|
|
67
47
|
new HttpInstrumentation({
|
|
68
|
-
ignoreIncomingRequestHook:
|
|
48
|
+
ignoreIncomingRequestHook: request => ignoreIncomingRequest?.(request) === true,
|
|
69
49
|
ignoreOutgoingRequestHook: request => isExporterRequest(request, endpoint),
|
|
70
50
|
}),
|
|
71
51
|
new ExpressInstrumentation(),
|
|
@@ -82,7 +62,7 @@ function createInstrumentations(endpointUrl) {
|
|
|
82
62
|
}
|
|
83
63
|
|
|
84
64
|
function registerServiceInstrumentations(options) {
|
|
85
|
-
const instrumentations = createInstrumentations(options.endpoint);
|
|
65
|
+
const instrumentations = createInstrumentations(options.endpoint, options.ignoreIncomingRequest);
|
|
86
66
|
registerInstrumentations({
|
|
87
67
|
instrumentations,
|
|
88
68
|
tracerProvider: options.tracerProvider,
|
|
@@ -92,6 +72,5 @@ function registerServiceInstrumentations(options) {
|
|
|
92
72
|
|
|
93
73
|
module.exports = {
|
|
94
74
|
createInstrumentations,
|
|
95
|
-
isRoutineRequest,
|
|
96
75
|
registerServiceInstrumentations,
|
|
97
76
|
};
|