@foam-ai/node 0.1.0-alpha.4 → 0.1.0-alpha.5
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 +299 -183
- package/dist/constants.d.ts +9 -8
- package/dist/constants.js +49 -6
- package/dist/endpoint.d.ts +2 -0
- package/dist/endpoint.js +11 -0
- package/dist/exporters.js +4 -6
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -1
- package/dist/ingest.js +15 -12
- package/dist/init.d.ts +3 -3
- package/dist/init.js +64 -35
- package/dist/instrumentations.js +25 -3
- package/dist/logs.d.ts +9 -0
- package/dist/logs.js +61 -0
- package/dist/network-capture/collector.js +96 -52
- 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 +6 -0
- package/dist/network-capture/redact.js +87 -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/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
package/dist/otlp.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendOtlpLog = sendOtlpLog;
|
|
4
|
+
const constants_js_1 = require("./constants.js");
|
|
5
|
+
const endpoint_js_1 = require("./endpoint.js");
|
|
6
|
+
// pcga11: Pipeline-independent OTLP log delivery.
|
|
7
|
+
// Use when the SDK's LoggerProvider/exporter never got set up or is
|
|
8
|
+
// broken (diagnostics). Not a client surface: no batching, no resource
|
|
9
|
+
// detectors, no trace correlation, one fetch per record. Client logs go
|
|
10
|
+
// through the Foam LoggerProvider in logs.ts.
|
|
11
|
+
async function sendOtlpLog({ token, resourceAttributes, scopeName, severityNumber, body, }) {
|
|
12
|
+
try {
|
|
13
|
+
await fetch(`${endpoint_js_1.endpoint}${constants_js_1.FOAM_OTLP_LOGS_PATH}`, {
|
|
14
|
+
method: "POST",
|
|
15
|
+
headers: {
|
|
16
|
+
Authorization: `Bearer ${token}`,
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
},
|
|
19
|
+
body: JSON.stringify({
|
|
20
|
+
resourceLogs: [
|
|
21
|
+
{
|
|
22
|
+
resource: {
|
|
23
|
+
attributes: Object.entries(resourceAttributes).map(([key, value]) => ({ key, value: { stringValue: value } })),
|
|
24
|
+
},
|
|
25
|
+
scopeLogs: [
|
|
26
|
+
{
|
|
27
|
+
scope: { name: scopeName },
|
|
28
|
+
logRecords: [
|
|
29
|
+
{
|
|
30
|
+
timeUnixNano: String(BigInt(Date.now()) * 1000000n),
|
|
31
|
+
severityNumber,
|
|
32
|
+
severityText: constants_js_1.SEVERITY_TEXT[severityNumber],
|
|
33
|
+
body: { stringValue: body },
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
}),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// pcga11: do not remove this catch block. Ingest must never throw into application code.
|
|
45
|
+
}
|
|
46
|
+
}
|
package/dist/report.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SeverityNumber } from "@opentelemetry/api-logs";
|
|
2
|
+
export declare function report({ name, environment, token, severity, message, error, }: {
|
|
3
|
+
name?: string;
|
|
4
|
+
environment?: string;
|
|
5
|
+
token?: string;
|
|
6
|
+
severity: SeverityNumber;
|
|
7
|
+
message: string;
|
|
8
|
+
error?: string;
|
|
9
|
+
}): Promise<void>;
|
package/dist/report.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.report = report;
|
|
4
|
+
const api_1 = require("@opentelemetry/api");
|
|
5
|
+
const api_logs_1 = require("@opentelemetry/api-logs");
|
|
6
|
+
const core_1 = require("@opentelemetry/core");
|
|
7
|
+
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
8
|
+
const constants_js_1 = require("./constants.js");
|
|
9
|
+
const otlp_js_1 = require("./otlp.js");
|
|
10
|
+
const state_js_1 = require("./state.js");
|
|
11
|
+
const logger = api_1.diag.createComponentLogger({ namespace: constants_js_1.FOAM_IDENTIFIER_NAME });
|
|
12
|
+
// pcga11: Guarded so repeat report() calls don't trigger diag's "logger will be overwritten" warning.
|
|
13
|
+
let reportingConfigured = false;
|
|
14
|
+
function ensureReportingConfigured() {
|
|
15
|
+
if (reportingConfigured) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
reportingConfigured = true;
|
|
19
|
+
const fromEnv = (0, core_1.diagLogLevelFromString)((0, core_1.getStringFromEnv)(constants_js_1.DIAG_LOG_LEVEL));
|
|
20
|
+
api_1.diag.setLogger(new api_1.DiagConsoleLogger(), fromEnv ?? api_1.DiagLogLevel.INFO);
|
|
21
|
+
}
|
|
22
|
+
// pcga11: State reports go to Foam's OTLP endpoint directly instead of through the
|
|
23
|
+
// logger provider or exporter, since those may themselves be broken or unregistered.
|
|
24
|
+
async function report({ name, environment, token, severity, message, error, }) {
|
|
25
|
+
ensureReportingConfigured();
|
|
26
|
+
// pcga11: Local diag logging happens before the token check so misconfiguration
|
|
27
|
+
// is visible in the console even when nothing can be sent.
|
|
28
|
+
if (severity >= api_logs_1.SeverityNumber.ERROR) {
|
|
29
|
+
logger.error(message);
|
|
30
|
+
}
|
|
31
|
+
else if (severity >= api_logs_1.SeverityNumber.WARN) {
|
|
32
|
+
logger.warn(message);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
logger.info(message);
|
|
36
|
+
}
|
|
37
|
+
// pcga11: Token is the only hard requirement (nothing can be sent without auth).
|
|
38
|
+
// name/environment fall back to "unknown" so misconfiguration reports still arrive.
|
|
39
|
+
if (!token) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
await (0, otlp_js_1.sendOtlpLog)({
|
|
43
|
+
token: token,
|
|
44
|
+
resourceAttributes: {
|
|
45
|
+
[semantic_conventions_1.ATTR_SERVICE_NAME]: name?.trim() || "unknown",
|
|
46
|
+
[semantic_conventions_1.ATTR_DEPLOYMENT_ENVIRONMENT_NAME]: environment?.trim() || "unknown",
|
|
47
|
+
},
|
|
48
|
+
scopeName: constants_js_1.FOAM_IDENTIFIER_NAME,
|
|
49
|
+
severityNumber: severity,
|
|
50
|
+
body: JSON.stringify({
|
|
51
|
+
state: { ...(0, state_js_1.getState)() },
|
|
52
|
+
message: `${constants_js_1.FOAM_IDENTIFIER_NAME} ${message}`,
|
|
53
|
+
error: error,
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
}
|
package/dist/state.d.ts
CHANGED
|
@@ -5,15 +5,22 @@ export declare enum Signals {
|
|
|
5
5
|
baggage = "baggage",
|
|
6
6
|
profile = "profile"
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
export declare enum SignalSources {
|
|
9
|
+
none = "none",
|
|
10
|
+
global = "global",
|
|
11
|
+
ingest = "ingest",
|
|
12
|
+
local = "local"
|
|
13
|
+
}
|
|
9
14
|
export interface State {
|
|
10
15
|
readonly initialized: boolean;
|
|
11
16
|
readonly instrumentations: readonly string[];
|
|
12
|
-
readonly signals: Readonly<Record<Signals,
|
|
17
|
+
readonly signals: Readonly<Record<Signals, SignalSources>>;
|
|
18
|
+
readonly params: Readonly<Record<string, unknown>>;
|
|
13
19
|
}
|
|
14
20
|
export declare const setInstrumentations: (names: readonly string[]) => void;
|
|
15
|
-
export declare const setSignal: (signal: Signals,
|
|
16
|
-
export declare const getSignal: (signal: Signals) =>
|
|
21
|
+
export declare const setSignal: (signal: Signals, source: SignalSources) => void;
|
|
22
|
+
export declare const getSignal: (signal: Signals) => SignalSources;
|
|
17
23
|
export declare const setInitialized: (initialized: boolean) => void;
|
|
18
24
|
export declare const getInitialized: () => boolean;
|
|
25
|
+
export declare const setParams: (params: Record<string, unknown>) => void;
|
|
19
26
|
export declare const getState: () => State;
|
package/dist/state.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getState = exports.getInitialized = exports.setInitialized = exports.getSignal = exports.setSignal = exports.setInstrumentations = exports.Signals = void 0;
|
|
3
|
+
exports.getState = exports.setParams = exports.getInitialized = exports.setInitialized = exports.getSignal = exports.setSignal = exports.setInstrumentations = exports.SignalSources = exports.Signals = void 0;
|
|
4
4
|
var Signals;
|
|
5
5
|
(function (Signals) {
|
|
6
6
|
Signals["traces"] = "traces";
|
|
@@ -9,23 +9,31 @@ var Signals;
|
|
|
9
9
|
Signals["baggage"] = "baggage";
|
|
10
10
|
Signals["profile"] = "profile";
|
|
11
11
|
})(Signals || (exports.Signals = Signals = {}));
|
|
12
|
+
var SignalSources;
|
|
13
|
+
(function (SignalSources) {
|
|
14
|
+
SignalSources["none"] = "none";
|
|
15
|
+
SignalSources["global"] = "global";
|
|
16
|
+
SignalSources["ingest"] = "ingest";
|
|
17
|
+
SignalSources["local"] = "local";
|
|
18
|
+
})(SignalSources || (exports.SignalSources = SignalSources = {}));
|
|
12
19
|
const state = {
|
|
13
20
|
initialized: false,
|
|
14
|
-
instrumentations: [],
|
|
21
|
+
instrumentations: [], // pcga11: The registered instrumentations that are enabled in the current application.
|
|
15
22
|
signals: {
|
|
16
|
-
traces:
|
|
17
|
-
metrics:
|
|
18
|
-
logs:
|
|
19
|
-
baggage:
|
|
20
|
-
profile:
|
|
23
|
+
traces: SignalSources.none,
|
|
24
|
+
metrics: SignalSources.none,
|
|
25
|
+
logs: SignalSources.none,
|
|
26
|
+
baggage: SignalSources.none,
|
|
27
|
+
profile: SignalSources.none,
|
|
21
28
|
},
|
|
29
|
+
params: {},
|
|
22
30
|
};
|
|
23
31
|
const setInstrumentations = (names) => {
|
|
24
32
|
state.instrumentations = [...names];
|
|
25
33
|
};
|
|
26
34
|
exports.setInstrumentations = setInstrumentations;
|
|
27
|
-
const setSignal = (signal,
|
|
28
|
-
state.signals[signal] =
|
|
35
|
+
const setSignal = (signal, source) => {
|
|
36
|
+
state.signals[signal] = source;
|
|
29
37
|
};
|
|
30
38
|
exports.setSignal = setSignal;
|
|
31
39
|
const getSignal = (signal) => state.signals[signal];
|
|
@@ -36,9 +44,18 @@ const setInitialized = (initialized) => {
|
|
|
36
44
|
exports.setInitialized = setInitialized;
|
|
37
45
|
const getInitialized = () => state.initialized;
|
|
38
46
|
exports.getInitialized = getInitialized;
|
|
47
|
+
const setParams = (params) => {
|
|
48
|
+
// pcga11: Safety precaution: never store tokens in the state.
|
|
49
|
+
if (params.token) {
|
|
50
|
+
delete params.token;
|
|
51
|
+
}
|
|
52
|
+
state.params = { ...params };
|
|
53
|
+
};
|
|
54
|
+
exports.setParams = setParams;
|
|
39
55
|
const getState = () => ({
|
|
40
56
|
initialized: state.initialized,
|
|
41
57
|
instrumentations: [...state.instrumentations],
|
|
42
58
|
signals: { ...state.signals },
|
|
59
|
+
params: { ...state.params },
|
|
43
60
|
});
|
|
44
61
|
exports.getState = getState;
|
package/dist/traces.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function recordException(error: unknown): void;
|
package/dist/traces.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.recordException = recordException;
|
|
4
|
+
const api_1 = require("@opentelemetry/api");
|
|
5
|
+
const utils_js_1 = require("./utils.js");
|
|
6
|
+
// pcga11: Not gated on the traces signal on purpose: the active span belongs to
|
|
7
|
+
// whichever SDK owns tracing, and the exception should land on that span either way.
|
|
8
|
+
function recordException(error) {
|
|
9
|
+
(0, utils_js_1.safely)(() => {
|
|
10
|
+
const span = api_1.trace.getActiveSpan();
|
|
11
|
+
if (!span?.isRecording()) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const exception = error instanceof Error ? error : String(error);
|
|
15
|
+
span.recordException(exception);
|
|
16
|
+
span.setStatus({
|
|
17
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
18
|
+
message: error instanceof Error ? error.message : String(error),
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
package/dist/utils.js
CHANGED
|
@@ -13,7 +13,7 @@ function safely(operation, fallback) {
|
|
|
13
13
|
}
|
|
14
14
|
function whenInitialized(signal, operation) {
|
|
15
15
|
return (...args) => {
|
|
16
|
-
if (
|
|
16
|
+
if ((0, state_js_1.getSignal)(signal) === state_js_1.SignalSources.none)
|
|
17
17
|
return;
|
|
18
18
|
safely(() => operation(...args));
|
|
19
19
|
};
|
package/package.json
CHANGED
package/dist/diagnostics.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { SeverityNumber } from "@opentelemetry/api-logs";
|
|
2
|
-
export declare function configureDiagnostics(): void;
|
|
3
|
-
export declare const info: (message: string) => void;
|
|
4
|
-
export declare const warn: (message: string) => void;
|
|
5
|
-
export declare const error: (message: string) => void;
|
|
6
|
-
export declare function sendStateDiagnosticLog({ name, environment, token, tier, severity, error, }: {
|
|
7
|
-
name: string;
|
|
8
|
-
environment: string;
|
|
9
|
-
token: string;
|
|
10
|
-
tier: "internal" | "external";
|
|
11
|
-
severity: SeverityNumber;
|
|
12
|
-
error?: string;
|
|
13
|
-
}): Promise<void>;
|
package/dist/diagnostics.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.error = exports.warn = exports.info = void 0;
|
|
4
|
-
exports.configureDiagnostics = configureDiagnostics;
|
|
5
|
-
exports.sendStateDiagnosticLog = sendStateDiagnosticLog;
|
|
6
|
-
const api_1 = require("@opentelemetry/api");
|
|
7
|
-
const core_1 = require("@opentelemetry/core");
|
|
8
|
-
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
9
|
-
const constants_js_1 = require("./constants.js");
|
|
10
|
-
const state_js_1 = require("./state.js");
|
|
11
|
-
const logger = api_1.diag.createComponentLogger({ namespace: constants_js_1.FOAM_IDENTIFIER_NAME });
|
|
12
|
-
function configureDiagnostics() {
|
|
13
|
-
const fromEnv = (0, core_1.diagLogLevelFromString)((0, core_1.getStringFromEnv)(constants_js_1.DIAG_LOG_LEVEL));
|
|
14
|
-
api_1.diag.setLogger(new api_1.DiagConsoleLogger(), fromEnv ?? api_1.DiagLogLevel.INFO);
|
|
15
|
-
}
|
|
16
|
-
const info = (message) => {
|
|
17
|
-
logger.info(message);
|
|
18
|
-
};
|
|
19
|
-
exports.info = info;
|
|
20
|
-
const warn = (message) => {
|
|
21
|
-
logger.warn(message);
|
|
22
|
-
};
|
|
23
|
-
exports.warn = warn;
|
|
24
|
-
const error = (message) => {
|
|
25
|
-
logger.error(message);
|
|
26
|
-
};
|
|
27
|
-
exports.error = error;
|
|
28
|
-
// pcga11: We send the diagnostic log to Foam's OTLP endpoint directly instead of using the logger provider or exporter to deliver diagnostics.
|
|
29
|
-
// We do not want to rely on the logger provider or exporter to deliver diagnostics. As they themselves may not be instrumented.
|
|
30
|
-
async function sendStateDiagnosticLog({ name, environment, token, tier, severity, error, }) {
|
|
31
|
-
if (!name?.trim() || !environment?.trim() || !token) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
try {
|
|
35
|
-
await fetch(`${constants_js_1.FOAM_ENDPOINT}${constants_js_1.FOAM_OTLP_LOGS_PATH}`, {
|
|
36
|
-
method: "POST",
|
|
37
|
-
headers: {
|
|
38
|
-
Authorization: `Bearer ${token}`,
|
|
39
|
-
"Content-Type": "application/json",
|
|
40
|
-
},
|
|
41
|
-
body: JSON.stringify({
|
|
42
|
-
resourceLogs: [
|
|
43
|
-
{
|
|
44
|
-
resource: {
|
|
45
|
-
attributes: [
|
|
46
|
-
{ key: semantic_conventions_1.ATTR_SERVICE_NAME, value: { stringValue: name } },
|
|
47
|
-
{
|
|
48
|
-
key: semantic_conventions_1.ATTR_DEPLOYMENT_ENVIRONMENT_NAME,
|
|
49
|
-
value: { stringValue: environment },
|
|
50
|
-
},
|
|
51
|
-
{ key: constants_js_1.FOAM_INGEST_TIER, value: { stringValue: tier } },
|
|
52
|
-
],
|
|
53
|
-
},
|
|
54
|
-
scopeLogs: [
|
|
55
|
-
{
|
|
56
|
-
scope: { name: constants_js_1.FOAM_IDENTIFIER_NAME },
|
|
57
|
-
logRecords: [
|
|
58
|
-
{
|
|
59
|
-
timeUnixNano: String(BigInt(Date.now()) * 1000000n),
|
|
60
|
-
severityNumber: severity,
|
|
61
|
-
severityText: constants_js_1.SEVERITY_TEXT[severity],
|
|
62
|
-
body: {
|
|
63
|
-
stringValue: JSON.stringify({
|
|
64
|
-
...(0, state_js_1.getState)(),
|
|
65
|
-
[constants_js_1.FOAM_INGEST_TIER]: tier,
|
|
66
|
-
...(error === undefined
|
|
67
|
-
? {}
|
|
68
|
-
: { error }),
|
|
69
|
-
}),
|
|
70
|
-
},
|
|
71
|
-
},
|
|
72
|
-
],
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
},
|
|
76
|
-
],
|
|
77
|
-
}),
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
// pcga11: do not remove this catch block. Ingest must never throw into application code.
|
|
82
|
-
}
|
|
83
|
-
}
|