@adonisjs/otel 1.0.0-next.3 → 1.0.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.
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { InstrumentationConfigMap } from '@opentelemetry/auto-instrumentations-node';
|
|
2
|
+
import type { HttpInstrumentationConfig } from './types/instrumentations.js';
|
|
3
|
+
/**
|
|
4
|
+
* Handles URL filtering for OpenTelemetry HTTP instrumentation.
|
|
5
|
+
* Determines which requests should be ignored (not traced).
|
|
6
|
+
*/
|
|
7
|
+
export declare class HttpUrlFilter {
|
|
8
|
+
#private;
|
|
9
|
+
static readonly DEFAULT_IGNORED_URLS: string[];
|
|
10
|
+
static readonly STATIC_FILE_EXTENSIONS: Set<string>;
|
|
11
|
+
constructor(config?: HttpInstrumentationConfig);
|
|
12
|
+
/**
|
|
13
|
+
* Check if a URL should be ignored (not traced).
|
|
14
|
+
* A URL is ignored if:
|
|
15
|
+
* - It's a static file and ignoreStaticFiles is true (default)
|
|
16
|
+
* - It matches the ignored URLs list (exact or prefix pattern)
|
|
17
|
+
* - The user's custom hook returns true
|
|
18
|
+
*/
|
|
19
|
+
shouldIgnore(url: string | undefined): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Apply HTTP instrumentation config to the merged config map
|
|
22
|
+
*/
|
|
23
|
+
applyToConfig(mergedConfig: InstrumentationConfigMap, userHttpConfig?: HttpInstrumentationConfig): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles URL filtering for OpenTelemetry HTTP instrumentation.
|
|
3
|
+
* Determines which requests should be ignored (not traced).
|
|
4
|
+
*/
|
|
5
|
+
export class HttpUrlFilter {
|
|
6
|
+
static DEFAULT_IGNORED_URLS = [
|
|
7
|
+
'/health',
|
|
8
|
+
'/healthz',
|
|
9
|
+
'/internal/healthz',
|
|
10
|
+
'/ready',
|
|
11
|
+
'/readiness',
|
|
12
|
+
'/metrics',
|
|
13
|
+
'/internal/metrics',
|
|
14
|
+
];
|
|
15
|
+
static STATIC_FILE_EXTENSIONS = new Set([
|
|
16
|
+
'css',
|
|
17
|
+
'js',
|
|
18
|
+
'mjs',
|
|
19
|
+
'cjs',
|
|
20
|
+
'ts',
|
|
21
|
+
'tsx',
|
|
22
|
+
'jsx',
|
|
23
|
+
'map',
|
|
24
|
+
'woff',
|
|
25
|
+
'woff2',
|
|
26
|
+
'ttf',
|
|
27
|
+
'eot',
|
|
28
|
+
'otf',
|
|
29
|
+
'svg',
|
|
30
|
+
'png',
|
|
31
|
+
'jpg',
|
|
32
|
+
'jpeg',
|
|
33
|
+
'gif',
|
|
34
|
+
'webp',
|
|
35
|
+
'ico',
|
|
36
|
+
'avif',
|
|
37
|
+
'mp4',
|
|
38
|
+
'webm',
|
|
39
|
+
'mp3',
|
|
40
|
+
'ogg',
|
|
41
|
+
'wav',
|
|
42
|
+
'pdf',
|
|
43
|
+
]);
|
|
44
|
+
#ignoredUrls;
|
|
45
|
+
#ignoreStaticFiles;
|
|
46
|
+
#userIgnoreHook;
|
|
47
|
+
constructor(config) {
|
|
48
|
+
this.#ignoredUrls = this.#buildIgnoredUrls(config);
|
|
49
|
+
this.#ignoreStaticFiles = config?.ignoreStaticFiles !== false;
|
|
50
|
+
this.#userIgnoreHook = config?.ignoreIncomingRequestHook;
|
|
51
|
+
}
|
|
52
|
+
#buildIgnoredUrls(config) {
|
|
53
|
+
const userUrls = config?.ignoredUrls || [];
|
|
54
|
+
const mergeWithDefaults = config?.mergeIgnoredUrls !== false;
|
|
55
|
+
if (!mergeWithDefaults)
|
|
56
|
+
return userUrls;
|
|
57
|
+
return [...HttpUrlFilter.DEFAULT_IGNORED_URLS, ...userUrls];
|
|
58
|
+
}
|
|
59
|
+
#isStaticFile(url) {
|
|
60
|
+
const lastSegment = url.split('/').pop() || '';
|
|
61
|
+
const dotIndex = lastSegment.lastIndexOf('.');
|
|
62
|
+
if (dotIndex === -1)
|
|
63
|
+
return false;
|
|
64
|
+
const extension = lastSegment.slice(dotIndex + 1).toLowerCase();
|
|
65
|
+
return HttpUrlFilter.STATIC_FILE_EXTENSIONS.has(extension);
|
|
66
|
+
}
|
|
67
|
+
#matchesPattern(urlPath, pattern) {
|
|
68
|
+
if (pattern.endsWith('/*')) {
|
|
69
|
+
const prefix = pattern.slice(0, -2);
|
|
70
|
+
return urlPath === prefix || urlPath.startsWith(prefix + '/');
|
|
71
|
+
}
|
|
72
|
+
return urlPath === pattern || urlPath.startsWith(pattern + '/');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check if a URL should be ignored (not traced).
|
|
76
|
+
* A URL is ignored if:
|
|
77
|
+
* - It's a static file and ignoreStaticFiles is true (default)
|
|
78
|
+
* - It matches the ignored URLs list (exact or prefix pattern)
|
|
79
|
+
* - The user's custom hook returns true
|
|
80
|
+
*/
|
|
81
|
+
shouldIgnore(url) {
|
|
82
|
+
if (!url)
|
|
83
|
+
return false;
|
|
84
|
+
const urlPath = url.split('?')[0];
|
|
85
|
+
if (this.#ignoreStaticFiles && this.#isStaticFile(urlPath))
|
|
86
|
+
return true;
|
|
87
|
+
if (this.#ignoredUrls.some((pattern) => this.#matchesPattern(urlPath, pattern)))
|
|
88
|
+
return true;
|
|
89
|
+
if (this.#userIgnoreHook)
|
|
90
|
+
return this.#userIgnoreHook({ url });
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Apply HTTP instrumentation config to the merged config map
|
|
95
|
+
*/
|
|
96
|
+
applyToConfig(mergedConfig, userHttpConfig) {
|
|
97
|
+
const httpKey = '@opentelemetry/instrumentation-http';
|
|
98
|
+
const currentConfig = mergedConfig[httpKey];
|
|
99
|
+
if (currentConfig && 'enabled' in currentConfig && currentConfig.enabled === false) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
mergedConfig[httpKey] = {
|
|
103
|
+
...currentConfig,
|
|
104
|
+
...userHttpConfig,
|
|
105
|
+
ignoreIncomingRequestHook: (req) => this.shouldIgnore(req.url),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
package/build/src/otel.d.ts
CHANGED
package/build/src/otel.js
CHANGED
|
@@ -5,6 +5,7 @@ import { ConsoleSpanExporter, ParentBasedSampler, SimpleSpanProcessor, TraceIdRa
|
|
|
5
5
|
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
|
|
6
6
|
import { ATTR_DEPLOYMENT_ENVIRONMENT_NAME, ATTR_SERVICE_INSTANCE_ID, } from '@opentelemetry/semantic-conventions/incubating';
|
|
7
7
|
import { HttpContext } from '@adonisjs/core/http';
|
|
8
|
+
import { HttpUrlFilter } from './http_url_filter.js';
|
|
8
9
|
/**
|
|
9
10
|
* OpenTelemetry SDK manager for AdonisJS.
|
|
10
11
|
*
|
|
@@ -24,16 +25,6 @@ import { HttpContext } from '@adonisjs/core/http';
|
|
|
24
25
|
* ```
|
|
25
26
|
*/
|
|
26
27
|
export class OtelManager {
|
|
27
|
-
static DEFAULT_IGNORED_URLS = [
|
|
28
|
-
'/health',
|
|
29
|
-
'/healthz',
|
|
30
|
-
'/internal/healthz',
|
|
31
|
-
'/ready',
|
|
32
|
-
'/readiness',
|
|
33
|
-
'/metrics',
|
|
34
|
-
'/internal/metrics',
|
|
35
|
-
'/favicon.ico',
|
|
36
|
-
];
|
|
37
28
|
static #instance = null;
|
|
38
29
|
sdk;
|
|
39
30
|
serviceName;
|
|
@@ -80,32 +71,6 @@ export class OtelManager {
|
|
|
80
71
|
...this.#config.resourceAttributes,
|
|
81
72
|
});
|
|
82
73
|
}
|
|
83
|
-
/**
|
|
84
|
-
* Get the resolved list of ignored URLs from HTTP instrumentation config
|
|
85
|
-
*/
|
|
86
|
-
#getIgnoredUrls(httpConfig) {
|
|
87
|
-
const userUrls = httpConfig?.ignoredUrls || [];
|
|
88
|
-
const mergeWithDefaults = httpConfig?.mergeIgnoredUrls !== false;
|
|
89
|
-
if (!mergeWithDefaults) {
|
|
90
|
-
return userUrls;
|
|
91
|
-
}
|
|
92
|
-
return [...OtelManager.DEFAULT_IGNORED_URLS, ...userUrls];
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Check if a URL should be ignored based on the ignored URLs list.
|
|
96
|
-
* Supports exact matches and wildcard patterns (e.g., '/internal/*')
|
|
97
|
-
*/
|
|
98
|
-
#shouldIgnoreUrl(url, ignoredUrls) {
|
|
99
|
-
if (!url)
|
|
100
|
-
return false;
|
|
101
|
-
return ignoredUrls.some((pattern) => {
|
|
102
|
-
if (pattern.endsWith('/*')) {
|
|
103
|
-
const prefix = pattern.slice(0, -1);
|
|
104
|
-
return url.startsWith(prefix);
|
|
105
|
-
}
|
|
106
|
-
return url.startsWith(pattern);
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
74
|
/**
|
|
110
75
|
* Check if a value is an Instrumentation instance
|
|
111
76
|
*/
|
|
@@ -185,34 +150,12 @@ export class OtelManager {
|
|
|
185
150
|
for (const name of disabledSet) {
|
|
186
151
|
mergedConfig[name] = { enabled: false };
|
|
187
152
|
}
|
|
188
|
-
|
|
153
|
+
const httpUrlFilter = new HttpUrlFilter(httpConfig);
|
|
154
|
+
httpUrlFilter.applyToConfig(mergedConfig, httpConfig);
|
|
189
155
|
this.#applyPinoInstrumentationConfig(mergedConfig, pinoConfig);
|
|
190
156
|
const autoInstrumentations = getNodeAutoInstrumentations(mergedConfig);
|
|
191
157
|
return [...autoInstrumentations, ...customInstances];
|
|
192
158
|
}
|
|
193
|
-
/**
|
|
194
|
-
* Apply HTTP instrumentation configuration with smart merging of ignoreIncomingRequestHook
|
|
195
|
-
*/
|
|
196
|
-
#applyHttpInstrumentationConfig(mergedConfig, userHttpConfig) {
|
|
197
|
-
const httpKey = '@opentelemetry/instrumentation-http';
|
|
198
|
-
const currentConfig = mergedConfig[httpKey];
|
|
199
|
-
if (currentConfig && 'enabled' in currentConfig && currentConfig.enabled === false) {
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
const ignoredUrls = this.#getIgnoredUrls(userHttpConfig);
|
|
203
|
-
const userIgnoreHook = userHttpConfig?.ignoreIncomingRequestHook;
|
|
204
|
-
mergedConfig[httpKey] = {
|
|
205
|
-
...currentConfig,
|
|
206
|
-
...userHttpConfig,
|
|
207
|
-
ignoreIncomingRequestHook: (req) => {
|
|
208
|
-
if (this.#shouldIgnoreUrl(req.url, ignoredUrls))
|
|
209
|
-
return true;
|
|
210
|
-
if (userIgnoreHook)
|
|
211
|
-
return userIgnoreHook(req);
|
|
212
|
-
return false;
|
|
213
|
-
},
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
159
|
/**
|
|
217
160
|
* Apply Pino instrumentation configuration with smart merging of logHook
|
|
218
161
|
*/
|
|
@@ -21,9 +21,9 @@ export interface HttpInstrumentationConfig extends Omit<NonNullable<Instrumentat
|
|
|
21
21
|
/**
|
|
22
22
|
* URLs to ignore in HTTP instrumentation.
|
|
23
23
|
* Merged with defaults unless `mergeIgnoredUrls` is false.
|
|
24
|
-
* Supports
|
|
24
|
+
* Supports exact matches and prefix patterns ('/internal/*').
|
|
25
25
|
*
|
|
26
|
-
* @default ['/health', '/healthz', '/ready', '/metrics',
|
|
26
|
+
* @default ['/health', '/healthz', '/ready', '/metrics', ...]
|
|
27
27
|
*/
|
|
28
28
|
ignoredUrls?: string[];
|
|
29
29
|
/**
|
|
@@ -31,9 +31,14 @@ export interface HttpInstrumentationConfig extends Omit<NonNullable<Instrumentat
|
|
|
31
31
|
* @default true
|
|
32
32
|
*/
|
|
33
33
|
mergeIgnoredUrls?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Whether to automatically ignore static files (css, js, images, fonts, etc.).
|
|
36
|
+
* @default true
|
|
37
|
+
*/
|
|
38
|
+
ignoreStaticFiles?: boolean;
|
|
34
39
|
/**
|
|
35
40
|
* Custom hook to ignore specific incoming requests.
|
|
36
|
-
* Called AFTER the ignoredUrls
|
|
41
|
+
* Called AFTER the ignoredUrls and static files checks.
|
|
37
42
|
*/
|
|
38
43
|
ignoreIncomingRequestHook?: (request: {
|
|
39
44
|
url?: string;
|
package/package.json
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adonisjs/otel",
|
|
3
3
|
"description": "OpenTelemetry integration for AdonisJS with sensible defaults and zero-config setup",
|
|
4
|
-
"version": "1.0.0
|
|
4
|
+
"version": "1.0.0",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.6.0"
|
|
7
7
|
},
|
|
8
8
|
"type": "module",
|
|
9
|
+
"homepage": "https://github.com/adonisjs/otel#readme",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/adonisjs/otel.git"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/adonisjs/otel/issues"
|
|
16
|
+
},
|
|
9
17
|
"files": [
|
|
10
18
|
"build/src",
|
|
11
19
|
"build/providers",
|
|
@@ -18,7 +26,8 @@
|
|
|
18
26
|
"exports": {
|
|
19
27
|
".": "./build/index.js",
|
|
20
28
|
"./init": "./build/src/start.js",
|
|
21
|
-
"./types": "./build/src/types.js",
|
|
29
|
+
"./types": "./build/src/types/index.js",
|
|
30
|
+
"./manager": "./build/src/otel.js",
|
|
22
31
|
"./helpers": "./build/src/helpers.js",
|
|
23
32
|
"./decorators": "./build/src/decorators.js",
|
|
24
33
|
"./otel_provider": "./build/providers/otel_provider.js",
|
|
@@ -37,6 +46,7 @@
|
|
|
37
46
|
"test": "c8 npm run quick:test",
|
|
38
47
|
"prebuild": "npm run lint && npm run clean",
|
|
39
48
|
"build": "tsc",
|
|
49
|
+
"checks": "npm run lint && npm run typecheck && npm run test",
|
|
40
50
|
"postbuild": "npm run copy:templates",
|
|
41
51
|
"release": "release-it",
|
|
42
52
|
"version": "npm run build",
|
|
@@ -97,8 +107,8 @@
|
|
|
97
107
|
"@adonisjs/core": "^6.2.0 || ^7.0.0"
|
|
98
108
|
},
|
|
99
109
|
"publishConfig": {
|
|
100
|
-
"
|
|
101
|
-
"
|
|
110
|
+
"provenance": true,
|
|
111
|
+
"access": "public"
|
|
102
112
|
},
|
|
103
113
|
"release-it": {
|
|
104
114
|
"git": {
|