@foam-ai/node 0.1.0-alpha.4 → 0.1.0-alpha.6
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 +393 -214
- package/dist/before-send.d.ts +16 -0
- package/dist/before-send.js +41 -0
- package/dist/constants.d.ts +10 -8
- package/dist/constants.js +19 -6
- package/dist/endpoint.d.ts +2 -0
- package/dist/endpoint.js +11 -0
- package/dist/exporters.d.ts +11 -3
- package/dist/exporters.js +127 -53
- package/dist/index.d.ts +7 -2
- package/dist/index.js +8 -1
- package/dist/ingest.d.ts +8 -2
- package/dist/ingest.js +28 -16
- package/dist/init.d.ts +7 -3
- package/dist/init.js +85 -37
- package/dist/instrumentations.js +25 -3
- package/dist/logs.d.ts +10 -0
- package/dist/logs.js +61 -0
- package/dist/network-capture/collector.js +168 -69
- package/dist/network-capture/http.d.ts +0 -1
- package/dist/network-capture/http.js +23 -25
- package/dist/network-capture/index.js +10 -0
- package/dist/network-capture/redact.d.ts +9 -0
- package/dist/network-capture/redact.js +401 -0
- package/dist/network-capture/undici.d.ts +0 -4
- package/dist/network-capture/undici.js +55 -22
- package/dist/otlp.d.ts +8 -0
- package/dist/otlp.js +46 -0
- package/dist/propagation.d.ts +1 -1
- package/dist/propagation.js +6 -4
- package/dist/redaction-keys.d.ts +3 -0
- package/dist/redaction-keys.js +421 -0
- package/dist/redaction.d.ts +24 -0
- package/dist/redaction.js +270 -0
- package/dist/report.d.ts +9 -0
- package/dist/report.js +56 -0
- package/dist/state.d.ts +11 -4
- package/dist/state.js +26 -9
- package/dist/traces.d.ts +1 -0
- package/dist/traces.js +21 -0
- package/dist/utils.js +1 -1
- package/package.json +1 -1
- package/dist/diagnostics.d.ts +0 -13
- package/dist/diagnostics.js +0 -83
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface BeforeSendSpanEvent {
|
|
2
|
+
readonly type: "span";
|
|
3
|
+
name: string;
|
|
4
|
+
attributes: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
interface BeforeSendLogEvent {
|
|
7
|
+
readonly type: "log";
|
|
8
|
+
body?: unknown;
|
|
9
|
+
severityText?: string;
|
|
10
|
+
attributes: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export type BeforeSendEvent = BeforeSendSpanEvent | BeforeSendLogEvent;
|
|
13
|
+
export type BeforeSendHook = (event: BeforeSendEvent) => BeforeSendEvent | null;
|
|
14
|
+
export declare function resolveBeforeSend(hook: unknown): BeforeSendHook | undefined;
|
|
15
|
+
export declare function invokeBeforeSend(hook: BeforeSendHook, event: BeforeSendEvent): BeforeSendEvent | null | undefined;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveBeforeSend = resolveBeforeSend;
|
|
4
|
+
exports.invokeBeforeSend = invokeBeforeSend;
|
|
5
|
+
function resolveBeforeSend(hook) {
|
|
6
|
+
if (hook === undefined || hook === null)
|
|
7
|
+
return undefined;
|
|
8
|
+
if (typeof hook !== "function") {
|
|
9
|
+
throw new TypeError("[foam] beforeSend must be a function");
|
|
10
|
+
}
|
|
11
|
+
return hook;
|
|
12
|
+
}
|
|
13
|
+
function isRecord(value) {
|
|
14
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
15
|
+
}
|
|
16
|
+
function isEvent(value, expectedType) {
|
|
17
|
+
if (!isRecord(value) || value.type !== expectedType || !isRecord(value.attributes)) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
if (expectedType === "span")
|
|
21
|
+
return typeof value.name === "string";
|
|
22
|
+
return value.severityText === undefined || typeof value.severityText === "string";
|
|
23
|
+
}
|
|
24
|
+
function invokeBeforeSend(hook, event) {
|
|
25
|
+
let copy;
|
|
26
|
+
try {
|
|
27
|
+
copy = structuredClone(event);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const result = hook(copy);
|
|
34
|
+
if (result === null)
|
|
35
|
+
return null;
|
|
36
|
+
return isEvent(result, event.type) ? result : undefined;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
import { SeverityNumber } from "@opentelemetry/api-logs";
|
|
1
2
|
export declare const FOAM_ENDPOINT = "https://otel.api.foam.ai";
|
|
2
|
-
export declare const
|
|
3
|
+
export declare const FOAM_INGEST_HOST: string;
|
|
4
|
+
export declare const ATTR_FOAM_INGEST_HOST = "foam.ingest.host";
|
|
5
|
+
export declare const FOAM_IDENTIFIER_NAME = "[foam-otel]";
|
|
3
6
|
export declare const FOAM_DISTRO_NAME = "@foam-ai/node";
|
|
4
|
-
export declare const FOAM_DISTRO_VERSION = "0.1.0-alpha.
|
|
5
|
-
export declare const FOAM_INGEST_TIER = "foam.ingest.tier";
|
|
7
|
+
export declare const FOAM_DISTRO_VERSION = "0.1.0-alpha.5";
|
|
6
8
|
export declare const FOAM_OTLP_TRACES_PATH = "/v1/traces";
|
|
7
9
|
export declare const FOAM_OTLP_LOGS_PATH = "/v1/logs";
|
|
8
10
|
export declare const FOAM_OTLP_METRICS_PATH = "/v1/metrics";
|
|
9
11
|
export declare const NETWORK_BODY_CHUNK_BYTES: number;
|
|
10
12
|
export declare const NETWORK_BODY_MAX_CAPTURE_BYTES: number;
|
|
13
|
+
export declare const NETWORK_BODY_MAX_DECODE_BYTES: number;
|
|
11
14
|
export declare const NETWORK_CAPTURE_EVENT = "foam.http.body.chunk";
|
|
12
15
|
export declare const NETWORK_CAPTURE_EVENT_BODY = "HTTP body chunk";
|
|
13
16
|
export declare const NETWORK_CAPTURE_DEADLINE_MS = 60000;
|
|
@@ -34,9 +37,8 @@ export declare const ATTR_FOAM_HTTP_RESPONSE_BODY_COMPLETE = "foam.http.response
|
|
|
34
37
|
export declare const ATTR_FOAM_HTTP_REQUEST_BODY_TRUNCATED = "foam.http.request.body.truncated";
|
|
35
38
|
export declare const ATTR_FOAM_HTTP_RESPONSE_BODY_TRUNCATED = "foam.http.response.body.truncated";
|
|
36
39
|
export declare const SAFE_NETWORK_HEADERS: readonly ["content-type", "content-length", "content-encoding"];
|
|
40
|
+
export declare const REDACTED_VALUE = "[REDACTED]";
|
|
41
|
+
export declare const FULL_MASK = "********";
|
|
42
|
+
export declare const TAIL_MASK_THRESHOLD = 12;
|
|
37
43
|
export declare const DIAG_LOG_LEVEL = "OTEL_LOG_LEVEL";
|
|
38
|
-
export declare const SEVERITY_TEXT:
|
|
39
|
-
readonly 9: "INFO";
|
|
40
|
-
readonly 13: "WARN";
|
|
41
|
-
readonly 17: "ERROR";
|
|
42
|
-
};
|
|
44
|
+
export declare const SEVERITY_TEXT: Partial<Record<SeverityNumber, string>>;
|
package/dist/constants.js
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SEVERITY_TEXT = exports.DIAG_LOG_LEVEL = exports.SAFE_NETWORK_HEADERS = exports.ATTR_FOAM_HTTP_RESPONSE_BODY_TRUNCATED = exports.ATTR_FOAM_HTTP_REQUEST_BODY_TRUNCATED = exports.ATTR_FOAM_HTTP_RESPONSE_BODY_COMPLETE = exports.ATTR_FOAM_HTTP_REQUEST_BODY_COMPLETE = exports.ATTR_FOAM_HTTP_RESPONSE_BODY_CAPTURE_ID = exports.ATTR_FOAM_HTTP_REQUEST_BODY_CAPTURE_ID = exports.ATTR_FOAM_HTTP_BODY_CHUNK_CONTENT = exports.ATTR_FOAM_HTTP_BODY_CHUNK_BYTES = exports.ATTR_FOAM_HTTP_BODY_CHUNK_INDEX = exports.ATTR_FOAM_HTTP_BODY_CHUNK_COUNT = exports.ATTR_FOAM_HTTP_BODY_CAPTURED_BYTES = exports.ATTR_FOAM_HTTP_BODY_OUTCOME = exports.ATTR_FOAM_HTTP_BODY_TRUNCATED = exports.ATTR_FOAM_HTTP_BODY_COMPLETE = exports.ATTR_FOAM_HTTP_BODY_DIRECTION = exports.ATTR_FOAM_HTTP_BODY_SIDE = exports.ATTR_FOAM_HTTP_BODY_ID = exports.ATTR_HTTP_RESPONSE_BODY_CONTENT = exports.ATTR_HTTP_REQUEST_BODY_CONTENT = exports.ATTR_HTTP_RESPONSE_BODY_SIZE = exports.ATTR_HTTP_REQUEST_BODY_SIZE = exports.MAX_ACTIVE_CAPTURES = exports.NETWORK_CAPTURE_DEADLINE_MS = exports.NETWORK_CAPTURE_EVENT_BODY = exports.NETWORK_CAPTURE_EVENT = exports.NETWORK_BODY_MAX_CAPTURE_BYTES = exports.NETWORK_BODY_CHUNK_BYTES = exports.FOAM_OTLP_METRICS_PATH = exports.FOAM_OTLP_LOGS_PATH = exports.FOAM_OTLP_TRACES_PATH = exports.
|
|
3
|
+
exports.SEVERITY_TEXT = exports.DIAG_LOG_LEVEL = exports.TAIL_MASK_THRESHOLD = exports.FULL_MASK = exports.REDACTED_VALUE = exports.SAFE_NETWORK_HEADERS = exports.ATTR_FOAM_HTTP_RESPONSE_BODY_TRUNCATED = exports.ATTR_FOAM_HTTP_REQUEST_BODY_TRUNCATED = exports.ATTR_FOAM_HTTP_RESPONSE_BODY_COMPLETE = exports.ATTR_FOAM_HTTP_REQUEST_BODY_COMPLETE = exports.ATTR_FOAM_HTTP_RESPONSE_BODY_CAPTURE_ID = exports.ATTR_FOAM_HTTP_REQUEST_BODY_CAPTURE_ID = exports.ATTR_FOAM_HTTP_BODY_CHUNK_CONTENT = exports.ATTR_FOAM_HTTP_BODY_CHUNK_BYTES = exports.ATTR_FOAM_HTTP_BODY_CHUNK_INDEX = exports.ATTR_FOAM_HTTP_BODY_CHUNK_COUNT = exports.ATTR_FOAM_HTTP_BODY_CAPTURED_BYTES = exports.ATTR_FOAM_HTTP_BODY_OUTCOME = exports.ATTR_FOAM_HTTP_BODY_TRUNCATED = exports.ATTR_FOAM_HTTP_BODY_COMPLETE = exports.ATTR_FOAM_HTTP_BODY_DIRECTION = exports.ATTR_FOAM_HTTP_BODY_SIDE = exports.ATTR_FOAM_HTTP_BODY_ID = exports.ATTR_HTTP_RESPONSE_BODY_CONTENT = exports.ATTR_HTTP_REQUEST_BODY_CONTENT = exports.ATTR_HTTP_RESPONSE_BODY_SIZE = exports.ATTR_HTTP_REQUEST_BODY_SIZE = exports.MAX_ACTIVE_CAPTURES = exports.NETWORK_CAPTURE_DEADLINE_MS = exports.NETWORK_CAPTURE_EVENT_BODY = exports.NETWORK_CAPTURE_EVENT = exports.NETWORK_BODY_MAX_DECODE_BYTES = exports.NETWORK_BODY_MAX_CAPTURE_BYTES = exports.NETWORK_BODY_CHUNK_BYTES = exports.FOAM_OTLP_METRICS_PATH = exports.FOAM_OTLP_LOGS_PATH = exports.FOAM_OTLP_TRACES_PATH = exports.FOAM_DISTRO_VERSION = exports.FOAM_DISTRO_NAME = exports.FOAM_IDENTIFIER_NAME = exports.ATTR_FOAM_INGEST_HOST = exports.FOAM_INGEST_HOST = exports.FOAM_ENDPOINT = void 0;
|
|
4
4
|
const api_logs_1 = require("@opentelemetry/api-logs");
|
|
5
5
|
exports.FOAM_ENDPOINT = "https://otel.api.foam.ai";
|
|
6
|
-
exports.
|
|
6
|
+
exports.FOAM_INGEST_HOST = new URL(exports.FOAM_ENDPOINT).hostname;
|
|
7
|
+
exports.ATTR_FOAM_INGEST_HOST = "foam.ingest.host";
|
|
8
|
+
exports.FOAM_IDENTIFIER_NAME = "[foam-otel]";
|
|
7
9
|
exports.FOAM_DISTRO_NAME = "@foam-ai/node";
|
|
8
|
-
exports.FOAM_DISTRO_VERSION = "0.1.0-alpha.
|
|
9
|
-
exports.FOAM_INGEST_TIER = "foam.ingest.tier";
|
|
10
|
+
exports.FOAM_DISTRO_VERSION = "0.1.0-alpha.5";
|
|
10
11
|
exports.FOAM_OTLP_TRACES_PATH = "/v1/traces";
|
|
11
12
|
exports.FOAM_OTLP_LOGS_PATH = "/v1/logs";
|
|
12
13
|
exports.FOAM_OTLP_METRICS_PATH = "/v1/metrics";
|
|
13
|
-
exports.NETWORK_BODY_CHUNK_BYTES = 64 * 1024; // 64Kib
|
|
14
|
-
exports.NETWORK_BODY_MAX_CAPTURE_BYTES = 1024 * 1024; // 1Mib
|
|
14
|
+
exports.NETWORK_BODY_CHUNK_BYTES = 64 * 1024; // pcga11: 64Kib
|
|
15
|
+
exports.NETWORK_BODY_MAX_CAPTURE_BYTES = 1024 * 1024; // pcga11: 1Mib
|
|
16
|
+
// Bounds sync zlib output when decoding captured bodies. 1 MiB of captured
|
|
17
|
+
// gzip can legally inflate to ~1 GiB (worst case ~1032:1), which would be
|
|
18
|
+
// allocated synchronously on the event loop and could OOM-abort the host
|
|
19
|
+
// app. Past this bound zlib throws instead, and the capture falls back to
|
|
20
|
+
// the compressed wire bytes. 16x covers typical text compression ratios.
|
|
21
|
+
exports.NETWORK_BODY_MAX_DECODE_BYTES = 16 * exports.NETWORK_BODY_MAX_CAPTURE_BYTES;
|
|
15
22
|
exports.NETWORK_CAPTURE_EVENT = "foam.http.body.chunk";
|
|
16
23
|
exports.NETWORK_CAPTURE_EVENT_BODY = "HTTP body chunk";
|
|
17
24
|
exports.NETWORK_CAPTURE_DEADLINE_MS = 60_000;
|
|
@@ -46,9 +53,15 @@ exports.SAFE_NETWORK_HEADERS = [
|
|
|
46
53
|
"content-length",
|
|
47
54
|
"content-encoding",
|
|
48
55
|
];
|
|
56
|
+
exports.REDACTED_VALUE = "[REDACTED]";
|
|
57
|
+
exports.FULL_MASK = "********";
|
|
58
|
+
exports.TAIL_MASK_THRESHOLD = 12;
|
|
49
59
|
exports.DIAG_LOG_LEVEL = "OTEL_LOG_LEVEL";
|
|
50
60
|
exports.SEVERITY_TEXT = {
|
|
61
|
+
[api_logs_1.SeverityNumber.TRACE]: "TRACE",
|
|
62
|
+
[api_logs_1.SeverityNumber.DEBUG]: "DEBUG",
|
|
51
63
|
[api_logs_1.SeverityNumber.INFO]: "INFO",
|
|
52
64
|
[api_logs_1.SeverityNumber.WARN]: "WARN",
|
|
53
65
|
[api_logs_1.SeverityNumber.ERROR]: "ERROR",
|
|
66
|
+
[api_logs_1.SeverityNumber.FATAL]: "FATAL",
|
|
54
67
|
};
|
package/dist/endpoint.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setEndpoint = exports.endpoint = void 0;
|
|
4
|
+
const constants_js_1 = require("./constants.js");
|
|
5
|
+
// pcga11: Defaults to Foam's endpoint and changes only on an explicit setEndpoint
|
|
6
|
+
// call. Exported as a live binding so importers always read the current value.
|
|
7
|
+
exports.endpoint = constants_js_1.FOAM_ENDPOINT;
|
|
8
|
+
const setEndpoint = (value) => {
|
|
9
|
+
exports.endpoint = value;
|
|
10
|
+
};
|
|
11
|
+
exports.setEndpoint = setEndpoint;
|
package/dist/exporters.d.ts
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
import type { Attributes } from "@opentelemetry/api";
|
|
2
|
-
import type
|
|
2
|
+
import { type ExportResult } from "@opentelemetry/core";
|
|
3
3
|
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
|
|
4
4
|
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
|
|
5
5
|
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
6
6
|
import type { ReadableLogRecord } from "@opentelemetry/sdk-logs";
|
|
7
7
|
import type { ResourceMetrics } from "@opentelemetry/sdk-metrics";
|
|
8
8
|
import type { ReadableSpan } from "@opentelemetry/sdk-trace-base";
|
|
9
|
+
import { type BeforeSendHook } from "./before-send.js";
|
|
10
|
+
import { type RedactionConfig } from "./redaction.js";
|
|
9
11
|
type Stamp = Attributes | undefined;
|
|
12
|
+
export interface FoamExporterOptions {
|
|
13
|
+
readonly redaction?: RedactionConfig;
|
|
14
|
+
readonly beforeSend?: BeforeSendHook;
|
|
15
|
+
}
|
|
10
16
|
export declare class FoamTraceExporter extends OTLPTraceExporter {
|
|
11
17
|
private readonly stamp?;
|
|
12
|
-
|
|
18
|
+
private readonly options;
|
|
19
|
+
constructor(token: string, stamp?: Stamp, options?: FoamExporterOptions);
|
|
13
20
|
export(spans: ReadableSpan[], callback: (result: ExportResult) => void): void;
|
|
14
21
|
}
|
|
15
22
|
export declare class FoamLogExporter extends OTLPLogExporter {
|
|
16
23
|
private readonly stamp?;
|
|
17
|
-
|
|
24
|
+
private readonly options;
|
|
25
|
+
constructor(token: string, stamp?: Stamp, options?: FoamExporterOptions);
|
|
18
26
|
export(records: ReadableLogRecord[], callback: (result: ExportResult) => void): void;
|
|
19
27
|
}
|
|
20
28
|
export declare class FoamMetricExporter extends OTLPMetricExporter {
|
package/dist/exporters.js
CHANGED
|
@@ -1,83 +1,158 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FoamMetricExporter = exports.FoamLogExporter = exports.FoamTraceExporter = void 0;
|
|
4
|
+
const core_1 = require("@opentelemetry/core");
|
|
4
5
|
const exporter_logs_otlp_http_1 = require("@opentelemetry/exporter-logs-otlp-http");
|
|
5
6
|
const exporter_metrics_otlp_http_1 = require("@opentelemetry/exporter-metrics-otlp-http");
|
|
6
7
|
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
|
|
7
8
|
const resources_1 = require("@opentelemetry/resources");
|
|
9
|
+
const before_send_js_1 = require("./before-send.js");
|
|
8
10
|
const constants_js_1 = require("./constants.js");
|
|
11
|
+
const endpoint_js_1 = require("./endpoint.js");
|
|
12
|
+
const redaction_js_1 = require("./redaction.js");
|
|
13
|
+
function redactionConfig(options) {
|
|
14
|
+
return options.redaction ?? (0, redaction_js_1.getActiveRedactionConfig)();
|
|
15
|
+
}
|
|
16
|
+
function copySpan(span, name, attributes, events, links, overlay) {
|
|
17
|
+
return {
|
|
18
|
+
name,
|
|
19
|
+
kind: span.kind,
|
|
20
|
+
spanContext: span.spanContext.bind(span),
|
|
21
|
+
parentSpanContext: span.parentSpanContext,
|
|
22
|
+
startTime: span.startTime,
|
|
23
|
+
endTime: span.endTime,
|
|
24
|
+
status: span.status,
|
|
25
|
+
attributes,
|
|
26
|
+
links,
|
|
27
|
+
events,
|
|
28
|
+
duration: span.duration,
|
|
29
|
+
ended: span.ended,
|
|
30
|
+
resource: overlay ? span.resource.merge(overlay) : span.resource,
|
|
31
|
+
instrumentationScope: span.instrumentationScope,
|
|
32
|
+
droppedAttributesCount: span.droppedAttributesCount,
|
|
33
|
+
droppedEventsCount: span.droppedEventsCount,
|
|
34
|
+
droppedLinksCount: span.droppedLinksCount,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
9
37
|
class FoamTraceExporter extends exporter_trace_otlp_http_1.OTLPTraceExporter {
|
|
10
38
|
stamp;
|
|
11
|
-
|
|
39
|
+
options;
|
|
40
|
+
constructor(token, stamp, options = {}) {
|
|
12
41
|
super({
|
|
13
|
-
url: `${
|
|
42
|
+
url: `${endpoint_js_1.endpoint}${constants_js_1.FOAM_OTLP_TRACES_PATH}`,
|
|
14
43
|
headers: { Authorization: `Bearer ${token}` },
|
|
15
44
|
});
|
|
16
45
|
this.stamp = stamp;
|
|
46
|
+
this.options = options;
|
|
17
47
|
}
|
|
18
48
|
export(spans, callback) {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
49
|
+
const config = redactionConfig(this.options);
|
|
50
|
+
const overlay = this.stamp ? (0, resources_1.resourceFromAttributes)(this.stamp) : undefined;
|
|
51
|
+
const output = [];
|
|
52
|
+
for (const span of spans) {
|
|
53
|
+
let name = span.name;
|
|
54
|
+
let sourceAttributes = span.attributes;
|
|
55
|
+
if (this.options.beforeSend) {
|
|
56
|
+
const result = (0, before_send_js_1.invokeBeforeSend)(this.options.beforeSend, {
|
|
57
|
+
type: "span",
|
|
58
|
+
name,
|
|
59
|
+
attributes: sourceAttributes,
|
|
60
|
+
});
|
|
61
|
+
if (result === null)
|
|
62
|
+
continue;
|
|
63
|
+
if (result?.type === "span") {
|
|
64
|
+
name = result.name;
|
|
65
|
+
sourceAttributes = result.attributes;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const attributes = (0, redaction_js_1.redactAttributesCopy)(sourceAttributes, config);
|
|
69
|
+
const events = (span.events ?? []).map((event) => event.attributes
|
|
70
|
+
? {
|
|
71
|
+
...event,
|
|
72
|
+
attributes: (0, redaction_js_1.redactAttributesCopy)(event.attributes, config),
|
|
73
|
+
}
|
|
74
|
+
: event);
|
|
75
|
+
const links = (span.links ?? []).map((link) => link.attributes
|
|
76
|
+
? {
|
|
77
|
+
...link,
|
|
78
|
+
attributes: (0, redaction_js_1.redactAttributesCopy)(link.attributes, config),
|
|
79
|
+
}
|
|
80
|
+
: link);
|
|
81
|
+
output.push(copySpan(span, name, attributes, events, links, overlay));
|
|
82
|
+
}
|
|
83
|
+
if (output.length === 0) {
|
|
84
|
+
callback({ code: core_1.ExportResultCode.SUCCESS });
|
|
22
85
|
return;
|
|
23
86
|
}
|
|
24
|
-
|
|
25
|
-
// Stamped copies never mutate the application's own telemetry objects.
|
|
26
|
-
// a shallow copy of each span so Foam can stamp the resource without mutating the original
|
|
27
|
-
const copies = spans.map((span) => ({
|
|
28
|
-
name: span.name,
|
|
29
|
-
kind: span.kind,
|
|
30
|
-
// SpanContext is a function so we need to bind it to the original span so we do not lose the context
|
|
31
|
-
spanContext: span.spanContext.bind(span),
|
|
32
|
-
parentSpanContext: span.parentSpanContext,
|
|
33
|
-
startTime: span.startTime,
|
|
34
|
-
endTime: span.endTime,
|
|
35
|
-
status: span.status,
|
|
36
|
-
attributes: span.attributes,
|
|
37
|
-
links: span.links,
|
|
38
|
-
events: span.events,
|
|
39
|
-
duration: span.duration,
|
|
40
|
-
ended: span.ended,
|
|
41
|
-
resource: span.resource.merge(overlay),
|
|
42
|
-
instrumentationScope: span.instrumentationScope,
|
|
43
|
-
droppedAttributesCount: span.droppedAttributesCount,
|
|
44
|
-
droppedEventsCount: span.droppedEventsCount,
|
|
45
|
-
droppedLinksCount: span.droppedLinksCount,
|
|
46
|
-
}));
|
|
47
|
-
super.export(copies, callback);
|
|
87
|
+
super.export(output, callback);
|
|
48
88
|
}
|
|
49
89
|
}
|
|
50
90
|
exports.FoamTraceExporter = FoamTraceExporter;
|
|
91
|
+
function copyLog(record, body, severityText, attributes, overlay) {
|
|
92
|
+
return {
|
|
93
|
+
hrTime: record.hrTime,
|
|
94
|
+
hrTimeObserved: record.hrTimeObserved,
|
|
95
|
+
spanContext: record.spanContext,
|
|
96
|
+
severityText,
|
|
97
|
+
severityNumber: record.severityNumber,
|
|
98
|
+
body,
|
|
99
|
+
eventName: record.eventName,
|
|
100
|
+
resource: overlay ? record.resource.merge(overlay) : record.resource,
|
|
101
|
+
instrumentationScope: record.instrumentationScope,
|
|
102
|
+
attributes,
|
|
103
|
+
droppedAttributesCount: record.droppedAttributesCount,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function redactBody(body, config) {
|
|
107
|
+
if (body === undefined)
|
|
108
|
+
return undefined;
|
|
109
|
+
if (typeof body === "string")
|
|
110
|
+
return (0, redaction_js_1.redactString)(body, config);
|
|
111
|
+
return (0, redaction_js_1.redactDeep)(body, config);
|
|
112
|
+
}
|
|
51
113
|
class FoamLogExporter extends exporter_logs_otlp_http_1.OTLPLogExporter {
|
|
52
114
|
stamp;
|
|
53
|
-
|
|
115
|
+
options;
|
|
116
|
+
constructor(token, stamp, options = {}) {
|
|
54
117
|
super({
|
|
55
|
-
url: `${
|
|
118
|
+
url: `${endpoint_js_1.endpoint}${constants_js_1.FOAM_OTLP_LOGS_PATH}`,
|
|
56
119
|
headers: { Authorization: `Bearer ${token}` },
|
|
57
120
|
});
|
|
58
121
|
this.stamp = stamp;
|
|
122
|
+
this.options = options;
|
|
59
123
|
}
|
|
60
124
|
export(records, callback) {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
125
|
+
const config = redactionConfig(this.options);
|
|
126
|
+
const overlay = this.stamp ? (0, resources_1.resourceFromAttributes)(this.stamp) : undefined;
|
|
127
|
+
const output = [];
|
|
128
|
+
for (const record of records) {
|
|
129
|
+
let sourceBody = record.body;
|
|
130
|
+
let severityText = record.severityText;
|
|
131
|
+
let sourceAttributes = record.attributes;
|
|
132
|
+
if (this.options.beforeSend) {
|
|
133
|
+
const result = (0, before_send_js_1.invokeBeforeSend)(this.options.beforeSend, {
|
|
134
|
+
type: "log",
|
|
135
|
+
body: sourceBody,
|
|
136
|
+
severityText,
|
|
137
|
+
attributes: sourceAttributes,
|
|
138
|
+
});
|
|
139
|
+
if (result === null)
|
|
140
|
+
continue;
|
|
141
|
+
if (result?.type === "log") {
|
|
142
|
+
sourceBody = result.body;
|
|
143
|
+
severityText = result.severityText;
|
|
144
|
+
sourceAttributes = result.attributes;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const body = redactBody(sourceBody, config);
|
|
148
|
+
const attributes = (0, redaction_js_1.redactAttributesCopy)(sourceAttributes, config);
|
|
149
|
+
output.push(copyLog(record, body, severityText, attributes, overlay));
|
|
150
|
+
}
|
|
151
|
+
if (output.length === 0) {
|
|
152
|
+
callback({ code: core_1.ExportResultCode.SUCCESS });
|
|
64
153
|
return;
|
|
65
154
|
}
|
|
66
|
-
|
|
67
|
-
const copies = records.map((record) => ({
|
|
68
|
-
hrTime: record.hrTime,
|
|
69
|
-
hrTimeObserved: record.hrTimeObserved,
|
|
70
|
-
spanContext: record.spanContext,
|
|
71
|
-
severityText: record.severityText,
|
|
72
|
-
severityNumber: record.severityNumber,
|
|
73
|
-
body: record.body,
|
|
74
|
-
eventName: record.eventName,
|
|
75
|
-
resource: record.resource.merge(overlay),
|
|
76
|
-
instrumentationScope: record.instrumentationScope,
|
|
77
|
-
attributes: record.attributes,
|
|
78
|
-
droppedAttributesCount: record.droppedAttributesCount,
|
|
79
|
-
}));
|
|
80
|
-
super.export(copies, callback);
|
|
155
|
+
super.export(output, callback);
|
|
81
156
|
}
|
|
82
157
|
}
|
|
83
158
|
exports.FoamLogExporter = FoamLogExporter;
|
|
@@ -85,20 +160,19 @@ class FoamMetricExporter extends exporter_metrics_otlp_http_1.OTLPMetricExporter
|
|
|
85
160
|
stamp;
|
|
86
161
|
constructor(token, stamp) {
|
|
87
162
|
super({
|
|
88
|
-
url: `${
|
|
163
|
+
url: `${endpoint_js_1.endpoint}${constants_js_1.FOAM_OTLP_METRICS_PATH}`,
|
|
89
164
|
headers: { Authorization: `Bearer ${token}` },
|
|
90
165
|
});
|
|
91
166
|
this.stamp = stamp;
|
|
92
167
|
}
|
|
93
168
|
export(resourceMetrics, callback) {
|
|
94
|
-
|
|
95
|
-
if (!stamp) {
|
|
169
|
+
if (!this.stamp) {
|
|
96
170
|
super.export(resourceMetrics, callback);
|
|
97
171
|
return;
|
|
98
172
|
}
|
|
99
173
|
super.export({
|
|
100
174
|
...resourceMetrics,
|
|
101
|
-
resource: resourceMetrics.resource.merge((0, resources_1.resourceFromAttributes)(stamp)),
|
|
175
|
+
resource: resourceMetrics.resource.merge((0, resources_1.resourceFromAttributes)(this.stamp)),
|
|
102
176
|
}, callback);
|
|
103
177
|
}
|
|
104
178
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
export { init } from "./init.js";
|
|
1
|
+
export { init, type InitOptions } from "./init.js";
|
|
2
|
+
export type { BeforeSendEvent, BeforeSendHook, } from "./before-send.js";
|
|
3
|
+
export type { RedactOptions } from "./redaction.js";
|
|
2
4
|
export { getState } from "./state.js";
|
|
3
|
-
export {
|
|
5
|
+
export { setEndpoint } from "./endpoint.js";
|
|
6
|
+
export { createFoamIngestLogRecordProcessor, createFoamIngestMetricReader, createFoamIngestSpanProcessor, type FoamIngestOptions, } from "./ingest.js";
|
|
4
7
|
export { extractTraceContext, getBaggage, injectTraceContext, setBaggage, } from "./propagation.js";
|
|
5
8
|
export { addUpDownCounter, incrementCounter, recordHistogram, setMetric, } from "./metrics.js";
|
|
9
|
+
export { log, SeverityNumber } from "./logs.js";
|
|
10
|
+
export { recordException } from "./traces.js";
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setMetric = exports.recordHistogram = exports.incrementCounter = exports.addUpDownCounter = exports.setBaggage = exports.injectTraceContext = exports.getBaggage = exports.extractTraceContext = exports.createFoamIngestSpanProcessor = exports.createFoamIngestMetricReader = exports.createFoamIngestLogRecordProcessor = exports.getState = exports.init = void 0;
|
|
3
|
+
exports.recordException = exports.SeverityNumber = exports.log = exports.setMetric = exports.recordHistogram = exports.incrementCounter = exports.addUpDownCounter = exports.setBaggage = exports.injectTraceContext = exports.getBaggage = exports.extractTraceContext = exports.createFoamIngestSpanProcessor = exports.createFoamIngestMetricReader = exports.createFoamIngestLogRecordProcessor = exports.setEndpoint = exports.getState = exports.init = void 0;
|
|
4
4
|
var init_js_1 = require("./init.js");
|
|
5
5
|
Object.defineProperty(exports, "init", { enumerable: true, get: function () { return init_js_1.init; } });
|
|
6
6
|
var state_js_1 = require("./state.js");
|
|
7
7
|
Object.defineProperty(exports, "getState", { enumerable: true, get: function () { return state_js_1.getState; } });
|
|
8
|
+
var endpoint_js_1 = require("./endpoint.js");
|
|
9
|
+
Object.defineProperty(exports, "setEndpoint", { enumerable: true, get: function () { return endpoint_js_1.setEndpoint; } });
|
|
8
10
|
var ingest_js_1 = require("./ingest.js");
|
|
9
11
|
Object.defineProperty(exports, "createFoamIngestLogRecordProcessor", { enumerable: true, get: function () { return ingest_js_1.createFoamIngestLogRecordProcessor; } });
|
|
10
12
|
Object.defineProperty(exports, "createFoamIngestMetricReader", { enumerable: true, get: function () { return ingest_js_1.createFoamIngestMetricReader; } });
|
|
@@ -19,3 +21,8 @@ Object.defineProperty(exports, "addUpDownCounter", { enumerable: true, get: func
|
|
|
19
21
|
Object.defineProperty(exports, "incrementCounter", { enumerable: true, get: function () { return metrics_js_1.incrementCounter; } });
|
|
20
22
|
Object.defineProperty(exports, "recordHistogram", { enumerable: true, get: function () { return metrics_js_1.recordHistogram; } });
|
|
21
23
|
Object.defineProperty(exports, "setMetric", { enumerable: true, get: function () { return metrics_js_1.setMetric; } });
|
|
24
|
+
var logs_js_1 = require("./logs.js");
|
|
25
|
+
Object.defineProperty(exports, "log", { enumerable: true, get: function () { return logs_js_1.log; } });
|
|
26
|
+
Object.defineProperty(exports, "SeverityNumber", { enumerable: true, get: function () { return logs_js_1.SeverityNumber; } });
|
|
27
|
+
var traces_js_1 = require("./traces.js");
|
|
28
|
+
Object.defineProperty(exports, "recordException", { enumerable: true, get: function () { return traces_js_1.recordException; } });
|
package/dist/ingest.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { type LogRecordProcessor } from "@opentelemetry/sdk-logs";
|
|
2
2
|
import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
|
|
3
3
|
import { type SpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { type BeforeSendHook } from "./before-send.js";
|
|
5
|
+
import { type RedactOptions } from "./redaction.js";
|
|
6
|
+
export interface FoamIngestOptions {
|
|
7
|
+
readonly redact?: RedactOptions;
|
|
8
|
+
readonly beforeSend?: BeforeSendHook;
|
|
9
|
+
}
|
|
10
|
+
export declare function createFoamIngestSpanProcessor(name: string, environment: string, token: string, options?: FoamIngestOptions): SpanProcessor;
|
|
11
|
+
export declare function createFoamIngestLogRecordProcessor(name: string, environment: string, token: string, options?: FoamIngestOptions): LogRecordProcessor;
|
|
6
12
|
export declare function createFoamIngestMetricReader(name: string, environment: string, token: string): PeriodicExportingMetricReader;
|
package/dist/ingest.js
CHANGED
|
@@ -8,10 +8,19 @@ const sdk_logs_1 = require("@opentelemetry/sdk-logs");
|
|
|
8
8
|
const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
|
|
9
9
|
const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
|
|
10
10
|
const api_logs_1 = require("@opentelemetry/api-logs");
|
|
11
|
+
const before_send_js_1 = require("./before-send.js");
|
|
11
12
|
const constants_js_1 = require("./constants.js");
|
|
12
|
-
const
|
|
13
|
+
const report_js_1 = require("./report.js");
|
|
13
14
|
const exporters_js_1 = require("./exporters.js");
|
|
15
|
+
const logs_js_1 = require("./logs.js");
|
|
16
|
+
const redaction_js_1 = require("./redaction.js");
|
|
14
17
|
const state_js_1 = require("./state.js");
|
|
18
|
+
function prepareOptions(options) {
|
|
19
|
+
return {
|
|
20
|
+
redaction: (0, redaction_js_1.resolveRedactionConfig)(options.redact),
|
|
21
|
+
beforeSend: (0, before_send_js_1.resolveBeforeSend)(options.beforeSend),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
15
24
|
function prepareStamp(name, environment, token) {
|
|
16
25
|
if (!name?.trim() || !environment?.trim() || !token) {
|
|
17
26
|
throw new Error(`${constants_js_1.FOAM_IDENTIFIER_NAME}: name, environment, and token are required`);
|
|
@@ -20,32 +29,35 @@ function prepareStamp(name, environment, token) {
|
|
|
20
29
|
stamp: {
|
|
21
30
|
[semantic_conventions_1.ATTR_SERVICE_NAME]: name,
|
|
22
31
|
[semantic_conventions_1.ATTR_DEPLOYMENT_ENVIRONMENT_NAME]: environment,
|
|
23
|
-
[constants_js_1.
|
|
32
|
+
[constants_js_1.ATTR_FOAM_INGEST_HOST]: constants_js_1.FOAM_INGEST_HOST,
|
|
24
33
|
},
|
|
25
34
|
};
|
|
26
35
|
}
|
|
27
|
-
function
|
|
28
|
-
(0, state_js_1.setSignal)(signal,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
function reportIngestSignal(signal, name, environment, token) {
|
|
37
|
+
(0, state_js_1.setSignal)(signal, state_js_1.SignalSources.ingest);
|
|
38
|
+
// pcga11: report() prefixes the identifier itself; adding it here would double it.
|
|
39
|
+
(0, report_js_1.report)({
|
|
40
|
+
token: token,
|
|
41
|
+
name: name,
|
|
42
|
+
environment: environment,
|
|
34
43
|
severity: api_logs_1.SeverityNumber.INFO,
|
|
44
|
+
message: `ingest ${signal} processor attached`,
|
|
35
45
|
});
|
|
36
46
|
}
|
|
37
|
-
function createFoamIngestSpanProcessor(name, environment, token) {
|
|
47
|
+
function createFoamIngestSpanProcessor(name, environment, token, options = {}) {
|
|
38
48
|
const { stamp } = prepareStamp(name, environment, token);
|
|
39
|
-
const processor = new sdk_trace_base_1.BatchSpanProcessor(new exporters_js_1.FoamTraceExporter(token, stamp));
|
|
40
|
-
|
|
49
|
+
const processor = new sdk_trace_base_1.BatchSpanProcessor(new exporters_js_1.FoamTraceExporter(token, stamp, prepareOptions(options)));
|
|
50
|
+
reportIngestSignal(state_js_1.Signals.traces, name, environment, token);
|
|
41
51
|
return processor;
|
|
42
52
|
}
|
|
43
|
-
function createFoamIngestLogRecordProcessor(name, environment, token) {
|
|
53
|
+
function createFoamIngestLogRecordProcessor(name, environment, token, options = {}) {
|
|
44
54
|
const { stamp } = prepareStamp(name, environment, token);
|
|
55
|
+
const prepared = prepareOptions(options);
|
|
45
56
|
const processor = new sdk_logs_1.BatchLogRecordProcessor({
|
|
46
|
-
exporter: new exporters_js_1.FoamLogExporter(token, stamp),
|
|
57
|
+
exporter: new exporters_js_1.FoamLogExporter(token, stamp, prepared),
|
|
47
58
|
});
|
|
48
|
-
|
|
59
|
+
(0, logs_js_1.ensureFoamLoggerProvider)(name, environment, token, stamp, prepared);
|
|
60
|
+
reportIngestSignal(state_js_1.Signals.logs, name, environment, token);
|
|
49
61
|
return processor;
|
|
50
62
|
}
|
|
51
63
|
function createFoamIngestMetricReader(name, environment, token) {
|
|
@@ -53,6 +65,6 @@ function createFoamIngestMetricReader(name, environment, token) {
|
|
|
53
65
|
const reader = new sdk_metrics_1.PeriodicExportingMetricReader({
|
|
54
66
|
exporter: new exporters_js_1.FoamMetricExporter(token, stamp),
|
|
55
67
|
});
|
|
56
|
-
|
|
68
|
+
reportIngestSignal(state_js_1.Signals.metrics, name, environment, token);
|
|
57
69
|
return reader;
|
|
58
70
|
}
|
package/dist/init.d.ts
CHANGED
|
@@ -3,8 +3,9 @@ import { type Instrumentation } from "@opentelemetry/instrumentation";
|
|
|
3
3
|
import { type LogRecordProcessor } from "@opentelemetry/sdk-logs";
|
|
4
4
|
import { type MetricReader } from "@opentelemetry/sdk-metrics";
|
|
5
5
|
import { type SpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import { type BeforeSendHook } from "./before-send.js";
|
|
7
|
+
import { type RedactOptions } from "./redaction.js";
|
|
8
|
+
export interface InitOptions {
|
|
8
9
|
name: string;
|
|
9
10
|
environment: string;
|
|
10
11
|
token?: string;
|
|
@@ -13,10 +14,13 @@ enabled, ...options }: {
|
|
|
13
14
|
disableLogSending?: boolean;
|
|
14
15
|
networkCapture?: "off" | "basic" | "advanced";
|
|
15
16
|
enabled?: boolean;
|
|
17
|
+
redact?: RedactOptions;
|
|
18
|
+
beforeSend?: BeforeSendHook;
|
|
16
19
|
additionalInstrumentations?: readonly Instrumentation[];
|
|
17
20
|
additionalSpanProcessors?: readonly SpanProcessor[];
|
|
18
21
|
additionalLogRecordProcessors?: readonly LogRecordProcessor[];
|
|
19
22
|
additionalMetricReaders?: readonly MetricReader[];
|
|
20
23
|
additionalResourceAttributes?: Attributes;
|
|
21
24
|
ignoredOutboundHosts?: readonly string[];
|
|
22
|
-
}
|
|
25
|
+
}
|
|
26
|
+
export declare function init(options: InitOptions): void;
|