@flareapp/core 2.2.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/dist/index.cjs +354 -8
- package/dist/index.d.cts +135 -2
- package/dist/index.d.mts +135 -2
- package/dist/index.mjs +353 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,9 +12,12 @@ the official SDKs use.
|
|
|
12
12
|
|
|
13
13
|
- `Flare` — the core class. Takes three optional injection points: `ScopeProvider`,
|
|
14
14
|
`ContextCollector`, `FileReader`.
|
|
15
|
+
- `Logger` — structured logging (`flare.logger`). Eight syslog levels, opt-in via
|
|
16
|
+
`enableLogs`; owns the log buffer, batching policy, and OTel envelope. A
|
|
17
|
+
`FlushScheduler` seam is injected per platform.
|
|
15
18
|
- `Scope`, `GlobalScopeProvider`, `ScopeProvider` — per-call mutable state.
|
|
16
19
|
- `FileReader`, `NullFileReader` — source-snippet reading abstraction.
|
|
17
|
-
- `Api` — the HTTP client used to send reports.
|
|
20
|
+
- `Api` — the HTTP client used to send reports and logs.
|
|
18
21
|
- Types: `Config`, `Report`, `Attributes`, `Glow`, `StackFrame`, etc.
|
|
19
22
|
- Util: `redactUrlQuery`, `resolveDenylist`, `convertToError`, `DEFAULT_URL_DENYLIST`.
|
|
20
23
|
|
package/dist/index.cjs
CHANGED
|
@@ -30,7 +30,7 @@ let error_stack_parser = require("error-stack-parser");
|
|
|
30
30
|
error_stack_parser = __toESM(error_stack_parser);
|
|
31
31
|
|
|
32
32
|
//#region src/env/index.ts
|
|
33
|
-
const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.
|
|
33
|
+
const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.4.0" : "?";
|
|
34
34
|
const KEY = typeof FLARE_JS_KEY === "undefined" ? "" : FLARE_JS_KEY;
|
|
35
35
|
const SOURCEMAP_VERSION = typeof FLARE_SOURCEMAP_VERSION === "undefined" ? "" : FLARE_SOURCEMAP_VERSION;
|
|
36
36
|
|
|
@@ -191,7 +191,311 @@ var Api = class {
|
|
|
191
191
|
if (debug) console.error(error);
|
|
192
192
|
});
|
|
193
193
|
}
|
|
194
|
+
logs(envelope, url, key, debug = false, keepalive = false) {
|
|
195
|
+
return fetch(url, {
|
|
196
|
+
method: "POST",
|
|
197
|
+
keepalive,
|
|
198
|
+
headers: {
|
|
199
|
+
"Accept": "application/json",
|
|
200
|
+
"Content-Type": "application/json",
|
|
201
|
+
"x-api-token": key ?? ""
|
|
202
|
+
},
|
|
203
|
+
body: flatJsonStringify(envelope)
|
|
204
|
+
}).then((response) => {
|
|
205
|
+
if (debug && response.status !== 201) console.error(`Received response with status ${response.status} from Flare logs`);
|
|
206
|
+
}, (error) => {
|
|
207
|
+
if (debug) console.error(error);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
//#endregion
|
|
213
|
+
//#region src/logging/otel.ts
|
|
214
|
+
function valueToOpenTelemetry(value, inPath = /* @__PURE__ */ new WeakSet()) {
|
|
215
|
+
if (typeof value === "string") return { stringValue: value };
|
|
216
|
+
if (typeof value === "boolean") return { boolValue: value };
|
|
217
|
+
if (typeof value === "number") {
|
|
218
|
+
if (!Number.isFinite(value)) return null;
|
|
219
|
+
return Number.isInteger(value) ? { intValue: value } : { doubleValue: value };
|
|
220
|
+
}
|
|
221
|
+
if (value === null || value === void 0) return null;
|
|
222
|
+
if (Array.isArray(value)) {
|
|
223
|
+
if (inPath.has(value)) return { stringValue: "[Circular]" };
|
|
224
|
+
inPath.add(value);
|
|
225
|
+
const values = [];
|
|
226
|
+
for (const item of value) {
|
|
227
|
+
const mapped = valueToOpenTelemetry(item, inPath);
|
|
228
|
+
if (mapped !== null) values.push(mapped);
|
|
229
|
+
}
|
|
230
|
+
inPath.delete(value);
|
|
231
|
+
return { arrayValue: { values } };
|
|
232
|
+
}
|
|
233
|
+
if (typeof value === "object") {
|
|
234
|
+
if (inPath.has(value)) return { stringValue: "[Circular]" };
|
|
235
|
+
inPath.add(value);
|
|
236
|
+
const values = [];
|
|
237
|
+
for (const [key, item] of Object.entries(value)) {
|
|
238
|
+
const mapped = valueToOpenTelemetry(item, inPath);
|
|
239
|
+
if (mapped !== null) values.push({
|
|
240
|
+
key,
|
|
241
|
+
value: mapped
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
inPath.delete(value);
|
|
245
|
+
return { kvlistValue: { values } };
|
|
246
|
+
}
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
function attributesToOpenTelemetry(attributes) {
|
|
250
|
+
const out = [];
|
|
251
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
252
|
+
const mapped = valueToOpenTelemetry(value);
|
|
253
|
+
if (mapped !== null) out.push({
|
|
254
|
+
key,
|
|
255
|
+
value: mapped
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return out;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/logging/envelope.ts
|
|
263
|
+
function buildLogsEnvelope(records, resourceAttributes, scopeName, scopeVersion) {
|
|
264
|
+
return { resourceLogs: [{
|
|
265
|
+
resource: {
|
|
266
|
+
attributes: attributesToOpenTelemetry(resourceAttributes),
|
|
267
|
+
droppedAttributesCount: 0
|
|
268
|
+
},
|
|
269
|
+
scopeLogs: [{
|
|
270
|
+
scope: {
|
|
271
|
+
name: scopeName,
|
|
272
|
+
version: scopeVersion,
|
|
273
|
+
attributes: [],
|
|
274
|
+
droppedAttributesCount: 0
|
|
275
|
+
},
|
|
276
|
+
logRecords: records.map((record) => ({
|
|
277
|
+
timeUnixNano: record.timeUnixNano,
|
|
278
|
+
observedTimeUnixNano: record.timeUnixNano,
|
|
279
|
+
severityNumber: record.severityNumber,
|
|
280
|
+
severityText: record.severityText,
|
|
281
|
+
body: { stringValue: record.message },
|
|
282
|
+
attributes: record.recordAttributes,
|
|
283
|
+
flags: 0,
|
|
284
|
+
droppedAttributesCount: 0
|
|
285
|
+
}))
|
|
286
|
+
}]
|
|
287
|
+
}] };
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region src/logging/severity.ts
|
|
292
|
+
const SEVERITY_NUMBERS = {
|
|
293
|
+
debug: 5,
|
|
294
|
+
info: 9,
|
|
295
|
+
notice: 10,
|
|
296
|
+
warning: 13,
|
|
297
|
+
error: 17,
|
|
298
|
+
critical: 18,
|
|
299
|
+
alert: 19,
|
|
300
|
+
emergency: 21
|
|
194
301
|
};
|
|
302
|
+
function severityNumber(level) {
|
|
303
|
+
return SEVERITY_NUMBERS[level];
|
|
304
|
+
}
|
|
305
|
+
function severityText(level) {
|
|
306
|
+
return level.toUpperCase();
|
|
307
|
+
}
|
|
308
|
+
function isAtOrAboveMinimum(level, minimum) {
|
|
309
|
+
return severityNumber(level) >= severityNumber(minimum);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
//#endregion
|
|
313
|
+
//#region src/logging/Logger.ts
|
|
314
|
+
var Logger = class {
|
|
315
|
+
buffer = [];
|
|
316
|
+
resourceAttributes = {};
|
|
317
|
+
timer;
|
|
318
|
+
timerActive = false;
|
|
319
|
+
constructor(deps) {
|
|
320
|
+
this.deps = deps;
|
|
321
|
+
const flush = (opts) => this.flush(opts);
|
|
322
|
+
this.deps.scheduler.register(flush);
|
|
323
|
+
}
|
|
324
|
+
debug(message, context = {}, attributes = {}) {
|
|
325
|
+
this.record("debug", message, context, attributes);
|
|
326
|
+
}
|
|
327
|
+
info(message, context = {}, attributes = {}) {
|
|
328
|
+
this.record("info", message, context, attributes);
|
|
329
|
+
}
|
|
330
|
+
notice(message, context = {}, attributes = {}) {
|
|
331
|
+
this.record("notice", message, context, attributes);
|
|
332
|
+
}
|
|
333
|
+
warning(message, context = {}, attributes = {}) {
|
|
334
|
+
this.record("warning", message, context, attributes);
|
|
335
|
+
}
|
|
336
|
+
error(message, context = {}, attributes = {}) {
|
|
337
|
+
this.record("error", message, context, attributes);
|
|
338
|
+
}
|
|
339
|
+
critical(message, context = {}, attributes = {}) {
|
|
340
|
+
this.record("critical", message, context, attributes);
|
|
341
|
+
}
|
|
342
|
+
alert(message, context = {}, attributes = {}) {
|
|
343
|
+
this.record("alert", message, context, attributes);
|
|
344
|
+
}
|
|
345
|
+
emergency(message, context = {}, attributes = {}) {
|
|
346
|
+
this.record("emergency", message, context, attributes);
|
|
347
|
+
}
|
|
348
|
+
bufferLength() {
|
|
349
|
+
return this.buffer.length;
|
|
350
|
+
}
|
|
351
|
+
record(level, message, context, attributes) {
|
|
352
|
+
const config = this.deps.getConfig();
|
|
353
|
+
if (!config.enableLogs) return;
|
|
354
|
+
if (config.minimumLogLevel && !isAtOrAboveMinimum(level, config.minimumLogLevel)) return;
|
|
355
|
+
const userAttributes = {
|
|
356
|
+
"log.context": context,
|
|
357
|
+
...attributes
|
|
358
|
+
};
|
|
359
|
+
const { record, resource } = this.deps.buildLogAttributes(userAttributes);
|
|
360
|
+
const buffered = {
|
|
361
|
+
timeUnixNano: String(Date.now()) + "000000",
|
|
362
|
+
severityNumber: severityNumber(level),
|
|
363
|
+
severityText: severityText(level),
|
|
364
|
+
message,
|
|
365
|
+
recordAttributes: attributesToOpenTelemetry(record),
|
|
366
|
+
resourceAttributes: resource
|
|
367
|
+
};
|
|
368
|
+
if (this.estimateBytes(buffered) > config.logFlushMaxBytes) {
|
|
369
|
+
if (config.debug) console.error("Flare: dropping oversized log record");
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
this.buffer.push(buffered);
|
|
373
|
+
this.resourceAttributes = resource;
|
|
374
|
+
this.evaluateTriggers(config);
|
|
375
|
+
this.trim(config);
|
|
376
|
+
}
|
|
377
|
+
evaluateTriggers(config) {
|
|
378
|
+
if (this.buffer.length >= config.maxLogBufferSize) {
|
|
379
|
+
this.flush();
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (this.bufferBytes() >= config.logFlushMaxBytes) {
|
|
383
|
+
this.flush();
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
this.armTimer(config);
|
|
387
|
+
}
|
|
388
|
+
armTimer(config) {
|
|
389
|
+
if (this.timerActive) return;
|
|
390
|
+
this.timerActive = true;
|
|
391
|
+
this.timer = setTimeout(() => this.flush(), config.logFlushIntervalMs);
|
|
392
|
+
this.timer.unref?.();
|
|
393
|
+
}
|
|
394
|
+
trim(config) {
|
|
395
|
+
if (this.buffer.length > config.maxLogBufferSize) this.buffer = this.buffer.slice(this.buffer.length - config.maxLogBufferSize);
|
|
396
|
+
while (this.buffer.length > 1 && this.bufferBytes() > config.logFlushMaxBytes) this.buffer.shift();
|
|
397
|
+
}
|
|
398
|
+
flush(opts) {
|
|
399
|
+
const config = this.deps.getConfig();
|
|
400
|
+
if (!config.enableLogs) return;
|
|
401
|
+
if (this.buffer.length === 0) return;
|
|
402
|
+
if (!assertKey(config.key, config.debug)) {
|
|
403
|
+
this.clearTimer();
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
this.clearTimer();
|
|
407
|
+
let records;
|
|
408
|
+
if (opts?.keepalive) {
|
|
409
|
+
records = this.packForKeepalive(config);
|
|
410
|
+
this.buffer = this.buffer.filter((log) => !records.includes(log));
|
|
411
|
+
if (this.buffer.length > 0) this.armTimer(config);
|
|
412
|
+
} else {
|
|
413
|
+
records = this.buffer;
|
|
414
|
+
this.buffer = [];
|
|
415
|
+
}
|
|
416
|
+
if (records.length === 0) return;
|
|
417
|
+
this.deps.track(this.deps.api.logs(this.buildEnvelope(records), config.logsIngestUrl, config.key, config.debug, !!opts?.keepalive));
|
|
418
|
+
}
|
|
419
|
+
clear() {
|
|
420
|
+
this.buffer = [];
|
|
421
|
+
this.clearTimer();
|
|
422
|
+
}
|
|
423
|
+
packForKeepalive(config) {
|
|
424
|
+
let selected = [];
|
|
425
|
+
for (let i = this.buffer.length - 1; i >= 0; i--) {
|
|
426
|
+
const trial = [this.buffer[i], ...selected];
|
|
427
|
+
if (new TextEncoder().encode(flatJsonStringify(this.buildEnvelope(trial))).length <= config.keepaliveMaxBytes) selected = trial;
|
|
428
|
+
else if (config.debug) console.error("Flare: dropping log record from keepalive envelope (over budget)");
|
|
429
|
+
}
|
|
430
|
+
return selected;
|
|
431
|
+
}
|
|
432
|
+
buildEnvelope(records) {
|
|
433
|
+
const sdk = this.deps.getSdkInfo();
|
|
434
|
+
return buildLogsEnvelope(records, this.resourceForFlush(), sdk.name, sdk.version);
|
|
435
|
+
}
|
|
436
|
+
resourceForFlush() {
|
|
437
|
+
const config = this.deps.getConfig();
|
|
438
|
+
const sdk = this.deps.getSdkInfo();
|
|
439
|
+
const framework = this.deps.getFramework();
|
|
440
|
+
const identity = {
|
|
441
|
+
"telemetry.sdk.language": "javascript",
|
|
442
|
+
"telemetry.sdk.name": sdk.name,
|
|
443
|
+
"telemetry.sdk.version": sdk.version,
|
|
444
|
+
"flare.language.name": "javascript"
|
|
445
|
+
};
|
|
446
|
+
if (config.serviceName) identity["service.name"] = config.serviceName;
|
|
447
|
+
if (config.version) identity["service.version"] = config.version;
|
|
448
|
+
if (config.stage) identity["service.stage"] = config.stage;
|
|
449
|
+
if (framework?.name) identity["flare.framework.name"] = framework.name;
|
|
450
|
+
if (framework?.version) identity["flare.framework.version"] = framework.version;
|
|
451
|
+
return {
|
|
452
|
+
...this.resourceAttributes,
|
|
453
|
+
...identity
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
clearTimer() {
|
|
457
|
+
if (this.timer) {
|
|
458
|
+
clearTimeout(this.timer);
|
|
459
|
+
this.timer = void 0;
|
|
460
|
+
}
|
|
461
|
+
this.timerActive = false;
|
|
462
|
+
}
|
|
463
|
+
estimateBytes(log) {
|
|
464
|
+
return flatJsonStringify(log).length;
|
|
465
|
+
}
|
|
466
|
+
bufferBytes() {
|
|
467
|
+
return this.buffer.reduce((sum, log) => sum + this.estimateBytes(log), 0);
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
//#endregion
|
|
472
|
+
//#region src/logging/FlushScheduler.ts
|
|
473
|
+
var NoopFlushScheduler = class {
|
|
474
|
+
register() {}
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
//#endregion
|
|
478
|
+
//#region src/logging/partition.ts
|
|
479
|
+
const RESOURCE_PREFIXES = [
|
|
480
|
+
"service.",
|
|
481
|
+
"telemetry.",
|
|
482
|
+
"host.",
|
|
483
|
+
"os.",
|
|
484
|
+
"process.",
|
|
485
|
+
"flare.framework.",
|
|
486
|
+
"flare.language."
|
|
487
|
+
];
|
|
488
|
+
const RECORD_LEVEL_EXCEPTIONS = new Set(["process.uptime"]);
|
|
489
|
+
function partitionAttributes(attributes) {
|
|
490
|
+
const resource = {};
|
|
491
|
+
const record = {};
|
|
492
|
+
for (const [key, value] of Object.entries(attributes)) if (!RECORD_LEVEL_EXCEPTIONS.has(key) && RESOURCE_PREFIXES.some((prefix) => key.startsWith(prefix))) resource[key] = value;
|
|
493
|
+
else record[key] = value;
|
|
494
|
+
return {
|
|
495
|
+
resource,
|
|
496
|
+
record
|
|
497
|
+
};
|
|
498
|
+
}
|
|
195
499
|
|
|
196
500
|
//#endregion
|
|
197
501
|
//#region src/Scope.ts
|
|
@@ -406,6 +710,7 @@ var NullFileReader = class {
|
|
|
406
710
|
const DEFAULT_SDK_NAME = "@flareapp/core";
|
|
407
711
|
var Flare = class {
|
|
408
712
|
inflight = /* @__PURE__ */ new Set();
|
|
713
|
+
_logger;
|
|
409
714
|
_config = {
|
|
410
715
|
key: null,
|
|
411
716
|
version: "",
|
|
@@ -419,7 +724,13 @@ var Flare = class {
|
|
|
419
724
|
replaceDefaultUrlDenylist: false,
|
|
420
725
|
sampleRate: 1,
|
|
421
726
|
beforeEvaluate: (error) => error,
|
|
422
|
-
beforeSubmit: (report) => report
|
|
727
|
+
beforeSubmit: (report) => report,
|
|
728
|
+
enableLogs: false,
|
|
729
|
+
logsIngestUrl: "https://ingress.flareapp.io/v1/logs",
|
|
730
|
+
maxLogBufferSize: 100,
|
|
731
|
+
logFlushIntervalMs: 5e3,
|
|
732
|
+
logFlushMaxBytes: 8e5,
|
|
733
|
+
keepaliveMaxBytes: 6e4
|
|
423
734
|
};
|
|
424
735
|
sdkInfo = {
|
|
425
736
|
name: DEFAULT_SDK_NAME,
|
|
@@ -438,11 +749,20 @@ var Flare = class {
|
|
|
438
749
|
* single global scope; Node uses an AsyncLocalStorage-
|
|
439
750
|
* backed provider so each request gets its own.
|
|
440
751
|
*/
|
|
441
|
-
constructor(api = new Api(), contextCollector = () => ({}), fileReader = new NullFileReader(), scopeProvider = new GlobalScopeProvider()) {
|
|
752
|
+
constructor(api = new Api(), contextCollector = () => ({}), fileReader = new NullFileReader(), scopeProvider = new GlobalScopeProvider(), scheduler = new NoopFlushScheduler()) {
|
|
442
753
|
this.api = api;
|
|
443
754
|
this.contextCollector = contextCollector;
|
|
444
755
|
this.fileReader = fileReader;
|
|
445
756
|
this.scopeProvider = scopeProvider;
|
|
757
|
+
this._logger = new Logger({
|
|
758
|
+
api: this.api,
|
|
759
|
+
getConfig: () => this._config,
|
|
760
|
+
getSdkInfo: () => this.sdkInfo,
|
|
761
|
+
getFramework: () => this.framework,
|
|
762
|
+
buildLogAttributes: (userAttributes) => this.buildLogAttributes(userAttributes),
|
|
763
|
+
track: (p) => this.track(p),
|
|
764
|
+
scheduler
|
|
765
|
+
});
|
|
446
766
|
}
|
|
447
767
|
/**
|
|
448
768
|
* Register an in-flight report so `flush()` can wait for it. Called by
|
|
@@ -581,6 +901,7 @@ var Flare = class {
|
|
|
581
901
|
* again if you need to wait for those too.
|
|
582
902
|
*/
|
|
583
903
|
flush(timeoutMs = 2e3) {
|
|
904
|
+
this._logger.flush();
|
|
584
905
|
const pending = [...this.inflight];
|
|
585
906
|
if (pending.length === 0) return Promise.resolve();
|
|
586
907
|
return new Promise((resolve) => {
|
|
@@ -597,18 +918,25 @@ var Flare = class {
|
|
|
597
918
|
get glows() {
|
|
598
919
|
return this.scopeProvider.active().glows;
|
|
599
920
|
}
|
|
921
|
+
get logger() {
|
|
922
|
+
return this._logger;
|
|
923
|
+
}
|
|
600
924
|
light(key = KEY, debug) {
|
|
601
925
|
this._config.key = key;
|
|
602
926
|
if (debug !== void 0) this._config.debug = debug;
|
|
927
|
+
this._logger.flush();
|
|
603
928
|
return this;
|
|
604
929
|
}
|
|
605
930
|
configure(config) {
|
|
931
|
+
const wasLogsEnabled = this._config.enableLogs;
|
|
606
932
|
this._config = {
|
|
607
933
|
...this._config,
|
|
608
934
|
...config
|
|
609
935
|
};
|
|
610
936
|
if (config.sampleRate !== void 0) this._config.sampleRate = Math.max(0, Math.min(1, config.sampleRate));
|
|
611
937
|
this._config.urlDenylist = resolveDenylist(config.urlDenylist, config.replaceDefaultUrlDenylist ?? this._config.replaceDefaultUrlDenylist);
|
|
938
|
+
if (wasLogsEnabled && this._config.enableLogs === false) this._logger.clear();
|
|
939
|
+
if (config.key !== void 0) this._logger.flush();
|
|
612
940
|
return this;
|
|
613
941
|
}
|
|
614
942
|
test() {
|
|
@@ -729,8 +1057,7 @@ var Flare = class {
|
|
|
729
1057
|
seenAtUnixNano
|
|
730
1058
|
});
|
|
731
1059
|
}
|
|
732
|
-
|
|
733
|
-
const activeScope = this.scopeProvider.active();
|
|
1060
|
+
buildBaseAttributes() {
|
|
734
1061
|
const baseAttributes = {
|
|
735
1062
|
"telemetry.sdk.language": "javascript",
|
|
736
1063
|
"telemetry.sdk.name": this.sdkInfo.name,
|
|
@@ -741,6 +1068,11 @@ var Flare = class {
|
|
|
741
1068
|
if (this._config.version) baseAttributes["service.version"] = this._config.version;
|
|
742
1069
|
if (this.framework?.name) baseAttributes["flare.framework.name"] = this.framework.name;
|
|
743
1070
|
if (this.framework?.version) baseAttributes["flare.framework.version"] = this.framework.version;
|
|
1071
|
+
return baseAttributes;
|
|
1072
|
+
}
|
|
1073
|
+
assembleAttributes(collectorAttributes, extraAttributes, includeBase) {
|
|
1074
|
+
const activeScope = this.scopeProvider.active();
|
|
1075
|
+
const baseAttributes = includeBase ? this.buildBaseAttributes() : {};
|
|
744
1076
|
const entryPoint = activeScope.entryPoint;
|
|
745
1077
|
const entryPointOverrides = {};
|
|
746
1078
|
if (entryPoint?.identifier !== void 0) entryPointOverrides["flare.entry_point.handler.identifier"] = entryPoint.identifier;
|
|
@@ -748,13 +1080,13 @@ var Flare = class {
|
|
|
748
1080
|
if (entryPoint?.name !== void 0) entryPointOverrides["flare.entry_point.handler.name"] = entryPoint.name;
|
|
749
1081
|
const attributes = {
|
|
750
1082
|
...baseAttributes,
|
|
751
|
-
...
|
|
1083
|
+
...collectorAttributes,
|
|
752
1084
|
...entryPointOverrides,
|
|
753
1085
|
...activeScope.pendingAttributes,
|
|
754
|
-
...
|
|
1086
|
+
...extraAttributes
|
|
755
1087
|
};
|
|
756
1088
|
const pendingCustom = activeScope.pendingAttributes["context.custom"];
|
|
757
|
-
const extraCustom =
|
|
1089
|
+
const extraCustom = extraAttributes["context.custom"];
|
|
758
1090
|
if (pendingCustom && extraCustom && typeof pendingCustom === "object" && typeof extraCustom === "object" && !Array.isArray(pendingCustom) && !Array.isArray(extraCustom)) attributes["context.custom"] = {
|
|
759
1091
|
...pendingCustom,
|
|
760
1092
|
...extraCustom
|
|
@@ -763,6 +1095,18 @@ var Flare = class {
|
|
|
763
1095
|
...attributes["context.custom"] ?? {},
|
|
764
1096
|
framework: this.framework.name.toLowerCase()
|
|
765
1097
|
};
|
|
1098
|
+
return attributes;
|
|
1099
|
+
}
|
|
1100
|
+
buildLogAttributes(userAttributes) {
|
|
1101
|
+
const { resource, record: collectorRecord } = partitionAttributes(this.contextCollector(this._config));
|
|
1102
|
+
return {
|
|
1103
|
+
resource,
|
|
1104
|
+
record: this.assembleAttributes(collectorRecord, userAttributes, false)
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
buildReport(input) {
|
|
1108
|
+
const activeScope = this.scopeProvider.active();
|
|
1109
|
+
const attributes = this.assembleAttributes(this.contextCollector(this._config), input.extraAttributes, true);
|
|
766
1110
|
const report = {
|
|
767
1111
|
exceptionClass: input.exceptionClass,
|
|
768
1112
|
message: input.message,
|
|
@@ -790,6 +1134,8 @@ exports.Api = Api;
|
|
|
790
1134
|
exports.DEFAULT_URL_DENYLIST = DEFAULT_URL_DENYLIST;
|
|
791
1135
|
exports.Flare = Flare;
|
|
792
1136
|
exports.GlobalScopeProvider = GlobalScopeProvider;
|
|
1137
|
+
exports.Logger = Logger;
|
|
1138
|
+
exports.NoopFlushScheduler = NoopFlushScheduler;
|
|
793
1139
|
exports.NullFileReader = NullFileReader;
|
|
794
1140
|
exports.Scope = Scope;
|
|
795
1141
|
exports.assert = assert;
|
package/dist/index.d.cts
CHANGED
|
@@ -16,6 +16,14 @@ type Config = {
|
|
|
16
16
|
urlDenylist: RegExp;
|
|
17
17
|
replaceDefaultUrlDenylist: boolean;
|
|
18
18
|
sampleRate: number;
|
|
19
|
+
enableLogs: boolean;
|
|
20
|
+
logsIngestUrl: string;
|
|
21
|
+
minimumLogLevel?: MessageLevel;
|
|
22
|
+
serviceName?: string;
|
|
23
|
+
maxLogBufferSize: number;
|
|
24
|
+
logFlushIntervalMs: number;
|
|
25
|
+
logFlushMaxBytes: number;
|
|
26
|
+
keepaliveMaxBytes: number;
|
|
19
27
|
beforeEvaluate: (error: Error) => Error | false | null | Promise<Error | false | null>;
|
|
20
28
|
beforeSubmit: (report: Report) => Report | false | null | Promise<Report | false | null>;
|
|
21
29
|
};
|
|
@@ -75,6 +83,64 @@ type Framework = {
|
|
|
75
83
|
name: string;
|
|
76
84
|
version?: string;
|
|
77
85
|
};
|
|
86
|
+
type AnyValue = {
|
|
87
|
+
stringValue: string;
|
|
88
|
+
} | {
|
|
89
|
+
boolValue: boolean;
|
|
90
|
+
} | {
|
|
91
|
+
intValue: number;
|
|
92
|
+
} | {
|
|
93
|
+
doubleValue: number;
|
|
94
|
+
} | {
|
|
95
|
+
arrayValue: {
|
|
96
|
+
values: AnyValue[];
|
|
97
|
+
};
|
|
98
|
+
} | {
|
|
99
|
+
kvlistValue: {
|
|
100
|
+
values: KeyValue[];
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
type KeyValue = {
|
|
104
|
+
key: string;
|
|
105
|
+
value: AnyValue;
|
|
106
|
+
};
|
|
107
|
+
type OtelResource = {
|
|
108
|
+
attributes: KeyValue[];
|
|
109
|
+
droppedAttributesCount: number;
|
|
110
|
+
};
|
|
111
|
+
type OtelScope = {
|
|
112
|
+
name: string;
|
|
113
|
+
version: string;
|
|
114
|
+
attributes: KeyValue[];
|
|
115
|
+
droppedAttributesCount: number;
|
|
116
|
+
};
|
|
117
|
+
type OtelLogRecord = {
|
|
118
|
+
timeUnixNano: string;
|
|
119
|
+
observedTimeUnixNano: string;
|
|
120
|
+
severityNumber: number;
|
|
121
|
+
severityText: string;
|
|
122
|
+
body: AnyValue;
|
|
123
|
+
attributes: KeyValue[];
|
|
124
|
+
flags: number;
|
|
125
|
+
droppedAttributesCount: number;
|
|
126
|
+
};
|
|
127
|
+
type LogsEnvelope = {
|
|
128
|
+
resourceLogs: Array<{
|
|
129
|
+
resource: OtelResource;
|
|
130
|
+
scopeLogs: Array<{
|
|
131
|
+
scope: OtelScope;
|
|
132
|
+
logRecords: OtelLogRecord[];
|
|
133
|
+
}>;
|
|
134
|
+
}>;
|
|
135
|
+
};
|
|
136
|
+
type BufferedLog = {
|
|
137
|
+
timeUnixNano: string;
|
|
138
|
+
severityNumber: number;
|
|
139
|
+
severityText: string;
|
|
140
|
+
message: string;
|
|
141
|
+
recordAttributes: KeyValue[];
|
|
142
|
+
resourceAttributes: Attributes;
|
|
143
|
+
};
|
|
78
144
|
//#endregion
|
|
79
145
|
//#region src/util/assert.d.ts
|
|
80
146
|
declare function assert(value: unknown, message: string, debug: boolean): boolean;
|
|
@@ -105,6 +171,68 @@ declare function redactUrlQuery(fullPath: string, denylist?: RegExp): string;
|
|
|
105
171
|
//#region src/api/Api.d.ts
|
|
106
172
|
declare class Api {
|
|
107
173
|
report(report: Report, url: string, key: string | null, reportBrowserExtensionErrors: boolean, debug?: boolean): Promise<void>;
|
|
174
|
+
logs(envelope: LogsEnvelope, url: string, key: string | null, debug?: boolean, keepalive?: boolean): Promise<void>;
|
|
175
|
+
}
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/logging/FlushScheduler.d.ts
|
|
178
|
+
type FlushFn = (opts?: {
|
|
179
|
+
keepalive?: boolean;
|
|
180
|
+
}) => void;
|
|
181
|
+
/**
|
|
182
|
+
* The seam through which a platform package wires the "drain on lifecycle end"
|
|
183
|
+
* trigger (browser unload, Node process exit). Core ships a no-op default; the
|
|
184
|
+
* count/weight/timer batching policy lives in `Logger` regardless.
|
|
185
|
+
*/
|
|
186
|
+
interface FlushScheduler {
|
|
187
|
+
register(flush: FlushFn): void;
|
|
188
|
+
}
|
|
189
|
+
declare class NoopFlushScheduler implements FlushScheduler {
|
|
190
|
+
register(): void;
|
|
191
|
+
}
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/logging/Logger.d.ts
|
|
194
|
+
type LoggerDeps = {
|
|
195
|
+
api: Api;
|
|
196
|
+
getConfig: () => Config;
|
|
197
|
+
getSdkInfo: () => SdkInfo;
|
|
198
|
+
getFramework: () => Framework | null;
|
|
199
|
+
buildLogAttributes: (userAttributes: Attributes) => {
|
|
200
|
+
record: Attributes;
|
|
201
|
+
resource: Attributes;
|
|
202
|
+
};
|
|
203
|
+
track: <T>(p: Promise<T>) => Promise<T>;
|
|
204
|
+
scheduler: FlushScheduler;
|
|
205
|
+
};
|
|
206
|
+
declare class Logger {
|
|
207
|
+
private deps;
|
|
208
|
+
private buffer;
|
|
209
|
+
private resourceAttributes;
|
|
210
|
+
private timer;
|
|
211
|
+
private timerActive;
|
|
212
|
+
constructor(deps: LoggerDeps);
|
|
213
|
+
debug(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
214
|
+
info(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
215
|
+
notice(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
216
|
+
warning(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
217
|
+
error(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
218
|
+
critical(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
219
|
+
alert(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
220
|
+
emergency(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
221
|
+
bufferLength(): number;
|
|
222
|
+
private record;
|
|
223
|
+
private evaluateTriggers;
|
|
224
|
+
private armTimer;
|
|
225
|
+
private trim;
|
|
226
|
+
flush(opts?: {
|
|
227
|
+
keepalive?: boolean;
|
|
228
|
+
}): void;
|
|
229
|
+
clear(): void;
|
|
230
|
+
private packForKeepalive;
|
|
231
|
+
private buildEnvelope;
|
|
232
|
+
private resourceForFlush;
|
|
233
|
+
private clearTimer;
|
|
234
|
+
private estimateBytes;
|
|
235
|
+
private bufferBytes;
|
|
108
236
|
}
|
|
109
237
|
//#endregion
|
|
110
238
|
//#region src/Scope.d.ts
|
|
@@ -206,6 +334,7 @@ declare class Flare {
|
|
|
206
334
|
private fileReader;
|
|
207
335
|
private scopeProvider;
|
|
208
336
|
private inflight;
|
|
337
|
+
private _logger;
|
|
209
338
|
private _config;
|
|
210
339
|
private sdkInfo;
|
|
211
340
|
private framework;
|
|
@@ -221,7 +350,7 @@ declare class Flare {
|
|
|
221
350
|
* single global scope; Node uses an AsyncLocalStorage-
|
|
222
351
|
* backed provider so each request gets its own.
|
|
223
352
|
*/
|
|
224
|
-
constructor(api?: Api, contextCollector?: ContextCollector, fileReader?: FileReader, scopeProvider?: ScopeProvider);
|
|
353
|
+
constructor(api?: Api, contextCollector?: ContextCollector, fileReader?: FileReader, scopeProvider?: ScopeProvider, scheduler?: FlushScheduler);
|
|
225
354
|
/**
|
|
226
355
|
* Register an in-flight report so `flush()` can wait for it. Called by
|
|
227
356
|
* every public report entry point (`report`, `reportSilently`,
|
|
@@ -356,6 +485,7 @@ declare class Flare {
|
|
|
356
485
|
flush(timeoutMs?: number): Promise<void>;
|
|
357
486
|
get config(): Readonly<Config>;
|
|
358
487
|
get glows(): readonly Glow[];
|
|
488
|
+
get logger(): Logger;
|
|
359
489
|
light(key?: string, debug?: boolean): this;
|
|
360
490
|
configure(config: Partial<Config>): this;
|
|
361
491
|
test(): Promise<void>;
|
|
@@ -375,6 +505,9 @@ declare class Flare {
|
|
|
375
505
|
reportMessage(message: string, level?: MessageLevel, attributes?: Attributes): Promise<void>;
|
|
376
506
|
private reportMessageInternal;
|
|
377
507
|
createReportFromError(error: Error, attributes?: Attributes, seenAtUnixNano?: number): Promise<Report | false>;
|
|
508
|
+
private buildBaseAttributes;
|
|
509
|
+
private assembleAttributes;
|
|
510
|
+
private buildLogAttributes;
|
|
378
511
|
private buildReport;
|
|
379
512
|
sendReport(report: Report): Promise<void>;
|
|
380
513
|
}
|
|
@@ -408,4 +541,4 @@ declare class NullFileReader implements FileReader {
|
|
|
408
541
|
//#region src/stacktrace/createStackTrace.d.ts
|
|
409
542
|
declare function createStackTrace(error: Error, debug: boolean, fileReader: FileReader): Promise<Array<StackFrame>>;
|
|
410
543
|
//#endregion
|
|
411
|
-
export { Api, type AttributeValue, type Attributes, type Config, type ContextCollector, DEFAULT_URL_DENYLIST, type EntryPointHandler, type FileReader, Flare, type Framework, GlobalScopeProvider, type Glow, type MessageLevel, NullFileReader, type OverriddenGrouping, type Report, Scope, type ScopeProvider, type SdkInfo, type SpanEvent, type StackFrame, assert, assertKey, convertToError, createStackTrace, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, readLinesFromFile, redactUrlQuery, resolveDenylist };
|
|
544
|
+
export { type AnyValue, Api, type AttributeValue, type Attributes, type BufferedLog, type Config, type ContextCollector, DEFAULT_URL_DENYLIST, type EntryPointHandler, type FileReader, Flare, type FlushFn, type FlushScheduler, type Framework, GlobalScopeProvider, type Glow, type KeyValue, Logger, type LoggerDeps, type LogsEnvelope, type MessageLevel, NoopFlushScheduler, NullFileReader, type OtelLogRecord, type OverriddenGrouping, type Report, Scope, type ScopeProvider, type SdkInfo, type SpanEvent, type StackFrame, assert, assertKey, convertToError, createStackTrace, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, readLinesFromFile, redactUrlQuery, resolveDenylist };
|
package/dist/index.d.mts
CHANGED
|
@@ -16,6 +16,14 @@ type Config = {
|
|
|
16
16
|
urlDenylist: RegExp;
|
|
17
17
|
replaceDefaultUrlDenylist: boolean;
|
|
18
18
|
sampleRate: number;
|
|
19
|
+
enableLogs: boolean;
|
|
20
|
+
logsIngestUrl: string;
|
|
21
|
+
minimumLogLevel?: MessageLevel;
|
|
22
|
+
serviceName?: string;
|
|
23
|
+
maxLogBufferSize: number;
|
|
24
|
+
logFlushIntervalMs: number;
|
|
25
|
+
logFlushMaxBytes: number;
|
|
26
|
+
keepaliveMaxBytes: number;
|
|
19
27
|
beforeEvaluate: (error: Error) => Error | false | null | Promise<Error | false | null>;
|
|
20
28
|
beforeSubmit: (report: Report) => Report | false | null | Promise<Report | false | null>;
|
|
21
29
|
};
|
|
@@ -75,6 +83,64 @@ type Framework = {
|
|
|
75
83
|
name: string;
|
|
76
84
|
version?: string;
|
|
77
85
|
};
|
|
86
|
+
type AnyValue = {
|
|
87
|
+
stringValue: string;
|
|
88
|
+
} | {
|
|
89
|
+
boolValue: boolean;
|
|
90
|
+
} | {
|
|
91
|
+
intValue: number;
|
|
92
|
+
} | {
|
|
93
|
+
doubleValue: number;
|
|
94
|
+
} | {
|
|
95
|
+
arrayValue: {
|
|
96
|
+
values: AnyValue[];
|
|
97
|
+
};
|
|
98
|
+
} | {
|
|
99
|
+
kvlistValue: {
|
|
100
|
+
values: KeyValue[];
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
type KeyValue = {
|
|
104
|
+
key: string;
|
|
105
|
+
value: AnyValue;
|
|
106
|
+
};
|
|
107
|
+
type OtelResource = {
|
|
108
|
+
attributes: KeyValue[];
|
|
109
|
+
droppedAttributesCount: number;
|
|
110
|
+
};
|
|
111
|
+
type OtelScope = {
|
|
112
|
+
name: string;
|
|
113
|
+
version: string;
|
|
114
|
+
attributes: KeyValue[];
|
|
115
|
+
droppedAttributesCount: number;
|
|
116
|
+
};
|
|
117
|
+
type OtelLogRecord = {
|
|
118
|
+
timeUnixNano: string;
|
|
119
|
+
observedTimeUnixNano: string;
|
|
120
|
+
severityNumber: number;
|
|
121
|
+
severityText: string;
|
|
122
|
+
body: AnyValue;
|
|
123
|
+
attributes: KeyValue[];
|
|
124
|
+
flags: number;
|
|
125
|
+
droppedAttributesCount: number;
|
|
126
|
+
};
|
|
127
|
+
type LogsEnvelope = {
|
|
128
|
+
resourceLogs: Array<{
|
|
129
|
+
resource: OtelResource;
|
|
130
|
+
scopeLogs: Array<{
|
|
131
|
+
scope: OtelScope;
|
|
132
|
+
logRecords: OtelLogRecord[];
|
|
133
|
+
}>;
|
|
134
|
+
}>;
|
|
135
|
+
};
|
|
136
|
+
type BufferedLog = {
|
|
137
|
+
timeUnixNano: string;
|
|
138
|
+
severityNumber: number;
|
|
139
|
+
severityText: string;
|
|
140
|
+
message: string;
|
|
141
|
+
recordAttributes: KeyValue[];
|
|
142
|
+
resourceAttributes: Attributes;
|
|
143
|
+
};
|
|
78
144
|
//#endregion
|
|
79
145
|
//#region src/util/assert.d.ts
|
|
80
146
|
declare function assert(value: unknown, message: string, debug: boolean): boolean;
|
|
@@ -105,6 +171,68 @@ declare function redactUrlQuery(fullPath: string, denylist?: RegExp): string;
|
|
|
105
171
|
//#region src/api/Api.d.ts
|
|
106
172
|
declare class Api {
|
|
107
173
|
report(report: Report, url: string, key: string | null, reportBrowserExtensionErrors: boolean, debug?: boolean): Promise<void>;
|
|
174
|
+
logs(envelope: LogsEnvelope, url: string, key: string | null, debug?: boolean, keepalive?: boolean): Promise<void>;
|
|
175
|
+
}
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/logging/FlushScheduler.d.ts
|
|
178
|
+
type FlushFn = (opts?: {
|
|
179
|
+
keepalive?: boolean;
|
|
180
|
+
}) => void;
|
|
181
|
+
/**
|
|
182
|
+
* The seam through which a platform package wires the "drain on lifecycle end"
|
|
183
|
+
* trigger (browser unload, Node process exit). Core ships a no-op default; the
|
|
184
|
+
* count/weight/timer batching policy lives in `Logger` regardless.
|
|
185
|
+
*/
|
|
186
|
+
interface FlushScheduler {
|
|
187
|
+
register(flush: FlushFn): void;
|
|
188
|
+
}
|
|
189
|
+
declare class NoopFlushScheduler implements FlushScheduler {
|
|
190
|
+
register(): void;
|
|
191
|
+
}
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/logging/Logger.d.ts
|
|
194
|
+
type LoggerDeps = {
|
|
195
|
+
api: Api;
|
|
196
|
+
getConfig: () => Config;
|
|
197
|
+
getSdkInfo: () => SdkInfo;
|
|
198
|
+
getFramework: () => Framework | null;
|
|
199
|
+
buildLogAttributes: (userAttributes: Attributes) => {
|
|
200
|
+
record: Attributes;
|
|
201
|
+
resource: Attributes;
|
|
202
|
+
};
|
|
203
|
+
track: <T>(p: Promise<T>) => Promise<T>;
|
|
204
|
+
scheduler: FlushScheduler;
|
|
205
|
+
};
|
|
206
|
+
declare class Logger {
|
|
207
|
+
private deps;
|
|
208
|
+
private buffer;
|
|
209
|
+
private resourceAttributes;
|
|
210
|
+
private timer;
|
|
211
|
+
private timerActive;
|
|
212
|
+
constructor(deps: LoggerDeps);
|
|
213
|
+
debug(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
214
|
+
info(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
215
|
+
notice(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
216
|
+
warning(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
217
|
+
error(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
218
|
+
critical(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
219
|
+
alert(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
220
|
+
emergency(message: string, context?: Attributes, attributes?: Attributes): void;
|
|
221
|
+
bufferLength(): number;
|
|
222
|
+
private record;
|
|
223
|
+
private evaluateTriggers;
|
|
224
|
+
private armTimer;
|
|
225
|
+
private trim;
|
|
226
|
+
flush(opts?: {
|
|
227
|
+
keepalive?: boolean;
|
|
228
|
+
}): void;
|
|
229
|
+
clear(): void;
|
|
230
|
+
private packForKeepalive;
|
|
231
|
+
private buildEnvelope;
|
|
232
|
+
private resourceForFlush;
|
|
233
|
+
private clearTimer;
|
|
234
|
+
private estimateBytes;
|
|
235
|
+
private bufferBytes;
|
|
108
236
|
}
|
|
109
237
|
//#endregion
|
|
110
238
|
//#region src/Scope.d.ts
|
|
@@ -206,6 +334,7 @@ declare class Flare {
|
|
|
206
334
|
private fileReader;
|
|
207
335
|
private scopeProvider;
|
|
208
336
|
private inflight;
|
|
337
|
+
private _logger;
|
|
209
338
|
private _config;
|
|
210
339
|
private sdkInfo;
|
|
211
340
|
private framework;
|
|
@@ -221,7 +350,7 @@ declare class Flare {
|
|
|
221
350
|
* single global scope; Node uses an AsyncLocalStorage-
|
|
222
351
|
* backed provider so each request gets its own.
|
|
223
352
|
*/
|
|
224
|
-
constructor(api?: Api, contextCollector?: ContextCollector, fileReader?: FileReader, scopeProvider?: ScopeProvider);
|
|
353
|
+
constructor(api?: Api, contextCollector?: ContextCollector, fileReader?: FileReader, scopeProvider?: ScopeProvider, scheduler?: FlushScheduler);
|
|
225
354
|
/**
|
|
226
355
|
* Register an in-flight report so `flush()` can wait for it. Called by
|
|
227
356
|
* every public report entry point (`report`, `reportSilently`,
|
|
@@ -356,6 +485,7 @@ declare class Flare {
|
|
|
356
485
|
flush(timeoutMs?: number): Promise<void>;
|
|
357
486
|
get config(): Readonly<Config>;
|
|
358
487
|
get glows(): readonly Glow[];
|
|
488
|
+
get logger(): Logger;
|
|
359
489
|
light(key?: string, debug?: boolean): this;
|
|
360
490
|
configure(config: Partial<Config>): this;
|
|
361
491
|
test(): Promise<void>;
|
|
@@ -375,6 +505,9 @@ declare class Flare {
|
|
|
375
505
|
reportMessage(message: string, level?: MessageLevel, attributes?: Attributes): Promise<void>;
|
|
376
506
|
private reportMessageInternal;
|
|
377
507
|
createReportFromError(error: Error, attributes?: Attributes, seenAtUnixNano?: number): Promise<Report | false>;
|
|
508
|
+
private buildBaseAttributes;
|
|
509
|
+
private assembleAttributes;
|
|
510
|
+
private buildLogAttributes;
|
|
378
511
|
private buildReport;
|
|
379
512
|
sendReport(report: Report): Promise<void>;
|
|
380
513
|
}
|
|
@@ -408,4 +541,4 @@ declare class NullFileReader implements FileReader {
|
|
|
408
541
|
//#region src/stacktrace/createStackTrace.d.ts
|
|
409
542
|
declare function createStackTrace(error: Error, debug: boolean, fileReader: FileReader): Promise<Array<StackFrame>>;
|
|
410
543
|
//#endregion
|
|
411
|
-
export { Api, type AttributeValue, type Attributes, type Config, type ContextCollector, DEFAULT_URL_DENYLIST, type EntryPointHandler, type FileReader, Flare, type Framework, GlobalScopeProvider, type Glow, type MessageLevel, NullFileReader, type OverriddenGrouping, type Report, Scope, type ScopeProvider, type SdkInfo, type SpanEvent, type StackFrame, assert, assertKey, convertToError, createStackTrace, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, readLinesFromFile, redactUrlQuery, resolveDenylist };
|
|
544
|
+
export { type AnyValue, Api, type AttributeValue, type Attributes, type BufferedLog, type Config, type ContextCollector, DEFAULT_URL_DENYLIST, type EntryPointHandler, type FileReader, Flare, type FlushFn, type FlushScheduler, type Framework, GlobalScopeProvider, type Glow, type KeyValue, Logger, type LoggerDeps, type LogsEnvelope, type MessageLevel, NoopFlushScheduler, NullFileReader, type OtelLogRecord, type OverriddenGrouping, type Report, Scope, type ScopeProvider, type SdkInfo, type SpanEvent, type StackFrame, assert, assertKey, convertToError, createStackTrace, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, readLinesFromFile, redactUrlQuery, resolveDenylist };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ErrorStackParser from "error-stack-parser";
|
|
2
2
|
|
|
3
3
|
//#region src/env/index.ts
|
|
4
|
-
const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.
|
|
4
|
+
const CLIENT_VERSION = typeof process !== "undefined" && true ? "2.4.0" : "?";
|
|
5
5
|
const KEY = typeof FLARE_JS_KEY === "undefined" ? "" : FLARE_JS_KEY;
|
|
6
6
|
const SOURCEMAP_VERSION = typeof FLARE_SOURCEMAP_VERSION === "undefined" ? "" : FLARE_SOURCEMAP_VERSION;
|
|
7
7
|
|
|
@@ -162,7 +162,311 @@ var Api = class {
|
|
|
162
162
|
if (debug) console.error(error);
|
|
163
163
|
});
|
|
164
164
|
}
|
|
165
|
+
logs(envelope, url, key, debug = false, keepalive = false) {
|
|
166
|
+
return fetch(url, {
|
|
167
|
+
method: "POST",
|
|
168
|
+
keepalive,
|
|
169
|
+
headers: {
|
|
170
|
+
"Accept": "application/json",
|
|
171
|
+
"Content-Type": "application/json",
|
|
172
|
+
"x-api-token": key ?? ""
|
|
173
|
+
},
|
|
174
|
+
body: flatJsonStringify(envelope)
|
|
175
|
+
}).then((response) => {
|
|
176
|
+
if (debug && response.status !== 201) console.error(`Received response with status ${response.status} from Flare logs`);
|
|
177
|
+
}, (error) => {
|
|
178
|
+
if (debug) console.error(error);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/logging/otel.ts
|
|
185
|
+
function valueToOpenTelemetry(value, inPath = /* @__PURE__ */ new WeakSet()) {
|
|
186
|
+
if (typeof value === "string") return { stringValue: value };
|
|
187
|
+
if (typeof value === "boolean") return { boolValue: value };
|
|
188
|
+
if (typeof value === "number") {
|
|
189
|
+
if (!Number.isFinite(value)) return null;
|
|
190
|
+
return Number.isInteger(value) ? { intValue: value } : { doubleValue: value };
|
|
191
|
+
}
|
|
192
|
+
if (value === null || value === void 0) return null;
|
|
193
|
+
if (Array.isArray(value)) {
|
|
194
|
+
if (inPath.has(value)) return { stringValue: "[Circular]" };
|
|
195
|
+
inPath.add(value);
|
|
196
|
+
const values = [];
|
|
197
|
+
for (const item of value) {
|
|
198
|
+
const mapped = valueToOpenTelemetry(item, inPath);
|
|
199
|
+
if (mapped !== null) values.push(mapped);
|
|
200
|
+
}
|
|
201
|
+
inPath.delete(value);
|
|
202
|
+
return { arrayValue: { values } };
|
|
203
|
+
}
|
|
204
|
+
if (typeof value === "object") {
|
|
205
|
+
if (inPath.has(value)) return { stringValue: "[Circular]" };
|
|
206
|
+
inPath.add(value);
|
|
207
|
+
const values = [];
|
|
208
|
+
for (const [key, item] of Object.entries(value)) {
|
|
209
|
+
const mapped = valueToOpenTelemetry(item, inPath);
|
|
210
|
+
if (mapped !== null) values.push({
|
|
211
|
+
key,
|
|
212
|
+
value: mapped
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
inPath.delete(value);
|
|
216
|
+
return { kvlistValue: { values } };
|
|
217
|
+
}
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
function attributesToOpenTelemetry(attributes) {
|
|
221
|
+
const out = [];
|
|
222
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
223
|
+
const mapped = valueToOpenTelemetry(value);
|
|
224
|
+
if (mapped !== null) out.push({
|
|
225
|
+
key,
|
|
226
|
+
value: mapped
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
return out;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
//#endregion
|
|
233
|
+
//#region src/logging/envelope.ts
|
|
234
|
+
function buildLogsEnvelope(records, resourceAttributes, scopeName, scopeVersion) {
|
|
235
|
+
return { resourceLogs: [{
|
|
236
|
+
resource: {
|
|
237
|
+
attributes: attributesToOpenTelemetry(resourceAttributes),
|
|
238
|
+
droppedAttributesCount: 0
|
|
239
|
+
},
|
|
240
|
+
scopeLogs: [{
|
|
241
|
+
scope: {
|
|
242
|
+
name: scopeName,
|
|
243
|
+
version: scopeVersion,
|
|
244
|
+
attributes: [],
|
|
245
|
+
droppedAttributesCount: 0
|
|
246
|
+
},
|
|
247
|
+
logRecords: records.map((record) => ({
|
|
248
|
+
timeUnixNano: record.timeUnixNano,
|
|
249
|
+
observedTimeUnixNano: record.timeUnixNano,
|
|
250
|
+
severityNumber: record.severityNumber,
|
|
251
|
+
severityText: record.severityText,
|
|
252
|
+
body: { stringValue: record.message },
|
|
253
|
+
attributes: record.recordAttributes,
|
|
254
|
+
flags: 0,
|
|
255
|
+
droppedAttributesCount: 0
|
|
256
|
+
}))
|
|
257
|
+
}]
|
|
258
|
+
}] };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
//#endregion
|
|
262
|
+
//#region src/logging/severity.ts
|
|
263
|
+
const SEVERITY_NUMBERS = {
|
|
264
|
+
debug: 5,
|
|
265
|
+
info: 9,
|
|
266
|
+
notice: 10,
|
|
267
|
+
warning: 13,
|
|
268
|
+
error: 17,
|
|
269
|
+
critical: 18,
|
|
270
|
+
alert: 19,
|
|
271
|
+
emergency: 21
|
|
165
272
|
};
|
|
273
|
+
function severityNumber(level) {
|
|
274
|
+
return SEVERITY_NUMBERS[level];
|
|
275
|
+
}
|
|
276
|
+
function severityText(level) {
|
|
277
|
+
return level.toUpperCase();
|
|
278
|
+
}
|
|
279
|
+
function isAtOrAboveMinimum(level, minimum) {
|
|
280
|
+
return severityNumber(level) >= severityNumber(minimum);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/logging/Logger.ts
|
|
285
|
+
var Logger = class {
|
|
286
|
+
buffer = [];
|
|
287
|
+
resourceAttributes = {};
|
|
288
|
+
timer;
|
|
289
|
+
timerActive = false;
|
|
290
|
+
constructor(deps) {
|
|
291
|
+
this.deps = deps;
|
|
292
|
+
const flush = (opts) => this.flush(opts);
|
|
293
|
+
this.deps.scheduler.register(flush);
|
|
294
|
+
}
|
|
295
|
+
debug(message, context = {}, attributes = {}) {
|
|
296
|
+
this.record("debug", message, context, attributes);
|
|
297
|
+
}
|
|
298
|
+
info(message, context = {}, attributes = {}) {
|
|
299
|
+
this.record("info", message, context, attributes);
|
|
300
|
+
}
|
|
301
|
+
notice(message, context = {}, attributes = {}) {
|
|
302
|
+
this.record("notice", message, context, attributes);
|
|
303
|
+
}
|
|
304
|
+
warning(message, context = {}, attributes = {}) {
|
|
305
|
+
this.record("warning", message, context, attributes);
|
|
306
|
+
}
|
|
307
|
+
error(message, context = {}, attributes = {}) {
|
|
308
|
+
this.record("error", message, context, attributes);
|
|
309
|
+
}
|
|
310
|
+
critical(message, context = {}, attributes = {}) {
|
|
311
|
+
this.record("critical", message, context, attributes);
|
|
312
|
+
}
|
|
313
|
+
alert(message, context = {}, attributes = {}) {
|
|
314
|
+
this.record("alert", message, context, attributes);
|
|
315
|
+
}
|
|
316
|
+
emergency(message, context = {}, attributes = {}) {
|
|
317
|
+
this.record("emergency", message, context, attributes);
|
|
318
|
+
}
|
|
319
|
+
bufferLength() {
|
|
320
|
+
return this.buffer.length;
|
|
321
|
+
}
|
|
322
|
+
record(level, message, context, attributes) {
|
|
323
|
+
const config = this.deps.getConfig();
|
|
324
|
+
if (!config.enableLogs) return;
|
|
325
|
+
if (config.minimumLogLevel && !isAtOrAboveMinimum(level, config.minimumLogLevel)) return;
|
|
326
|
+
const userAttributes = {
|
|
327
|
+
"log.context": context,
|
|
328
|
+
...attributes
|
|
329
|
+
};
|
|
330
|
+
const { record, resource } = this.deps.buildLogAttributes(userAttributes);
|
|
331
|
+
const buffered = {
|
|
332
|
+
timeUnixNano: String(Date.now()) + "000000",
|
|
333
|
+
severityNumber: severityNumber(level),
|
|
334
|
+
severityText: severityText(level),
|
|
335
|
+
message,
|
|
336
|
+
recordAttributes: attributesToOpenTelemetry(record),
|
|
337
|
+
resourceAttributes: resource
|
|
338
|
+
};
|
|
339
|
+
if (this.estimateBytes(buffered) > config.logFlushMaxBytes) {
|
|
340
|
+
if (config.debug) console.error("Flare: dropping oversized log record");
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
this.buffer.push(buffered);
|
|
344
|
+
this.resourceAttributes = resource;
|
|
345
|
+
this.evaluateTriggers(config);
|
|
346
|
+
this.trim(config);
|
|
347
|
+
}
|
|
348
|
+
evaluateTriggers(config) {
|
|
349
|
+
if (this.buffer.length >= config.maxLogBufferSize) {
|
|
350
|
+
this.flush();
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
if (this.bufferBytes() >= config.logFlushMaxBytes) {
|
|
354
|
+
this.flush();
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
this.armTimer(config);
|
|
358
|
+
}
|
|
359
|
+
armTimer(config) {
|
|
360
|
+
if (this.timerActive) return;
|
|
361
|
+
this.timerActive = true;
|
|
362
|
+
this.timer = setTimeout(() => this.flush(), config.logFlushIntervalMs);
|
|
363
|
+
this.timer.unref?.();
|
|
364
|
+
}
|
|
365
|
+
trim(config) {
|
|
366
|
+
if (this.buffer.length > config.maxLogBufferSize) this.buffer = this.buffer.slice(this.buffer.length - config.maxLogBufferSize);
|
|
367
|
+
while (this.buffer.length > 1 && this.bufferBytes() > config.logFlushMaxBytes) this.buffer.shift();
|
|
368
|
+
}
|
|
369
|
+
flush(opts) {
|
|
370
|
+
const config = this.deps.getConfig();
|
|
371
|
+
if (!config.enableLogs) return;
|
|
372
|
+
if (this.buffer.length === 0) return;
|
|
373
|
+
if (!assertKey(config.key, config.debug)) {
|
|
374
|
+
this.clearTimer();
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
this.clearTimer();
|
|
378
|
+
let records;
|
|
379
|
+
if (opts?.keepalive) {
|
|
380
|
+
records = this.packForKeepalive(config);
|
|
381
|
+
this.buffer = this.buffer.filter((log) => !records.includes(log));
|
|
382
|
+
if (this.buffer.length > 0) this.armTimer(config);
|
|
383
|
+
} else {
|
|
384
|
+
records = this.buffer;
|
|
385
|
+
this.buffer = [];
|
|
386
|
+
}
|
|
387
|
+
if (records.length === 0) return;
|
|
388
|
+
this.deps.track(this.deps.api.logs(this.buildEnvelope(records), config.logsIngestUrl, config.key, config.debug, !!opts?.keepalive));
|
|
389
|
+
}
|
|
390
|
+
clear() {
|
|
391
|
+
this.buffer = [];
|
|
392
|
+
this.clearTimer();
|
|
393
|
+
}
|
|
394
|
+
packForKeepalive(config) {
|
|
395
|
+
let selected = [];
|
|
396
|
+
for (let i = this.buffer.length - 1; i >= 0; i--) {
|
|
397
|
+
const trial = [this.buffer[i], ...selected];
|
|
398
|
+
if (new TextEncoder().encode(flatJsonStringify(this.buildEnvelope(trial))).length <= config.keepaliveMaxBytes) selected = trial;
|
|
399
|
+
else if (config.debug) console.error("Flare: dropping log record from keepalive envelope (over budget)");
|
|
400
|
+
}
|
|
401
|
+
return selected;
|
|
402
|
+
}
|
|
403
|
+
buildEnvelope(records) {
|
|
404
|
+
const sdk = this.deps.getSdkInfo();
|
|
405
|
+
return buildLogsEnvelope(records, this.resourceForFlush(), sdk.name, sdk.version);
|
|
406
|
+
}
|
|
407
|
+
resourceForFlush() {
|
|
408
|
+
const config = this.deps.getConfig();
|
|
409
|
+
const sdk = this.deps.getSdkInfo();
|
|
410
|
+
const framework = this.deps.getFramework();
|
|
411
|
+
const identity = {
|
|
412
|
+
"telemetry.sdk.language": "javascript",
|
|
413
|
+
"telemetry.sdk.name": sdk.name,
|
|
414
|
+
"telemetry.sdk.version": sdk.version,
|
|
415
|
+
"flare.language.name": "javascript"
|
|
416
|
+
};
|
|
417
|
+
if (config.serviceName) identity["service.name"] = config.serviceName;
|
|
418
|
+
if (config.version) identity["service.version"] = config.version;
|
|
419
|
+
if (config.stage) identity["service.stage"] = config.stage;
|
|
420
|
+
if (framework?.name) identity["flare.framework.name"] = framework.name;
|
|
421
|
+
if (framework?.version) identity["flare.framework.version"] = framework.version;
|
|
422
|
+
return {
|
|
423
|
+
...this.resourceAttributes,
|
|
424
|
+
...identity
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
clearTimer() {
|
|
428
|
+
if (this.timer) {
|
|
429
|
+
clearTimeout(this.timer);
|
|
430
|
+
this.timer = void 0;
|
|
431
|
+
}
|
|
432
|
+
this.timerActive = false;
|
|
433
|
+
}
|
|
434
|
+
estimateBytes(log) {
|
|
435
|
+
return flatJsonStringify(log).length;
|
|
436
|
+
}
|
|
437
|
+
bufferBytes() {
|
|
438
|
+
return this.buffer.reduce((sum, log) => sum + this.estimateBytes(log), 0);
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
//#endregion
|
|
443
|
+
//#region src/logging/FlushScheduler.ts
|
|
444
|
+
var NoopFlushScheduler = class {
|
|
445
|
+
register() {}
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
//#endregion
|
|
449
|
+
//#region src/logging/partition.ts
|
|
450
|
+
const RESOURCE_PREFIXES = [
|
|
451
|
+
"service.",
|
|
452
|
+
"telemetry.",
|
|
453
|
+
"host.",
|
|
454
|
+
"os.",
|
|
455
|
+
"process.",
|
|
456
|
+
"flare.framework.",
|
|
457
|
+
"flare.language."
|
|
458
|
+
];
|
|
459
|
+
const RECORD_LEVEL_EXCEPTIONS = new Set(["process.uptime"]);
|
|
460
|
+
function partitionAttributes(attributes) {
|
|
461
|
+
const resource = {};
|
|
462
|
+
const record = {};
|
|
463
|
+
for (const [key, value] of Object.entries(attributes)) if (!RECORD_LEVEL_EXCEPTIONS.has(key) && RESOURCE_PREFIXES.some((prefix) => key.startsWith(prefix))) resource[key] = value;
|
|
464
|
+
else record[key] = value;
|
|
465
|
+
return {
|
|
466
|
+
resource,
|
|
467
|
+
record
|
|
468
|
+
};
|
|
469
|
+
}
|
|
166
470
|
|
|
167
471
|
//#endregion
|
|
168
472
|
//#region src/Scope.ts
|
|
@@ -377,6 +681,7 @@ var NullFileReader = class {
|
|
|
377
681
|
const DEFAULT_SDK_NAME = "@flareapp/core";
|
|
378
682
|
var Flare = class {
|
|
379
683
|
inflight = /* @__PURE__ */ new Set();
|
|
684
|
+
_logger;
|
|
380
685
|
_config = {
|
|
381
686
|
key: null,
|
|
382
687
|
version: "",
|
|
@@ -390,7 +695,13 @@ var Flare = class {
|
|
|
390
695
|
replaceDefaultUrlDenylist: false,
|
|
391
696
|
sampleRate: 1,
|
|
392
697
|
beforeEvaluate: (error) => error,
|
|
393
|
-
beforeSubmit: (report) => report
|
|
698
|
+
beforeSubmit: (report) => report,
|
|
699
|
+
enableLogs: false,
|
|
700
|
+
logsIngestUrl: "https://ingress.flareapp.io/v1/logs",
|
|
701
|
+
maxLogBufferSize: 100,
|
|
702
|
+
logFlushIntervalMs: 5e3,
|
|
703
|
+
logFlushMaxBytes: 8e5,
|
|
704
|
+
keepaliveMaxBytes: 6e4
|
|
394
705
|
};
|
|
395
706
|
sdkInfo = {
|
|
396
707
|
name: DEFAULT_SDK_NAME,
|
|
@@ -409,11 +720,20 @@ var Flare = class {
|
|
|
409
720
|
* single global scope; Node uses an AsyncLocalStorage-
|
|
410
721
|
* backed provider so each request gets its own.
|
|
411
722
|
*/
|
|
412
|
-
constructor(api = new Api(), contextCollector = () => ({}), fileReader = new NullFileReader(), scopeProvider = new GlobalScopeProvider()) {
|
|
723
|
+
constructor(api = new Api(), contextCollector = () => ({}), fileReader = new NullFileReader(), scopeProvider = new GlobalScopeProvider(), scheduler = new NoopFlushScheduler()) {
|
|
413
724
|
this.api = api;
|
|
414
725
|
this.contextCollector = contextCollector;
|
|
415
726
|
this.fileReader = fileReader;
|
|
416
727
|
this.scopeProvider = scopeProvider;
|
|
728
|
+
this._logger = new Logger({
|
|
729
|
+
api: this.api,
|
|
730
|
+
getConfig: () => this._config,
|
|
731
|
+
getSdkInfo: () => this.sdkInfo,
|
|
732
|
+
getFramework: () => this.framework,
|
|
733
|
+
buildLogAttributes: (userAttributes) => this.buildLogAttributes(userAttributes),
|
|
734
|
+
track: (p) => this.track(p),
|
|
735
|
+
scheduler
|
|
736
|
+
});
|
|
417
737
|
}
|
|
418
738
|
/**
|
|
419
739
|
* Register an in-flight report so `flush()` can wait for it. Called by
|
|
@@ -552,6 +872,7 @@ var Flare = class {
|
|
|
552
872
|
* again if you need to wait for those too.
|
|
553
873
|
*/
|
|
554
874
|
flush(timeoutMs = 2e3) {
|
|
875
|
+
this._logger.flush();
|
|
555
876
|
const pending = [...this.inflight];
|
|
556
877
|
if (pending.length === 0) return Promise.resolve();
|
|
557
878
|
return new Promise((resolve) => {
|
|
@@ -568,18 +889,25 @@ var Flare = class {
|
|
|
568
889
|
get glows() {
|
|
569
890
|
return this.scopeProvider.active().glows;
|
|
570
891
|
}
|
|
892
|
+
get logger() {
|
|
893
|
+
return this._logger;
|
|
894
|
+
}
|
|
571
895
|
light(key = KEY, debug) {
|
|
572
896
|
this._config.key = key;
|
|
573
897
|
if (debug !== void 0) this._config.debug = debug;
|
|
898
|
+
this._logger.flush();
|
|
574
899
|
return this;
|
|
575
900
|
}
|
|
576
901
|
configure(config) {
|
|
902
|
+
const wasLogsEnabled = this._config.enableLogs;
|
|
577
903
|
this._config = {
|
|
578
904
|
...this._config,
|
|
579
905
|
...config
|
|
580
906
|
};
|
|
581
907
|
if (config.sampleRate !== void 0) this._config.sampleRate = Math.max(0, Math.min(1, config.sampleRate));
|
|
582
908
|
this._config.urlDenylist = resolveDenylist(config.urlDenylist, config.replaceDefaultUrlDenylist ?? this._config.replaceDefaultUrlDenylist);
|
|
909
|
+
if (wasLogsEnabled && this._config.enableLogs === false) this._logger.clear();
|
|
910
|
+
if (config.key !== void 0) this._logger.flush();
|
|
583
911
|
return this;
|
|
584
912
|
}
|
|
585
913
|
test() {
|
|
@@ -700,8 +1028,7 @@ var Flare = class {
|
|
|
700
1028
|
seenAtUnixNano
|
|
701
1029
|
});
|
|
702
1030
|
}
|
|
703
|
-
|
|
704
|
-
const activeScope = this.scopeProvider.active();
|
|
1031
|
+
buildBaseAttributes() {
|
|
705
1032
|
const baseAttributes = {
|
|
706
1033
|
"telemetry.sdk.language": "javascript",
|
|
707
1034
|
"telemetry.sdk.name": this.sdkInfo.name,
|
|
@@ -712,6 +1039,11 @@ var Flare = class {
|
|
|
712
1039
|
if (this._config.version) baseAttributes["service.version"] = this._config.version;
|
|
713
1040
|
if (this.framework?.name) baseAttributes["flare.framework.name"] = this.framework.name;
|
|
714
1041
|
if (this.framework?.version) baseAttributes["flare.framework.version"] = this.framework.version;
|
|
1042
|
+
return baseAttributes;
|
|
1043
|
+
}
|
|
1044
|
+
assembleAttributes(collectorAttributes, extraAttributes, includeBase) {
|
|
1045
|
+
const activeScope = this.scopeProvider.active();
|
|
1046
|
+
const baseAttributes = includeBase ? this.buildBaseAttributes() : {};
|
|
715
1047
|
const entryPoint = activeScope.entryPoint;
|
|
716
1048
|
const entryPointOverrides = {};
|
|
717
1049
|
if (entryPoint?.identifier !== void 0) entryPointOverrides["flare.entry_point.handler.identifier"] = entryPoint.identifier;
|
|
@@ -719,13 +1051,13 @@ var Flare = class {
|
|
|
719
1051
|
if (entryPoint?.name !== void 0) entryPointOverrides["flare.entry_point.handler.name"] = entryPoint.name;
|
|
720
1052
|
const attributes = {
|
|
721
1053
|
...baseAttributes,
|
|
722
|
-
...
|
|
1054
|
+
...collectorAttributes,
|
|
723
1055
|
...entryPointOverrides,
|
|
724
1056
|
...activeScope.pendingAttributes,
|
|
725
|
-
...
|
|
1057
|
+
...extraAttributes
|
|
726
1058
|
};
|
|
727
1059
|
const pendingCustom = activeScope.pendingAttributes["context.custom"];
|
|
728
|
-
const extraCustom =
|
|
1060
|
+
const extraCustom = extraAttributes["context.custom"];
|
|
729
1061
|
if (pendingCustom && extraCustom && typeof pendingCustom === "object" && typeof extraCustom === "object" && !Array.isArray(pendingCustom) && !Array.isArray(extraCustom)) attributes["context.custom"] = {
|
|
730
1062
|
...pendingCustom,
|
|
731
1063
|
...extraCustom
|
|
@@ -734,6 +1066,18 @@ var Flare = class {
|
|
|
734
1066
|
...attributes["context.custom"] ?? {},
|
|
735
1067
|
framework: this.framework.name.toLowerCase()
|
|
736
1068
|
};
|
|
1069
|
+
return attributes;
|
|
1070
|
+
}
|
|
1071
|
+
buildLogAttributes(userAttributes) {
|
|
1072
|
+
const { resource, record: collectorRecord } = partitionAttributes(this.contextCollector(this._config));
|
|
1073
|
+
return {
|
|
1074
|
+
resource,
|
|
1075
|
+
record: this.assembleAttributes(collectorRecord, userAttributes, false)
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
buildReport(input) {
|
|
1079
|
+
const activeScope = this.scopeProvider.active();
|
|
1080
|
+
const attributes = this.assembleAttributes(this.contextCollector(this._config), input.extraAttributes, true);
|
|
737
1081
|
const report = {
|
|
738
1082
|
exceptionClass: input.exceptionClass,
|
|
739
1083
|
message: input.message,
|
|
@@ -757,4 +1101,4 @@ var Flare = class {
|
|
|
757
1101
|
};
|
|
758
1102
|
|
|
759
1103
|
//#endregion
|
|
760
|
-
export { Api, DEFAULT_URL_DENYLIST, Flare, GlobalScopeProvider, NullFileReader, Scope, assert, assertKey, convertToError, createStackTrace, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, readLinesFromFile, redactUrlQuery, resolveDenylist };
|
|
1104
|
+
export { Api, DEFAULT_URL_DENYLIST, Flare, GlobalScopeProvider, Logger, NoopFlushScheduler, NullFileReader, Scope, assert, assertKey, convertToError, createStackTrace, extractCode, flatJsonStringify, getCodeSnippet, glowsToEvents, now, readLinesFromFile, redactUrlQuery, resolveDenylist };
|