@brizz/sdk 0.1.1 → 0.1.2-rc.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/README.md +339 -19
- package/dist/index.cjs +2937 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +178 -0
- package/dist/index.d.ts +177 -12
- package/dist/index.js +2895 -26
- package/dist/index.js.map +1 -1
- package/dist/loader.mjs +72 -0
- package/dist/preload.cjs +2787 -0
- package/dist/preload.cjs.map +1 -0
- package/dist/preload.d.cts +2 -0
- package/dist/preload.d.ts +2 -0
- package/dist/preload.js +2777 -0
- package/dist/preload.js.map +1 -0
- package/package.json +48 -35
- package/dist/index.d.ts.map +0 -1
- package/dist/internal/config.d.ts +0 -17
- package/dist/internal/config.d.ts.map +0 -1
- package/dist/internal/config.js +0 -94
- package/dist/internal/config.js.map +0 -1
- package/dist/internal/instrumentation/auto-init.d.ts +0 -3
- package/dist/internal/instrumentation/auto-init.d.ts.map +0 -1
- package/dist/internal/instrumentation/auto-init.js +0 -87
- package/dist/internal/instrumentation/auto-init.js.map +0 -1
- package/dist/internal/instrumentation/index.d.ts +0 -2
- package/dist/internal/instrumentation/index.d.ts.map +0 -1
- package/dist/internal/instrumentation/index.js +0 -6
- package/dist/internal/instrumentation/index.js.map +0 -1
- package/dist/internal/instrumentation/registry.d.ts +0 -30
- package/dist/internal/instrumentation/registry.d.ts.map +0 -1
- package/dist/internal/instrumentation/registry.js +0 -94
- package/dist/internal/instrumentation/registry.js.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/index.d.ts +0 -4
- package/dist/internal/instrumentation/vercel-ai/index.d.ts.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/index.js +0 -8
- package/dist/internal/instrumentation/vercel-ai/index.js.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/instrumentation.d.ts +0 -16
- package/dist/internal/instrumentation/vercel-ai/instrumentation.d.ts.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/instrumentation.js +0 -119
- package/dist/internal/instrumentation/vercel-ai/instrumentation.js.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/patchers/base-patcher.d.ts +0 -24
- package/dist/internal/instrumentation/vercel-ai/patchers/base-patcher.d.ts.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/patchers/base-patcher.js +0 -57
- package/dist/internal/instrumentation/vercel-ai/patchers/base-patcher.js.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/patchers/embeddings-patcher.d.ts +0 -16
- package/dist/internal/instrumentation/vercel-ai/patchers/embeddings-patcher.d.ts.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/patchers/embeddings-patcher.js +0 -58
- package/dist/internal/instrumentation/vercel-ai/patchers/embeddings-patcher.js.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/patchers/generate-text-patcher.d.ts +0 -8
- package/dist/internal/instrumentation/vercel-ai/patchers/generate-text-patcher.d.ts.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/patchers/generate-text-patcher.js +0 -59
- package/dist/internal/instrumentation/vercel-ai/patchers/generate-text-patcher.js.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/patchers/index.d.ts +0 -5
- package/dist/internal/instrumentation/vercel-ai/patchers/index.d.ts.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/patchers/index.js +0 -12
- package/dist/internal/instrumentation/vercel-ai/patchers/index.js.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/patchers/stream-text-patcher.d.ts +0 -12
- package/dist/internal/instrumentation/vercel-ai/patchers/stream-text-patcher.d.ts.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/patchers/stream-text-patcher.js +0 -41
- package/dist/internal/instrumentation/vercel-ai/patchers/stream-text-patcher.js.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/semconv.d.ts +0 -53
- package/dist/internal/instrumentation/vercel-ai/semconv.d.ts.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/semconv.js +0 -57
- package/dist/internal/instrumentation/vercel-ai/semconv.js.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/stream-handler.d.ts +0 -13
- package/dist/internal/instrumentation/vercel-ai/stream-handler.d.ts.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/stream-handler.js +0 -101
- package/dist/internal/instrumentation/vercel-ai/stream-handler.js.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/telemetry-recorder.d.ts +0 -13
- package/dist/internal/instrumentation/vercel-ai/telemetry-recorder.d.ts.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/telemetry-recorder.js +0 -115
- package/dist/internal/instrumentation/vercel-ai/telemetry-recorder.js.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/types.d.ts +0 -197
- package/dist/internal/instrumentation/vercel-ai/types.d.ts.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/types.js +0 -3
- package/dist/internal/instrumentation/vercel-ai/types.js.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/utils.d.ts +0 -14
- package/dist/internal/instrumentation/vercel-ai/utils.d.ts.map +0 -1
- package/dist/internal/instrumentation/vercel-ai/utils.js +0 -243
- package/dist/internal/instrumentation/vercel-ai/utils.js.map +0 -1
- package/dist/internal/log/index.d.ts +0 -2
- package/dist/internal/log/index.d.ts.map +0 -1
- package/dist/internal/log/index.js +0 -7
- package/dist/internal/log/index.js.map +0 -1
- package/dist/internal/log/logging.d.ts +0 -21
- package/dist/internal/log/logging.d.ts.map +0 -1
- package/dist/internal/log/logging.js +0 -154
- package/dist/internal/log/logging.js.map +0 -1
- package/dist/internal/logger.d.ts +0 -23
- package/dist/internal/logger.d.ts.map +0 -1
- package/dist/internal/logger.js +0 -163
- package/dist/internal/logger.js.map +0 -1
- package/dist/internal/masking/index.d.ts +0 -4
- package/dist/internal/masking/index.d.ts.map +0 -1
- package/dist/internal/masking/index.js +0 -9
- package/dist/internal/masking/index.js.map +0 -1
- package/dist/internal/masking/patterns.d.ts +0 -3
- package/dist/internal/masking/patterns.d.ts.map +0 -1
- package/dist/internal/masking/patterns.js +0 -378
- package/dist/internal/masking/patterns.js.map +0 -1
- package/dist/internal/masking/types.d.ts +0 -33
- package/dist/internal/masking/types.d.ts.map +0 -1
- package/dist/internal/masking/types.js +0 -3
- package/dist/internal/masking/types.js.map +0 -1
- package/dist/internal/masking/utils.d.ts +0 -6
- package/dist/internal/masking/utils.d.ts.map +0 -1
- package/dist/internal/masking/utils.js +0 -232
- package/dist/internal/masking/utils.js.map +0 -1
- package/dist/internal/metric/index.d.ts +0 -2
- package/dist/internal/metric/index.d.ts.map +0 -1
- package/dist/internal/metric/index.js +0 -8
- package/dist/internal/metric/index.js.map +0 -1
- package/dist/internal/metric/metrics.d.ts +0 -18
- package/dist/internal/metric/metrics.d.ts.map +0 -1
- package/dist/internal/metric/metrics.js +0 -88
- package/dist/internal/metric/metrics.js.map +0 -1
- package/dist/internal/sdk.d.ts +0 -36
- package/dist/internal/sdk.d.ts.map +0 -1
- package/dist/internal/sdk.js +0 -159
- package/dist/internal/sdk.js.map +0 -1
- package/dist/internal/trace/index.d.ts +0 -3
- package/dist/internal/trace/index.d.ts.map +0 -1
- package/dist/internal/trace/index.js +0 -11
- package/dist/internal/trace/index.js.map +0 -1
- package/dist/internal/trace/processors/log-masked.d.ts +0 -16
- package/dist/internal/trace/processors/log-masked.d.ts.map +0 -1
- package/dist/internal/trace/processors/log-masked.js +0 -81
- package/dist/internal/trace/processors/log-masked.js.map +0 -1
- package/dist/internal/trace/processors/span-masked.d.ts +0 -16
- package/dist/internal/trace/processors/span-masked.d.ts.map +0 -1
- package/dist/internal/trace/processors/span-masked.js +0 -87
- package/dist/internal/trace/processors/span-masked.js.map +0 -1
- package/dist/internal/trace/tracing.d.ts +0 -18
- package/dist/internal/trace/tracing.d.ts.map +0 -1
- package/dist/internal/trace/tracing.js +0 -103
- package/dist/internal/trace/tracing.js.map +0 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2937 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
Brizz: () => Brizz,
|
|
34
|
+
DEFAULT_PII_PATTERNS: () => DEFAULT_PII_PATTERNS,
|
|
35
|
+
LogLevel: () => LogLevel,
|
|
36
|
+
SeverityNumber: () => import_api_logs3.SeverityNumber,
|
|
37
|
+
VercelAIInstrumentation: () => VercelAIInstrumentation,
|
|
38
|
+
WithSessionId: () => WithSessionId,
|
|
39
|
+
detectRuntime: () => detectRuntime,
|
|
40
|
+
emitEvent: () => emitEvent,
|
|
41
|
+
getLogLevel: () => getLogLevel,
|
|
42
|
+
getMetricsExporter: () => getMetricsExporter,
|
|
43
|
+
getMetricsReader: () => getMetricsReader,
|
|
44
|
+
getSpanExporter: () => getSpanExporter,
|
|
45
|
+
getSpanProcessor: () => getSpanProcessor,
|
|
46
|
+
init: () => init_exports,
|
|
47
|
+
logger: () => logger,
|
|
48
|
+
maskAttributes: () => maskAttributes,
|
|
49
|
+
maskValue: () => maskValue,
|
|
50
|
+
maybeRegisterESMLoader: () => maybeRegisterESMLoader,
|
|
51
|
+
setLogLevel: () => setLogLevel
|
|
52
|
+
});
|
|
53
|
+
module.exports = __toCommonJS(src_exports);
|
|
54
|
+
|
|
55
|
+
// src/internal/instrumentation/auto-init.ts
|
|
56
|
+
var import_auto_instrumentations_node = require("@opentelemetry/auto-instrumentations-node");
|
|
57
|
+
var import_instrumentation3 = require("@opentelemetry/instrumentation");
|
|
58
|
+
var import_instrumentation_anthropic = require("@traceloop/instrumentation-anthropic");
|
|
59
|
+
var import_instrumentation_bedrock = require("@traceloop/instrumentation-bedrock");
|
|
60
|
+
var import_instrumentation_chromadb = require("@traceloop/instrumentation-chromadb");
|
|
61
|
+
var import_instrumentation_cohere = require("@traceloop/instrumentation-cohere");
|
|
62
|
+
var import_instrumentation_langchain = require("@traceloop/instrumentation-langchain");
|
|
63
|
+
var import_instrumentation_llamaindex = require("@traceloop/instrumentation-llamaindex");
|
|
64
|
+
var import_instrumentation_openai = require("@traceloop/instrumentation-openai");
|
|
65
|
+
var import_instrumentation_pinecone = require("@traceloop/instrumentation-pinecone");
|
|
66
|
+
var import_instrumentation_qdrant = require("@traceloop/instrumentation-qdrant");
|
|
67
|
+
var import_instrumentation_together = require("@traceloop/instrumentation-together");
|
|
68
|
+
var import_instrumentation_vertexai = require("@traceloop/instrumentation-vertexai");
|
|
69
|
+
|
|
70
|
+
// src/internal/logger.ts
|
|
71
|
+
var import_api = require("@opentelemetry/api");
|
|
72
|
+
var import_pino = __toESM(require("pino"), 1);
|
|
73
|
+
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
74
|
+
LogLevel2[LogLevel2["NONE"] = 0] = "NONE";
|
|
75
|
+
LogLevel2[LogLevel2["ERROR"] = 1] = "ERROR";
|
|
76
|
+
LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
|
|
77
|
+
LogLevel2[LogLevel2["INFO"] = 3] = "INFO";
|
|
78
|
+
LogLevel2[LogLevel2["DEBUG"] = 4] = "DEBUG";
|
|
79
|
+
return LogLevel2;
|
|
80
|
+
})(LogLevel || {});
|
|
81
|
+
var DEFAULT_LOG_LEVEL = 2 /* WARN */;
|
|
82
|
+
var PinoLogger = class {
|
|
83
|
+
_level = DEFAULT_LOG_LEVEL;
|
|
84
|
+
_pinoLogger = null;
|
|
85
|
+
constructor() {
|
|
86
|
+
const envLevel = this.getLogLevelFromEnv();
|
|
87
|
+
this._level = envLevel;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Lazy initialization of Pino logger to ensure it's created AFTER Jest spies
|
|
91
|
+
* are set up during tests. This prevents the pino-pretty transport from
|
|
92
|
+
* bypassing stdout/stderr spies.
|
|
93
|
+
*/
|
|
94
|
+
ensurePinoLogger() {
|
|
95
|
+
if (!this._pinoLogger) {
|
|
96
|
+
this._pinoLogger = (0, import_pino.default)({
|
|
97
|
+
name: "Brizz",
|
|
98
|
+
level: this.logLevelToPino(this._level),
|
|
99
|
+
// Disable transport in test environment to allow proper spy capture
|
|
100
|
+
transport: this.isProduction() || this.isTest() ? void 0 : {
|
|
101
|
+
target: "pino-pretty",
|
|
102
|
+
options: {
|
|
103
|
+
singleLine: true,
|
|
104
|
+
colorize: true,
|
|
105
|
+
translateTime: "HH:MM:ss",
|
|
106
|
+
ignore: "pid,hostname",
|
|
107
|
+
messageFormat: "[{name}] {msg}"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return this._pinoLogger;
|
|
113
|
+
}
|
|
114
|
+
isProduction() {
|
|
115
|
+
return process.env["NODE_ENV"] === "production";
|
|
116
|
+
}
|
|
117
|
+
isTest() {
|
|
118
|
+
return process.env["NODE_ENV"] === "test";
|
|
119
|
+
}
|
|
120
|
+
getLogLevelFromEnv() {
|
|
121
|
+
const envLevel = process.env["BRIZZ_LOG_LEVEL"];
|
|
122
|
+
return envLevel ? parseLogLevel(envLevel) : DEFAULT_LOG_LEVEL;
|
|
123
|
+
}
|
|
124
|
+
logLevelToPino(level) {
|
|
125
|
+
switch (level) {
|
|
126
|
+
case 4 /* DEBUG */:
|
|
127
|
+
return "debug";
|
|
128
|
+
case 3 /* INFO */:
|
|
129
|
+
return "info";
|
|
130
|
+
case 2 /* WARN */:
|
|
131
|
+
return "warn";
|
|
132
|
+
case 1 /* ERROR */:
|
|
133
|
+
return "error";
|
|
134
|
+
default:
|
|
135
|
+
return "silent";
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
formatMeta(meta) {
|
|
139
|
+
if (meta.length === 0) {
|
|
140
|
+
return {};
|
|
141
|
+
}
|
|
142
|
+
if (meta.length === 1 && typeof meta[0] === "object" && meta[0] !== null) {
|
|
143
|
+
return meta[0];
|
|
144
|
+
}
|
|
145
|
+
return { metadata: meta };
|
|
146
|
+
}
|
|
147
|
+
setLevel(level) {
|
|
148
|
+
this._level = level;
|
|
149
|
+
if (this._pinoLogger) {
|
|
150
|
+
this._pinoLogger.level = this.logLevelToPino(level);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
getLevel() {
|
|
154
|
+
return this._level;
|
|
155
|
+
}
|
|
156
|
+
debug = (msg, ...meta) => {
|
|
157
|
+
if (this._level >= 4 /* DEBUG */) {
|
|
158
|
+
this.ensurePinoLogger().debug(this.formatMeta(meta), msg);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
info = (msg, ...meta) => {
|
|
162
|
+
if (this._level >= 3 /* INFO */) {
|
|
163
|
+
this.ensurePinoLogger().info(this.formatMeta(meta), msg);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
warn = (msg, ...meta) => {
|
|
167
|
+
if (this._level >= 2 /* WARN */) {
|
|
168
|
+
this.ensurePinoLogger().warn(this.formatMeta(meta), msg);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
error = (msg, ...meta) => {
|
|
172
|
+
if (this._level >= 1 /* ERROR */) {
|
|
173
|
+
this.ensurePinoLogger().error(this.formatMeta(meta), msg);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
function parseLogLevel(level) {
|
|
178
|
+
if (!level) {
|
|
179
|
+
return DEFAULT_LOG_LEVEL;
|
|
180
|
+
}
|
|
181
|
+
const normalizedLevel = level.toLowerCase().trim();
|
|
182
|
+
switch (normalizedLevel) {
|
|
183
|
+
case "debug":
|
|
184
|
+
return 4 /* DEBUG */;
|
|
185
|
+
case "info":
|
|
186
|
+
return 3 /* INFO */;
|
|
187
|
+
case "warn":
|
|
188
|
+
case "warning":
|
|
189
|
+
return 2 /* WARN */;
|
|
190
|
+
case "error":
|
|
191
|
+
return 1 /* ERROR */;
|
|
192
|
+
case "none":
|
|
193
|
+
case "off":
|
|
194
|
+
case "silent":
|
|
195
|
+
return 0 /* NONE */;
|
|
196
|
+
default: {
|
|
197
|
+
const numLevel = Number.parseInt(normalizedLevel, 10);
|
|
198
|
+
if (!Number.isNaN(numLevel) && numLevel >= 0 && numLevel <= 4) {
|
|
199
|
+
return numLevel;
|
|
200
|
+
}
|
|
201
|
+
return DEFAULT_LOG_LEVEL;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
var logger = new PinoLogger();
|
|
206
|
+
function setLogLevel(level) {
|
|
207
|
+
const resolvedLevel = typeof level === "string" ? parseLogLevel(level) : level;
|
|
208
|
+
logger.setLevel(resolvedLevel);
|
|
209
|
+
}
|
|
210
|
+
function getLogLevel() {
|
|
211
|
+
return logger.getLevel();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// src/internal/instrumentation/vercel-ai/instrumentation.ts
|
|
215
|
+
var import_instrumentation = require("@opentelemetry/instrumentation");
|
|
216
|
+
|
|
217
|
+
// src/internal/instrumentation/vercel-ai/patchers/base-patcher.ts
|
|
218
|
+
var import_api2 = require("@opentelemetry/api");
|
|
219
|
+
|
|
220
|
+
// src/internal/instrumentation/vercel-ai/semconv.ts
|
|
221
|
+
var ATTR_GEN_AI_SYSTEM = "gen_ai.system";
|
|
222
|
+
var ATTR_GEN_AI_OPERATION_NAME = "gen_ai.operation.name";
|
|
223
|
+
var ATTR_GEN_AI_REQUEST_MODEL = "gen_ai.request.model";
|
|
224
|
+
var ATTR_GEN_AI_REQUEST_MAX_TOKENS = "gen_ai.request.max_tokens";
|
|
225
|
+
var ATTR_GEN_AI_REQUEST_TEMPERATURE = "gen_ai.request.temperature";
|
|
226
|
+
var ATTR_GEN_AI_REQUEST_TOP_P = "gen_ai.request.top_p";
|
|
227
|
+
var ATTR_GEN_AI_REQUEST_TOP_K = "gen_ai.request.top_k";
|
|
228
|
+
var ATTR_GEN_AI_REQUEST_STOP_SEQUENCES = "gen_ai.request.stop_sequences";
|
|
229
|
+
var ATTR_GEN_AI_REQUEST_FREQUENCY_PENALTY = "gen_ai.request.frequency_penalty";
|
|
230
|
+
var ATTR_GEN_AI_REQUEST_PRESENCE_PENALTY = "gen_ai.request.presence_penalty";
|
|
231
|
+
var ATTR_GEN_AI_RESPONSE_ID = "gen_ai.response.id";
|
|
232
|
+
var ATTR_GEN_AI_RESPONSE_MODEL = "gen_ai.response.model";
|
|
233
|
+
var ATTR_GEN_AI_RESPONSE_FINISH_REASONS = "gen_ai.response.finish_reasons";
|
|
234
|
+
var ATTR_GEN_AI_TOKEN_TYPE = "gen_ai.token.type";
|
|
235
|
+
var ATTR_GEN_AI_PROMPT = "gen_ai.prompt";
|
|
236
|
+
var ATTR_GEN_AI_COMPLETION = "gen_ai.completion";
|
|
237
|
+
var ATTR_GEN_AI_OPENAI_API_BASE = "gen_ai.openai.api_base";
|
|
238
|
+
var ATTR_EVENT_NAME = "event.name";
|
|
239
|
+
var EVENT_GEN_AI_USER_MESSAGE = "gen_ai.user.message";
|
|
240
|
+
var EVENT_GEN_AI_ASSISTANT_MESSAGE = "gen_ai.assistant.message";
|
|
241
|
+
var EVENT_GEN_AI_SYSTEM_MESSAGE = "gen_ai.system.message";
|
|
242
|
+
var EVENT_GEN_AI_TOOL_MESSAGE = "gen_ai.tool.message";
|
|
243
|
+
var METRIC_GEN_AI_CLIENT_OPERATION_DURATION = "gen_ai.client.operation.duration";
|
|
244
|
+
var METRIC_GEN_AI_CLIENT_TOKEN_USAGE = "gen_ai.client.token.usage";
|
|
245
|
+
var OPERATION_NAME_CHAT = "chat";
|
|
246
|
+
var OPERATION_NAME_EMBEDDINGS = "embeddings";
|
|
247
|
+
var TOKEN_TYPE_INPUT = "input";
|
|
248
|
+
var TOKEN_TYPE_OUTPUT = "output";
|
|
249
|
+
var PROVIDER_OPENAI = "openai";
|
|
250
|
+
var PROVIDER_ANTHROPIC = "anthropic";
|
|
251
|
+
var PROVIDER_GOOGLE = "google";
|
|
252
|
+
var PROVIDER_AMAZON = "amazon";
|
|
253
|
+
var PROVIDER_AZURE = "azure";
|
|
254
|
+
var PROVIDER_VERCEL = "vercel";
|
|
255
|
+
var PROVIDER_UNKNOWN = "unknown";
|
|
256
|
+
var SPAN_NAME_GEN_AI_CHAT = "gen_ai.chat";
|
|
257
|
+
var SPAN_NAME_GEN_AI_EMBEDDINGS = "gen_ai.embeddings";
|
|
258
|
+
|
|
259
|
+
// src/internal/instrumentation/vercel-ai/utils.ts
|
|
260
|
+
function detectProvider(model) {
|
|
261
|
+
if (typeof model === "object" && model !== null) {
|
|
262
|
+
const modelObj = model;
|
|
263
|
+
if (modelObj.provider) {
|
|
264
|
+
return {
|
|
265
|
+
system: normalizeProviderName(modelObj.provider),
|
|
266
|
+
apiBase: extractApiBase(modelObj)
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
if (modelObj.modelId) {
|
|
270
|
+
return detectProviderFromModelId(modelObj.modelId);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (typeof model === "string") {
|
|
274
|
+
return detectProviderFromModelId(model);
|
|
275
|
+
}
|
|
276
|
+
return { system: PROVIDER_UNKNOWN };
|
|
277
|
+
}
|
|
278
|
+
function detectProviderFromModelId(modelId) {
|
|
279
|
+
const lowerModel = modelId.toLowerCase();
|
|
280
|
+
if (lowerModel.startsWith("gpt-") || lowerModel.startsWith("text-davinci-") || lowerModel.startsWith("text-embedding-") || lowerModel.startsWith("dall-e") || lowerModel.startsWith("whisper-") || lowerModel.startsWith("tts-")) {
|
|
281
|
+
return { system: PROVIDER_OPENAI };
|
|
282
|
+
}
|
|
283
|
+
if (lowerModel.startsWith("claude-")) {
|
|
284
|
+
return { system: PROVIDER_ANTHROPIC };
|
|
285
|
+
}
|
|
286
|
+
if (lowerModel.startsWith("gemini-") || lowerModel.startsWith("palm-") || lowerModel.includes("bison") || lowerModel.includes("gecko")) {
|
|
287
|
+
return { system: PROVIDER_GOOGLE };
|
|
288
|
+
}
|
|
289
|
+
if (lowerModel.startsWith("amazon.") || lowerModel.startsWith("anthropic.claude-") || lowerModel.startsWith("ai21.") || lowerModel.startsWith("cohere.") || lowerModel.startsWith("meta.llama")) {
|
|
290
|
+
return { system: PROVIDER_AMAZON };
|
|
291
|
+
}
|
|
292
|
+
if (lowerModel.includes("azure") || lowerModel.includes(".openai.azure.com")) {
|
|
293
|
+
return { system: PROVIDER_AZURE };
|
|
294
|
+
}
|
|
295
|
+
const parts = modelId.split(/[-._/]/);
|
|
296
|
+
if (parts.length > 0 && parts[0]) {
|
|
297
|
+
return { system: normalizeProviderName(parts[0]) };
|
|
298
|
+
}
|
|
299
|
+
return { system: PROVIDER_UNKNOWN };
|
|
300
|
+
}
|
|
301
|
+
function normalizeProviderName(provider) {
|
|
302
|
+
const normalized = provider.toLowerCase().trim();
|
|
303
|
+
switch (normalized) {
|
|
304
|
+
case "openai":
|
|
305
|
+
case "open-ai":
|
|
306
|
+
case "open_ai": {
|
|
307
|
+
return PROVIDER_OPENAI;
|
|
308
|
+
}
|
|
309
|
+
case "anthropic":
|
|
310
|
+
case "claude": {
|
|
311
|
+
return PROVIDER_ANTHROPIC;
|
|
312
|
+
}
|
|
313
|
+
case "google":
|
|
314
|
+
case "vertex":
|
|
315
|
+
case "vertexai":
|
|
316
|
+
case "vertex-ai":
|
|
317
|
+
case "gemini": {
|
|
318
|
+
return PROVIDER_GOOGLE;
|
|
319
|
+
}
|
|
320
|
+
case "amazon":
|
|
321
|
+
case "aws":
|
|
322
|
+
case "bedrock":
|
|
323
|
+
case "amazon-bedrock": {
|
|
324
|
+
return PROVIDER_AMAZON;
|
|
325
|
+
}
|
|
326
|
+
case "azure":
|
|
327
|
+
case "azure-openai":
|
|
328
|
+
case "microsoft": {
|
|
329
|
+
return PROVIDER_AZURE;
|
|
330
|
+
}
|
|
331
|
+
case "vercel":
|
|
332
|
+
case "vercel-ai": {
|
|
333
|
+
return PROVIDER_VERCEL;
|
|
334
|
+
}
|
|
335
|
+
default: {
|
|
336
|
+
return normalized;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function extractApiBase(model) {
|
|
341
|
+
if (typeof model === "object" && model !== null) {
|
|
342
|
+
const anyModel = model;
|
|
343
|
+
return anyModel.apiBase || anyModel.baseURL || anyModel.endpoint || void 0;
|
|
344
|
+
}
|
|
345
|
+
return void 0;
|
|
346
|
+
}
|
|
347
|
+
function extractModelId(model) {
|
|
348
|
+
if (typeof model === "string") {
|
|
349
|
+
return model;
|
|
350
|
+
}
|
|
351
|
+
if (typeof model === "object" && model !== null) {
|
|
352
|
+
return model.modelId || "unknown";
|
|
353
|
+
}
|
|
354
|
+
return "unknown";
|
|
355
|
+
}
|
|
356
|
+
function messagesToAttributes(messages, prefix, captureContent) {
|
|
357
|
+
const attributes = {};
|
|
358
|
+
for (const [index, msg] of messages.entries()) {
|
|
359
|
+
const baseKey = `${prefix}.${index}`;
|
|
360
|
+
attributes[`${baseKey}.role`] = msg.role;
|
|
361
|
+
if (captureContent && msg.content) {
|
|
362
|
+
if (typeof msg.content === "string") {
|
|
363
|
+
attributes[`${baseKey}.content`] = msg.content;
|
|
364
|
+
} else if (Array.isArray(msg.content)) {
|
|
365
|
+
const textParts = msg.content.filter((part) => part.type === "text" && part.text).map((part) => part.text).join(" ");
|
|
366
|
+
if (textParts) {
|
|
367
|
+
attributes[`${baseKey}.content`] = textParts;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (msg.toolInvocations && msg.toolInvocations.length > 0) {
|
|
372
|
+
attributes[`${baseKey}.tool_calls`] = msg.toolInvocations.length;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return attributes;
|
|
376
|
+
}
|
|
377
|
+
function promptToAttributes(prompt, captureContent) {
|
|
378
|
+
const attributes = {};
|
|
379
|
+
attributes[`${ATTR_GEN_AI_PROMPT}.0.role`] = "user";
|
|
380
|
+
if (captureContent) {
|
|
381
|
+
attributes[`${ATTR_GEN_AI_PROMPT}.0.content`] = prompt;
|
|
382
|
+
}
|
|
383
|
+
return attributes;
|
|
384
|
+
}
|
|
385
|
+
function completionToAttributes(text, finishReason, captureContent) {
|
|
386
|
+
const attributes = {};
|
|
387
|
+
attributes[`${ATTR_GEN_AI_COMPLETION}.0.role`] = "assistant";
|
|
388
|
+
if (captureContent) {
|
|
389
|
+
attributes[`${ATTR_GEN_AI_COMPLETION}.0.content`] = text;
|
|
390
|
+
}
|
|
391
|
+
if (finishReason) {
|
|
392
|
+
attributes[`${ATTR_GEN_AI_COMPLETION}.0.finish_reason`] = finishReason;
|
|
393
|
+
}
|
|
394
|
+
return attributes;
|
|
395
|
+
}
|
|
396
|
+
function tokenUsageToAttributes(usage) {
|
|
397
|
+
if (!usage) {
|
|
398
|
+
return {};
|
|
399
|
+
}
|
|
400
|
+
const attributes = {};
|
|
401
|
+
if (usage.inputTokens !== void 0) {
|
|
402
|
+
attributes["gen_ai.usage.prompt_tokens"] = usage.inputTokens;
|
|
403
|
+
attributes["gen_ai.usage.input_tokens"] = usage.inputTokens;
|
|
404
|
+
attributes["llm.usage.prompt_tokens"] = usage.inputTokens;
|
|
405
|
+
} else if (usage.promptTokens !== void 0) {
|
|
406
|
+
attributes["gen_ai.usage.prompt_tokens"] = usage.promptTokens;
|
|
407
|
+
attributes["gen_ai.usage.input_tokens"] = usage.promptTokens;
|
|
408
|
+
attributes["llm.usage.prompt_tokens"] = usage.promptTokens;
|
|
409
|
+
}
|
|
410
|
+
if (usage.outputTokens !== void 0) {
|
|
411
|
+
attributes["gen_ai.usage.completion_tokens"] = usage.outputTokens;
|
|
412
|
+
attributes["gen_ai.usage.output_tokens"] = usage.outputTokens;
|
|
413
|
+
attributes["llm.usage.completion_tokens"] = usage.outputTokens;
|
|
414
|
+
} else if (usage.completionTokens !== void 0) {
|
|
415
|
+
attributes["gen_ai.usage.completion_tokens"] = usage.completionTokens;
|
|
416
|
+
attributes["gen_ai.usage.output_tokens"] = usage.completionTokens;
|
|
417
|
+
attributes["llm.usage.completion_tokens"] = usage.completionTokens;
|
|
418
|
+
}
|
|
419
|
+
if (usage.totalTokens === void 0) {
|
|
420
|
+
const inputTokens = usage.inputTokens || usage.promptTokens;
|
|
421
|
+
const outputTokens = usage.outputTokens || usage.completionTokens;
|
|
422
|
+
if (inputTokens !== void 0 && outputTokens !== void 0) {
|
|
423
|
+
const totalTokens = inputTokens + outputTokens;
|
|
424
|
+
attributes["gen_ai.usage.total_tokens"] = totalTokens;
|
|
425
|
+
attributes["llm.usage.total_tokens"] = totalTokens;
|
|
426
|
+
}
|
|
427
|
+
} else {
|
|
428
|
+
attributes["gen_ai.usage.total_tokens"] = usage.totalTokens;
|
|
429
|
+
attributes["llm.usage.total_tokens"] = usage.totalTokens;
|
|
430
|
+
}
|
|
431
|
+
return attributes;
|
|
432
|
+
}
|
|
433
|
+
function shouldRecordError(error) {
|
|
434
|
+
if (error instanceof Error) {
|
|
435
|
+
const message = error.message.toLowerCase();
|
|
436
|
+
if (message.includes("abort") || message.includes("cancel")) {
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return true;
|
|
441
|
+
}
|
|
442
|
+
function getEnvBool(name) {
|
|
443
|
+
const value = process.env[name];
|
|
444
|
+
if (value === void 0) {
|
|
445
|
+
return void 0;
|
|
446
|
+
}
|
|
447
|
+
return value.toLowerCase() === "true" || value === "1";
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// src/internal/instrumentation/vercel-ai/patchers/base-patcher.ts
|
|
451
|
+
var BasePatcher = class {
|
|
452
|
+
constructor(context8) {
|
|
453
|
+
this.context = context8;
|
|
454
|
+
}
|
|
455
|
+
createSpan(spanName, params, operationName, additionalAttributes) {
|
|
456
|
+
const provider = detectProvider(params.model);
|
|
457
|
+
const modelId = extractModelId(params.model);
|
|
458
|
+
const span = this.context.tracer.startSpan(spanName, {
|
|
459
|
+
kind: import_api2.SpanKind.CLIENT,
|
|
460
|
+
attributes: {
|
|
461
|
+
[ATTR_GEN_AI_SYSTEM]: provider.system,
|
|
462
|
+
[ATTR_GEN_AI_OPERATION_NAME]: operationName,
|
|
463
|
+
[ATTR_GEN_AI_REQUEST_MODEL]: modelId,
|
|
464
|
+
...params.maxTokens && { [ATTR_GEN_AI_REQUEST_MAX_TOKENS]: params.maxTokens },
|
|
465
|
+
...params.temperature !== void 0 && {
|
|
466
|
+
[ATTR_GEN_AI_REQUEST_TEMPERATURE]: params.temperature
|
|
467
|
+
},
|
|
468
|
+
...params.topP !== void 0 && { [ATTR_GEN_AI_REQUEST_TOP_P]: params.topP },
|
|
469
|
+
...params.topK !== void 0 && { [ATTR_GEN_AI_REQUEST_TOP_K]: params.topK },
|
|
470
|
+
...params.frequencyPenalty !== void 0 && {
|
|
471
|
+
[ATTR_GEN_AI_REQUEST_FREQUENCY_PENALTY]: params.frequencyPenalty
|
|
472
|
+
},
|
|
473
|
+
...params.presencePenalty !== void 0 && {
|
|
474
|
+
[ATTR_GEN_AI_REQUEST_PRESENCE_PENALTY]: params.presencePenalty
|
|
475
|
+
},
|
|
476
|
+
...params.stopSequences && {
|
|
477
|
+
[ATTR_GEN_AI_REQUEST_STOP_SEQUENCES]: params.stopSequences
|
|
478
|
+
},
|
|
479
|
+
...provider.apiBase && { [ATTR_GEN_AI_OPENAI_API_BASE]: provider.apiBase },
|
|
480
|
+
...additionalAttributes
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
return { span, provider, modelId };
|
|
484
|
+
}
|
|
485
|
+
handleError(error, span) {
|
|
486
|
+
if (shouldRecordError(error)) {
|
|
487
|
+
span.recordException(error);
|
|
488
|
+
span.setStatus({ code: import_api2.SpanStatusCode.ERROR, message: error.message });
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
finalizeDuration(span, startTime, config, provider, modelId, operationName) {
|
|
492
|
+
if (config.enableMetrics) {
|
|
493
|
+
const duration = (globalThis.performance.now() - startTime) / 1e3;
|
|
494
|
+
this.context.recordDurationMetric(duration, provider.system, modelId, operationName);
|
|
495
|
+
}
|
|
496
|
+
span.end();
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// src/internal/instrumentation/vercel-ai/patchers/generate-text-patcher.ts
|
|
501
|
+
var import_api3 = require("@opentelemetry/api");
|
|
502
|
+
var GenerateTextPatcher = class extends BasePatcher {
|
|
503
|
+
patch(original) {
|
|
504
|
+
return async (params) => {
|
|
505
|
+
const config = this.context.getConfig();
|
|
506
|
+
const startTime = globalThis.performance.now();
|
|
507
|
+
const { span, provider, modelId } = this.createSpan(
|
|
508
|
+
SPAN_NAME_GEN_AI_CHAT,
|
|
509
|
+
params,
|
|
510
|
+
OPERATION_NAME_CHAT
|
|
511
|
+
);
|
|
512
|
+
if (params.prompt) {
|
|
513
|
+
span.setAttributes(
|
|
514
|
+
promptToAttributes(params.prompt, config.captureMessageContent || false)
|
|
515
|
+
);
|
|
516
|
+
} else if (params.messages) {
|
|
517
|
+
span.setAttributes(
|
|
518
|
+
messagesToAttributes(
|
|
519
|
+
params.messages,
|
|
520
|
+
"gen_ai.prompt",
|
|
521
|
+
config.captureMessageContent || false
|
|
522
|
+
)
|
|
523
|
+
);
|
|
524
|
+
if (config.emitEvents) {
|
|
525
|
+
this.context.emitMessageEvents(params.messages, provider.system, span);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
try {
|
|
529
|
+
const result = await import_api3.context.with(
|
|
530
|
+
import_api3.trace.setSpan(import_api3.context.active(), span),
|
|
531
|
+
() => original(params)
|
|
532
|
+
);
|
|
533
|
+
if (result.response) {
|
|
534
|
+
span.setAttributes({
|
|
535
|
+
...result.response.id && { [ATTR_GEN_AI_RESPONSE_ID]: result.response.id },
|
|
536
|
+
...result.response.model && { [ATTR_GEN_AI_RESPONSE_MODEL]: result.response.model }
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
if (result.finishReason) {
|
|
540
|
+
span.setAttribute(ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [result.finishReason]);
|
|
541
|
+
}
|
|
542
|
+
span.setAttributes(
|
|
543
|
+
completionToAttributes(
|
|
544
|
+
result.text,
|
|
545
|
+
result.finishReason,
|
|
546
|
+
config.captureMessageContent || false
|
|
547
|
+
)
|
|
548
|
+
);
|
|
549
|
+
const usage = result.usage || result.totalUsage || result.steps?.[0]?.usage;
|
|
550
|
+
if (usage) {
|
|
551
|
+
span.setAttributes(tokenUsageToAttributes(usage));
|
|
552
|
+
if (config.enableMetrics) {
|
|
553
|
+
this.context.recordTokenMetrics(usage, provider.system, modelId);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
if (config.emitEvents) {
|
|
557
|
+
this.context.emitAssistantMessageEvent(result.text, provider.system, span);
|
|
558
|
+
}
|
|
559
|
+
span.setStatus({ code: import_api3.SpanStatusCode.OK });
|
|
560
|
+
return result;
|
|
561
|
+
} catch (error) {
|
|
562
|
+
this.handleError(error, span);
|
|
563
|
+
throw error;
|
|
564
|
+
} finally {
|
|
565
|
+
this.finalizeDuration(span, startTime, config, provider, modelId, OPERATION_NAME_CHAT);
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
// src/internal/instrumentation/vercel-ai/patchers/stream-text-patcher.ts
|
|
572
|
+
var import_api4 = require("@opentelemetry/api");
|
|
573
|
+
var StreamTextPatcher = class extends BasePatcher {
|
|
574
|
+
constructor(context8, streamHandler) {
|
|
575
|
+
super(context8);
|
|
576
|
+
this.streamHandler = streamHandler;
|
|
577
|
+
}
|
|
578
|
+
patch(original) {
|
|
579
|
+
return async (params) => {
|
|
580
|
+
const config = this.context.getConfig();
|
|
581
|
+
const startTime = globalThis.performance.now();
|
|
582
|
+
const { span, provider, modelId } = this.createSpan(
|
|
583
|
+
SPAN_NAME_GEN_AI_CHAT,
|
|
584
|
+
params,
|
|
585
|
+
OPERATION_NAME_CHAT,
|
|
586
|
+
{ "gen_ai.streaming": true }
|
|
587
|
+
);
|
|
588
|
+
if (params.prompt) {
|
|
589
|
+
span.setAttributes(
|
|
590
|
+
promptToAttributes(params.prompt, config.captureMessageContent || false)
|
|
591
|
+
);
|
|
592
|
+
} else if (params.messages) {
|
|
593
|
+
span.setAttributes(
|
|
594
|
+
messagesToAttributes(
|
|
595
|
+
params.messages,
|
|
596
|
+
"gen_ai.prompt",
|
|
597
|
+
config.captureMessageContent || false
|
|
598
|
+
)
|
|
599
|
+
);
|
|
600
|
+
if (config.emitEvents) {
|
|
601
|
+
this.context.emitMessageEvents(params.messages, provider.system, span);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
try {
|
|
605
|
+
const stream = await import_api4.context.with(
|
|
606
|
+
import_api4.trace.setSpan(import_api4.context.active(), span),
|
|
607
|
+
() => original(params)
|
|
608
|
+
);
|
|
609
|
+
return this.streamHandler.wrapStream(stream, span, config, provider, modelId, startTime);
|
|
610
|
+
} catch (error) {
|
|
611
|
+
this.handleError(error, span);
|
|
612
|
+
span.end();
|
|
613
|
+
throw error;
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
// src/internal/instrumentation/vercel-ai/patchers/embeddings-patcher.ts
|
|
620
|
+
var import_api5 = require("@opentelemetry/api");
|
|
621
|
+
var EmbeddingsPatcher = class extends BasePatcher {
|
|
622
|
+
patch(original, isMany = false) {
|
|
623
|
+
return async (params) => {
|
|
624
|
+
const config = this.context.getConfig();
|
|
625
|
+
const startTime = globalThis.performance.now();
|
|
626
|
+
const additionalAttributes = isMany ? { "gen_ai.embeddings.count": params.values ? params.values.length : 0 } : {};
|
|
627
|
+
const { span, provider, modelId } = this.createSpan(
|
|
628
|
+
SPAN_NAME_GEN_AI_EMBEDDINGS,
|
|
629
|
+
params,
|
|
630
|
+
OPERATION_NAME_EMBEDDINGS,
|
|
631
|
+
additionalAttributes
|
|
632
|
+
);
|
|
633
|
+
if (!isMany && config.captureMessageContent && params.value) {
|
|
634
|
+
span.setAttribute("gen_ai.prompt.0.content", params.value);
|
|
635
|
+
}
|
|
636
|
+
try {
|
|
637
|
+
const result = await import_api5.context.with(
|
|
638
|
+
import_api5.trace.setSpan(import_api5.context.active(), span),
|
|
639
|
+
() => original(params)
|
|
640
|
+
);
|
|
641
|
+
if (result.response) {
|
|
642
|
+
span.setAttributes({
|
|
643
|
+
...result.response.id && { [ATTR_GEN_AI_RESPONSE_ID]: result.response.id },
|
|
644
|
+
...result.response.model && { [ATTR_GEN_AI_RESPONSE_MODEL]: result.response.model }
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
if (isMany) {
|
|
648
|
+
if (result.embeddings && result.embeddings.length > 0 && result.embeddings[0]) {
|
|
649
|
+
span.setAttribute("gen_ai.response.embedding_dimensions", result.embeddings[0].length);
|
|
650
|
+
}
|
|
651
|
+
} else {
|
|
652
|
+
if (result.embedding) {
|
|
653
|
+
span.setAttribute("gen_ai.response.embedding_dimensions", result.embedding.length);
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (result.usage) {
|
|
657
|
+
span.setAttributes(tokenUsageToAttributes(result.usage));
|
|
658
|
+
if (config.enableMetrics) {
|
|
659
|
+
this.context.recordTokenMetrics(result.usage, provider.system, modelId);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
span.setStatus({ code: import_api5.SpanStatusCode.OK });
|
|
663
|
+
return result;
|
|
664
|
+
} catch (error) {
|
|
665
|
+
this.handleError(error, span);
|
|
666
|
+
throw error;
|
|
667
|
+
} finally {
|
|
668
|
+
this.finalizeDuration(span, startTime, config, provider, modelId, OPERATION_NAME_EMBEDDINGS);
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
|
|
674
|
+
// src/internal/instrumentation/vercel-ai/stream-handler.ts
|
|
675
|
+
var import_api6 = require("@opentelemetry/api");
|
|
676
|
+
var StreamHandler = class {
|
|
677
|
+
constructor(context8) {
|
|
678
|
+
this.context = context8;
|
|
679
|
+
}
|
|
680
|
+
wrapStream(stream, span, config, provider, modelId, startTime) {
|
|
681
|
+
const self = this;
|
|
682
|
+
let fullText = "";
|
|
683
|
+
let finishReason;
|
|
684
|
+
let usage;
|
|
685
|
+
let response;
|
|
686
|
+
const wrappedStream = new Proxy(stream, {
|
|
687
|
+
get(target, prop) {
|
|
688
|
+
if (prop === Symbol.asyncIterator) {
|
|
689
|
+
return async function* () {
|
|
690
|
+
try {
|
|
691
|
+
for await (const chunk of target) {
|
|
692
|
+
if (chunk.type === "text-delta" && chunk.textDelta) {
|
|
693
|
+
fullText += chunk.textDelta;
|
|
694
|
+
} else if (chunk.type === "finish") {
|
|
695
|
+
finishReason = chunk.finishReason;
|
|
696
|
+
usage = chunk.usage;
|
|
697
|
+
} else if (chunk.type === "response-metadata") {
|
|
698
|
+
response = chunk.response;
|
|
699
|
+
}
|
|
700
|
+
yield chunk;
|
|
701
|
+
}
|
|
702
|
+
} finally {
|
|
703
|
+
self.finalizeStream(
|
|
704
|
+
span,
|
|
705
|
+
config,
|
|
706
|
+
provider,
|
|
707
|
+
modelId,
|
|
708
|
+
startTime,
|
|
709
|
+
fullText,
|
|
710
|
+
finishReason,
|
|
711
|
+
usage,
|
|
712
|
+
response
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
if (prop === "textStream" || prop === "fullStream") {
|
|
718
|
+
const originalStream = target[prop];
|
|
719
|
+
return {
|
|
720
|
+
[Symbol.asyncIterator]: async function* () {
|
|
721
|
+
try {
|
|
722
|
+
for await (const chunk of originalStream) {
|
|
723
|
+
if (prop === "textStream") {
|
|
724
|
+
fullText += chunk;
|
|
725
|
+
}
|
|
726
|
+
yield chunk;
|
|
727
|
+
}
|
|
728
|
+
} finally {
|
|
729
|
+
const streamUsage = await target.usage.catch(() => null);
|
|
730
|
+
if (streamUsage) {
|
|
731
|
+
usage = streamUsage;
|
|
732
|
+
}
|
|
733
|
+
self.finalizeStream(
|
|
734
|
+
span,
|
|
735
|
+
config,
|
|
736
|
+
provider,
|
|
737
|
+
modelId,
|
|
738
|
+
startTime,
|
|
739
|
+
fullText,
|
|
740
|
+
finishReason,
|
|
741
|
+
usage,
|
|
742
|
+
response
|
|
743
|
+
);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
const value = target[prop];
|
|
749
|
+
if (typeof value === "function") {
|
|
750
|
+
return value.bind(target);
|
|
751
|
+
}
|
|
752
|
+
return value;
|
|
753
|
+
}
|
|
754
|
+
});
|
|
755
|
+
return wrappedStream;
|
|
756
|
+
}
|
|
757
|
+
finalizeStream(span, config, provider, modelId, startTime, fullText, finishReason, usage, response) {
|
|
758
|
+
if (response) {
|
|
759
|
+
span.setAttributes({
|
|
760
|
+
...response.id && { [ATTR_GEN_AI_RESPONSE_ID]: response.id },
|
|
761
|
+
...response.model && { [ATTR_GEN_AI_RESPONSE_MODEL]: response.model }
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
if (finishReason) {
|
|
765
|
+
span.setAttribute(ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [finishReason]);
|
|
766
|
+
}
|
|
767
|
+
if (fullText) {
|
|
768
|
+
span.setAttributes(
|
|
769
|
+
completionToAttributes(
|
|
770
|
+
fullText,
|
|
771
|
+
finishReason,
|
|
772
|
+
config.captureMessageContent || false
|
|
773
|
+
)
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
if (usage) {
|
|
777
|
+
span.setAttributes(tokenUsageToAttributes(usage));
|
|
778
|
+
if (config.enableMetrics) {
|
|
779
|
+
this.context.recordTokenMetrics(usage, provider.system, modelId);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
if (config.enableMetrics) {
|
|
783
|
+
const duration = (performance.now() - startTime) / 1e3;
|
|
784
|
+
this.context.recordDurationMetric(duration, provider.system, modelId, OPERATION_NAME_CHAT);
|
|
785
|
+
}
|
|
786
|
+
span.setStatus({ code: import_api6.SpanStatusCode.OK });
|
|
787
|
+
span.end();
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
// src/internal/instrumentation/vercel-ai/telemetry-recorder.ts
|
|
792
|
+
var import_api7 = require("@opentelemetry/api");
|
|
793
|
+
var import_api_logs = require("@opentelemetry/api-logs");
|
|
794
|
+
var TelemetryRecorder = class {
|
|
795
|
+
constructor(genaiClientOperationDuration, genaiClientTokenUsage, logger2) {
|
|
796
|
+
this.genaiClientOperationDuration = genaiClientOperationDuration;
|
|
797
|
+
this.genaiClientTokenUsage = genaiClientTokenUsage;
|
|
798
|
+
this.logger = logger2;
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Record token usage metrics
|
|
802
|
+
*/
|
|
803
|
+
recordTokenMetrics(usage, system, model) {
|
|
804
|
+
if (!this.genaiClientTokenUsage) {
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
const commonAttrs = {
|
|
808
|
+
[ATTR_GEN_AI_SYSTEM]: system,
|
|
809
|
+
[ATTR_GEN_AI_REQUEST_MODEL]: model
|
|
810
|
+
};
|
|
811
|
+
const inputTokens = usage.inputTokens || usage.promptTokens;
|
|
812
|
+
const outputTokens = usage.outputTokens || usage.completionTokens;
|
|
813
|
+
if (inputTokens !== void 0) {
|
|
814
|
+
this.genaiClientTokenUsage.record(inputTokens, {
|
|
815
|
+
...commonAttrs,
|
|
816
|
+
[ATTR_GEN_AI_TOKEN_TYPE]: TOKEN_TYPE_INPUT
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
if (outputTokens !== void 0) {
|
|
820
|
+
this.genaiClientTokenUsage.record(outputTokens, {
|
|
821
|
+
...commonAttrs,
|
|
822
|
+
[ATTR_GEN_AI_TOKEN_TYPE]: TOKEN_TYPE_OUTPUT
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Record operation duration metric
|
|
828
|
+
*/
|
|
829
|
+
recordDurationMetric(duration, system, model, operation) {
|
|
830
|
+
if (!this.genaiClientOperationDuration) {
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
this.genaiClientOperationDuration.record(duration, {
|
|
834
|
+
[ATTR_GEN_AI_SYSTEM]: system,
|
|
835
|
+
[ATTR_GEN_AI_REQUEST_MODEL]: model,
|
|
836
|
+
[ATTR_GEN_AI_OPERATION_NAME]: operation
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
/**
|
|
840
|
+
* Emit message events
|
|
841
|
+
*/
|
|
842
|
+
emitMessageEvents(messages, system, span) {
|
|
843
|
+
if (!this.logger) {
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
const ctx = import_api7.trace.setSpan(import_api7.context.active(), span);
|
|
847
|
+
for (const msg of messages) {
|
|
848
|
+
let eventName;
|
|
849
|
+
switch (msg.role) {
|
|
850
|
+
case "system": {
|
|
851
|
+
eventName = EVENT_GEN_AI_SYSTEM_MESSAGE;
|
|
852
|
+
break;
|
|
853
|
+
}
|
|
854
|
+
case "user": {
|
|
855
|
+
eventName = EVENT_GEN_AI_USER_MESSAGE;
|
|
856
|
+
break;
|
|
857
|
+
}
|
|
858
|
+
case "assistant": {
|
|
859
|
+
eventName = EVENT_GEN_AI_ASSISTANT_MESSAGE;
|
|
860
|
+
break;
|
|
861
|
+
}
|
|
862
|
+
case "tool":
|
|
863
|
+
case "function": {
|
|
864
|
+
eventName = EVENT_GEN_AI_TOOL_MESSAGE;
|
|
865
|
+
break;
|
|
866
|
+
}
|
|
867
|
+
default: {
|
|
868
|
+
continue;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
this.logger.emit({
|
|
872
|
+
timestamp: Date.now(),
|
|
873
|
+
context: ctx,
|
|
874
|
+
severityNumber: import_api_logs.SeverityNumber.INFO,
|
|
875
|
+
attributes: {
|
|
876
|
+
[ATTR_EVENT_NAME]: eventName,
|
|
877
|
+
[ATTR_GEN_AI_SYSTEM]: system
|
|
878
|
+
},
|
|
879
|
+
body: {
|
|
880
|
+
role: msg.role,
|
|
881
|
+
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
|
|
882
|
+
name: msg.name
|
|
883
|
+
}
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Emit assistant message event
|
|
889
|
+
*/
|
|
890
|
+
emitAssistantMessageEvent(text, system, span) {
|
|
891
|
+
if (!this.logger) {
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
const ctx = import_api7.trace.setSpan(import_api7.context.active(), span);
|
|
895
|
+
this.logger.emit({
|
|
896
|
+
timestamp: Date.now(),
|
|
897
|
+
context: ctx,
|
|
898
|
+
severityNumber: import_api_logs.SeverityNumber.INFO,
|
|
899
|
+
attributes: {
|
|
900
|
+
[ATTR_EVENT_NAME]: EVENT_GEN_AI_ASSISTANT_MESSAGE,
|
|
901
|
+
[ATTR_GEN_AI_SYSTEM]: system
|
|
902
|
+
},
|
|
903
|
+
body: {
|
|
904
|
+
role: "assistant",
|
|
905
|
+
content: text
|
|
906
|
+
}
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
|
|
911
|
+
// src/internal/instrumentation/vercel-ai/instrumentation.ts
|
|
912
|
+
var PACKAGE_NAME = "@brizz/vercel-ai-instrumentation";
|
|
913
|
+
var PACKAGE_VERSION = "0.1.0";
|
|
914
|
+
var VercelAIInstrumentation = class _VercelAIInstrumentation extends import_instrumentation.InstrumentationBase {
|
|
915
|
+
_genaiClientOperationDuration;
|
|
916
|
+
_genaiClientTokenUsage;
|
|
917
|
+
_telemetryRecorder;
|
|
918
|
+
_streamHandler;
|
|
919
|
+
_patchers = /* @__PURE__ */ new Map();
|
|
920
|
+
// Holds last patched namespace when available (reserved for future factory wrapping)
|
|
921
|
+
_vercelAiNamespace = null;
|
|
922
|
+
static _WRAPPED_SYMBOL = Symbol.for("brizz.vercel-ai.patched");
|
|
923
|
+
constructor(config = {}) {
|
|
924
|
+
super(PACKAGE_NAME, PACKAGE_VERSION, config);
|
|
925
|
+
const cfg = this.getConfig();
|
|
926
|
+
const envCC = getEnvBool("OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT");
|
|
927
|
+
if (envCC !== void 0) {
|
|
928
|
+
cfg.captureMessageContent = envCC;
|
|
929
|
+
}
|
|
930
|
+
this._initializeComponents();
|
|
931
|
+
}
|
|
932
|
+
setConfig(config = {}) {
|
|
933
|
+
const {
|
|
934
|
+
captureMessageContent = true,
|
|
935
|
+
enableMetrics = true,
|
|
936
|
+
emitEvents = true,
|
|
937
|
+
...validConfig
|
|
938
|
+
} = config;
|
|
939
|
+
const fullConfig = {
|
|
940
|
+
...validConfig,
|
|
941
|
+
captureMessageContent,
|
|
942
|
+
enableMetrics,
|
|
943
|
+
emitEvents
|
|
944
|
+
};
|
|
945
|
+
super.setConfig(fullConfig);
|
|
946
|
+
}
|
|
947
|
+
_initializeComponents() {
|
|
948
|
+
this._telemetryRecorder = new TelemetryRecorder(
|
|
949
|
+
this._genaiClientOperationDuration,
|
|
950
|
+
this._genaiClientTokenUsage,
|
|
951
|
+
this.logger
|
|
952
|
+
);
|
|
953
|
+
this._streamHandler = new StreamHandler({
|
|
954
|
+
recordTokenMetrics: this._telemetryRecorder.recordTokenMetrics.bind(this._telemetryRecorder),
|
|
955
|
+
recordDurationMetric: this._telemetryRecorder.recordDurationMetric.bind(
|
|
956
|
+
this._telemetryRecorder
|
|
957
|
+
)
|
|
958
|
+
});
|
|
959
|
+
const patcherContext = {
|
|
960
|
+
tracer: this.tracer,
|
|
961
|
+
getConfig: this.getConfig.bind(this),
|
|
962
|
+
recordTokenMetrics: this._telemetryRecorder.recordTokenMetrics.bind(this._telemetryRecorder),
|
|
963
|
+
recordDurationMetric: this._telemetryRecorder.recordDurationMetric.bind(
|
|
964
|
+
this._telemetryRecorder
|
|
965
|
+
),
|
|
966
|
+
emitMessageEvents: this._telemetryRecorder.emitMessageEvents.bind(this._telemetryRecorder),
|
|
967
|
+
emitAssistantMessageEvent: this._telemetryRecorder.emitAssistantMessageEvent.bind(
|
|
968
|
+
this._telemetryRecorder
|
|
969
|
+
)
|
|
970
|
+
};
|
|
971
|
+
this._patchers.set("generateText", new GenerateTextPatcher(patcherContext));
|
|
972
|
+
this._patchers.set("streamText", new StreamTextPatcher(patcherContext, this._streamHandler));
|
|
973
|
+
this._patchers.set("embed", new EmbeddingsPatcher(patcherContext));
|
|
974
|
+
this._patchers.set("embedMany", new EmbeddingsPatcher(patcherContext));
|
|
975
|
+
}
|
|
976
|
+
init() {
|
|
977
|
+
return [
|
|
978
|
+
new import_instrumentation.InstrumentationNodeModuleDefinition(
|
|
979
|
+
"ai",
|
|
980
|
+
[">=4.0.0 <6"],
|
|
981
|
+
(moduleExports) => {
|
|
982
|
+
logger.info("Starting instrumentation of Vercel AI SDK module");
|
|
983
|
+
this._vercelAiNamespace = moduleExports;
|
|
984
|
+
const patched = this._patchModuleExports(moduleExports);
|
|
985
|
+
return patched ?? moduleExports;
|
|
986
|
+
},
|
|
987
|
+
(moduleExports) => {
|
|
988
|
+
logger.debug("Uninstrumenting @vercel/ai module");
|
|
989
|
+
return moduleExports;
|
|
990
|
+
}
|
|
991
|
+
)
|
|
992
|
+
];
|
|
993
|
+
}
|
|
994
|
+
_updateMetricInstruments() {
|
|
995
|
+
const config = this.getConfig();
|
|
996
|
+
if (!config.enableMetrics) {
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
999
|
+
this._genaiClientOperationDuration = this.meter.createHistogram(
|
|
1000
|
+
METRIC_GEN_AI_CLIENT_OPERATION_DURATION,
|
|
1001
|
+
{
|
|
1002
|
+
description: "GenAI operation duration",
|
|
1003
|
+
unit: "s",
|
|
1004
|
+
advice: {
|
|
1005
|
+
explicitBucketBoundaries: [
|
|
1006
|
+
0.01,
|
|
1007
|
+
0.02,
|
|
1008
|
+
0.04,
|
|
1009
|
+
0.08,
|
|
1010
|
+
0.16,
|
|
1011
|
+
0.32,
|
|
1012
|
+
0.64,
|
|
1013
|
+
1.28,
|
|
1014
|
+
2.56,
|
|
1015
|
+
5.12,
|
|
1016
|
+
10.24,
|
|
1017
|
+
20.48,
|
|
1018
|
+
40.96,
|
|
1019
|
+
81.92
|
|
1020
|
+
]
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
);
|
|
1024
|
+
this._genaiClientTokenUsage = this.meter.createHistogram(METRIC_GEN_AI_CLIENT_TOKEN_USAGE, {
|
|
1025
|
+
description: "Measures number of input and output tokens used",
|
|
1026
|
+
unit: "{token}",
|
|
1027
|
+
advice: {
|
|
1028
|
+
explicitBucketBoundaries: [
|
|
1029
|
+
1,
|
|
1030
|
+
4,
|
|
1031
|
+
16,
|
|
1032
|
+
64,
|
|
1033
|
+
256,
|
|
1034
|
+
1024,
|
|
1035
|
+
4096,
|
|
1036
|
+
16384,
|
|
1037
|
+
65536,
|
|
1038
|
+
262144,
|
|
1039
|
+
1048576,
|
|
1040
|
+
4194304,
|
|
1041
|
+
16777216,
|
|
1042
|
+
67108864
|
|
1043
|
+
]
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
this._telemetryRecorder = new TelemetryRecorder(
|
|
1047
|
+
this._genaiClientOperationDuration,
|
|
1048
|
+
this._genaiClientTokenUsage,
|
|
1049
|
+
this.logger
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Patch known AI SDK functions in-place on the provided module exports object.
|
|
1054
|
+
* This approach is compatible with both CJS and ESM module loaders.
|
|
1055
|
+
*/
|
|
1056
|
+
_patchModuleExports(moduleExports) {
|
|
1057
|
+
if (!moduleExports || typeof moduleExports !== "object") {
|
|
1058
|
+
return null;
|
|
1059
|
+
}
|
|
1060
|
+
let inPlacePatched = true;
|
|
1061
|
+
const wrapFunction = (name, isEmbedMany = false) => {
|
|
1062
|
+
const current = moduleExports[name];
|
|
1063
|
+
if (typeof current !== "function") {
|
|
1064
|
+
return;
|
|
1065
|
+
}
|
|
1066
|
+
const currentFn = current;
|
|
1067
|
+
if (currentFn[_VercelAIInstrumentation._WRAPPED_SYMBOL]) {
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
const descriptor = Object.getOwnPropertyDescriptor(moduleExports, name);
|
|
1071
|
+
if (descriptor && (!descriptor.writable || !descriptor.configurable) && !descriptor.set) {
|
|
1072
|
+
inPlacePatched = false;
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
const patcher = this._patchers.get(name);
|
|
1076
|
+
if (!patcher) {
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
const patched = isEmbedMany ? patcher.patch(currentFn, true) : patcher.patch(currentFn);
|
|
1080
|
+
try {
|
|
1081
|
+
Object.defineProperty(patched, _VercelAIInstrumentation._WRAPPED_SYMBOL, {
|
|
1082
|
+
value: true,
|
|
1083
|
+
enumerable: false,
|
|
1084
|
+
configurable: false
|
|
1085
|
+
});
|
|
1086
|
+
} catch {
|
|
1087
|
+
}
|
|
1088
|
+
try {
|
|
1089
|
+
moduleExports[name] = patched;
|
|
1090
|
+
} catch {
|
|
1091
|
+
inPlacePatched = false;
|
|
1092
|
+
}
|
|
1093
|
+
};
|
|
1094
|
+
wrapFunction("generateText");
|
|
1095
|
+
wrapFunction("streamText");
|
|
1096
|
+
wrapFunction("embed");
|
|
1097
|
+
wrapFunction("embedMany", true);
|
|
1098
|
+
if (!inPlacePatched) {
|
|
1099
|
+
const proxiedModule = new Proxy(moduleExports, {
|
|
1100
|
+
get: (target, prop, receiver) => {
|
|
1101
|
+
const originalValue = Reflect.get(target, prop, receiver);
|
|
1102
|
+
if (typeof originalValue === "function" && typeof prop === "string" && this._patchers.has(prop)) {
|
|
1103
|
+
const patcher = this._patchers.get(prop);
|
|
1104
|
+
const isEmbedMany = prop === "embedMany";
|
|
1105
|
+
const wrapped = isEmbedMany ? patcher.patch(originalValue, true) : patcher.patch(originalValue);
|
|
1106
|
+
return wrapped;
|
|
1107
|
+
}
|
|
1108
|
+
return originalValue;
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
return proxiedModule;
|
|
1112
|
+
}
|
|
1113
|
+
return moduleExports;
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Manual instrumentation hook for bundlers/Next.js. Applies in-place wrapping
|
|
1117
|
+
* on the provided module namespace.
|
|
1118
|
+
*/
|
|
1119
|
+
manuallyInstrument(module3) {
|
|
1120
|
+
try {
|
|
1121
|
+
const result = this._patchModuleExports(module3);
|
|
1122
|
+
if (result !== null) {
|
|
1123
|
+
logger.debug("Applied manual Vercel AI instrumentation");
|
|
1124
|
+
this._vercelAiNamespace = result;
|
|
1125
|
+
return result;
|
|
1126
|
+
}
|
|
1127
|
+
logger.warn("Manual Vercel AI instrumentation received invalid module");
|
|
1128
|
+
return module3;
|
|
1129
|
+
} catch (error) {
|
|
1130
|
+
logger.error(`Failed manual Vercel AI instrumentation: ${String(error)}`);
|
|
1131
|
+
return this._vercelAiNamespace || module3;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
/**
|
|
1135
|
+
* Wrap a created provider/client instance (factory return) when possible.
|
|
1136
|
+
* Call this from wrappers that construct provider clients (e.g., OpenAI SDK).
|
|
1137
|
+
*/
|
|
1138
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1139
|
+
wrapFactoryReturn(instance) {
|
|
1140
|
+
return instance;
|
|
1141
|
+
}
|
|
1142
|
+
};
|
|
1143
|
+
|
|
1144
|
+
// src/internal/instrumentation/auto-init.ts
|
|
1145
|
+
var autoInstrumentationsLoaded = false;
|
|
1146
|
+
var exceptionLogger = (error) => {
|
|
1147
|
+
logger.error(`Exception in instrumentation: ${String(error)}`);
|
|
1148
|
+
};
|
|
1149
|
+
function loadNodeAutoInstrumentations() {
|
|
1150
|
+
try {
|
|
1151
|
+
const nodeInstrumentations = (0, import_auto_instrumentations_node.getNodeAutoInstrumentations)();
|
|
1152
|
+
(0, import_instrumentation3.registerInstrumentations)({ instrumentations: nodeInstrumentations });
|
|
1153
|
+
return nodeInstrumentations;
|
|
1154
|
+
} catch (error) {
|
|
1155
|
+
logger.error(`Failed to load Node.js auto-instrumentations: ${String(error)}`);
|
|
1156
|
+
return [];
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
function loadGenAIInstrumentations() {
|
|
1160
|
+
const instrumentations = [];
|
|
1161
|
+
const genAIInstrumentationClasses = [
|
|
1162
|
+
{ class: VercelAIInstrumentation, name: "Vercel AI" },
|
|
1163
|
+
// Load first to avoid conflicts
|
|
1164
|
+
{ class: import_instrumentation_openai.OpenAIInstrumentation, name: "OpenAI" },
|
|
1165
|
+
{ class: import_instrumentation_anthropic.AnthropicInstrumentation, name: "Anthropic" },
|
|
1166
|
+
{ class: import_instrumentation_cohere.CohereInstrumentation, name: "Cohere" },
|
|
1167
|
+
{ class: import_instrumentation_vertexai.VertexAIInstrumentation, name: "Vertex AI" },
|
|
1168
|
+
{ class: import_instrumentation_bedrock.BedrockInstrumentation, name: "Bedrock" },
|
|
1169
|
+
{ class: import_instrumentation_pinecone.PineconeInstrumentation, name: "Pinecone" },
|
|
1170
|
+
{ class: import_instrumentation_langchain.LangChainInstrumentation, name: "LangChain" },
|
|
1171
|
+
{ class: import_instrumentation_llamaindex.LlamaIndexInstrumentation, name: "LlamaIndex" },
|
|
1172
|
+
{ class: import_instrumentation_chromadb.ChromaDBInstrumentation, name: "ChromaDB" },
|
|
1173
|
+
{ class: import_instrumentation_qdrant.QdrantInstrumentation, name: "Qdrant" },
|
|
1174
|
+
{ class: import_instrumentation_together.TogetherInstrumentation, name: "Together" }
|
|
1175
|
+
];
|
|
1176
|
+
for (const config of genAIInstrumentationClasses) {
|
|
1177
|
+
try {
|
|
1178
|
+
const instrumentation = new config.class({ exceptionLogger });
|
|
1179
|
+
instrumentations.push(instrumentation);
|
|
1180
|
+
logger.debug(`Auto-loaded ${config.name} instrumentation`);
|
|
1181
|
+
} catch (error) {
|
|
1182
|
+
logger.error(`Failed to auto-load ${config.name} instrumentation: ${String(error)}`);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
try {
|
|
1186
|
+
(0, import_instrumentation3.registerInstrumentations)({ instrumentations });
|
|
1187
|
+
logger.info(`Auto-registered ${instrumentations.length} GenAI instrumentations`);
|
|
1188
|
+
} catch (error) {
|
|
1189
|
+
logger.error(`Failed to register GenAI instrumentations: ${String(error)}`);
|
|
1190
|
+
}
|
|
1191
|
+
return instrumentations;
|
|
1192
|
+
}
|
|
1193
|
+
function autoInitializeInstrumentations() {
|
|
1194
|
+
if (autoInstrumentationsLoaded) {
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
try {
|
|
1198
|
+
const nodeInstrumentations = loadNodeAutoInstrumentations();
|
|
1199
|
+
const genAIInstrumentations = loadGenAIInstrumentations();
|
|
1200
|
+
autoInstrumentationsLoaded = true;
|
|
1201
|
+
logger.info(
|
|
1202
|
+
`Auto-initialization complete: ${nodeInstrumentations.length} node + ${genAIInstrumentations.length} GenAI instrumentations`
|
|
1203
|
+
);
|
|
1204
|
+
} catch (error) {
|
|
1205
|
+
logger.error(`Auto-initialization failed: ${String(error)}`);
|
|
1206
|
+
autoInstrumentationsLoaded = false;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
autoInitializeInstrumentations();
|
|
1210
|
+
|
|
1211
|
+
// src/internal/sdk.ts
|
|
1212
|
+
var import_resources2 = require("@opentelemetry/resources");
|
|
1213
|
+
var import_sdk_node = require("@opentelemetry/sdk-node");
|
|
1214
|
+
|
|
1215
|
+
// src/internal/config.ts
|
|
1216
|
+
function resolveConfig(options) {
|
|
1217
|
+
const envLogLevel = process.env["BRIZZ_LOG_LEVEL"] || options.logLevel?.toString() || DEFAULT_LOG_LEVEL.toString();
|
|
1218
|
+
let resolvedLogLevel;
|
|
1219
|
+
if (envLogLevel) {
|
|
1220
|
+
resolvedLogLevel = parseLogLevel(envLogLevel);
|
|
1221
|
+
} else if (typeof options.logLevel === "string") {
|
|
1222
|
+
resolvedLogLevel = parseLogLevel(options.logLevel);
|
|
1223
|
+
} else {
|
|
1224
|
+
resolvedLogLevel = options.logLevel || DEFAULT_LOG_LEVEL;
|
|
1225
|
+
}
|
|
1226
|
+
setLogLevel(resolvedLogLevel);
|
|
1227
|
+
let maskingStatus;
|
|
1228
|
+
if (options.masking === true) {
|
|
1229
|
+
maskingStatus = "enabled";
|
|
1230
|
+
} else if (options.masking === false) {
|
|
1231
|
+
maskingStatus = "disabled";
|
|
1232
|
+
} else if (typeof options.masking === "object") {
|
|
1233
|
+
maskingStatus = "custom";
|
|
1234
|
+
} else {
|
|
1235
|
+
maskingStatus = "default-disabled";
|
|
1236
|
+
}
|
|
1237
|
+
logger.debug("Starting configuration resolution", {
|
|
1238
|
+
appName: options.appName,
|
|
1239
|
+
baseUrl: options.baseUrl,
|
|
1240
|
+
hasApiKey: !!options.apiKey,
|
|
1241
|
+
disableBatch: options.disableBatch,
|
|
1242
|
+
logLevel: resolvedLogLevel,
|
|
1243
|
+
headersCount: Object.keys(options.headers || {}).length,
|
|
1244
|
+
masking: maskingStatus
|
|
1245
|
+
});
|
|
1246
|
+
let resolvedMasking;
|
|
1247
|
+
if (options.masking === true) {
|
|
1248
|
+
resolvedMasking = {
|
|
1249
|
+
spanMasking: {},
|
|
1250
|
+
eventMasking: {}
|
|
1251
|
+
};
|
|
1252
|
+
} else if (options.masking && typeof options.masking === "object") {
|
|
1253
|
+
resolvedMasking = options.masking;
|
|
1254
|
+
}
|
|
1255
|
+
const resolvedConfig = {
|
|
1256
|
+
...options,
|
|
1257
|
+
appName: process.env["BRIZZ_APP_NAME"] || options.appName || "unknown-app",
|
|
1258
|
+
baseUrl: process.env["BRIZZ_BASE_URL"] || options.baseUrl || "https://telemetry.brizz.dev",
|
|
1259
|
+
headers: { ...options.headers },
|
|
1260
|
+
apiKey: process.env["BRIZZ_API_KEY"] || options.apiKey,
|
|
1261
|
+
disableBatch: process.env["BRIZZ_DISABLE_BATCH"] === "true" || !!options.disableBatch,
|
|
1262
|
+
logLevel: resolvedLogLevel,
|
|
1263
|
+
masking: resolvedMasking
|
|
1264
|
+
};
|
|
1265
|
+
if (resolvedConfig.apiKey) {
|
|
1266
|
+
resolvedConfig.headers["Authorization"] = `Bearer ${resolvedConfig.apiKey}`;
|
|
1267
|
+
}
|
|
1268
|
+
if (process.env["BRIZZ_HEADERS"]) {
|
|
1269
|
+
try {
|
|
1270
|
+
const envHeaders = JSON.parse(process.env["BRIZZ_HEADERS"]);
|
|
1271
|
+
Object.assign(resolvedConfig.headers, envHeaders);
|
|
1272
|
+
logger.debug("Added headers from environment variable", {
|
|
1273
|
+
headers: Object.keys(envHeaders)
|
|
1274
|
+
});
|
|
1275
|
+
} catch (error) {
|
|
1276
|
+
logger.error("Failed to parse BRIZZ_HEADERS environment variable", { error });
|
|
1277
|
+
throw new Error("Invalid JSON in BRIZZ_HEADERS environment variable");
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
logger.debug("Configuration resolved with environment variables", {
|
|
1281
|
+
appName: resolvedConfig.appName,
|
|
1282
|
+
baseUrl: resolvedConfig.baseUrl,
|
|
1283
|
+
hasApiKey: !!resolvedConfig.apiKey,
|
|
1284
|
+
disableBatch: resolvedConfig.disableBatch,
|
|
1285
|
+
envOverrides: {
|
|
1286
|
+
hasEnvApiKey: !!process.env["BRIZZ_API_KEY"],
|
|
1287
|
+
hasEnvBaseUrl: !!process.env["BRIZZ_BASE_URL"],
|
|
1288
|
+
hasEnvBatch: !!process.env["BRIZZ_DISABLE_BATCH"],
|
|
1289
|
+
hasEnvHeaders: !!process.env["BRIZZ_HEADERS"]
|
|
1290
|
+
}
|
|
1291
|
+
});
|
|
1292
|
+
return resolvedConfig;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
// src/internal/instrumentation/registry.ts
|
|
1296
|
+
var import_instrumentation_anthropic2 = require("@traceloop/instrumentation-anthropic");
|
|
1297
|
+
var import_instrumentation_bedrock2 = require("@traceloop/instrumentation-bedrock");
|
|
1298
|
+
var import_instrumentation_chromadb2 = require("@traceloop/instrumentation-chromadb");
|
|
1299
|
+
var import_instrumentation_cohere2 = require("@traceloop/instrumentation-cohere");
|
|
1300
|
+
var import_instrumentation_langchain2 = require("@traceloop/instrumentation-langchain");
|
|
1301
|
+
var import_instrumentation_llamaindex2 = require("@traceloop/instrumentation-llamaindex");
|
|
1302
|
+
var import_instrumentation_openai2 = require("@traceloop/instrumentation-openai");
|
|
1303
|
+
var import_instrumentation_pinecone2 = require("@traceloop/instrumentation-pinecone");
|
|
1304
|
+
var import_instrumentation_qdrant2 = require("@traceloop/instrumentation-qdrant");
|
|
1305
|
+
var import_instrumentation_together2 = require("@traceloop/instrumentation-together");
|
|
1306
|
+
var import_instrumentation_vertexai2 = require("@traceloop/instrumentation-vertexai");
|
|
1307
|
+
var InstrumentationRegistry = class _InstrumentationRegistry {
|
|
1308
|
+
static instance;
|
|
1309
|
+
manualModules = null;
|
|
1310
|
+
static getInstance() {
|
|
1311
|
+
if (!_InstrumentationRegistry.instance) {
|
|
1312
|
+
_InstrumentationRegistry.instance = new _InstrumentationRegistry();
|
|
1313
|
+
}
|
|
1314
|
+
return _InstrumentationRegistry.instance;
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Set manual instrumentation modules for Next.js/Webpack environments
|
|
1318
|
+
*/
|
|
1319
|
+
setManualModules(modules) {
|
|
1320
|
+
this.manualModules = modules;
|
|
1321
|
+
logger.info("Manual instrumentation modules configured for Next.js/Webpack compatibility");
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Helper to load instrumentation with optional manual module
|
|
1325
|
+
*/
|
|
1326
|
+
loadInstrumentation(InstrumentationClass, name, manualModule, exceptionLogger2) {
|
|
1327
|
+
try {
|
|
1328
|
+
const inst = new InstrumentationClass({
|
|
1329
|
+
exceptionLogger: exceptionLogger2 || ((error) => logger.error(`Exception in instrumentation: ${String(error)}`))
|
|
1330
|
+
});
|
|
1331
|
+
if (manualModule) {
|
|
1332
|
+
inst.manuallyInstrument(manualModule);
|
|
1333
|
+
logger.debug(`Manual instrumentation enabled for ${name}`);
|
|
1334
|
+
}
|
|
1335
|
+
return inst;
|
|
1336
|
+
} catch (error) {
|
|
1337
|
+
logger.error(`Failed to load ${name} instrumentation: ${String(error)}`);
|
|
1338
|
+
return null;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* Get manual instrumentations only.
|
|
1343
|
+
* Auto-instrumentations are handled at import time.
|
|
1344
|
+
*/
|
|
1345
|
+
getManualInstrumentations() {
|
|
1346
|
+
if (!this.manualModules || Object.keys(this.manualModules).length === 0) {
|
|
1347
|
+
logger.debug("No manual instrumentation modules configured");
|
|
1348
|
+
return [];
|
|
1349
|
+
}
|
|
1350
|
+
const instrumentations = [];
|
|
1351
|
+
const exceptionLogger2 = (error) => {
|
|
1352
|
+
logger.error(`Exception in manual instrumentation: ${String(error)}`);
|
|
1353
|
+
};
|
|
1354
|
+
this.loadManualInstrumentations(instrumentations, exceptionLogger2);
|
|
1355
|
+
logger.info(`Loaded ${instrumentations.length} manual instrumentations`);
|
|
1356
|
+
return instrumentations;
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Load manual instrumentations only (with modules provided by user).
|
|
1360
|
+
* @private
|
|
1361
|
+
*/
|
|
1362
|
+
loadManualInstrumentations(instrumentations, exceptionLogger2) {
|
|
1363
|
+
const instrumentationConfigs = [
|
|
1364
|
+
{ class: import_instrumentation_openai2.OpenAIInstrumentation, name: "OpenAI", module: this.manualModules?.openAI },
|
|
1365
|
+
{ class: import_instrumentation_anthropic2.AnthropicInstrumentation, name: "Anthropic", module: this.manualModules?.anthropic },
|
|
1366
|
+
{ class: import_instrumentation_cohere2.CohereInstrumentation, name: "Cohere", module: this.manualModules?.cohere },
|
|
1367
|
+
{
|
|
1368
|
+
class: import_instrumentation_vertexai2.VertexAIInstrumentation,
|
|
1369
|
+
name: "Vertex AI",
|
|
1370
|
+
module: this.manualModules?.google_vertexai
|
|
1371
|
+
},
|
|
1372
|
+
{ class: import_instrumentation_bedrock2.BedrockInstrumentation, name: "Bedrock", module: this.manualModules?.bedrock },
|
|
1373
|
+
{ class: import_instrumentation_pinecone2.PineconeInstrumentation, name: "Pinecone", module: this.manualModules?.pinecone },
|
|
1374
|
+
{ class: import_instrumentation_langchain2.LangChainInstrumentation, name: "LangChain", module: this.manualModules?.langchain },
|
|
1375
|
+
{
|
|
1376
|
+
class: import_instrumentation_llamaindex2.LlamaIndexInstrumentation,
|
|
1377
|
+
name: "LlamaIndex",
|
|
1378
|
+
module: this.manualModules?.llamaindex
|
|
1379
|
+
},
|
|
1380
|
+
{ class: import_instrumentation_chromadb2.ChromaDBInstrumentation, name: "ChromaDB", module: this.manualModules?.chromadb },
|
|
1381
|
+
{ class: import_instrumentation_qdrant2.QdrantInstrumentation, name: "Qdrant", module: this.manualModules?.qdrant },
|
|
1382
|
+
{ class: import_instrumentation_together2.TogetherInstrumentation, name: "Together", module: this.manualModules?.together },
|
|
1383
|
+
{ class: VercelAIInstrumentation, name: "Vercel AI", module: this.manualModules?.vercelAI }
|
|
1384
|
+
];
|
|
1385
|
+
for (const config of instrumentationConfigs) {
|
|
1386
|
+
if (config.module) {
|
|
1387
|
+
const instrumentation = this.loadInstrumentation(
|
|
1388
|
+
config.class,
|
|
1389
|
+
config.name,
|
|
1390
|
+
config.module,
|
|
1391
|
+
exceptionLogger2
|
|
1392
|
+
);
|
|
1393
|
+
if (instrumentation) {
|
|
1394
|
+
instrumentations.push(instrumentation);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
|
|
1401
|
+
// src/internal/log/logging.ts
|
|
1402
|
+
var import_api_logs2 = require("@opentelemetry/api-logs");
|
|
1403
|
+
var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
|
|
1404
|
+
var import_resources = require("@opentelemetry/resources");
|
|
1405
|
+
var import_sdk_logs2 = require("@opentelemetry/sdk-logs");
|
|
1406
|
+
|
|
1407
|
+
// src/internal/log/processors/log-processor.ts
|
|
1408
|
+
var import_api9 = require("@opentelemetry/api");
|
|
1409
|
+
var import_sdk_logs = require("@opentelemetry/sdk-logs");
|
|
1410
|
+
|
|
1411
|
+
// src/internal/masking/patterns.ts
|
|
1412
|
+
var DEFAULT_PII_PATTERNS = [
|
|
1413
|
+
// Email addresses
|
|
1414
|
+
{
|
|
1415
|
+
name: "email_addresses",
|
|
1416
|
+
pattern: String.raw`\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b`
|
|
1417
|
+
},
|
|
1418
|
+
// Phone numbers (US format)
|
|
1419
|
+
{
|
|
1420
|
+
name: "us_phone_numbers",
|
|
1421
|
+
pattern: String.raw`(?:^|[\s])(?:\+?1[-.\s]*)?(?:\([0-9]{3}\)\s?[0-9]{3}[-.\s]?[0-9]{4}|[0-9]{3}[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}|[0-9]{10})(?=[\s]|$)`
|
|
1422
|
+
},
|
|
1423
|
+
// Social Security Numbers
|
|
1424
|
+
{
|
|
1425
|
+
name: "ssn",
|
|
1426
|
+
pattern: String.raw`\b(?!000|666|9\d{2})\d{3}[-\s]?(?!00)\d{2}[-\s]?(?!0000)\d{4}\b`
|
|
1427
|
+
},
|
|
1428
|
+
// Credit card numbers
|
|
1429
|
+
{
|
|
1430
|
+
name: "credit_cards",
|
|
1431
|
+
pattern: String.raw`\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\\d{3})\\d{11})\b`
|
|
1432
|
+
},
|
|
1433
|
+
{
|
|
1434
|
+
name: "credit_cards_with_separators",
|
|
1435
|
+
pattern: String.raw`\b(?:4\\d{3}|5[1-5]\\d{2}|3[47]\\d{2})[-\s]?\\d{4}[-\s]?\\d{4}[-\s]?\\d{4}\b`
|
|
1436
|
+
},
|
|
1437
|
+
// IP addresses (IPv4)
|
|
1438
|
+
{
|
|
1439
|
+
name: "ipv4_addresses",
|
|
1440
|
+
pattern: String.raw`\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?!\.[0-9])\b`
|
|
1441
|
+
},
|
|
1442
|
+
// API keys/tokens
|
|
1443
|
+
{
|
|
1444
|
+
name: "generic_api_keys",
|
|
1445
|
+
pattern: String.raw`\b(?:[Aa][Pp][Ii][_-]?[Kk][Ee][Yy]|[Tt][Oo][Kk][Ee][Nn]|[Ss][Ee][Cc][Rr][Ee][Tt])[_-]?[=:]?\s*["']?(?:[a-zA-Z0-9\-_.]{20,})["']?\b`
|
|
1446
|
+
},
|
|
1447
|
+
{
|
|
1448
|
+
name: "openai_keys",
|
|
1449
|
+
pattern: String.raw`\bsk[-_][a-zA-Z0-9]{20,}\b`
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
name: "base64_secrets",
|
|
1453
|
+
pattern: String.raw`\b[A-Za-z0-9+/]{64,}={0,2}\b`
|
|
1454
|
+
},
|
|
1455
|
+
// AWS Keys
|
|
1456
|
+
{
|
|
1457
|
+
name: "aws_access_keys",
|
|
1458
|
+
pattern: String.raw`\b(?:AKIA|ABIA|ACCA|ASIA)[0-9A-Z]{16}\b`
|
|
1459
|
+
},
|
|
1460
|
+
{
|
|
1461
|
+
name: "aws_secret_keys",
|
|
1462
|
+
pattern: String.raw`\b[A-Za-z0-9/+=]*[A-Z][A-Za-z0-9/+=]*[a-z][A-Za-z0-9/+=]*[/+=][A-Za-z0-9/+=]{30,}\b`
|
|
1463
|
+
},
|
|
1464
|
+
// GitHub tokens
|
|
1465
|
+
{
|
|
1466
|
+
name: "github_tokens",
|
|
1467
|
+
pattern: String.raw`\bghp_[a-zA-Z0-9]{36}\b`
|
|
1468
|
+
},
|
|
1469
|
+
// Slack tokens
|
|
1470
|
+
{
|
|
1471
|
+
name: "slack_tokens",
|
|
1472
|
+
pattern: String.raw`\bxox[baprs]-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24,34}\b`
|
|
1473
|
+
},
|
|
1474
|
+
// Stripe keys
|
|
1475
|
+
{
|
|
1476
|
+
name: "stripe_keys",
|
|
1477
|
+
pattern: String.raw`\b(?:sk|pk)_(?:test|live)_[a-zA-Z0-9]{24,}\b`
|
|
1478
|
+
},
|
|
1479
|
+
// JWT tokens
|
|
1480
|
+
{
|
|
1481
|
+
name: "jwt_tokens",
|
|
1482
|
+
pattern: String.raw`\beyJ[A-Za-z0-9_-]{2,}\\.[A-Za-z0-9_-]{2,}\\.[A-Za-z0-9_-]{2,}\b`
|
|
1483
|
+
},
|
|
1484
|
+
// MAC addresses
|
|
1485
|
+
{
|
|
1486
|
+
name: "mac_addresses",
|
|
1487
|
+
pattern: String.raw`\b(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\b`
|
|
1488
|
+
},
|
|
1489
|
+
// IPv6 addresses
|
|
1490
|
+
{
|
|
1491
|
+
name: "ipv6_addresses",
|
|
1492
|
+
pattern: String.raw`\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b`
|
|
1493
|
+
},
|
|
1494
|
+
// Medical records
|
|
1495
|
+
{
|
|
1496
|
+
name: "medical_record_numbers",
|
|
1497
|
+
pattern: String.raw`\b(?:[Mm][Rr][Nn])[-\s]?\d{6,10}\b`
|
|
1498
|
+
},
|
|
1499
|
+
// Bitcoin addresses
|
|
1500
|
+
{
|
|
1501
|
+
name: "bitcoin_addresses",
|
|
1502
|
+
pattern: String.raw`\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\b`
|
|
1503
|
+
},
|
|
1504
|
+
// Ethereum addresses
|
|
1505
|
+
{
|
|
1506
|
+
name: "ethereum_addresses",
|
|
1507
|
+
pattern: String.raw`\b0x[a-fA-F0-9]{40}(?![a-fA-F0-9])\b`
|
|
1508
|
+
},
|
|
1509
|
+
// UUIDs
|
|
1510
|
+
{
|
|
1511
|
+
name: "uuids",
|
|
1512
|
+
pattern: String.raw`\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}(?![0-9a-fA-F-])\b`
|
|
1513
|
+
},
|
|
1514
|
+
// Database connection strings
|
|
1515
|
+
{
|
|
1516
|
+
name: "database_connections",
|
|
1517
|
+
pattern: String.raw`\b(?:[Mm][Oo][Nn][Gg][Oo][Dd][Bb]|[Pp][Oo][Ss][Tt][Gg][Rr][Ee][Ss]|[Mm][Yy][Ss][Qq][Ll]|[Rr][Ee][Dd][Ii][Ss]|[Mm][Ss][Ss][Qq][Ll]|[Oo][Rr][Aa][Cc][Ll][Ee]):\\/\\/[^\\s]+\b`
|
|
1518
|
+
},
|
|
1519
|
+
// Private keys
|
|
1520
|
+
{
|
|
1521
|
+
name: "rsa_private_keys",
|
|
1522
|
+
pattern: "-----BEGIN (?:RSA )?PRIVATE KEY-----"
|
|
1523
|
+
},
|
|
1524
|
+
{
|
|
1525
|
+
name: "pgp_private_keys",
|
|
1526
|
+
pattern: "-----BEGIN PGP PRIVATE KEY BLOCK-----"
|
|
1527
|
+
},
|
|
1528
|
+
{
|
|
1529
|
+
name: "certificates",
|
|
1530
|
+
pattern: "-----BEGIN CERTIFICATE-----"
|
|
1531
|
+
},
|
|
1532
|
+
// Date of birth patterns
|
|
1533
|
+
{
|
|
1534
|
+
name: "date_of_birth_us",
|
|
1535
|
+
pattern: String.raw`\b(?:0[1-9]|1[0-2])[-/](?:0[1-9]|[12]\\d|3[01])[-/](?:19|20)\\d{2}\b`
|
|
1536
|
+
},
|
|
1537
|
+
{
|
|
1538
|
+
name: "date_of_birth_iso",
|
|
1539
|
+
pattern: String.raw`\b(?:19|20)\\d{2}[-/](?:0[1-9]|1[0-2])[-/](?:0[1-9]|[12]\\d|3[01])\b`
|
|
1540
|
+
},
|
|
1541
|
+
// US Identification Numbers
|
|
1542
|
+
{
|
|
1543
|
+
name: "us_passport_numbers",
|
|
1544
|
+
pattern: String.raw`\b[A-Z]?\\d{6,9}\b`
|
|
1545
|
+
},
|
|
1546
|
+
{
|
|
1547
|
+
name: "drivers_license",
|
|
1548
|
+
pattern: String.raw`\b[A-Z]{1,2}\\d{3,8}[-\s]?\\d{2,5}[-\s]?\\d{2,5}[-\s]?\\d{1,5}[-\s]?\\d?\b`
|
|
1549
|
+
},
|
|
1550
|
+
{
|
|
1551
|
+
name: "bank_account_numbers",
|
|
1552
|
+
pattern: String.raw`\b\\d{10,17}\b`
|
|
1553
|
+
},
|
|
1554
|
+
{
|
|
1555
|
+
name: "aba_routing_numbers",
|
|
1556
|
+
pattern: String.raw`\b((0[0-9])|(1[0-2])|(2[1-9])|(3[0-2])|(6[1-9])|(7[0-2])|80)([0-9]{7})\b`
|
|
1557
|
+
},
|
|
1558
|
+
{
|
|
1559
|
+
name: "health_insurance_numbers",
|
|
1560
|
+
pattern: String.raw`\b\\d{10}[A-Z]\b`
|
|
1561
|
+
},
|
|
1562
|
+
{
|
|
1563
|
+
name: "employee_ids",
|
|
1564
|
+
pattern: String.raw`\b(?:[Ee][Mm][Pp]|[Ee][Mm][Pp][Ll][Oo][Yy][Ee][Ee]|[Ee])[-\s]?\\d{5,8}\b`
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
name: "tax_ein",
|
|
1568
|
+
pattern: String.raw`\b\\d{2}-\\d{7}\b`
|
|
1569
|
+
},
|
|
1570
|
+
{
|
|
1571
|
+
name: "medicare_beneficiary_id",
|
|
1572
|
+
pattern: String.raw`\b[1-9][A-Z][A-Z0-9]\\d-[A-Z][A-Z0-9]\\d-[A-Z][A-Z0-9]\\d{2}\b`
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
name: "national_provider_id",
|
|
1576
|
+
pattern: String.raw`\b1\\d{9}\b`
|
|
1577
|
+
},
|
|
1578
|
+
{
|
|
1579
|
+
name: "dea_numbers",
|
|
1580
|
+
pattern: String.raw`\b[A-Z]{2}\\d{7}\b`
|
|
1581
|
+
},
|
|
1582
|
+
{
|
|
1583
|
+
name: "itin",
|
|
1584
|
+
pattern: String.raw`\b9\\d{2}(?:[ \\-]?)[7,8]\\d(?:[ \\-]?)\\d{4}\b`
|
|
1585
|
+
},
|
|
1586
|
+
// Vehicle and Location
|
|
1587
|
+
{
|
|
1588
|
+
name: "vin_numbers",
|
|
1589
|
+
pattern: String.raw`\b[A-HJ-NPR-Z0-9]{17}\b`
|
|
1590
|
+
},
|
|
1591
|
+
{
|
|
1592
|
+
name: "coordinates",
|
|
1593
|
+
pattern: String.raw`\b[-+]?(?:[0-8]?\\d(?:\\.\\d+)?|90(?:\\.0+)?),\\s*[-+]?(?:1[0-7]\\d(?:\\.\\d+)?|180(?:\\.0+)?|[0-9]?\\d(?:\\.\\d+)?)\b`
|
|
1594
|
+
},
|
|
1595
|
+
{
|
|
1596
|
+
name: "us_license_plates",
|
|
1597
|
+
pattern: String.raw`\b[A-Z]{1,3}[-\s]\\d{1,4}[A-Z]?\b|\b\\d{1,2}[A-Z]{1,3}\\d{1,4}\b`
|
|
1598
|
+
},
|
|
1599
|
+
{
|
|
1600
|
+
name: "us_zip_codes",
|
|
1601
|
+
pattern: String.raw`\b(\\d{5}-\\d{4}|\\d{5})\b`
|
|
1602
|
+
},
|
|
1603
|
+
{
|
|
1604
|
+
name: "us_street_addresses",
|
|
1605
|
+
pattern: String.raw`\b\\d{1,8}\b[\\s\\S]{10,100}?\b(AK|AL|AR|AZ|CA|CO|CT|DC|DE|FL|GA|HI|IA|ID|IL|IN|KS|KY|LA|MA|MD|ME|MI|MN|MO|MS|MT|NC|ND|NE|NH|NJ|NM|NV|NY|OH|OK|OR|PA|RI|SC|SD|TN|TX|UT|VA|VT|WA|WI|WV|WY)\b\\s\\d{5}\b`
|
|
1606
|
+
},
|
|
1607
|
+
// International Banking
|
|
1608
|
+
{
|
|
1609
|
+
name: "iban",
|
|
1610
|
+
pattern: String.raw`\b[A-Z]{2}\d{2}[A-Z0-9]{4}\d{7}([A-Z0-9]?){0,16}\b`
|
|
1611
|
+
},
|
|
1612
|
+
{
|
|
1613
|
+
name: "swift_bic",
|
|
1614
|
+
pattern: String.raw`\b[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?\b`
|
|
1615
|
+
},
|
|
1616
|
+
// Additional API Keys and Tokens
|
|
1617
|
+
{
|
|
1618
|
+
name: "google_oauth",
|
|
1619
|
+
pattern: String.raw`\bya29\\.[a-zA-Z0-9_-]{60,}\b`
|
|
1620
|
+
},
|
|
1621
|
+
{
|
|
1622
|
+
name: "firebase_tokens",
|
|
1623
|
+
pattern: String.raw`\bAAAA[A-Za-z0-9_-]{100,}\b`
|
|
1624
|
+
},
|
|
1625
|
+
{
|
|
1626
|
+
name: "google_app_ids",
|
|
1627
|
+
pattern: String.raw`\b[0-9]+-\w+\.apps\.googleusercontent\.com\b`
|
|
1628
|
+
},
|
|
1629
|
+
{
|
|
1630
|
+
name: "facebook_secrets",
|
|
1631
|
+
pattern: String.raw`\b(facebook_secret|FACEBOOK_SECRET|facebook_app_secret|FACEBOOK_APP_SECRET)[a-z_ =\\s"'\\:]{0,5}[^a-zA-Z0-9][a-f0-9]{32}[^a-zA-Z0-9]`
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
name: "github_keys",
|
|
1635
|
+
pattern: String.raw`\b(GITHUB_SECRET|GITHUB_KEY|github_secret|github_key|github_token|GITHUB_TOKEN|github_api_key|GITHUB_API_KEY)[a-z_ =\\s\"'\\:]{0,10}[^a-zA-Z0-9][a-zA-Z0-9]{40}[^a-zA-Z0-9]`
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
name: "heroku_keys",
|
|
1639
|
+
pattern: String.raw`\b(heroku_api_key|HEROKU_API_KEY|heroku_secret|HEROKU_SECRET)[a-z_ =\\s\"'\\:]{0,10}[^a-zA-Z0-9-]\\w{8}(?:-\\w{4}){3}-\\w{12}[^a-zA-Z0-9\\-]`
|
|
1640
|
+
},
|
|
1641
|
+
{
|
|
1642
|
+
name: "slack_api_keys",
|
|
1643
|
+
pattern: String.raw`\b(slack_api_key|SLACK_API_KEY|slack_key|SLACK_KEY)[a-z_ =\\s\"'\\:]{0,10}[^a-f0-9][a-f0-9]{32}[^a-f0-9]`
|
|
1644
|
+
},
|
|
1645
|
+
{
|
|
1646
|
+
name: "slack_api_tokens",
|
|
1647
|
+
pattern: String.raw`\b(xox[pb](?:-[a-zA-Z0-9]+){4,})\b`
|
|
1648
|
+
},
|
|
1649
|
+
// Extended Private Keys and Certificates
|
|
1650
|
+
{
|
|
1651
|
+
name: "dsa_private_keys",
|
|
1652
|
+
pattern: String.raw`-----BEGIN DSA PRIVATE KEY-----(?:[a-zA-Z0-9\+\=\/"']|\s)+?-----END DSA PRIVATE KEY-----`
|
|
1653
|
+
},
|
|
1654
|
+
{
|
|
1655
|
+
name: "ec_private_keys",
|
|
1656
|
+
pattern: String.raw`-----BEGIN (?:EC|ECDSA) PRIVATE KEY-----(?:[a-zA-Z0-9\+\=\/"']|\s)+?-----END (?:EC|ECDSA) PRIVATE KEY-----`
|
|
1657
|
+
},
|
|
1658
|
+
{
|
|
1659
|
+
name: "encrypted_private_keys",
|
|
1660
|
+
pattern: String.raw`-----BEGIN ENCRYPTED PRIVATE KEY-----(?:.|\s)+?-----END ENCRYPTED PRIVATE KEY-----`
|
|
1661
|
+
},
|
|
1662
|
+
{
|
|
1663
|
+
name: "ssl_certificates",
|
|
1664
|
+
pattern: String.raw`-----BEGIN CERTIFICATE-----(?:.|\n)+?\s-----END CERTIFICATE-----`
|
|
1665
|
+
},
|
|
1666
|
+
{
|
|
1667
|
+
name: "ssh_dss_public",
|
|
1668
|
+
pattern: String.raw`\bssh-dss [0-9A-Za-z+/]+[=]{2}\b`
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
name: "ssh_rsa_public",
|
|
1672
|
+
pattern: String.raw`\bssh-rsa AAAA[0-9A-Za-z+/]+[=]{0,3} [^@]+@[^@]+\b`
|
|
1673
|
+
},
|
|
1674
|
+
{
|
|
1675
|
+
name: "putty_ssh_keys",
|
|
1676
|
+
pattern: String.raw`PuTTY-User-Key-File-2: ssh-(?:rsa|dss)\s*Encryption: none(?:.|\s?)*?Private-MAC:`
|
|
1677
|
+
},
|
|
1678
|
+
// International Phone Numbers
|
|
1679
|
+
{
|
|
1680
|
+
name: "france_phone_numbers",
|
|
1681
|
+
pattern: String.raw`\b([0O]?[1lI][1lI])?[3E][3E][0O]?[\\dOIlZEASB]{9}\b`
|
|
1682
|
+
},
|
|
1683
|
+
{
|
|
1684
|
+
name: "german_phone_numbers",
|
|
1685
|
+
pattern: String.raw`\b[\d\w]\d{2}[\d\w]{6}\d[\d\w]\b`
|
|
1686
|
+
},
|
|
1687
|
+
{
|
|
1688
|
+
name: "uk_phone_numbers",
|
|
1689
|
+
pattern: String.raw`\b([0O]?[1lI][1lI])?[4A][4A][\\dOIlZEASB]{10,11}\b`
|
|
1690
|
+
},
|
|
1691
|
+
// International IDs
|
|
1692
|
+
{
|
|
1693
|
+
name: "uk_drivers_license",
|
|
1694
|
+
pattern: String.raw`\b[A-Z]{5}\d{6}[A-Z]{2}\d{1}[A-Z]{2}\b`
|
|
1695
|
+
},
|
|
1696
|
+
{
|
|
1697
|
+
name: "uk_passport",
|
|
1698
|
+
pattern: String.raw`\b\\d{10}GB[RP]\\d{7}[UMF]{1}\\d{9}\b`
|
|
1699
|
+
},
|
|
1700
|
+
{
|
|
1701
|
+
name: "argentina_dni",
|
|
1702
|
+
pattern: String.raw`\b\\d{2}\\.\\d{3}\\.\\d{3}\b`
|
|
1703
|
+
},
|
|
1704
|
+
{
|
|
1705
|
+
name: "australia_tfn",
|
|
1706
|
+
pattern: String.raw`\b[Tt][Ff][Nn](:|:\\s|\\s|)(\\d{8,9})\b`
|
|
1707
|
+
},
|
|
1708
|
+
{
|
|
1709
|
+
name: "canada_passport",
|
|
1710
|
+
pattern: String.raw`\b[\\w]{2}[\\d]{6}\b`
|
|
1711
|
+
},
|
|
1712
|
+
{
|
|
1713
|
+
name: "croatia_vat",
|
|
1714
|
+
pattern: String.raw`\bHR\\d{11}\b`
|
|
1715
|
+
},
|
|
1716
|
+
{
|
|
1717
|
+
name: "czech_vat",
|
|
1718
|
+
pattern: String.raw`\bCZ\\d{8,10}\b`
|
|
1719
|
+
},
|
|
1720
|
+
{
|
|
1721
|
+
name: "denmark_personal_id",
|
|
1722
|
+
pattern: String.raw`\b(?:\\d{10}|\\d{6}[-\\s]\\d{4})\b`
|
|
1723
|
+
},
|
|
1724
|
+
{
|
|
1725
|
+
name: "france_national_id",
|
|
1726
|
+
pattern: String.raw`\b\\d{12}\b`
|
|
1727
|
+
},
|
|
1728
|
+
{
|
|
1729
|
+
name: "france_ssn",
|
|
1730
|
+
pattern: String.raw`\b(?:\\d{13}|\\d{13}\\s\\d{2})\b`
|
|
1731
|
+
},
|
|
1732
|
+
{
|
|
1733
|
+
name: "france_passport",
|
|
1734
|
+
pattern: String.raw`\b\\d{2}11\\d{5}\b`
|
|
1735
|
+
},
|
|
1736
|
+
{
|
|
1737
|
+
name: "california_drivers_license",
|
|
1738
|
+
pattern: String.raw`\b[A-Z]{1}\\d{7}\b`
|
|
1739
|
+
},
|
|
1740
|
+
// Medical and Healthcare
|
|
1741
|
+
{
|
|
1742
|
+
name: "hipaa_ndc",
|
|
1743
|
+
pattern: String.raw`\b\\d{4,5}-\\d{3,4}-\\d{1,2}\b`
|
|
1744
|
+
},
|
|
1745
|
+
// Security and Network
|
|
1746
|
+
{
|
|
1747
|
+
name: "cve_numbers",
|
|
1748
|
+
pattern: String.raw`\b[Cc][Vv][Ee]-\\d{4}-\\d{4,7}\b`
|
|
1749
|
+
},
|
|
1750
|
+
{
|
|
1751
|
+
name: "microsoft_oauth",
|
|
1752
|
+
pattern: String.raw`https://login\.microsoftonline\.com/common/oauth2/v2\.0/token|https://login\.windows\.net/common/oauth2/token`
|
|
1753
|
+
},
|
|
1754
|
+
{
|
|
1755
|
+
name: "postgres_connections",
|
|
1756
|
+
pattern: String.raw`\b(?:[Pp][Oo][Ss][Tt][Gg][Rr][Ee][Ss]|[Pp][Gg][Ss][Qq][Ll])\\:\\/\\/`
|
|
1757
|
+
},
|
|
1758
|
+
{
|
|
1759
|
+
name: "box_links",
|
|
1760
|
+
pattern: String.raw`https://app\.box\.com/[s|l]/\S+`
|
|
1761
|
+
},
|
|
1762
|
+
{
|
|
1763
|
+
name: "dropbox_links",
|
|
1764
|
+
pattern: String.raw`https://www\.dropbox\.com/(?:s|l)/\S+`
|
|
1765
|
+
},
|
|
1766
|
+
// Credit Card Variants
|
|
1767
|
+
{
|
|
1768
|
+
name: "amex_cards",
|
|
1769
|
+
pattern: String.raw`\b3[47][0-9]{13}\b`
|
|
1770
|
+
},
|
|
1771
|
+
{
|
|
1772
|
+
name: "visa_cards",
|
|
1773
|
+
pattern: String.raw`\b4[0-9]{12}(?:[0-9]{3})?\b`
|
|
1774
|
+
},
|
|
1775
|
+
{
|
|
1776
|
+
name: "discover_cards",
|
|
1777
|
+
pattern: String.raw`\b65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}\b`
|
|
1778
|
+
},
|
|
1779
|
+
{
|
|
1780
|
+
name: "enhanced_credit_cards",
|
|
1781
|
+
pattern: String.raw`\b((4\\d{3}|5[1-5]\\d{2}|2\\d{3}|3[47]\\d{1,2})[\\s\\-]?\\d{4,6}[\\s\\-]?\\d{4,6}?([\\s\\-]\\d{3,4})?(\\d{3})?)\b`
|
|
1782
|
+
},
|
|
1783
|
+
// Bank Routing Numbers (US specific)
|
|
1784
|
+
{
|
|
1785
|
+
name: "bbva_routing_ca",
|
|
1786
|
+
pattern: String.raw`\\b321170538\\b`
|
|
1787
|
+
},
|
|
1788
|
+
{
|
|
1789
|
+
name: "boa_routing_ca",
|
|
1790
|
+
pattern: String.raw`\\b(?:121|026)00(?:0|9)(?:358|593)\\b`
|
|
1791
|
+
},
|
|
1792
|
+
{
|
|
1793
|
+
name: "chase_routing_ca",
|
|
1794
|
+
pattern: String.raw`\\b322271627\\b`
|
|
1795
|
+
},
|
|
1796
|
+
{
|
|
1797
|
+
name: "citibank_routing_ca",
|
|
1798
|
+
pattern: String.raw`\\b32(?:11|22)71(?:18|72)4\\b`
|
|
1799
|
+
},
|
|
1800
|
+
{
|
|
1801
|
+
name: "usbank_routing_ca",
|
|
1802
|
+
pattern: String.raw`\\b12(?:1122676|2235821)\\b`
|
|
1803
|
+
},
|
|
1804
|
+
{
|
|
1805
|
+
name: "united_bank_routing_ca",
|
|
1806
|
+
pattern: String.raw`\\b122243350\\b`
|
|
1807
|
+
},
|
|
1808
|
+
{
|
|
1809
|
+
name: "wells_fargo_routing_ca",
|
|
1810
|
+
pattern: String.raw`\\b121042882\\b`
|
|
1811
|
+
},
|
|
1812
|
+
// Unrealistic alphanumeric identifiers
|
|
1813
|
+
{
|
|
1814
|
+
name: "generic_non_usual",
|
|
1815
|
+
pattern: String.raw`(?:^|\s)(?=[A-Za-z0-9_\)\*\=@]*[A-Za-z])(?=[A-Za-z0-9_\)\*\=@]*[0-9])([A-Za-z0-9_\)\*\=@]{5,})(?=\s|$)`
|
|
1816
|
+
}
|
|
1817
|
+
];
|
|
1818
|
+
|
|
1819
|
+
// src/internal/masking/utils.ts
|
|
1820
|
+
function isValidPatternName(name) {
|
|
1821
|
+
return /^[a-zA-Z0-9_]+$/.test(name);
|
|
1822
|
+
}
|
|
1823
|
+
function isLikelyReDoSPattern(pattern) {
|
|
1824
|
+
const dangerousPatterns = [
|
|
1825
|
+
// Nested quantifiers like (a+)+, (a*)+, (a+)*
|
|
1826
|
+
/\([^)]*[+*]\)[+*]/,
|
|
1827
|
+
// Alternation with overlapping groups like (a|a)*
|
|
1828
|
+
/\([^)]*\|[^)]*\)[+*]/,
|
|
1829
|
+
// Complex backtracking patterns - but more specific
|
|
1830
|
+
/\([^)]*[+*][^)]*[+*][^)]*\)[+*]/
|
|
1831
|
+
];
|
|
1832
|
+
return dangerousPatterns.some((dangerous) => dangerous.test(pattern));
|
|
1833
|
+
}
|
|
1834
|
+
function getGroupedPattern(patternEntry) {
|
|
1835
|
+
let name = patternEntry.name;
|
|
1836
|
+
if (!name || name === "") {
|
|
1837
|
+
name = `pattern_${Math.random().toString(16).slice(2)}`;
|
|
1838
|
+
}
|
|
1839
|
+
if (!isValidPatternName(name)) {
|
|
1840
|
+
throw new Error(
|
|
1841
|
+
`Pattern name '${name}' must only contain alphanumeric characters and underscores`
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
if (isLikelyReDoSPattern(patternEntry.pattern)) {
|
|
1845
|
+
throw new Error(`Potentially dangerous ReDoS pattern detected: '${patternEntry.pattern}'`);
|
|
1846
|
+
}
|
|
1847
|
+
try {
|
|
1848
|
+
new RegExp(patternEntry.pattern);
|
|
1849
|
+
} catch (error) {
|
|
1850
|
+
throw new Error(`Invalid regex pattern '${patternEntry.pattern}': ${String(error)}`);
|
|
1851
|
+
}
|
|
1852
|
+
return `(?<${name}>${patternEntry.pattern})`;
|
|
1853
|
+
}
|
|
1854
|
+
function isIPatternEntry(obj) {
|
|
1855
|
+
return typeof obj === "object" && obj !== null && typeof obj.pattern === "string" && (obj.name === void 0 || typeof obj.name === "string");
|
|
1856
|
+
}
|
|
1857
|
+
function isIEventMaskingRule(obj) {
|
|
1858
|
+
return typeof obj === "object" && obj !== null && typeof obj.mode === "string" && Array.isArray(obj.patterns) && obj.patterns.every(
|
|
1859
|
+
(p) => isIPatternEntry(p) || typeof p === "string"
|
|
1860
|
+
) && (obj.attributePattern === void 0 || typeof obj.attributePattern === "string");
|
|
1861
|
+
}
|
|
1862
|
+
function convertPatternsToPatternEntries(patterns) {
|
|
1863
|
+
const patternEntries = [];
|
|
1864
|
+
for (const pattern of patterns) {
|
|
1865
|
+
if (typeof pattern === "string") {
|
|
1866
|
+
patternEntries.push({ pattern, name: "" });
|
|
1867
|
+
} else if (isIPatternEntry(pattern)) {
|
|
1868
|
+
patternEntries.push(pattern);
|
|
1869
|
+
} else {
|
|
1870
|
+
throw new Error("Patterns must be either strings or PatternEntry instances");
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
return patternEntries;
|
|
1874
|
+
}
|
|
1875
|
+
function compilePatternEntries(patternEntries) {
|
|
1876
|
+
const patternGroups = [];
|
|
1877
|
+
for (const patternEntry of patternEntries) {
|
|
1878
|
+
try {
|
|
1879
|
+
patternGroups.push(getGroupedPattern(patternEntry));
|
|
1880
|
+
} catch (error) {
|
|
1881
|
+
logger.warn(`Invalid pattern '${patternEntry.name}': ${patternEntry.pattern}`, error);
|
|
1882
|
+
continue;
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
if (patternGroups.length === 0) {
|
|
1886
|
+
return null;
|
|
1887
|
+
}
|
|
1888
|
+
try {
|
|
1889
|
+
return new RegExp(patternGroups.join("|"));
|
|
1890
|
+
} catch (error) {
|
|
1891
|
+
logger.warn("Failed to compile pattern entries into regex", error);
|
|
1892
|
+
return null;
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
function getCompiledAttributeNamePattern(rule) {
|
|
1896
|
+
if (!rule.attributePattern) {
|
|
1897
|
+
logger.debug("No attribute pattern provided, using default .*");
|
|
1898
|
+
return /.*/;
|
|
1899
|
+
}
|
|
1900
|
+
let compiledPatternString = rule.attributePattern;
|
|
1901
|
+
if (isIEventMaskingRule(rule) && rule.eventNamePattern) {
|
|
1902
|
+
compiledPatternString = `(${compiledPatternString})|(${rule.eventNamePattern})`;
|
|
1903
|
+
}
|
|
1904
|
+
return new RegExp(compiledPatternString);
|
|
1905
|
+
}
|
|
1906
|
+
function shouldContinueExecution(startTime, iterations, timeoutMs) {
|
|
1907
|
+
if (Date.now() - startTime > timeoutMs) {
|
|
1908
|
+
logger.warn("Regex execution timed out - potential ReDoS pattern detected");
|
|
1909
|
+
return false;
|
|
1910
|
+
}
|
|
1911
|
+
const maxIterations = 1e3;
|
|
1912
|
+
if (iterations > maxIterations) {
|
|
1913
|
+
logger.warn("Regex execution exceeded maximum iterations - potential ReDoS pattern detected");
|
|
1914
|
+
return false;
|
|
1915
|
+
}
|
|
1916
|
+
return true;
|
|
1917
|
+
}
|
|
1918
|
+
function createGlobalPattern(pattern) {
|
|
1919
|
+
return new RegExp(
|
|
1920
|
+
pattern.source,
|
|
1921
|
+
pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g"
|
|
1922
|
+
);
|
|
1923
|
+
}
|
|
1924
|
+
function executeRegexWithTimeout(pattern, value, timeoutMs = 100) {
|
|
1925
|
+
const matches = [];
|
|
1926
|
+
const globalPattern = createGlobalPattern(pattern);
|
|
1927
|
+
const startTime = Date.now();
|
|
1928
|
+
let match;
|
|
1929
|
+
let iterations = 0;
|
|
1930
|
+
while ((match = globalPattern.exec(value)) !== null) {
|
|
1931
|
+
if (!shouldContinueExecution(startTime, ++iterations, timeoutMs)) {
|
|
1932
|
+
break;
|
|
1933
|
+
}
|
|
1934
|
+
matches.push(match);
|
|
1935
|
+
if (match[0].length === 0) {
|
|
1936
|
+
globalPattern.lastIndex = match.index + 1;
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
return matches;
|
|
1940
|
+
}
|
|
1941
|
+
function maskStringByPattern(value, pattern, mode = "full") {
|
|
1942
|
+
const matches = [];
|
|
1943
|
+
try {
|
|
1944
|
+
const regexMatches = executeRegexWithTimeout(pattern, value);
|
|
1945
|
+
for (const match of regexMatches) {
|
|
1946
|
+
matches.push({
|
|
1947
|
+
start: match.index,
|
|
1948
|
+
end: match.index + match[0].length,
|
|
1949
|
+
text: match[0],
|
|
1950
|
+
groups: match.groups
|
|
1951
|
+
});
|
|
1952
|
+
}
|
|
1953
|
+
} catch (error) {
|
|
1954
|
+
logger.warn("Regex execution failed, skipping masking", error);
|
|
1955
|
+
return value;
|
|
1956
|
+
}
|
|
1957
|
+
for (const matchInfo of matches.reverse()) {
|
|
1958
|
+
let patternName = "unknown";
|
|
1959
|
+
if (matchInfo.groups) {
|
|
1960
|
+
for (const [groupName, groupValue] of Object.entries(matchInfo.groups)) {
|
|
1961
|
+
if (groupValue !== void 0) {
|
|
1962
|
+
if (groupName.includes("_") && /\d$/.test(groupName)) {
|
|
1963
|
+
const parts = groupName.split("_");
|
|
1964
|
+
patternName = parts[0] || groupName;
|
|
1965
|
+
} else {
|
|
1966
|
+
patternName = groupName;
|
|
1967
|
+
}
|
|
1968
|
+
break;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
logger.info(`Masking detected: pattern '${patternName}' found match in value`);
|
|
1973
|
+
const masked = mode === "partial" ? matchInfo.text[0] + "*****" : "*****";
|
|
1974
|
+
value = value.slice(0, matchInfo.start) + masked + value.slice(matchInfo.end);
|
|
1975
|
+
}
|
|
1976
|
+
return value;
|
|
1977
|
+
}
|
|
1978
|
+
function maskStringByPatternBasedRule(value, rule) {
|
|
1979
|
+
const patternEntries = convertPatternsToPatternEntries(rule.patterns);
|
|
1980
|
+
if (patternEntries.length === 0) {
|
|
1981
|
+
logger.warn("No patterns provided for masking rule, returning original value");
|
|
1982
|
+
return value;
|
|
1983
|
+
}
|
|
1984
|
+
const mode = rule.mode;
|
|
1985
|
+
if (!patternEntries || patternEntries.length === 0) {
|
|
1986
|
+
return mode === "partial" && value ? value[0] + "*****" : "*****";
|
|
1987
|
+
}
|
|
1988
|
+
const compiledPatterns = compilePatternEntries(patternEntries);
|
|
1989
|
+
if (!compiledPatterns) {
|
|
1990
|
+
return value;
|
|
1991
|
+
}
|
|
1992
|
+
return maskStringByPattern(value, compiledPatterns, mode);
|
|
1993
|
+
}
|
|
1994
|
+
function maskValue(value, rule) {
|
|
1995
|
+
if (typeof value === "string") {
|
|
1996
|
+
return maskStringByPatternBasedRule(value, rule);
|
|
1997
|
+
} else if (typeof value === "boolean" || typeof value === "number") {
|
|
1998
|
+
return maskStringByPatternBasedRule(String(value), rule);
|
|
1999
|
+
} else if (Array.isArray(value)) {
|
|
2000
|
+
return value.map((v) => maskStringByPatternBasedRule(String(v), rule));
|
|
2001
|
+
} else if (value !== null && typeof value === "object") {
|
|
2002
|
+
const result = {};
|
|
2003
|
+
for (const [k, v] of Object.entries(value)) {
|
|
2004
|
+
result[k] = maskValue(v, rule);
|
|
2005
|
+
}
|
|
2006
|
+
return result;
|
|
2007
|
+
} else {
|
|
2008
|
+
throw new Error(`Unsupported value type for masking: ${typeof value}`);
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
function maskAttributes(attributes, rules, outputOriginalValue = false) {
|
|
2012
|
+
if (!attributes || Object.keys(attributes).length === 0) {
|
|
2013
|
+
return {};
|
|
2014
|
+
}
|
|
2015
|
+
const maskedAttributes = { ...attributes };
|
|
2016
|
+
for (const rule of rules) {
|
|
2017
|
+
const compiledAttributeNamePattern = getCompiledAttributeNamePattern(rule);
|
|
2018
|
+
const attributesToMask = compiledAttributeNamePattern ? Object.keys(maskedAttributes).filter((attr) => compiledAttributeNamePattern.test(attr)) : Object.keys(maskedAttributes);
|
|
2019
|
+
for (const attribute of attributesToMask) {
|
|
2020
|
+
const value = maskedAttributes[attribute];
|
|
2021
|
+
if (value === null || value === void 0) {
|
|
2022
|
+
continue;
|
|
2023
|
+
}
|
|
2024
|
+
if (outputOriginalValue) {
|
|
2025
|
+
logger.debug(`Masking attribute '${attribute}' with original value`, { value });
|
|
2026
|
+
}
|
|
2027
|
+
maskedAttributes[attribute] = maskValue(value, rule);
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
return maskedAttributes;
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
// src/internal/semantic-conventions.ts
|
|
2034
|
+
var import_api8 = require("@opentelemetry/api");
|
|
2035
|
+
var BRIZZ = "brizz";
|
|
2036
|
+
var PROPERTIES = "properties";
|
|
2037
|
+
var SESSION_ID = "session.id";
|
|
2038
|
+
var PROPERTIES_CONTEXT_KEY = (0, import_api8.createContextKey)(PROPERTIES);
|
|
2039
|
+
|
|
2040
|
+
// src/internal/log/processors/log-processor.ts
|
|
2041
|
+
var DEFAULT_LOG_MASKING_RULES = [
|
|
2042
|
+
{
|
|
2043
|
+
mode: "partial",
|
|
2044
|
+
attributePattern: "event.name",
|
|
2045
|
+
patterns: DEFAULT_PII_PATTERNS
|
|
2046
|
+
}
|
|
2047
|
+
];
|
|
2048
|
+
var BrizzSimpleLogRecordProcessor = class extends import_sdk_logs.SimpleLogRecordProcessor {
|
|
2049
|
+
config;
|
|
2050
|
+
constructor(exporter, config) {
|
|
2051
|
+
super(exporter);
|
|
2052
|
+
this.config = config;
|
|
2053
|
+
}
|
|
2054
|
+
onEmit(logRecord) {
|
|
2055
|
+
const maskingConfig = this.config.masking?.eventMasking;
|
|
2056
|
+
if (maskingConfig) {
|
|
2057
|
+
maskLog(logRecord, maskingConfig);
|
|
2058
|
+
}
|
|
2059
|
+
const associationProperties = import_api9.context.active().getValue(PROPERTIES_CONTEXT_KEY);
|
|
2060
|
+
if (associationProperties) {
|
|
2061
|
+
for (const [key, value] of Object.entries(associationProperties)) {
|
|
2062
|
+
logRecord.setAttribute(`${BRIZZ}.${key}`, value);
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
super.onEmit(logRecord);
|
|
2066
|
+
}
|
|
2067
|
+
};
|
|
2068
|
+
var BrizzBatchLogRecordProcessor = class extends import_sdk_logs.BatchLogRecordProcessor {
|
|
2069
|
+
config;
|
|
2070
|
+
constructor(exporter, config) {
|
|
2071
|
+
super(exporter);
|
|
2072
|
+
this.config = config;
|
|
2073
|
+
}
|
|
2074
|
+
onEmit(logRecord) {
|
|
2075
|
+
const maskingConfig = this.config.masking?.eventMasking;
|
|
2076
|
+
if (maskingConfig) {
|
|
2077
|
+
maskLog(logRecord, maskingConfig);
|
|
2078
|
+
}
|
|
2079
|
+
const associationProperties = import_api9.context.active().getValue(PROPERTIES_CONTEXT_KEY);
|
|
2080
|
+
if (associationProperties) {
|
|
2081
|
+
for (const [key, value] of Object.entries(associationProperties)) {
|
|
2082
|
+
logRecord.setAttribute(`${BRIZZ}.${key}`, value);
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
super.onEmit(logRecord);
|
|
2086
|
+
}
|
|
2087
|
+
};
|
|
2088
|
+
function maskLog(logRecord, config) {
|
|
2089
|
+
if (!logRecord.attributes) {
|
|
2090
|
+
return logRecord;
|
|
2091
|
+
}
|
|
2092
|
+
let rules = config.rules || [];
|
|
2093
|
+
if (!config.disableDefaultRules) {
|
|
2094
|
+
rules = [...DEFAULT_LOG_MASKING_RULES, ...rules];
|
|
2095
|
+
}
|
|
2096
|
+
try {
|
|
2097
|
+
if (logRecord.attributes && Object.keys(logRecord.attributes).length > 0) {
|
|
2098
|
+
const attributesRecord = {};
|
|
2099
|
+
for (const [key, value] of Object.entries(logRecord.attributes)) {
|
|
2100
|
+
attributesRecord[key] = value;
|
|
2101
|
+
}
|
|
2102
|
+
const maskedAttributes = maskAttributes(attributesRecord, rules);
|
|
2103
|
+
if (maskedAttributes) {
|
|
2104
|
+
const newAttributes = {};
|
|
2105
|
+
for (const [key, value] of Object.entries(maskedAttributes)) {
|
|
2106
|
+
newAttributes[key] = value;
|
|
2107
|
+
}
|
|
2108
|
+
logRecord.setAttributes(newAttributes);
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
if (config.maskBody && logRecord.body !== void 0 && logRecord.body !== null) {
|
|
2112
|
+
let maskedBody = logRecord.body;
|
|
2113
|
+
for (const rule of rules) {
|
|
2114
|
+
maskedBody = maskValue(maskedBody, rule);
|
|
2115
|
+
}
|
|
2116
|
+
logRecord.setBody(maskedBody);
|
|
2117
|
+
}
|
|
2118
|
+
return logRecord;
|
|
2119
|
+
} catch (error) {
|
|
2120
|
+
logger.error("Error masking log record:", error);
|
|
2121
|
+
return logRecord;
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
// src/internal/log/logging.ts
|
|
2126
|
+
var LoggingModule = class _LoggingModule {
|
|
2127
|
+
static instance = null;
|
|
2128
|
+
logExporter = null;
|
|
2129
|
+
logProcessor = null;
|
|
2130
|
+
loggerProvider = null;
|
|
2131
|
+
static getInstance() {
|
|
2132
|
+
if (!_LoggingModule.instance) {
|
|
2133
|
+
throw new Error("Brizz must be initialized before accessing LoggingModule");
|
|
2134
|
+
}
|
|
2135
|
+
return _LoggingModule.instance;
|
|
2136
|
+
}
|
|
2137
|
+
/**
|
|
2138
|
+
* Initialize the logging module with the provided configuration
|
|
2139
|
+
*/
|
|
2140
|
+
setup(config) {
|
|
2141
|
+
logger.info("Setting up logging module");
|
|
2142
|
+
this.initLogExporter(config);
|
|
2143
|
+
this.initLogProcessor(config);
|
|
2144
|
+
this.initLoggerProvider(config);
|
|
2145
|
+
_LoggingModule.instance = this;
|
|
2146
|
+
logger.info("Logging module setup completed");
|
|
2147
|
+
}
|
|
2148
|
+
/**
|
|
2149
|
+
* Initialize the log exporter
|
|
2150
|
+
*/
|
|
2151
|
+
initLogExporter(config) {
|
|
2152
|
+
if (this.logExporter) {
|
|
2153
|
+
logger.debug("Log exporter already initialized, skipping re-initialization");
|
|
2154
|
+
return;
|
|
2155
|
+
}
|
|
2156
|
+
if (config.customLogExporter) {
|
|
2157
|
+
logger.debug("Using custom log exporter");
|
|
2158
|
+
this.logExporter = config.customLogExporter;
|
|
2159
|
+
logger.debug("Custom log exporter initialized successfully");
|
|
2160
|
+
return;
|
|
2161
|
+
}
|
|
2162
|
+
const logsUrl = config.baseUrl.replace(/\/$/, "") + "/v1/logs";
|
|
2163
|
+
logger.debug("Initializing default OTLP log exporter", { url: logsUrl });
|
|
2164
|
+
const headers = { ...config.headers };
|
|
2165
|
+
this.logExporter = new import_exporter_logs_otlp_http.OTLPLogExporter({
|
|
2166
|
+
url: logsUrl,
|
|
2167
|
+
headers
|
|
2168
|
+
});
|
|
2169
|
+
logger.debug("OTLP log exporter initialized successfully");
|
|
2170
|
+
}
|
|
2171
|
+
/**
|
|
2172
|
+
* Initialize the log processor with masking support
|
|
2173
|
+
*/
|
|
2174
|
+
initLogProcessor(config) {
|
|
2175
|
+
if (this.logProcessor) {
|
|
2176
|
+
logger.debug("Log processor already initialized, skipping re-initialization");
|
|
2177
|
+
return;
|
|
2178
|
+
}
|
|
2179
|
+
if (!this.logExporter) {
|
|
2180
|
+
throw new Error("Log exporter must be initialized before processor");
|
|
2181
|
+
}
|
|
2182
|
+
logger.debug("Initializing log processor", {
|
|
2183
|
+
disableBatch: config.disableBatch,
|
|
2184
|
+
hasMasking: !!config.masking?.eventMasking
|
|
2185
|
+
});
|
|
2186
|
+
this.logProcessor = config.disableBatch ? new BrizzSimpleLogRecordProcessor(this.logExporter, config) : new BrizzBatchLogRecordProcessor(this.logExporter, config);
|
|
2187
|
+
logger.debug("Log processor initialized successfully");
|
|
2188
|
+
}
|
|
2189
|
+
/**
|
|
2190
|
+
* Initialize the logger provider
|
|
2191
|
+
*/
|
|
2192
|
+
initLoggerProvider(config) {
|
|
2193
|
+
if (this.loggerProvider) {
|
|
2194
|
+
logger.debug("Logger provider already initialized, skipping re-initialization");
|
|
2195
|
+
return;
|
|
2196
|
+
}
|
|
2197
|
+
if (!this.logProcessor) {
|
|
2198
|
+
throw new Error("Log processor must be initialized before logger provider");
|
|
2199
|
+
}
|
|
2200
|
+
logger.debug("Creating resource with service name", {
|
|
2201
|
+
serviceName: config.appName
|
|
2202
|
+
});
|
|
2203
|
+
const resource = (0, import_resources.resourceFromAttributes)({
|
|
2204
|
+
"service.name": config.appName
|
|
2205
|
+
});
|
|
2206
|
+
logger.debug("Creating logger provider with resource");
|
|
2207
|
+
this.loggerProvider = new import_sdk_logs2.LoggerProvider({
|
|
2208
|
+
resource,
|
|
2209
|
+
processors: [this.logProcessor]
|
|
2210
|
+
});
|
|
2211
|
+
logger.debug("Logger provider initialization completed");
|
|
2212
|
+
}
|
|
2213
|
+
/**
|
|
2214
|
+
* Emit a custom event to the telemetry pipeline
|
|
2215
|
+
*/
|
|
2216
|
+
emitEvent(name, attributes, body, severityNumber = import_api_logs2.SeverityNumber.INFO) {
|
|
2217
|
+
logger.debug("Attempting to emit event", {
|
|
2218
|
+
name,
|
|
2219
|
+
hasAttributes: !!attributes,
|
|
2220
|
+
attributesCount: attributes ? Object.keys(attributes).length : 0,
|
|
2221
|
+
hasBody: !!body,
|
|
2222
|
+
severityNumber
|
|
2223
|
+
});
|
|
2224
|
+
if (!this.loggerProvider) {
|
|
2225
|
+
logger.error("Cannot emit event: Logger provider not initialized");
|
|
2226
|
+
throw new Error("Logging module not initialized");
|
|
2227
|
+
}
|
|
2228
|
+
const logAttributes = { "event.name": name };
|
|
2229
|
+
if (attributes) {
|
|
2230
|
+
Object.assign(logAttributes, attributes);
|
|
2231
|
+
logger.debug("Combined log attributes", { attributes: Object.keys(logAttributes) });
|
|
2232
|
+
}
|
|
2233
|
+
logger.debug("Getting logger instance for brizz_events");
|
|
2234
|
+
const eventLogger = this.loggerProvider.getLogger("brizz.events");
|
|
2235
|
+
logger.debug("Emitting log record with eventName", { eventName: name });
|
|
2236
|
+
try {
|
|
2237
|
+
eventLogger.emit({
|
|
2238
|
+
eventName: name,
|
|
2239
|
+
attributes: logAttributes,
|
|
2240
|
+
severityNumber,
|
|
2241
|
+
body
|
|
2242
|
+
});
|
|
2243
|
+
logger.debug("Event successfully emitted", { eventName: name });
|
|
2244
|
+
} catch (error) {
|
|
2245
|
+
logger.error(`Failed to emit event '${name}'`, { error, eventName: name });
|
|
2246
|
+
logger.error("Log record that failed", {
|
|
2247
|
+
eventName: name,
|
|
2248
|
+
hasAttributes: logAttributes,
|
|
2249
|
+
severityNumber,
|
|
2250
|
+
hasBody: body
|
|
2251
|
+
});
|
|
2252
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
/**
|
|
2256
|
+
* Check if the module is initialized
|
|
2257
|
+
*/
|
|
2258
|
+
isInitialized() {
|
|
2259
|
+
return this.loggerProvider !== null;
|
|
2260
|
+
}
|
|
2261
|
+
/**
|
|
2262
|
+
* Get the logger provider
|
|
2263
|
+
*/
|
|
2264
|
+
getLoggerProvider() {
|
|
2265
|
+
return this.loggerProvider;
|
|
2266
|
+
}
|
|
2267
|
+
/**
|
|
2268
|
+
* Shutdown the logging module
|
|
2269
|
+
*/
|
|
2270
|
+
async shutdown() {
|
|
2271
|
+
logger.debug("Shutting down logging module");
|
|
2272
|
+
if (this.loggerProvider) {
|
|
2273
|
+
await this.loggerProvider.shutdown();
|
|
2274
|
+
this.loggerProvider = null;
|
|
2275
|
+
}
|
|
2276
|
+
this.logProcessor = null;
|
|
2277
|
+
this.logExporter = null;
|
|
2278
|
+
if (_LoggingModule.instance === this) {
|
|
2279
|
+
_LoggingModule.instance = null;
|
|
2280
|
+
}
|
|
2281
|
+
logger.debug("Logging module shutdown completed");
|
|
2282
|
+
}
|
|
2283
|
+
};
|
|
2284
|
+
function emitEvent(name, attributes, body, severityNumber = import_api_logs2.SeverityNumber.INFO) {
|
|
2285
|
+
return LoggingModule.getInstance().emitEvent(name, attributes, body, severityNumber);
|
|
2286
|
+
}
|
|
2287
|
+
|
|
2288
|
+
// src/internal/metric/metrics.ts
|
|
2289
|
+
var import_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
|
|
2290
|
+
var import_sdk_metrics = require("@opentelemetry/sdk-metrics");
|
|
2291
|
+
var MetricsModule = class _MetricsModule {
|
|
2292
|
+
static instance = null;
|
|
2293
|
+
metricsExporter = null;
|
|
2294
|
+
metricsReader = null;
|
|
2295
|
+
static getInstance() {
|
|
2296
|
+
if (!_MetricsModule.instance) {
|
|
2297
|
+
throw new Error("Brizz must be initialized before accessing MetricsModule");
|
|
2298
|
+
}
|
|
2299
|
+
return _MetricsModule.instance;
|
|
2300
|
+
}
|
|
2301
|
+
/**
|
|
2302
|
+
* Initialize the metrics module with the provided configuration
|
|
2303
|
+
*/
|
|
2304
|
+
setup(config) {
|
|
2305
|
+
logger.info("Setting up metrics module");
|
|
2306
|
+
this.initMetricsReader(config);
|
|
2307
|
+
_MetricsModule.instance = this;
|
|
2308
|
+
logger.info("Metrics module setup completed");
|
|
2309
|
+
}
|
|
2310
|
+
/**
|
|
2311
|
+
* Initialize the metrics exporter
|
|
2312
|
+
*/
|
|
2313
|
+
initMetricsExporter(config) {
|
|
2314
|
+
if (this.metricsExporter) {
|
|
2315
|
+
logger.debug("Metrics exporter already initialized, skipping re-initialization");
|
|
2316
|
+
return;
|
|
2317
|
+
}
|
|
2318
|
+
const metricsUrl = config.baseUrl.replace(/\/$/, "") + "/v1/metrics";
|
|
2319
|
+
logger.debug("Initializing metrics exporter", { url: metricsUrl });
|
|
2320
|
+
this.metricsExporter = new import_exporter_metrics_otlp_http.OTLPMetricExporter({
|
|
2321
|
+
url: metricsUrl,
|
|
2322
|
+
headers: config.headers
|
|
2323
|
+
});
|
|
2324
|
+
logger.debug("Metrics exporter initialized successfully");
|
|
2325
|
+
}
|
|
2326
|
+
/**
|
|
2327
|
+
* Initialize the metrics reader
|
|
2328
|
+
*/
|
|
2329
|
+
initMetricsReader(config) {
|
|
2330
|
+
if (this.metricsReader) {
|
|
2331
|
+
logger.debug("Metrics reader already initialized, skipping re-initialization");
|
|
2332
|
+
return;
|
|
2333
|
+
}
|
|
2334
|
+
if (config.customMetricReader) {
|
|
2335
|
+
logger.debug("Using custom metric reader");
|
|
2336
|
+
this.metricsReader = config.customMetricReader;
|
|
2337
|
+
logger.debug("Custom metric reader initialized successfully");
|
|
2338
|
+
return;
|
|
2339
|
+
}
|
|
2340
|
+
logger.debug(
|
|
2341
|
+
"Using default metrics flow - creating OTLP exporter and PeriodicExportingMetricReader"
|
|
2342
|
+
);
|
|
2343
|
+
this.initMetricsExporter(config);
|
|
2344
|
+
if (!this.metricsExporter) {
|
|
2345
|
+
throw new Error("Failed to initialize metrics exporter");
|
|
2346
|
+
}
|
|
2347
|
+
this.metricsReader = new import_sdk_metrics.PeriodicExportingMetricReader({
|
|
2348
|
+
exporter: this.metricsExporter
|
|
2349
|
+
});
|
|
2350
|
+
logger.debug("Default metrics reader initialized successfully");
|
|
2351
|
+
}
|
|
2352
|
+
/**
|
|
2353
|
+
* Get the metrics exporter
|
|
2354
|
+
*/
|
|
2355
|
+
getMetricsExporter() {
|
|
2356
|
+
if (!this.metricsExporter) {
|
|
2357
|
+
throw new Error("Metrics module not initialized");
|
|
2358
|
+
}
|
|
2359
|
+
return this.metricsExporter;
|
|
2360
|
+
}
|
|
2361
|
+
/**
|
|
2362
|
+
* Get the metrics reader
|
|
2363
|
+
*/
|
|
2364
|
+
getMetricsReader() {
|
|
2365
|
+
if (!this.metricsReader) {
|
|
2366
|
+
throw new Error("Metrics module not initialized");
|
|
2367
|
+
}
|
|
2368
|
+
return this.metricsReader;
|
|
2369
|
+
}
|
|
2370
|
+
/**
|
|
2371
|
+
* Shutdown the metrics module
|
|
2372
|
+
*/
|
|
2373
|
+
shutdown() {
|
|
2374
|
+
logger.debug("Shutting down metrics module");
|
|
2375
|
+
this.metricsReader = null;
|
|
2376
|
+
this.metricsExporter = null;
|
|
2377
|
+
if (_MetricsModule.instance === this) {
|
|
2378
|
+
_MetricsModule.instance = null;
|
|
2379
|
+
}
|
|
2380
|
+
logger.debug("Metrics module shutdown completed");
|
|
2381
|
+
}
|
|
2382
|
+
};
|
|
2383
|
+
function getMetricsExporter() {
|
|
2384
|
+
return MetricsModule.getInstance().getMetricsExporter();
|
|
2385
|
+
}
|
|
2386
|
+
function getMetricsReader() {
|
|
2387
|
+
return MetricsModule.getInstance().getMetricsReader();
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
// src/internal/trace/tracing.ts
|
|
2391
|
+
var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
|
|
2392
|
+
|
|
2393
|
+
// src/internal/trace/processors/span-processor.ts
|
|
2394
|
+
var import_api10 = require("@opentelemetry/api");
|
|
2395
|
+
var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
|
|
2396
|
+
var DEFAULT_MASKING_RULES = [
|
|
2397
|
+
{
|
|
2398
|
+
mode: "partial",
|
|
2399
|
+
attributePattern: "gen_ai.prompt",
|
|
2400
|
+
patterns: DEFAULT_PII_PATTERNS
|
|
2401
|
+
},
|
|
2402
|
+
{
|
|
2403
|
+
mode: "partial",
|
|
2404
|
+
attributePattern: "gen_ai.completion",
|
|
2405
|
+
patterns: DEFAULT_PII_PATTERNS
|
|
2406
|
+
},
|
|
2407
|
+
{
|
|
2408
|
+
mode: "partial",
|
|
2409
|
+
attributePattern: "traceloop.entity.input",
|
|
2410
|
+
patterns: DEFAULT_PII_PATTERNS
|
|
2411
|
+
},
|
|
2412
|
+
{
|
|
2413
|
+
mode: "partial",
|
|
2414
|
+
attributePattern: "traceloop.entity.output",
|
|
2415
|
+
patterns: DEFAULT_PII_PATTERNS
|
|
2416
|
+
}
|
|
2417
|
+
];
|
|
2418
|
+
var BrizzSimpleSpanProcessor = class extends import_sdk_trace_base.SimpleSpanProcessor {
|
|
2419
|
+
config;
|
|
2420
|
+
constructor(spanExporter, config) {
|
|
2421
|
+
super(spanExporter);
|
|
2422
|
+
this.config = config;
|
|
2423
|
+
}
|
|
2424
|
+
// Will work with the following code:
|
|
2425
|
+
// const span = tracer.startSpan('sensitive-operation',{attributes:{
|
|
2426
|
+
// 'user.password': 'secret123',
|
|
2427
|
+
// 'user.email': 'user@example.com',
|
|
2428
|
+
// }});
|
|
2429
|
+
//
|
|
2430
|
+
// Won't work because onStart is called before attributes are set:
|
|
2431
|
+
// span.setAttributes({
|
|
2432
|
+
// 'user.password': 'secret123',
|
|
2433
|
+
// 'user.email': 'user@example.com'
|
|
2434
|
+
// });
|
|
2435
|
+
onStart(span, parentContext) {
|
|
2436
|
+
const maskingConfig = this.config.masking?.spanMasking;
|
|
2437
|
+
if (maskingConfig) {
|
|
2438
|
+
maskSpan(span, maskingConfig);
|
|
2439
|
+
}
|
|
2440
|
+
const associationProperties = import_api10.context.active().getValue(PROPERTIES_CONTEXT_KEY);
|
|
2441
|
+
if (associationProperties) {
|
|
2442
|
+
for (const [key, value] of Object.entries(associationProperties)) {
|
|
2443
|
+
span.setAttribute(`${BRIZZ}.${key}`, value);
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
super.onStart(span, parentContext);
|
|
2447
|
+
}
|
|
2448
|
+
};
|
|
2449
|
+
var BrizzBatchSpanProcessor = class extends import_sdk_trace_base.BatchSpanProcessor {
|
|
2450
|
+
config;
|
|
2451
|
+
constructor(spanExporter, config) {
|
|
2452
|
+
super(spanExporter);
|
|
2453
|
+
this.config = config;
|
|
2454
|
+
}
|
|
2455
|
+
onStart(span, parentContext) {
|
|
2456
|
+
const maskingConfig = this.config.masking?.spanMasking;
|
|
2457
|
+
if (maskingConfig) {
|
|
2458
|
+
maskSpan(span, maskingConfig);
|
|
2459
|
+
}
|
|
2460
|
+
const associationProperties = import_api10.context.active().getValue(PROPERTIES_CONTEXT_KEY);
|
|
2461
|
+
if (associationProperties) {
|
|
2462
|
+
for (const [key, value] of Object.entries(associationProperties)) {
|
|
2463
|
+
span.setAttribute(`${BRIZZ}.${key}`, value);
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
super.onStart(span, parentContext);
|
|
2467
|
+
}
|
|
2468
|
+
};
|
|
2469
|
+
function maskSpan(span, config) {
|
|
2470
|
+
if (!span.attributes || Object.keys(span.attributes).length === 0) {
|
|
2471
|
+
return span;
|
|
2472
|
+
}
|
|
2473
|
+
let rules = config.rules || [];
|
|
2474
|
+
if (!config.disableDefaultRules) {
|
|
2475
|
+
rules = [...DEFAULT_MASKING_RULES, ...rules];
|
|
2476
|
+
}
|
|
2477
|
+
try {
|
|
2478
|
+
const attributesRecord = {};
|
|
2479
|
+
for (const [key, value] of Object.entries(span.attributes)) {
|
|
2480
|
+
attributesRecord[key] = value;
|
|
2481
|
+
}
|
|
2482
|
+
const maskedAttributes = maskAttributes(attributesRecord, rules);
|
|
2483
|
+
if (maskedAttributes && Object.keys(maskedAttributes).length > 0) {
|
|
2484
|
+
const merged = { ...span.attributes };
|
|
2485
|
+
for (const [key, value] of Object.entries(maskedAttributes)) {
|
|
2486
|
+
merged[key] = value;
|
|
2487
|
+
}
|
|
2488
|
+
span.setAttributes(merged);
|
|
2489
|
+
}
|
|
2490
|
+
return span;
|
|
2491
|
+
} catch (error) {
|
|
2492
|
+
logger.error("Error masking span:", error);
|
|
2493
|
+
return span;
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
// src/internal/trace/tracing.ts
|
|
2498
|
+
var TracingModule = class _TracingModule {
|
|
2499
|
+
static instance = null;
|
|
2500
|
+
spanExporter = null;
|
|
2501
|
+
spanProcessor = null;
|
|
2502
|
+
static getInstance() {
|
|
2503
|
+
if (!_TracingModule.instance) {
|
|
2504
|
+
throw new Error("Brizz must be initialized before accessing TracingModule");
|
|
2505
|
+
}
|
|
2506
|
+
return _TracingModule.instance;
|
|
2507
|
+
}
|
|
2508
|
+
/**
|
|
2509
|
+
* Initialize the tracing module with the provided configuration
|
|
2510
|
+
*/
|
|
2511
|
+
setup(config) {
|
|
2512
|
+
logger.info("Setting up tracing module");
|
|
2513
|
+
this.initSpanExporter(config);
|
|
2514
|
+
this.initSpanProcessor(config);
|
|
2515
|
+
_TracingModule.instance = this;
|
|
2516
|
+
logger.info("Tracing module setup completed");
|
|
2517
|
+
}
|
|
2518
|
+
/**
|
|
2519
|
+
* Initialize the span exporter
|
|
2520
|
+
*/
|
|
2521
|
+
initSpanExporter(config) {
|
|
2522
|
+
if (this.spanExporter) {
|
|
2523
|
+
logger.debug("Span exporter already initialized, skipping re-initialization");
|
|
2524
|
+
return;
|
|
2525
|
+
}
|
|
2526
|
+
if (config.customSpanExporter) {
|
|
2527
|
+
logger.debug("Using custom span exporter");
|
|
2528
|
+
this.spanExporter = config.customSpanExporter;
|
|
2529
|
+
logger.debug("Custom span exporter initialized successfully");
|
|
2530
|
+
return;
|
|
2531
|
+
}
|
|
2532
|
+
const tracesUrl = config.baseUrl.replace(/\/$/, "") + "/v1/traces";
|
|
2533
|
+
logger.debug("Initializing default OTLP span exporter", { url: tracesUrl });
|
|
2534
|
+
this.spanExporter = new import_exporter_trace_otlp_http.OTLPTraceExporter({
|
|
2535
|
+
url: tracesUrl,
|
|
2536
|
+
headers: config.headers
|
|
2537
|
+
});
|
|
2538
|
+
logger.debug("OTLP span exporter initialized successfully");
|
|
2539
|
+
}
|
|
2540
|
+
/**
|
|
2541
|
+
* Initialize the span processor with masking support
|
|
2542
|
+
*/
|
|
2543
|
+
initSpanProcessor(config) {
|
|
2544
|
+
if (this.spanProcessor) {
|
|
2545
|
+
logger.debug("Span processor already initialized, skipping re-initialization");
|
|
2546
|
+
return;
|
|
2547
|
+
}
|
|
2548
|
+
if (!this.spanExporter) {
|
|
2549
|
+
throw new Error("Span exporter must be initialized before processor");
|
|
2550
|
+
}
|
|
2551
|
+
logger.debug("Initializing span processor", {
|
|
2552
|
+
disableBatch: config.disableBatch,
|
|
2553
|
+
hasMasking: !!config.masking?.spanMasking
|
|
2554
|
+
});
|
|
2555
|
+
this.spanProcessor = config.disableBatch ? new BrizzSimpleSpanProcessor(this.spanExporter, config) : new BrizzBatchSpanProcessor(this.spanExporter, config);
|
|
2556
|
+
logger.debug("Span processor initialized successfully");
|
|
2557
|
+
}
|
|
2558
|
+
/**
|
|
2559
|
+
* Get the span exporter
|
|
2560
|
+
*/
|
|
2561
|
+
getSpanExporter() {
|
|
2562
|
+
if (!this.spanExporter) {
|
|
2563
|
+
throw new Error("Tracing module not initialized");
|
|
2564
|
+
}
|
|
2565
|
+
return this.spanExporter;
|
|
2566
|
+
}
|
|
2567
|
+
/**
|
|
2568
|
+
* Get the span processor
|
|
2569
|
+
*/
|
|
2570
|
+
getSpanProcessor() {
|
|
2571
|
+
if (!this.spanProcessor) {
|
|
2572
|
+
throw new Error("Tracing module not initialized");
|
|
2573
|
+
}
|
|
2574
|
+
return this.spanProcessor;
|
|
2575
|
+
}
|
|
2576
|
+
async shutdown() {
|
|
2577
|
+
logger.debug("Shutting down tracing module");
|
|
2578
|
+
if (this.spanProcessor) {
|
|
2579
|
+
await this.spanProcessor.shutdown();
|
|
2580
|
+
this.spanProcessor = null;
|
|
2581
|
+
}
|
|
2582
|
+
if (this.spanExporter) {
|
|
2583
|
+
await this.spanExporter.shutdown();
|
|
2584
|
+
this.spanExporter = null;
|
|
2585
|
+
}
|
|
2586
|
+
_TracingModule.instance = null;
|
|
2587
|
+
logger.debug("Tracing module shutdown completed");
|
|
2588
|
+
}
|
|
2589
|
+
};
|
|
2590
|
+
function getSpanExporter() {
|
|
2591
|
+
return TracingModule.getInstance().getSpanExporter();
|
|
2592
|
+
}
|
|
2593
|
+
function getSpanProcessor() {
|
|
2594
|
+
return TracingModule.getInstance().getSpanProcessor();
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
// src/internal/trace/session.ts
|
|
2598
|
+
var import_api11 = require("@opentelemetry/api");
|
|
2599
|
+
function withProperties(properties, fn, thisArg, ...args) {
|
|
2600
|
+
if (Object.keys(properties).length === 0) {
|
|
2601
|
+
return fn.apply(thisArg, args);
|
|
2602
|
+
}
|
|
2603
|
+
const newContext = import_api11.context.active().setValue(PROPERTIES_CONTEXT_KEY, properties);
|
|
2604
|
+
return import_api11.context.with(newContext, fn, thisArg, ...args);
|
|
2605
|
+
}
|
|
2606
|
+
function WithSessionId(sessionId, fn, thisArg, ...args) {
|
|
2607
|
+
return withProperties({ [SESSION_ID]: sessionId }, fn, thisArg, ...args);
|
|
2608
|
+
}
|
|
2609
|
+
|
|
2610
|
+
// src/internal/sdk.ts
|
|
2611
|
+
var _Brizz = class __Brizz {
|
|
2612
|
+
static instance = null;
|
|
2613
|
+
/** Flag indicating if SDK initialization has completed successfully */
|
|
2614
|
+
_initialized = false;
|
|
2615
|
+
/** OpenTelemetry sdk instance */
|
|
2616
|
+
_sdk = null;
|
|
2617
|
+
static getInstance() {
|
|
2618
|
+
if (!__Brizz.instance) {
|
|
2619
|
+
throw new Error("Brizz must be initialized before accessing TracingModule");
|
|
2620
|
+
}
|
|
2621
|
+
return __Brizz.instance;
|
|
2622
|
+
}
|
|
2623
|
+
/**
|
|
2624
|
+
* Initialize the Brizz SDK with the provided configuration.
|
|
2625
|
+
*
|
|
2626
|
+
* @param {IBrizzInitializeOptions} options - Configuration options for the SDK
|
|
2627
|
+
* @throws {Error} - If initialization fails
|
|
2628
|
+
*
|
|
2629
|
+
* @example
|
|
2630
|
+
* ```typescript
|
|
2631
|
+
* Brizz.initialize({
|
|
2632
|
+
* appName: 'my-app',
|
|
2633
|
+
* baseUrl: 'http://localhost:4318',
|
|
2634
|
+
* apiKey: 'your-api-key'
|
|
2635
|
+
* });
|
|
2636
|
+
* ```
|
|
2637
|
+
*/
|
|
2638
|
+
initialize(options) {
|
|
2639
|
+
if (this._initialized) {
|
|
2640
|
+
logger.warn("Brizz SDK already initialized");
|
|
2641
|
+
return;
|
|
2642
|
+
}
|
|
2643
|
+
logger.info("Starting Brizz SDK initialization");
|
|
2644
|
+
try {
|
|
2645
|
+
const resolvedConfig = resolveConfig(options);
|
|
2646
|
+
this.initializeModules(resolvedConfig);
|
|
2647
|
+
this.setupInstrumentation(options);
|
|
2648
|
+
this.createAndStartNodeSDK(options, resolvedConfig);
|
|
2649
|
+
this._initialized = true;
|
|
2650
|
+
logger.info("Brizz SDK initialization completed successfully", {
|
|
2651
|
+
moduleSystem: this.detectModuleSystem()
|
|
2652
|
+
});
|
|
2653
|
+
} catch (error) {
|
|
2654
|
+
logger.error("Failed to initialize Brizz SDK", { error });
|
|
2655
|
+
throw new Error(`Failed to initialize SDK: ${String(error)}`);
|
|
2656
|
+
}
|
|
2657
|
+
}
|
|
2658
|
+
/**
|
|
2659
|
+
* Set up instrumentation registry and configure manual modules.
|
|
2660
|
+
* @private
|
|
2661
|
+
*/
|
|
2662
|
+
setupInstrumentation(options) {
|
|
2663
|
+
const registry = InstrumentationRegistry.getInstance();
|
|
2664
|
+
if (options.instrumentModules && Object.keys(options.instrumentModules).length > 0) {
|
|
2665
|
+
registry.setManualModules(options.instrumentModules);
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
/**
|
|
2669
|
+
* Create and start NodeSDK if not disabled.
|
|
2670
|
+
* Only handles manual instrumentations now - auto instrumentations are loaded at import time.
|
|
2671
|
+
* @private
|
|
2672
|
+
*/
|
|
2673
|
+
createAndStartNodeSDK(options, resolvedConfig) {
|
|
2674
|
+
if (options.disableNodeSdk) {
|
|
2675
|
+
logger.info("NodeSDK disabled - only telemetry modules initialized");
|
|
2676
|
+
return;
|
|
2677
|
+
}
|
|
2678
|
+
const registry = InstrumentationRegistry.getInstance();
|
|
2679
|
+
const manualInstrumentations = registry.getManualInstrumentations();
|
|
2680
|
+
this._sdk = new import_sdk_node.NodeSDK({
|
|
2681
|
+
spanProcessors: [getSpanProcessor()],
|
|
2682
|
+
metricReader: getMetricsReader(),
|
|
2683
|
+
resource: (0, import_resources2.resourceFromAttributes)({
|
|
2684
|
+
"service.name": resolvedConfig.appName
|
|
2685
|
+
}),
|
|
2686
|
+
instrumentations: manualInstrumentations
|
|
2687
|
+
});
|
|
2688
|
+
this._sdk.start();
|
|
2689
|
+
if (manualInstrumentations.length > 0) {
|
|
2690
|
+
logger.info(`NodeSDK started with ${manualInstrumentations.length} manual instrumentations`);
|
|
2691
|
+
} else {
|
|
2692
|
+
logger.info("NodeSDK started - using auto-instrumentations loaded at import time");
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
/**
|
|
2696
|
+
* Initialize telemetry modules.
|
|
2697
|
+
*
|
|
2698
|
+
* Sets up the tracing, metrics, and logging modules with their
|
|
2699
|
+
* respective exporters and processors.
|
|
2700
|
+
*
|
|
2701
|
+
* @param {IResolvedBrizzConfig} config - Resolved configuration
|
|
2702
|
+
* @private
|
|
2703
|
+
*/
|
|
2704
|
+
initializeModules(config) {
|
|
2705
|
+
logger.info("Initializing telemetry modules");
|
|
2706
|
+
logger.debug("Initializing tracing module");
|
|
2707
|
+
const tracingModule = new TracingModule();
|
|
2708
|
+
tracingModule.setup(config);
|
|
2709
|
+
logger.debug("Initializing metrics module");
|
|
2710
|
+
const metricsModule = new MetricsModule();
|
|
2711
|
+
metricsModule.setup(config);
|
|
2712
|
+
logger.debug("Initializing logging module");
|
|
2713
|
+
const loggingModule = new LoggingModule();
|
|
2714
|
+
loggingModule.setup(config);
|
|
2715
|
+
logger.info("All telemetry modules initialized successfully");
|
|
2716
|
+
}
|
|
2717
|
+
/**
|
|
2718
|
+
* Detect the current module system (ESM or CJS) using reliable indicators
|
|
2719
|
+
*
|
|
2720
|
+
* @returns {string} - 'ESM' or 'CJS'
|
|
2721
|
+
* @private
|
|
2722
|
+
*/
|
|
2723
|
+
detectModuleSystem() {
|
|
2724
|
+
const inCJS = typeof module !== "undefined" && typeof exports !== "undefined" && typeof require === "function" && typeof __filename === "string" && typeof __dirname === "string" && this === (typeof exports !== "undefined" ? exports : void 0);
|
|
2725
|
+
return inCJS ? "CJS" : "ESM";
|
|
2726
|
+
}
|
|
2727
|
+
/**
|
|
2728
|
+
* Gracefully shutdown the Brizz SDK.
|
|
2729
|
+
*
|
|
2730
|
+
* This method stops all telemetry collection, flushes any pending data,
|
|
2731
|
+
* and releases resources. Should be called before application termination.
|
|
2732
|
+
*
|
|
2733
|
+
* @returns {Promise<void>} - Resolves when shutdown is complete
|
|
2734
|
+
* @throws {Error} - If shutdown fails
|
|
2735
|
+
*
|
|
2736
|
+
* @example
|
|
2737
|
+
* ```typescript
|
|
2738
|
+
* // Shutdown before app exit
|
|
2739
|
+
* await Brizz.shutdown();
|
|
2740
|
+
* ```
|
|
2741
|
+
*/
|
|
2742
|
+
async shutdown() {
|
|
2743
|
+
if (!this._initialized) {
|
|
2744
|
+
logger.warn("Brizz SDK not initialized");
|
|
2745
|
+
return;
|
|
2746
|
+
}
|
|
2747
|
+
try {
|
|
2748
|
+
await this.shutdownModules();
|
|
2749
|
+
await this._sdk?.shutdown();
|
|
2750
|
+
this._initialized = false;
|
|
2751
|
+
this._sdk = null;
|
|
2752
|
+
__Brizz.instance = null;
|
|
2753
|
+
logger.info("Brizz SDK shut down successfully");
|
|
2754
|
+
} catch (error) {
|
|
2755
|
+
if (error instanceof Error && error.message.includes("ENOTFOUND")) {
|
|
2756
|
+
logger.debug(`Network error during shutdown (expected in tests): ${error.message}`);
|
|
2757
|
+
} else {
|
|
2758
|
+
logger.error(`Failed to shutdown Brizz SDK: ${String(error)}`);
|
|
2759
|
+
throw error;
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
/**
|
|
2764
|
+
* Shutdown all telemetry modules.
|
|
2765
|
+
* @private
|
|
2766
|
+
*/
|
|
2767
|
+
async shutdownModules() {
|
|
2768
|
+
logger.info("Shutting down telemetry modules");
|
|
2769
|
+
try {
|
|
2770
|
+
try {
|
|
2771
|
+
const tracingModule = TracingModule.getInstance();
|
|
2772
|
+
await tracingModule.shutdown();
|
|
2773
|
+
} catch {
|
|
2774
|
+
logger.debug("Tracing module already shut down or not initialized");
|
|
2775
|
+
}
|
|
2776
|
+
try {
|
|
2777
|
+
const metricsModule = MetricsModule.getInstance();
|
|
2778
|
+
metricsModule.shutdown();
|
|
2779
|
+
} catch {
|
|
2780
|
+
logger.debug("Metrics module already shut down or not initialized");
|
|
2781
|
+
}
|
|
2782
|
+
try {
|
|
2783
|
+
const loggingModule = LoggingModule.getInstance();
|
|
2784
|
+
await loggingModule.shutdown();
|
|
2785
|
+
} catch {
|
|
2786
|
+
logger.debug("Logging module already shut down or not initialized");
|
|
2787
|
+
}
|
|
2788
|
+
logger.info("All telemetry modules shut down successfully");
|
|
2789
|
+
} catch (error) {
|
|
2790
|
+
logger.error("Error shutting down modules", { error });
|
|
2791
|
+
throw error;
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
};
|
|
2795
|
+
var Brizz = new _Brizz();
|
|
2796
|
+
|
|
2797
|
+
// src/index.ts
|
|
2798
|
+
var import_api_logs3 = require("@opentelemetry/api-logs");
|
|
2799
|
+
|
|
2800
|
+
// src/node/runtime.ts
|
|
2801
|
+
function detectRuntime() {
|
|
2802
|
+
const [major, minor] = process.versions.node.split(".").map(Number);
|
|
2803
|
+
const noNodeJSGlobals = typeof __filename === "undefined" && typeof __dirname === "undefined";
|
|
2804
|
+
const noModuleSystem = typeof module === "undefined" && typeof exports === "undefined";
|
|
2805
|
+
const hasRequire = typeof require === "function";
|
|
2806
|
+
const isESM = noNodeJSGlobals && noModuleSystem;
|
|
2807
|
+
const isCJS = hasRequire && typeof module !== "undefined" && typeof exports !== "undefined" && typeof __filename === "string" && typeof __dirname === "string";
|
|
2808
|
+
const supportsLoaderAPI = (major ?? 0) >= 21 || (major ?? 0) === 20 && (minor ?? 0) >= 6 || (major ?? 0) === 18 && (minor ?? 0) >= 19;
|
|
2809
|
+
const supportsRegister = !!process.features?.typescript || !!globalThis.module?.register;
|
|
2810
|
+
logger.debug("Runtime detection results:", {
|
|
2811
|
+
nodeVersion: `${major ?? 0}.${minor ?? 0}`,
|
|
2812
|
+
isESM,
|
|
2813
|
+
isCJS,
|
|
2814
|
+
supportsLoaderAPI,
|
|
2815
|
+
supportsRegister,
|
|
2816
|
+
detectionLogic: {
|
|
2817
|
+
noNodeJSGlobals,
|
|
2818
|
+
noModuleSystem,
|
|
2819
|
+
hasRequire,
|
|
2820
|
+
esmCondition: `${noNodeJSGlobals} && ${noModuleSystem} = ${isESM}`,
|
|
2821
|
+
cjsCondition: `require && module && exports && __filename && __dirname = ${isCJS}`
|
|
2822
|
+
},
|
|
2823
|
+
checks: {
|
|
2824
|
+
__filename: typeof __filename,
|
|
2825
|
+
__dirname: typeof __dirname,
|
|
2826
|
+
require: typeof require,
|
|
2827
|
+
module: typeof module,
|
|
2828
|
+
exports: typeof exports,
|
|
2829
|
+
"process.features": process.features,
|
|
2830
|
+
"globalThis.module": globalThis.module
|
|
2831
|
+
}
|
|
2832
|
+
});
|
|
2833
|
+
return {
|
|
2834
|
+
isESM,
|
|
2835
|
+
isCJS,
|
|
2836
|
+
nodeVersion: process.versions.node,
|
|
2837
|
+
supportsLoaderAPI,
|
|
2838
|
+
supportsRegister
|
|
2839
|
+
};
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
// src/node/loader.ts
|
|
2843
|
+
var import_node_module = __toESM(require("module"), 1);
|
|
2844
|
+
var import_import_in_the_middle = require("import-in-the-middle");
|
|
2845
|
+
var import_meta = {};
|
|
2846
|
+
var loaderDebug = (() => {
|
|
2847
|
+
const isDebug = process.env["BRIZZ_ESM_DEBUG"] === "true" || process.env["BRIZZ_LOG_LEVEL"] === "debug";
|
|
2848
|
+
return {
|
|
2849
|
+
log: (msg, data) => {
|
|
2850
|
+
if (!isDebug) {
|
|
2851
|
+
return;
|
|
2852
|
+
}
|
|
2853
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2854
|
+
const dataStr = data ? ` ${JSON.stringify(data)}` : "";
|
|
2855
|
+
console.log(`[${timestamp}] [ESM-LOADER] ${msg}${dataStr}`);
|
|
2856
|
+
},
|
|
2857
|
+
error: (msg, error) => {
|
|
2858
|
+
if (!isDebug) {
|
|
2859
|
+
return;
|
|
2860
|
+
}
|
|
2861
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2862
|
+
const errorStr = error instanceof Error ? ` ${error.message}` : error ? ` ${JSON.stringify(error)}` : "";
|
|
2863
|
+
console.error(`[${timestamp}] [ESM-LOADER] ERROR: ${msg}${errorStr}`);
|
|
2864
|
+
}
|
|
2865
|
+
};
|
|
2866
|
+
})();
|
|
2867
|
+
var LOADER_REGISTERED_KEY = Symbol.for("__brizz_esm_loader_registered__");
|
|
2868
|
+
function checkLoaderAPISupport() {
|
|
2869
|
+
const [major, minor] = process.versions.node.split(".").map(Number);
|
|
2870
|
+
if (major === void 0 || minor === void 0) {
|
|
2871
|
+
loaderDebug.log("Failed to detect Node version, assuming loader API is supported");
|
|
2872
|
+
return true;
|
|
2873
|
+
}
|
|
2874
|
+
const supported = major >= 21 || major === 20 && minor >= 6 || major === 18 && minor >= 19;
|
|
2875
|
+
loaderDebug.log("Loader API support check:", {
|
|
2876
|
+
nodeVersion: `${major}.${minor}`,
|
|
2877
|
+
supportsLoaderAPI: supported
|
|
2878
|
+
});
|
|
2879
|
+
return supported;
|
|
2880
|
+
}
|
|
2881
|
+
function maybeRegisterESMLoader() {
|
|
2882
|
+
if (globalThis[LOADER_REGISTERED_KEY] === true) {
|
|
2883
|
+
loaderDebug.log("ESM loader already registered, skipping");
|
|
2884
|
+
return false;
|
|
2885
|
+
}
|
|
2886
|
+
globalThis[LOADER_REGISTERED_KEY] = true;
|
|
2887
|
+
loaderDebug.log("Starting ESM loader registration...");
|
|
2888
|
+
if (!checkLoaderAPISupport()) {
|
|
2889
|
+
loaderDebug.log("Node.js version does not support loader API, skipping");
|
|
2890
|
+
return false;
|
|
2891
|
+
}
|
|
2892
|
+
try {
|
|
2893
|
+
loaderDebug.log("Creating MessageChannel for import-in-the-middle...");
|
|
2894
|
+
const { addHookMessagePort } = (0, import_import_in_the_middle.createAddHookMessageChannel)();
|
|
2895
|
+
loaderDebug.log("Registering import-in-the-middle/hook.mjs...");
|
|
2896
|
+
import_node_module.default.register("import-in-the-middle/hook.mjs", import_meta.url, {
|
|
2897
|
+
data: { addHookMessagePort },
|
|
2898
|
+
transferList: [addHookMessagePort]
|
|
2899
|
+
});
|
|
2900
|
+
loaderDebug.log("ESM loader successfully registered!");
|
|
2901
|
+
return true;
|
|
2902
|
+
} catch (error) {
|
|
2903
|
+
loaderDebug.error("Failed to register ESM loader:", error);
|
|
2904
|
+
globalThis[LOADER_REGISTERED_KEY] = false;
|
|
2905
|
+
return false;
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
if (globalThis[LOADER_REGISTERED_KEY] !== true) {
|
|
2909
|
+
loaderDebug.log("Loader module imported, attempting to register...");
|
|
2910
|
+
maybeRegisterESMLoader();
|
|
2911
|
+
}
|
|
2912
|
+
|
|
2913
|
+
// src/init.ts
|
|
2914
|
+
var init_exports = {};
|
|
2915
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2916
|
+
0 && (module.exports = {
|
|
2917
|
+
Brizz,
|
|
2918
|
+
DEFAULT_PII_PATTERNS,
|
|
2919
|
+
LogLevel,
|
|
2920
|
+
SeverityNumber,
|
|
2921
|
+
VercelAIInstrumentation,
|
|
2922
|
+
WithSessionId,
|
|
2923
|
+
detectRuntime,
|
|
2924
|
+
emitEvent,
|
|
2925
|
+
getLogLevel,
|
|
2926
|
+
getMetricsExporter,
|
|
2927
|
+
getMetricsReader,
|
|
2928
|
+
getSpanExporter,
|
|
2929
|
+
getSpanProcessor,
|
|
2930
|
+
init,
|
|
2931
|
+
logger,
|
|
2932
|
+
maskAttributes,
|
|
2933
|
+
maskValue,
|
|
2934
|
+
maybeRegisterESMLoader,
|
|
2935
|
+
setLogLevel
|
|
2936
|
+
});
|
|
2937
|
+
//# sourceMappingURL=index.cjs.map
|