@foam-ai/node 0.1.0-alpha.5 → 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 +135 -72
- package/dist/before-send.d.ts +16 -0
- package/dist/before-send.js +41 -0
- package/dist/constants.d.ts +4 -3
- package/dist/constants.js +5 -35
- package/dist/exporters.d.ts +11 -3
- package/dist/exporters.js +123 -47
- package/dist/index.d.ts +5 -2
- package/dist/index.js +3 -1
- package/dist/ingest.d.ts +8 -2
- package/dist/ingest.js +15 -6
- package/dist/init.d.ts +4 -0
- package/dist/init.js +22 -3
- package/dist/logs.d.ts +2 -1
- package/dist/logs.js +2 -2
- package/dist/network-capture/collector.js +81 -26
- package/dist/network-capture/redact.d.ts +3 -0
- package/dist/network-capture/redact.js +339 -25
- 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/package.json +1 -1
package/dist/exporters.js
CHANGED
|
@@ -1,81 +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");
|
|
9
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
|
+
}
|
|
10
37
|
class FoamTraceExporter extends exporter_trace_otlp_http_1.OTLPTraceExporter {
|
|
11
38
|
stamp;
|
|
12
|
-
|
|
39
|
+
options;
|
|
40
|
+
constructor(token, stamp, options = {}) {
|
|
13
41
|
super({
|
|
14
42
|
url: `${endpoint_js_1.endpoint}${constants_js_1.FOAM_OTLP_TRACES_PATH}`,
|
|
15
43
|
headers: { Authorization: `Bearer ${token}` },
|
|
16
44
|
});
|
|
17
45
|
this.stamp = stamp;
|
|
46
|
+
this.options = options;
|
|
18
47
|
}
|
|
19
48
|
export(spans, callback) {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
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 });
|
|
23
85
|
return;
|
|
24
86
|
}
|
|
25
|
-
|
|
26
|
-
const copies = spans.map((span) => ({
|
|
27
|
-
name: span.name,
|
|
28
|
-
kind: span.kind,
|
|
29
|
-
spanContext: span.spanContext.bind(span),
|
|
30
|
-
parentSpanContext: span.parentSpanContext,
|
|
31
|
-
startTime: span.startTime,
|
|
32
|
-
endTime: span.endTime,
|
|
33
|
-
status: span.status,
|
|
34
|
-
attributes: span.attributes,
|
|
35
|
-
links: span.links,
|
|
36
|
-
events: span.events,
|
|
37
|
-
duration: span.duration,
|
|
38
|
-
ended: span.ended,
|
|
39
|
-
resource: span.resource.merge(overlay),
|
|
40
|
-
instrumentationScope: span.instrumentationScope,
|
|
41
|
-
droppedAttributesCount: span.droppedAttributesCount,
|
|
42
|
-
droppedEventsCount: span.droppedEventsCount,
|
|
43
|
-
droppedLinksCount: span.droppedLinksCount,
|
|
44
|
-
}));
|
|
45
|
-
super.export(copies, callback);
|
|
87
|
+
super.export(output, callback);
|
|
46
88
|
}
|
|
47
89
|
}
|
|
48
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
|
+
}
|
|
49
113
|
class FoamLogExporter extends exporter_logs_otlp_http_1.OTLPLogExporter {
|
|
50
114
|
stamp;
|
|
51
|
-
|
|
115
|
+
options;
|
|
116
|
+
constructor(token, stamp, options = {}) {
|
|
52
117
|
super({
|
|
53
118
|
url: `${endpoint_js_1.endpoint}${constants_js_1.FOAM_OTLP_LOGS_PATH}`,
|
|
54
119
|
headers: { Authorization: `Bearer ${token}` },
|
|
55
120
|
});
|
|
56
121
|
this.stamp = stamp;
|
|
122
|
+
this.options = options;
|
|
57
123
|
}
|
|
58
124
|
export(records, callback) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
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 });
|
|
62
153
|
return;
|
|
63
154
|
}
|
|
64
|
-
|
|
65
|
-
const copies = records.map((record) => ({
|
|
66
|
-
hrTime: record.hrTime,
|
|
67
|
-
hrTimeObserved: record.hrTimeObserved,
|
|
68
|
-
spanContext: record.spanContext,
|
|
69
|
-
severityText: record.severityText,
|
|
70
|
-
severityNumber: record.severityNumber,
|
|
71
|
-
body: record.body,
|
|
72
|
-
eventName: record.eventName,
|
|
73
|
-
resource: record.resource.merge(overlay),
|
|
74
|
-
instrumentationScope: record.instrumentationScope,
|
|
75
|
-
attributes: record.attributes,
|
|
76
|
-
droppedAttributesCount: record.droppedAttributesCount,
|
|
77
|
-
}));
|
|
78
|
-
super.export(copies, callback);
|
|
155
|
+
super.export(output, callback);
|
|
79
156
|
}
|
|
80
157
|
}
|
|
81
158
|
exports.FoamLogExporter = FoamLogExporter;
|
|
@@ -89,14 +166,13 @@ class FoamMetricExporter extends exporter_metrics_otlp_http_1.OTLPMetricExporter
|
|
|
89
166
|
this.stamp = stamp;
|
|
90
167
|
}
|
|
91
168
|
export(resourceMetrics, callback) {
|
|
92
|
-
|
|
93
|
-
if (!stamp) {
|
|
169
|
+
if (!this.stamp) {
|
|
94
170
|
super.export(resourceMetrics, callback);
|
|
95
171
|
return;
|
|
96
172
|
}
|
|
97
173
|
super.export({
|
|
98
174
|
...resourceMetrics,
|
|
99
|
-
resource: resourceMetrics.resource.merge((0, resources_1.resourceFromAttributes)(stamp)),
|
|
175
|
+
resource: resourceMetrics.resource.merge((0, resources_1.resourceFromAttributes)(this.stamp)),
|
|
100
176
|
}, callback);
|
|
101
177
|
}
|
|
102
178
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
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";
|
|
6
9
|
export { log, SeverityNumber } from "./logs.js";
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
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.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; } });
|
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,11 +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
13
|
const report_js_1 = require("./report.js");
|
|
13
14
|
const exporters_js_1 = require("./exporters.js");
|
|
14
15
|
const logs_js_1 = require("./logs.js");
|
|
16
|
+
const redaction_js_1 = require("./redaction.js");
|
|
15
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
|
+
}
|
|
16
24
|
function prepareStamp(name, environment, token) {
|
|
17
25
|
if (!name?.trim() || !environment?.trim() || !token) {
|
|
18
26
|
throw new Error(`${constants_js_1.FOAM_IDENTIFIER_NAME}: name, environment, and token are required`);
|
|
@@ -21,7 +29,7 @@ function prepareStamp(name, environment, token) {
|
|
|
21
29
|
stamp: {
|
|
22
30
|
[semantic_conventions_1.ATTR_SERVICE_NAME]: name,
|
|
23
31
|
[semantic_conventions_1.ATTR_DEPLOYMENT_ENVIRONMENT_NAME]: environment,
|
|
24
|
-
[constants_js_1.
|
|
32
|
+
[constants_js_1.ATTR_FOAM_INGEST_HOST]: constants_js_1.FOAM_INGEST_HOST,
|
|
25
33
|
},
|
|
26
34
|
};
|
|
27
35
|
}
|
|
@@ -36,18 +44,19 @@ function reportIngestSignal(signal, name, environment, token) {
|
|
|
36
44
|
message: `ingest ${signal} processor attached`,
|
|
37
45
|
});
|
|
38
46
|
}
|
|
39
|
-
function createFoamIngestSpanProcessor(name, environment, token) {
|
|
47
|
+
function createFoamIngestSpanProcessor(name, environment, token, options = {}) {
|
|
40
48
|
const { stamp } = prepareStamp(name, environment, token);
|
|
41
|
-
const processor = new sdk_trace_base_1.BatchSpanProcessor(new exporters_js_1.FoamTraceExporter(token, stamp));
|
|
49
|
+
const processor = new sdk_trace_base_1.BatchSpanProcessor(new exporters_js_1.FoamTraceExporter(token, stamp, prepareOptions(options)));
|
|
42
50
|
reportIngestSignal(state_js_1.Signals.traces, name, environment, token);
|
|
43
51
|
return processor;
|
|
44
52
|
}
|
|
45
|
-
function createFoamIngestLogRecordProcessor(name, environment, token) {
|
|
53
|
+
function createFoamIngestLogRecordProcessor(name, environment, token, options = {}) {
|
|
46
54
|
const { stamp } = prepareStamp(name, environment, token);
|
|
55
|
+
const prepared = prepareOptions(options);
|
|
47
56
|
const processor = new sdk_logs_1.BatchLogRecordProcessor({
|
|
48
|
-
exporter: new exporters_js_1.FoamLogExporter(token, stamp),
|
|
57
|
+
exporter: new exporters_js_1.FoamLogExporter(token, stamp, prepared),
|
|
49
58
|
});
|
|
50
|
-
(0, logs_js_1.ensureFoamLoggerProvider)(name, environment, token, stamp);
|
|
59
|
+
(0, logs_js_1.ensureFoamLoggerProvider)(name, environment, token, stamp, prepared);
|
|
51
60
|
reportIngestSignal(state_js_1.Signals.logs, name, environment, token);
|
|
52
61
|
return processor;
|
|
53
62
|
}
|
package/dist/init.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ 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
|
+
import { type BeforeSendHook } from "./before-send.js";
|
|
7
|
+
import { type RedactOptions } from "./redaction.js";
|
|
6
8
|
export interface InitOptions {
|
|
7
9
|
name: string;
|
|
8
10
|
environment: string;
|
|
@@ -12,6 +14,8 @@ export interface InitOptions {
|
|
|
12
14
|
disableLogSending?: boolean;
|
|
13
15
|
networkCapture?: "off" | "basic" | "advanced";
|
|
14
16
|
enabled?: boolean;
|
|
17
|
+
redact?: RedactOptions;
|
|
18
|
+
beforeSend?: BeforeSendHook;
|
|
15
19
|
additionalInstrumentations?: readonly Instrumentation[];
|
|
16
20
|
additionalSpanProcessors?: readonly SpanProcessor[];
|
|
17
21
|
additionalLogRecordProcessors?: readonly LogRecordProcessor[];
|
package/dist/init.js
CHANGED
|
@@ -13,11 +13,15 @@ const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
|
|
|
13
13
|
const report_js_1 = require("./report.js");
|
|
14
14
|
const exporters_js_1 = require("./exporters.js");
|
|
15
15
|
const instrumentations_js_1 = require("./instrumentations.js");
|
|
16
|
+
const before_send_js_1 = require("./before-send.js");
|
|
16
17
|
const logs_js_1 = require("./logs.js");
|
|
18
|
+
const redaction_js_1 = require("./redaction.js");
|
|
17
19
|
const state_js_1 = require("./state.js");
|
|
18
|
-
// TODO(pcga11): conflicts
|
|
20
|
+
// TODO(pcga11): conflicts handling pending.
|
|
19
21
|
function init(options) {
|
|
20
22
|
const { sampleRate = 1, disableLogSending = false, networkCapture = "basic", enabled = true, } = options;
|
|
23
|
+
const redactionConfig = (0, redaction_js_1.resolveRedactionConfig)(options.redact);
|
|
24
|
+
const beforeSend = (0, before_send_js_1.resolveBeforeSend)(options.beforeSend);
|
|
21
25
|
// pcga11: Set params before any early return so every state is reported, including failed or disabled attempts.
|
|
22
26
|
(0, state_js_1.setParams)({ name: options.name, environment: options.environment });
|
|
23
27
|
// pcga11: We keep this option because companies often want to turn the integration off in specific envs
|
|
@@ -54,11 +58,20 @@ function init(options) {
|
|
|
54
58
|
});
|
|
55
59
|
return;
|
|
56
60
|
}
|
|
61
|
+
if (!Number.isFinite(sampleRate) || sampleRate < 0 || sampleRate > 1) {
|
|
62
|
+
(0, report_js_1.report)({
|
|
63
|
+
token: options.token,
|
|
64
|
+
severity: api_logs_1.SeverityNumber.ERROR,
|
|
65
|
+
message: 'Parameter sampleRate must be a finite number between 0 and 1',
|
|
66
|
+
});
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
57
69
|
// pcga11: Hoisted so the catch block can shut down providers whose batch/periodic
|
|
58
70
|
// export timers started in their constructors, even when init fails midway.
|
|
59
71
|
let tracerProvider;
|
|
60
72
|
let meterProvider;
|
|
61
73
|
try {
|
|
74
|
+
(0, redaction_js_1.setActiveRedactionConfig)(redactionConfig);
|
|
62
75
|
const resource = (0, resource_js_1.createFoamResource)(options.name, options.environment, options.version, options.additionalResourceAttributes);
|
|
63
76
|
// pcga11: The context manager is what makes the "current" context (active span, baggage)
|
|
64
77
|
// follow execution across await/callback boundaries, via Node's AsyncLocalStorage. Without
|
|
@@ -83,7 +96,10 @@ function init(options) {
|
|
|
83
96
|
root: new sdk_trace_base_1.TraceIdRatioBasedSampler(sampleRate),
|
|
84
97
|
}),
|
|
85
98
|
spanProcessors: [
|
|
86
|
-
new sdk_trace_base_1.BatchSpanProcessor(new exporters_js_1.FoamTraceExporter(options.token
|
|
99
|
+
new sdk_trace_base_1.BatchSpanProcessor(new exporters_js_1.FoamTraceExporter(options.token, undefined, {
|
|
100
|
+
redaction: redactionConfig,
|
|
101
|
+
beforeSend,
|
|
102
|
+
})),
|
|
87
103
|
...(options.additionalSpanProcessors ?? []),
|
|
88
104
|
],
|
|
89
105
|
});
|
|
@@ -100,7 +116,10 @@ function init(options) {
|
|
|
100
116
|
resource,
|
|
101
117
|
processors: [
|
|
102
118
|
new sdk_logs_1.BatchLogRecordProcessor({
|
|
103
|
-
exporter: new exporters_js_1.FoamLogExporter(options.token
|
|
119
|
+
exporter: new exporters_js_1.FoamLogExporter(options.token, undefined, {
|
|
120
|
+
redaction: redactionConfig,
|
|
121
|
+
beforeSend,
|
|
122
|
+
}),
|
|
104
123
|
}),
|
|
105
124
|
...(options.additionalLogRecordProcessors ?? []),
|
|
106
125
|
],
|
package/dist/logs.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { Attributes } from "@opentelemetry/api";
|
|
2
2
|
import { SeverityNumber } from "@opentelemetry/api-logs";
|
|
3
3
|
import { LoggerProvider } from "@opentelemetry/sdk-logs";
|
|
4
|
+
import { type FoamExporterOptions } from "./exporters.js";
|
|
4
5
|
export declare function setFoamLoggerProvider(provider: LoggerProvider): void;
|
|
5
6
|
export declare function getFoamLoggerProvider(): LoggerProvider | undefined;
|
|
6
7
|
export declare function clearFoamLoggerProvider(): void;
|
|
7
|
-
export declare function ensureFoamLoggerProvider(name: string, environment: string, token: string, stamp?: Attributes): LoggerProvider;
|
|
8
|
+
export declare function ensureFoamLoggerProvider(name: string, environment: string, token: string, stamp?: Attributes, options?: FoamExporterOptions): LoggerProvider;
|
|
8
9
|
export declare const log: (body: string, severityNumber?: SeverityNumber, attributes?: Attributes) => void;
|
|
9
10
|
export { SeverityNumber };
|
package/dist/logs.js
CHANGED
|
@@ -25,7 +25,7 @@ function getFoamLoggerProvider() {
|
|
|
25
25
|
function clearFoamLoggerProvider() {
|
|
26
26
|
foamLoggerProvider = undefined;
|
|
27
27
|
}
|
|
28
|
-
function ensureFoamLoggerProvider(name, environment, token, stamp) {
|
|
28
|
+
function ensureFoamLoggerProvider(name, environment, token, stamp, options) {
|
|
29
29
|
const existing = foamLoggerProvider;
|
|
30
30
|
if (existing) {
|
|
31
31
|
return existing;
|
|
@@ -34,7 +34,7 @@ function ensureFoamLoggerProvider(name, environment, token, stamp) {
|
|
|
34
34
|
resource: (0, resource_js_1.createFoamResource)(name, environment),
|
|
35
35
|
processors: [
|
|
36
36
|
new sdk_logs_1.BatchLogRecordProcessor({
|
|
37
|
-
exporter: new exporters_js_1.FoamLogExporter(token, stamp),
|
|
37
|
+
exporter: new exporters_js_1.FoamLogExporter(token, stamp, options),
|
|
38
38
|
}),
|
|
39
39
|
],
|
|
40
40
|
});
|
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.BodyCollector = void 0;
|
|
4
37
|
exports.setHeaderAttributes = setHeaderAttributes;
|
|
@@ -6,7 +39,7 @@ const api_1 = require("@opentelemetry/api");
|
|
|
6
39
|
const api_logs_1 = require("@opentelemetry/api-logs");
|
|
7
40
|
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
8
41
|
const node_crypto_1 = require("node:crypto");
|
|
9
|
-
const
|
|
42
|
+
const zlib = __importStar(require("node:zlib"));
|
|
10
43
|
const constants_js_1 = require("../constants.js");
|
|
11
44
|
const utils_js_1 = require("../utils.js");
|
|
12
45
|
const redact_js_1 = require("./redact.js");
|
|
@@ -78,31 +111,45 @@ function bodyByteLength(value, encoding) {
|
|
|
78
111
|
function decodeBody(bytes, contentEncoding) {
|
|
79
112
|
if (contentEncoding === undefined)
|
|
80
113
|
return bytes;
|
|
81
|
-
const
|
|
82
|
-
|
|
114
|
+
const encodings = headerValues(contentEncoding)
|
|
115
|
+
.flatMap((value) => value.split(","))
|
|
116
|
+
.map((value) => value.trim().toLowerCase())
|
|
117
|
+
.filter((value) => value && value !== "identity");
|
|
118
|
+
if (encodings.length === 0)
|
|
83
119
|
return bytes;
|
|
84
|
-
// maxOutputLength turns a decompression bomb into a caught throw instead
|
|
85
|
-
// of an unrecoverable synchronous OOM allocation.
|
|
86
120
|
const limits = { maxOutputLength: constants_js_1.NETWORK_BODY_MAX_DECODE_BYTES };
|
|
121
|
+
let decoded = bytes;
|
|
87
122
|
try {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
123
|
+
for (const encoding of encodings.reverse()) {
|
|
124
|
+
if (encoding === "gzip" || encoding === "x-gzip") {
|
|
125
|
+
decoded = zlib.gunzipSync(decoded, limits);
|
|
126
|
+
}
|
|
127
|
+
else if (encoding === "deflate") {
|
|
128
|
+
try {
|
|
129
|
+
decoded = zlib.inflateSync(decoded, limits);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
decoded = zlib.unzipSync(decoded, limits);
|
|
133
|
+
}
|
|
94
134
|
}
|
|
95
|
-
|
|
96
|
-
|
|
135
|
+
else if (encoding === "br") {
|
|
136
|
+
decoded = zlib.brotliDecompressSync(decoded, limits);
|
|
137
|
+
}
|
|
138
|
+
else if (encoding === "zstd") {
|
|
139
|
+
const decompress = zlib.zstdDecompressSync;
|
|
140
|
+
if (!decompress)
|
|
141
|
+
return undefined;
|
|
142
|
+
decoded = decompress(decoded, limits);
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
return undefined;
|
|
97
146
|
}
|
|
98
147
|
}
|
|
99
|
-
|
|
100
|
-
return (0, node_zlib_1.brotliDecompressSync)(bytes, limits);
|
|
148
|
+
return decoded;
|
|
101
149
|
}
|
|
102
150
|
catch {
|
|
103
151
|
return undefined;
|
|
104
152
|
}
|
|
105
|
-
return undefined;
|
|
106
153
|
}
|
|
107
154
|
function textEncoding(contentType) {
|
|
108
155
|
const raw = headerValues(contentType)[0];
|
|
@@ -113,20 +160,18 @@ function textEncoding(contentType) {
|
|
|
113
160
|
const charset = parts
|
|
114
161
|
.find((part) => part.toLowerCase().startsWith("charset="))
|
|
115
162
|
?.slice("charset=".length)
|
|
163
|
+
.trim()
|
|
164
|
+
.replace(/^["']|["']$/g, "")
|
|
116
165
|
.toLowerCase();
|
|
117
|
-
const isText =
|
|
118
|
-
media.endsWith("/json") ||
|
|
119
|
-
media.endsWith("+json") ||
|
|
120
|
-
media.endsWith("/xml") ||
|
|
121
|
-
media.endsWith("+xml") ||
|
|
122
|
-
media.endsWith("/yaml") ||
|
|
123
|
-
media.endsWith("+yaml") ||
|
|
124
|
-
media === "application/x-www-form-urlencoded" ||
|
|
125
|
-
Boolean(charset);
|
|
166
|
+
const isText = (0, redact_js_1.isTextualBodyMediaType)(media) || Boolean(charset);
|
|
126
167
|
if (!isText)
|
|
127
168
|
return undefined;
|
|
128
169
|
if (charset && Buffer.isEncoding(charset))
|
|
129
170
|
return charset;
|
|
171
|
+
if (charset === "iso-8859-1" || charset === "windows-1252")
|
|
172
|
+
return "latin1";
|
|
173
|
+
if (media.startsWith("multipart/"))
|
|
174
|
+
return "latin1";
|
|
130
175
|
return "utf8";
|
|
131
176
|
}
|
|
132
177
|
// Last index such that `buf.subarray(0, end)` is complete UTF-8, capped at `max`.
|
|
@@ -283,6 +328,7 @@ class BodyCollector {
|
|
|
283
328
|
// the span; binary uses the same `http.*.body.content` name on the event.
|
|
284
329
|
let binaryContent;
|
|
285
330
|
let chunkSource = wire;
|
|
331
|
+
let chunkSourceIsDecodedText = false;
|
|
286
332
|
if (wire !== undefined) {
|
|
287
333
|
const decoded = decodeBody(wire, headers["content-encoding"]);
|
|
288
334
|
if (decoded === undefined) {
|
|
@@ -298,6 +344,7 @@ class BodyCollector {
|
|
|
298
344
|
// redacted, so the (possibly compressed) wire bytes are replaced
|
|
299
345
|
// with the redacted text.
|
|
300
346
|
chunkSource = Buffer.from(redacted.text, encoding);
|
|
347
|
+
chunkSourceIsDecodedText = true;
|
|
301
348
|
}
|
|
302
349
|
}
|
|
303
350
|
else {
|
|
@@ -319,10 +366,18 @@ class BodyCollector {
|
|
|
319
366
|
[constants_js_1.ATTR_FOAM_HTTP_BODY_TRUNCATED]: this.truncated,
|
|
320
367
|
[constants_js_1.ATTR_FOAM_HTTP_BODY_OUTCOME]: outcome,
|
|
321
368
|
[this.attr.size]: this.observedBytes,
|
|
322
|
-
[constants_js_1.ATTR_FOAM_HTTP_BODY_CAPTURED_BYTES]:
|
|
369
|
+
[constants_js_1.ATTR_FOAM_HTTP_BODY_CAPTURED_BYTES]: chunkSourceIsDecodedText
|
|
370
|
+
? (chunkSource?.byteLength ?? 0)
|
|
371
|
+
: this.capturedBytes,
|
|
323
372
|
[constants_js_1.ATTR_FOAM_HTTP_BODY_CHUNK_COUNT]: chunks.length,
|
|
324
373
|
};
|
|
325
374
|
for (const name of ["content-type", "content-encoding"]) {
|
|
375
|
+
if (name === "content-encoding" &&
|
|
376
|
+
chunkSourceIsDecodedText &&
|
|
377
|
+
headers[name] !== undefined) {
|
|
378
|
+
common[this.attr.header(name)] = ["identity"];
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
326
381
|
if (headers[name] !== undefined) {
|
|
327
382
|
common[this.attr.header(name)] = headerValues(headers[name]);
|
|
328
383
|
}
|
|
@@ -3,4 +3,7 @@ export interface RedactionResult {
|
|
|
3
3
|
readonly changed: boolean;
|
|
4
4
|
}
|
|
5
5
|
export declare function isSensitiveBodyKey(key: string): boolean;
|
|
6
|
+
export declare function isNdjsonMediaType(media: string): boolean;
|
|
7
|
+
export declare function isJsonSequenceMediaType(media: string): boolean;
|
|
8
|
+
export declare function isTextualBodyMediaType(media: string): boolean;
|
|
6
9
|
export declare function redactBodyText(text: string, contentType: unknown): RedactionResult;
|