@atrim/instrument-node 0.4.0 → 0.4.1
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 +7 -6
- package/target/dist/index.cjs +251 -195
- package/target/dist/index.cjs.map +1 -1
- package/target/dist/index.d.cts +57 -3
- package/target/dist/index.d.ts +57 -3
- package/target/dist/index.js +229 -197
- package/target/dist/index.js.map +1 -1
- package/target/dist/integrations/effect/index.cjs +220 -191
- package/target/dist/integrations/effect/index.cjs.map +1 -1
- package/target/dist/integrations/effect/index.d.cts +17 -1
- package/target/dist/integrations/effect/index.d.ts +17 -1
- package/target/dist/integrations/effect/index.js +219 -192
- package/target/dist/integrations/effect/index.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atrim/instrument-node",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "OpenTelemetry instrumentation for Node.js with centralized YAML configuration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,6 +54,9 @@
|
|
|
54
54
|
"LICENSE"
|
|
55
55
|
],
|
|
56
56
|
"dependencies": {
|
|
57
|
+
"@effect/opentelemetry": "^0.59.0",
|
|
58
|
+
"@effect/platform": "^0.93.0",
|
|
59
|
+
"@effect/platform-node": "latest",
|
|
57
60
|
"@opentelemetry/auto-instrumentations-node": "^0.67.0",
|
|
58
61
|
"@opentelemetry/exporter-trace-otlp-http": "^0.208.0",
|
|
59
62
|
"@opentelemetry/instrumentation": "^0.208.0",
|
|
@@ -64,8 +67,6 @@
|
|
|
64
67
|
"zod": "^3.22.0"
|
|
65
68
|
},
|
|
66
69
|
"devDependencies": {
|
|
67
|
-
"@effect/opentelemetry": "^0.59.0",
|
|
68
|
-
"@effect/platform": "^0.93.0",
|
|
69
70
|
"@opentelemetry/api": "^1.9.0",
|
|
70
71
|
"@opentelemetry/resources": "^2.2.0",
|
|
71
72
|
"@opentelemetry/sdk-logs": "^0.208.0",
|
|
@@ -81,7 +82,7 @@
|
|
|
81
82
|
"tsx": "^4.7.0",
|
|
82
83
|
"typescript": "^5.7.2",
|
|
83
84
|
"vitest": "^4.0.8",
|
|
84
|
-
"@atrim/instrument-core": "0.4.
|
|
85
|
+
"@atrim/instrument-core": "0.4.1"
|
|
85
86
|
},
|
|
86
87
|
"peerDependencies": {
|
|
87
88
|
"@effect/opentelemetry": ">=0.40.0",
|
|
@@ -121,9 +122,9 @@
|
|
|
121
122
|
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
122
123
|
"format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
123
124
|
"clean": "rm -rf target",
|
|
124
|
-
"publish:dev:version": "npm version $(git describe --tags --abbrev=0 | sed 's/^v//')-$(git rev-parse --short HEAD)-$(date -u +%Y%m%d%H%M%S) --no-git-tag-version",
|
|
125
|
+
"publish:dev:version": "npm version $(git describe --tags --abbrev=0 | sed 's/^.*@//' | sed 's/^v//')-$(git rev-parse --short HEAD)-$(date -u +%Y%m%d%H%M%S) --no-git-tag-version",
|
|
125
126
|
"publish:dev:save": "node -p \"require('./package.json').version\" > .version",
|
|
126
|
-
"publish:dev:publish": "pnpm build &&
|
|
127
|
+
"publish:dev:publish": "pnpm build && pnpm publish --tag dev --access public --no-git-checks",
|
|
127
128
|
"publish:dev:reset": "npm version 1.0.0 --no-git-tag-version",
|
|
128
129
|
"publish:dev": "pnpm publish:dev:version && pnpm publish:dev:save && pnpm publish:dev:publish && pnpm publish:dev:reset"
|
|
129
130
|
}
|
package/target/dist/index.cjs
CHANGED
|
@@ -5,12 +5,37 @@ var sdkNode = require('@opentelemetry/sdk-node');
|
|
|
5
5
|
var sdkTraceBase = require('@opentelemetry/sdk-trace-base');
|
|
6
6
|
var autoInstrumentationsNode = require('@opentelemetry/auto-instrumentations-node');
|
|
7
7
|
var api = require('@opentelemetry/api');
|
|
8
|
-
var
|
|
9
|
-
var
|
|
8
|
+
var FileSystem = require('@effect/platform/FileSystem');
|
|
9
|
+
var HttpClient = require('@effect/platform/HttpClient');
|
|
10
|
+
var HttpClientRequest = require('@effect/platform/HttpClientRequest');
|
|
10
11
|
var yaml = require('yaml');
|
|
11
12
|
var zod = require('zod');
|
|
12
13
|
var exporterTraceOtlpHttp = require('@opentelemetry/exporter-trace-otlp-http');
|
|
13
14
|
var promises = require('fs/promises');
|
|
15
|
+
var path = require('path');
|
|
16
|
+
var platformNode = require('@effect/platform-node');
|
|
17
|
+
var platform = require('@effect/platform');
|
|
18
|
+
|
|
19
|
+
function _interopNamespace(e) {
|
|
20
|
+
if (e && e.__esModule) return e;
|
|
21
|
+
var n = Object.create(null);
|
|
22
|
+
if (e) {
|
|
23
|
+
Object.keys(e).forEach(function (k) {
|
|
24
|
+
if (k !== 'default') {
|
|
25
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
26
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
get: function () { return e[k]; }
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
n.default = e;
|
|
34
|
+
return Object.freeze(n);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var HttpClient__namespace = /*#__PURE__*/_interopNamespace(HttpClient);
|
|
38
|
+
var HttpClientRequest__namespace = /*#__PURE__*/_interopNamespace(HttpClientRequest);
|
|
14
39
|
|
|
15
40
|
var __defProp = Object.defineProperty;
|
|
16
41
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -75,233 +100,183 @@ var InstrumentationConfigSchema = zod.z.object({
|
|
|
75
100
|
http: HttpFilteringConfigSchema.optional()
|
|
76
101
|
});
|
|
77
102
|
(class extends effect.Data.TaggedError("ConfigError") {
|
|
103
|
+
get message() {
|
|
104
|
+
return this.reason;
|
|
105
|
+
}
|
|
78
106
|
});
|
|
79
107
|
var ConfigUrlError = class extends effect.Data.TaggedError("ConfigUrlError") {
|
|
108
|
+
get message() {
|
|
109
|
+
return this.reason;
|
|
110
|
+
}
|
|
80
111
|
};
|
|
81
112
|
var ConfigValidationError = class extends effect.Data.TaggedError("ConfigValidationError") {
|
|
113
|
+
get message() {
|
|
114
|
+
return this.reason;
|
|
115
|
+
}
|
|
82
116
|
};
|
|
83
117
|
var ConfigFileError = class extends effect.Data.TaggedError("ConfigFileError") {
|
|
118
|
+
get message() {
|
|
119
|
+
return this.reason;
|
|
120
|
+
}
|
|
84
121
|
};
|
|
85
122
|
(class extends effect.Data.TaggedError("ServiceDetectionError") {
|
|
123
|
+
get message() {
|
|
124
|
+
return this.reason;
|
|
125
|
+
}
|
|
86
126
|
});
|
|
87
127
|
(class extends effect.Data.TaggedError("InitializationError") {
|
|
128
|
+
get message() {
|
|
129
|
+
return this.reason;
|
|
130
|
+
}
|
|
88
131
|
});
|
|
89
132
|
(class extends effect.Data.TaggedError("ExportError") {
|
|
133
|
+
get message() {
|
|
134
|
+
return this.reason;
|
|
135
|
+
}
|
|
90
136
|
});
|
|
91
137
|
(class extends effect.Data.TaggedError("ShutdownError") {
|
|
138
|
+
get message() {
|
|
139
|
+
return this.reason;
|
|
140
|
+
}
|
|
92
141
|
});
|
|
93
142
|
var SECURITY_DEFAULTS = {
|
|
94
143
|
maxConfigSize: 1e6,
|
|
95
144
|
// 1MB
|
|
96
|
-
requestTimeout: 5e3
|
|
97
|
-
|
|
98
|
-
// Only HTTPS for remote configs
|
|
99
|
-
cacheTimeout: 3e5
|
|
100
|
-
// 5 minutes
|
|
145
|
+
requestTimeout: 5e3
|
|
146
|
+
// 5 seconds
|
|
101
147
|
};
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
117
|
-
{ pattern: "^health\\.", description: "Health checks" }
|
|
118
|
-
]
|
|
119
|
-
},
|
|
120
|
-
effect: {
|
|
121
|
-
auto_extract_metadata: true
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
var validateConfigEffect = (rawConfig) => effect.Effect.try({
|
|
126
|
-
try: () => InstrumentationConfigSchema.parse(rawConfig),
|
|
127
|
-
catch: (error) => new ConfigValidationError({
|
|
128
|
-
reason: "Invalid configuration schema",
|
|
129
|
-
cause: error
|
|
130
|
-
})
|
|
131
|
-
});
|
|
132
|
-
var loadConfigFromFileEffect = (filePath) => effect.Effect.gen(function* () {
|
|
133
|
-
const fileContents = yield* effect.Effect.try({
|
|
134
|
-
try: () => fs.readFileSync(filePath, "utf8"),
|
|
135
|
-
catch: (error) => new ConfigFileError({
|
|
136
|
-
reason: `Failed to read config file at ${filePath}`,
|
|
148
|
+
var ConfigLoader = class extends effect.Context.Tag("ConfigLoader")() {
|
|
149
|
+
};
|
|
150
|
+
var parseYamlContent = (content, uri) => effect.Effect.gen(function* () {
|
|
151
|
+
const parsed = yield* effect.Effect.try({
|
|
152
|
+
try: () => yaml.parse(content),
|
|
153
|
+
catch: (error) => new ConfigValidationError({
|
|
154
|
+
reason: uri ? `Failed to parse YAML from ${uri}` : "Failed to parse YAML",
|
|
155
|
+
cause: error
|
|
156
|
+
})
|
|
157
|
+
});
|
|
158
|
+
return yield* effect.Effect.try({
|
|
159
|
+
try: () => InstrumentationConfigSchema.parse(parsed),
|
|
160
|
+
catch: (error) => new ConfigValidationError({
|
|
161
|
+
reason: uri ? `Invalid configuration schema from ${uri}` : "Invalid configuration schema",
|
|
137
162
|
cause: error
|
|
138
163
|
})
|
|
139
164
|
});
|
|
140
|
-
|
|
165
|
+
});
|
|
166
|
+
var loadFromFileWithFs = (fs, path, uri) => effect.Effect.gen(function* () {
|
|
167
|
+
const content = yield* fs.readFileString(path).pipe(
|
|
168
|
+
effect.Effect.mapError(
|
|
169
|
+
(error) => new ConfigFileError({
|
|
170
|
+
reason: `Failed to read config file at ${uri}`,
|
|
171
|
+
cause: error
|
|
172
|
+
})
|
|
173
|
+
)
|
|
174
|
+
);
|
|
175
|
+
if (content.length > SECURITY_DEFAULTS.maxConfigSize) {
|
|
141
176
|
return yield* effect.Effect.fail(
|
|
142
177
|
new ConfigFileError({
|
|
143
178
|
reason: `Config file exceeds maximum size of ${SECURITY_DEFAULTS.maxConfigSize} bytes`
|
|
144
179
|
})
|
|
145
180
|
);
|
|
146
181
|
}
|
|
147
|
-
|
|
148
|
-
try {
|
|
149
|
-
rawConfig = yaml.parse(fileContents);
|
|
150
|
-
} catch (error) {
|
|
151
|
-
return yield* effect.Effect.fail(
|
|
152
|
-
new ConfigValidationError({
|
|
153
|
-
reason: "Invalid YAML syntax",
|
|
154
|
-
cause: error
|
|
155
|
-
})
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
return yield* validateConfigEffect(rawConfig);
|
|
182
|
+
return yield* parseYamlContent(content, uri);
|
|
159
183
|
});
|
|
160
|
-
var
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
184
|
+
var loadFromHttpWithClient = (client, url) => effect.Effect.scoped(
|
|
185
|
+
effect.Effect.gen(function* () {
|
|
186
|
+
if (url.startsWith("http://")) {
|
|
187
|
+
return yield* effect.Effect.fail(
|
|
188
|
+
new ConfigUrlError({
|
|
189
|
+
reason: "Insecure protocol: only HTTPS URLs are allowed"
|
|
190
|
+
})
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
const request = HttpClientRequest__namespace.get(url).pipe(
|
|
194
|
+
HttpClientRequest__namespace.setHeaders({
|
|
195
|
+
Accept: "application/yaml, text/yaml, application/x-yaml"
|
|
169
196
|
})
|
|
170
197
|
);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
198
|
+
const response = yield* client.execute(request).pipe(
|
|
199
|
+
effect.Effect.timeout(`${SECURITY_DEFAULTS.requestTimeout} millis`),
|
|
200
|
+
effect.Effect.mapError((error) => {
|
|
201
|
+
if (error._tag === "TimeoutException") {
|
|
202
|
+
return new ConfigUrlError({
|
|
203
|
+
reason: `Config fetch timeout after ${SECURITY_DEFAULTS.requestTimeout}ms from ${url}`
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return new ConfigUrlError({
|
|
207
|
+
reason: `Failed to load config from URL: ${url}`,
|
|
208
|
+
cause: error
|
|
209
|
+
});
|
|
176
210
|
})
|
|
177
211
|
);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
212
|
+
if (response.status >= 400) {
|
|
213
|
+
return yield* effect.Effect.fail(
|
|
214
|
+
new ConfigUrlError({
|
|
215
|
+
reason: `HTTP ${response.status} from ${url}`
|
|
216
|
+
})
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
const text = yield* response.text.pipe(
|
|
220
|
+
effect.Effect.mapError(
|
|
221
|
+
(error) => new ConfigUrlError({
|
|
222
|
+
reason: `Failed to read response body from ${url}`,
|
|
223
|
+
cause: error
|
|
224
|
+
})
|
|
225
|
+
)
|
|
226
|
+
);
|
|
227
|
+
if (text.length > SECURITY_DEFAULTS.maxConfigSize) {
|
|
228
|
+
return yield* effect.Effect.fail(
|
|
229
|
+
new ConfigUrlError({
|
|
230
|
+
reason: `Config exceeds maximum size of ${SECURITY_DEFAULTS.maxConfigSize} bytes`
|
|
231
|
+
})
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
return yield* parseYamlContent(text, url);
|
|
235
|
+
})
|
|
236
|
+
);
|
|
237
|
+
var makeConfigLoader = effect.Effect.gen(function* () {
|
|
238
|
+
const fs = yield* effect.Effect.serviceOption(FileSystem.FileSystem);
|
|
239
|
+
const http = yield* HttpClient__namespace.HttpClient;
|
|
240
|
+
const loadFromUriUncached = (uri) => effect.Effect.gen(function* () {
|
|
241
|
+
if (uri.startsWith("file://")) {
|
|
242
|
+
const path = uri.slice(7);
|
|
243
|
+
if (fs._tag === "None") {
|
|
244
|
+
return yield* effect.Effect.fail(
|
|
245
|
+
new ConfigFileError({
|
|
246
|
+
reason: "FileSystem not available (browser environment?)",
|
|
247
|
+
cause: { uri }
|
|
201
248
|
})
|
|
202
249
|
);
|
|
203
250
|
}
|
|
204
|
-
return
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
251
|
+
return yield* loadFromFileWithFs(fs.value, path, uri);
|
|
252
|
+
}
|
|
253
|
+
if (uri.startsWith("http://") || uri.startsWith("https://")) {
|
|
254
|
+
return yield* loadFromHttpWithClient(http, uri);
|
|
255
|
+
}
|
|
256
|
+
if (fs._tag === "Some") {
|
|
257
|
+
return yield* loadFromFileWithFs(fs.value, uri, uri);
|
|
258
|
+
} else {
|
|
259
|
+
return yield* loadFromHttpWithClient(http, uri);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
const loadFromUriCached = yield* effect.Effect.cachedFunction(loadFromUriUncached);
|
|
263
|
+
return ConfigLoader.of({
|
|
264
|
+
loadFromUri: loadFromUriCached,
|
|
265
|
+
loadFromInline: (content) => effect.Effect.gen(function* () {
|
|
266
|
+
if (typeof content === "string") {
|
|
267
|
+
return yield* parseYamlContent(content);
|
|
268
|
+
}
|
|
269
|
+
return yield* effect.Effect.try({
|
|
270
|
+
try: () => InstrumentationConfigSchema.parse(content),
|
|
271
|
+
catch: (error) => new ConfigValidationError({
|
|
272
|
+
reason: "Invalid configuration schema",
|
|
273
|
+
cause: error
|
|
274
|
+
})
|
|
275
|
+
});
|
|
227
276
|
})
|
|
228
277
|
});
|
|
229
|
-
if (text.length > SECURITY_DEFAULTS.maxConfigSize) {
|
|
230
|
-
return yield* effect.Effect.fail(
|
|
231
|
-
new ConfigUrlError({
|
|
232
|
-
reason: `Config exceeds maximum size of ${SECURITY_DEFAULTS.maxConfigSize} bytes`
|
|
233
|
-
})
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
let rawConfig;
|
|
237
|
-
try {
|
|
238
|
-
rawConfig = yaml.parse(text);
|
|
239
|
-
} catch (error) {
|
|
240
|
-
return yield* effect.Effect.fail(
|
|
241
|
-
new ConfigValidationError({
|
|
242
|
-
reason: "Invalid YAML syntax",
|
|
243
|
-
cause: error
|
|
244
|
-
})
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
return yield* validateConfigEffect(rawConfig);
|
|
248
278
|
});
|
|
249
|
-
var
|
|
250
|
-
capacity: 100,
|
|
251
|
-
timeToLive: effect.Duration.minutes(5),
|
|
252
|
-
lookup: (url) => fetchAndParseConfig(url)
|
|
253
|
-
});
|
|
254
|
-
var cacheInstance = null;
|
|
255
|
-
var getCache = effect.Effect.gen(function* () {
|
|
256
|
-
if (!cacheInstance) {
|
|
257
|
-
cacheInstance = yield* makeConfigCache();
|
|
258
|
-
}
|
|
259
|
-
return cacheInstance;
|
|
260
|
-
});
|
|
261
|
-
var loadConfigFromUrlEffect = (url, cacheTimeout = SECURITY_DEFAULTS.cacheTimeout) => effect.Effect.gen(function* () {
|
|
262
|
-
if (cacheTimeout === 0) {
|
|
263
|
-
return yield* fetchAndParseConfig(url);
|
|
264
|
-
}
|
|
265
|
-
const cache = yield* getCache;
|
|
266
|
-
return yield* cache.get(url);
|
|
267
|
-
});
|
|
268
|
-
var loadConfigEffect = (options = {}) => effect.Effect.gen(function* () {
|
|
269
|
-
if (options.config) {
|
|
270
|
-
return yield* validateConfigEffect(options.config);
|
|
271
|
-
}
|
|
272
|
-
const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
|
|
273
|
-
if (envConfigPath) {
|
|
274
|
-
if (envConfigPath.startsWith("http://") || envConfigPath.startsWith("https://")) {
|
|
275
|
-
return yield* loadConfigFromUrlEffect(envConfigPath, options.cacheTimeout);
|
|
276
|
-
}
|
|
277
|
-
return yield* loadConfigFromFileEffect(envConfigPath);
|
|
278
|
-
}
|
|
279
|
-
if (options.configUrl) {
|
|
280
|
-
return yield* loadConfigFromUrlEffect(options.configUrl, options.cacheTimeout);
|
|
281
|
-
}
|
|
282
|
-
if (options.configPath) {
|
|
283
|
-
return yield* loadConfigFromFileEffect(options.configPath);
|
|
284
|
-
}
|
|
285
|
-
const defaultPath = path.join(process.cwd(), "instrumentation.yaml");
|
|
286
|
-
const exists = yield* effect.Effect.sync(() => fs.existsSync(defaultPath));
|
|
287
|
-
if (exists) {
|
|
288
|
-
return yield* loadConfigFromFileEffect(defaultPath);
|
|
289
|
-
}
|
|
290
|
-
return getDefaultConfig();
|
|
291
|
-
});
|
|
292
|
-
async function loadConfig(options = {}) {
|
|
293
|
-
return effect.Effect.runPromise(
|
|
294
|
-
loadConfigEffect(options).pipe(
|
|
295
|
-
// Convert typed errors to regular Error with reason message for backward compatibility
|
|
296
|
-
effect.Effect.mapError((error) => {
|
|
297
|
-
const message = error.reason;
|
|
298
|
-
const newError = new Error(message);
|
|
299
|
-
newError.cause = error.cause;
|
|
300
|
-
return newError;
|
|
301
|
-
})
|
|
302
|
-
)
|
|
303
|
-
);
|
|
304
|
-
}
|
|
279
|
+
var ConfigLoaderLive = effect.Layer.effect(ConfigLoader, makeConfigLoader);
|
|
305
280
|
var PatternMatcher = class {
|
|
306
281
|
constructor(config) {
|
|
307
282
|
__publicField2(this, "ignorePatterns", []);
|
|
@@ -727,6 +702,84 @@ async function getServiceNameAsync() {
|
|
|
727
702
|
async function getServiceVersionAsync() {
|
|
728
703
|
return effect.Effect.runPromise(getServiceVersion);
|
|
729
704
|
}
|
|
705
|
+
var NodeConfigLoaderLive = ConfigLoaderLive.pipe(
|
|
706
|
+
effect.Layer.provide(effect.Layer.mergeAll(platformNode.NodeContext.layer, platform.FetchHttpClient.layer))
|
|
707
|
+
);
|
|
708
|
+
var cachedLoaderPromise = null;
|
|
709
|
+
function getCachedLoader() {
|
|
710
|
+
if (!cachedLoaderPromise) {
|
|
711
|
+
cachedLoaderPromise = effect.Effect.runPromise(
|
|
712
|
+
effect.Effect.gen(function* () {
|
|
713
|
+
return yield* ConfigLoader;
|
|
714
|
+
}).pipe(effect.Effect.provide(NodeConfigLoaderLive))
|
|
715
|
+
);
|
|
716
|
+
}
|
|
717
|
+
return cachedLoaderPromise;
|
|
718
|
+
}
|
|
719
|
+
function _resetConfigLoaderCache() {
|
|
720
|
+
cachedLoaderPromise = null;
|
|
721
|
+
}
|
|
722
|
+
async function loadConfig(uri, options) {
|
|
723
|
+
if (options?.cacheTimeout === 0) {
|
|
724
|
+
const program = effect.Effect.gen(function* () {
|
|
725
|
+
const loader2 = yield* ConfigLoader;
|
|
726
|
+
return yield* loader2.loadFromUri(uri);
|
|
727
|
+
});
|
|
728
|
+
return effect.Effect.runPromise(program.pipe(effect.Effect.provide(NodeConfigLoaderLive)));
|
|
729
|
+
}
|
|
730
|
+
const loader = await getCachedLoader();
|
|
731
|
+
return effect.Effect.runPromise(loader.loadFromUri(uri));
|
|
732
|
+
}
|
|
733
|
+
async function loadConfigFromInline(content) {
|
|
734
|
+
const loader = await getCachedLoader();
|
|
735
|
+
return effect.Effect.runPromise(loader.loadFromInline(content));
|
|
736
|
+
}
|
|
737
|
+
function getDefaultConfig() {
|
|
738
|
+
return {
|
|
739
|
+
version: "1.0",
|
|
740
|
+
instrumentation: {
|
|
741
|
+
enabled: true,
|
|
742
|
+
logging: "on",
|
|
743
|
+
description: "Default instrumentation configuration",
|
|
744
|
+
instrument_patterns: [
|
|
745
|
+
{ pattern: "^app\\.", enabled: true, description: "Application operations" },
|
|
746
|
+
{ pattern: "^http\\.server\\.", enabled: true, description: "HTTP server operations" },
|
|
747
|
+
{ pattern: "^http\\.client\\.", enabled: true, description: "HTTP client operations" }
|
|
748
|
+
],
|
|
749
|
+
ignore_patterns: [
|
|
750
|
+
{ pattern: "^test\\.", description: "Test utilities" },
|
|
751
|
+
{ pattern: "^internal\\.", description: "Internal operations" },
|
|
752
|
+
{ pattern: "^health\\.", description: "Health checks" }
|
|
753
|
+
]
|
|
754
|
+
},
|
|
755
|
+
effect: {
|
|
756
|
+
auto_extract_metadata: true
|
|
757
|
+
}
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
async function loadConfigWithOptions(options = {}) {
|
|
761
|
+
const loadOptions = options.cacheTimeout !== void 0 ? { cacheTimeout: options.cacheTimeout } : void 0;
|
|
762
|
+
if (options.config) {
|
|
763
|
+
return loadConfigFromInline(options.config);
|
|
764
|
+
}
|
|
765
|
+
const envConfigPath = process.env.ATRIM_INSTRUMENTATION_CONFIG;
|
|
766
|
+
if (envConfigPath) {
|
|
767
|
+
return loadConfig(envConfigPath, loadOptions);
|
|
768
|
+
}
|
|
769
|
+
if (options.configUrl) {
|
|
770
|
+
return loadConfig(options.configUrl, loadOptions);
|
|
771
|
+
}
|
|
772
|
+
if (options.configPath) {
|
|
773
|
+
return loadConfig(options.configPath, loadOptions);
|
|
774
|
+
}
|
|
775
|
+
const { existsSync } = await import('fs');
|
|
776
|
+
const { join: join2 } = await import('path');
|
|
777
|
+
const defaultPath = join2(process.cwd(), "instrumentation.yaml");
|
|
778
|
+
if (existsSync(defaultPath)) {
|
|
779
|
+
return loadConfig(defaultPath, loadOptions);
|
|
780
|
+
}
|
|
781
|
+
return getDefaultConfig();
|
|
782
|
+
}
|
|
730
783
|
|
|
731
784
|
// src/core/sdk-initializer.ts
|
|
732
785
|
var sdkInstance = null;
|
|
@@ -866,7 +919,7 @@ async function initializeSdk(options = {}) {
|
|
|
866
919
|
}
|
|
867
920
|
}
|
|
868
921
|
async function performInitialization(options) {
|
|
869
|
-
const config = await
|
|
922
|
+
const config = await loadConfigWithOptions(options);
|
|
870
923
|
const loggingLevel = config.instrumentation.logging || "on";
|
|
871
924
|
logger.setLevel(loggingLevel);
|
|
872
925
|
const alreadyInitialized = isTracingAlreadyInitialized();
|
|
@@ -1022,13 +1075,13 @@ function logInitialization(config, serviceName, serviceVersion, options, autoIns
|
|
|
1022
1075
|
async function initializeInstrumentation(options = {}) {
|
|
1023
1076
|
const sdk = await initializeSdk(options);
|
|
1024
1077
|
if (sdk) {
|
|
1025
|
-
const config = await
|
|
1078
|
+
const config = await loadConfigWithOptions(options);
|
|
1026
1079
|
initializePatternMatcher(config);
|
|
1027
1080
|
}
|
|
1028
1081
|
return sdk;
|
|
1029
1082
|
}
|
|
1030
1083
|
async function initializePatternMatchingOnly(options = {}) {
|
|
1031
|
-
const config = await
|
|
1084
|
+
const config = await loadConfigWithOptions(options);
|
|
1032
1085
|
initializePatternMatcher(config);
|
|
1033
1086
|
logger.log("@atrim/instrumentation: Pattern matching initialized (legacy mode)");
|
|
1034
1087
|
logger.log(
|
|
@@ -1045,7 +1098,7 @@ var initializeInstrumentationEffect = (options = {}) => effect.Effect.gen(functi
|
|
|
1045
1098
|
});
|
|
1046
1099
|
if (sdk) {
|
|
1047
1100
|
yield* effect.Effect.tryPromise({
|
|
1048
|
-
try: () =>
|
|
1101
|
+
try: () => loadConfigWithOptions(options),
|
|
1049
1102
|
catch: (error) => new ConfigError2({
|
|
1050
1103
|
reason: "Failed to load config for pattern matcher",
|
|
1051
1104
|
cause: error
|
|
@@ -1062,7 +1115,7 @@ var initializeInstrumentationEffect = (options = {}) => effect.Effect.gen(functi
|
|
|
1062
1115
|
});
|
|
1063
1116
|
var initializePatternMatchingOnlyEffect = (options = {}) => effect.Effect.gen(function* () {
|
|
1064
1117
|
const config = yield* effect.Effect.tryPromise({
|
|
1065
|
-
try: () =>
|
|
1118
|
+
try: () => loadConfigWithOptions(options),
|
|
1066
1119
|
catch: (error) => new ConfigError2({
|
|
1067
1120
|
reason: "Failed to load configuration",
|
|
1068
1121
|
cause: error
|
|
@@ -1184,6 +1237,7 @@ exports.ShutdownError = ShutdownError2;
|
|
|
1184
1237
|
exports.annotateCacheOperation = annotateCacheOperation;
|
|
1185
1238
|
exports.annotateDbQuery = annotateDbQuery;
|
|
1186
1239
|
exports.annotateHttpRequest = annotateHttpRequest;
|
|
1240
|
+
exports.clearConfigCache = _resetConfigLoaderCache;
|
|
1187
1241
|
exports.createOtlpExporter = createOtlpExporter;
|
|
1188
1242
|
exports.detectServiceInfo = detectServiceInfoAsync;
|
|
1189
1243
|
exports.detectServiceInfoEffect = detectServiceInfo;
|
|
@@ -1200,6 +1254,8 @@ exports.initializeInstrumentationEffect = initializeInstrumentationEffect;
|
|
|
1200
1254
|
exports.initializePatternMatchingOnly = initializePatternMatchingOnly;
|
|
1201
1255
|
exports.initializePatternMatchingOnlyEffect = initializePatternMatchingOnlyEffect;
|
|
1202
1256
|
exports.loadConfig = loadConfig;
|
|
1257
|
+
exports.loadConfigFromInline = loadConfigFromInline;
|
|
1258
|
+
exports.loadConfigWithOptions = loadConfigWithOptions;
|
|
1203
1259
|
exports.markSpanError = markSpanError;
|
|
1204
1260
|
exports.markSpanSuccess = markSpanSuccess;
|
|
1205
1261
|
exports.recordException = recordException;
|