@capxul/observability 4.20.0-beta.31 → 4.20.0-beta.32
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 +14 -0
- package/dist/devtools.d.mts +7 -0
- package/dist/devtools.mjs +72 -0
- package/dist/engineering.mjs +119 -105
- package/dist/index.d.mts +5050 -577
- package/dist/index.mjs +2 -2
- package/dist/{src-L9SjUzWV.mjs → src-BPQVVRCG.mjs} +1120 -87
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@ naming events rather than producing them.
|
|
|
34
34
|
|
|
35
35
|
```text
|
|
36
36
|
src/
|
|
37
|
+
├── devtools.ts
|
|
37
38
|
├── engineering-delivery.ts
|
|
38
39
|
├── engineering.ts
|
|
39
40
|
├── index.ts
|
|
@@ -41,6 +42,7 @@ src/
|
|
|
41
42
|
├── telemetry-port.ts
|
|
42
43
|
├── __tests__/
|
|
43
44
|
│ ├── engineering-delivery.test.ts
|
|
45
|
+
│ ├── devtools.test.ts
|
|
44
46
|
│ ├── engineering.test.ts
|
|
45
47
|
│ ├── operations.test.ts
|
|
46
48
|
│ ├── posthog-browser-privacy.test.ts
|
|
@@ -92,6 +94,18 @@ src/
|
|
|
92
94
|
|
|
93
95
|
## The required envelope (ADR-0020 A1 amendment)
|
|
94
96
|
|
|
97
|
+
The `@capxul/observability/devtools` subpath exports `withDevTools(layer, url)` and
|
|
98
|
+
`validateDevToolsUrl(url)` for local Effect inspection. An omitted URL keeps the
|
|
99
|
+
original layer. An explicit local WebSocket URL adds the native Effect 4
|
|
100
|
+
DevTools connection after the host's services and metric registry are built.
|
|
101
|
+
The connection closes with the host scope. Local spans retain their original
|
|
102
|
+
detail; existing remote exporters keep their own privacy policy. The local
|
|
103
|
+
tracer does not mutate the remote exporter's span methods. Its optional protocol
|
|
104
|
+
loads only when enabled. The separate entry stays out of Convex's static runtime graph.
|
|
105
|
+
|
|
106
|
+
See [the development workflow](../../docs/canon/development-and-verification.md#local-effect-devtools)
|
|
107
|
+
for the editor and agent collector commands.
|
|
108
|
+
|
|
95
109
|
One PostHog project holds every environment, so `capxul_env` — not project
|
|
96
110
|
isolation — is what keeps a production surface from reading dev traffic. It is
|
|
97
111
|
REQUIRED on every catalog event, together with `producer`. Call sites do not
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
//#region src/devtools.d.ts
|
|
3
|
+
/** Local inspection is an explicit host choice, independent of remote telemetry. */
|
|
4
|
+
export declare function validateDevToolsUrl(value: string): string;
|
|
5
|
+
/** Acquire after the host layer so traces and metrics use the same context. */
|
|
6
|
+
export declare function withDevTools<R, E, I>(layer: Layer.Layer<R, E, I>, url: string | undefined): Layer.Layer<R, E, I>;
|
|
7
|
+
//#endregion
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Effect, Layer, Tracer } from "effect";
|
|
2
|
+
//#region src/devtools.ts
|
|
3
|
+
/** Local inspection is an explicit host choice, independent of remote telemetry. */
|
|
4
|
+
function validateDevToolsUrl(value) {
|
|
5
|
+
const url = new URL(value);
|
|
6
|
+
if (!["ws:", "wss:"].includes(url.protocol) || ![
|
|
7
|
+
"localhost",
|
|
8
|
+
"127.0.0.1",
|
|
9
|
+
"[::1]",
|
|
10
|
+
"host.docker.internal"
|
|
11
|
+
].includes(url.hostname) || url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "") throw new TypeError("devToolsUrl must be a local WebSocket URL without credentials");
|
|
12
|
+
return url.href;
|
|
13
|
+
}
|
|
14
|
+
function localSpan(delegate) {
|
|
15
|
+
const attributes = new Map(delegate.attributes);
|
|
16
|
+
let status = delegate.status;
|
|
17
|
+
return {
|
|
18
|
+
_tag: "Span",
|
|
19
|
+
name: delegate.name,
|
|
20
|
+
spanId: delegate.spanId,
|
|
21
|
+
traceId: delegate.traceId,
|
|
22
|
+
parent: delegate.parent,
|
|
23
|
+
annotations: delegate.annotations,
|
|
24
|
+
sampled: delegate.sampled,
|
|
25
|
+
kind: delegate.kind,
|
|
26
|
+
attributes,
|
|
27
|
+
get status() {
|
|
28
|
+
return status;
|
|
29
|
+
},
|
|
30
|
+
get links() {
|
|
31
|
+
return delegate.links;
|
|
32
|
+
},
|
|
33
|
+
attribute(key, value) {
|
|
34
|
+
attributes.set(key, value);
|
|
35
|
+
delegate.attribute(key, value);
|
|
36
|
+
},
|
|
37
|
+
event(name, time, values) {
|
|
38
|
+
delegate.event(name, time, values);
|
|
39
|
+
},
|
|
40
|
+
addLinks(links) {
|
|
41
|
+
delegate.addLinks(links);
|
|
42
|
+
},
|
|
43
|
+
end(endTime, exit) {
|
|
44
|
+
delegate.end(endTime, exit);
|
|
45
|
+
status = {
|
|
46
|
+
_tag: "Ended",
|
|
47
|
+
startTime: status.startTime,
|
|
48
|
+
endTime,
|
|
49
|
+
exit
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** Acquire after the host layer so traces and metrics use the same context. */
|
|
55
|
+
function withDevTools(layer, url) {
|
|
56
|
+
if (url === void 0) return layer;
|
|
57
|
+
const endpoint = validateDevToolsUrl(url);
|
|
58
|
+
return Layer.unwrap(Effect.promise(async () => {
|
|
59
|
+
const [{ DevToolsClient }, { Socket }] = await Promise.all([import("effect/devtools"), import("effect/socket")]);
|
|
60
|
+
const client = DevToolsClient.layer.pipe(Layer.provide(Socket.layerWebSocket(endpoint)), Layer.provide(Socket.layerWebSocketConstructorGlobal));
|
|
61
|
+
return Layer.effect(Tracer.Tracer, Effect.gen(function* () {
|
|
62
|
+
const delegate = yield* Effect.tracer;
|
|
63
|
+
const mirror = Tracer.make({
|
|
64
|
+
span: (options) => localSpan(delegate.span(options)),
|
|
65
|
+
...delegate.context === void 0 ? {} : { context: delegate.context.bind(delegate) }
|
|
66
|
+
});
|
|
67
|
+
return yield* DevToolsClient.makeTracer.pipe(Effect.provideService(Tracer.Tracer, mirror));
|
|
68
|
+
})).pipe(Layer.provide(client), Layer.provideMerge(layer));
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { validateDevToolsUrl, withDevTools };
|
package/dist/engineering.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { G as CLI_COMMAND_NAMES, K as CLI_INVOCATION_KINDS, W as CLI_CAPABILITIES, _n as redactSecrets, bn as CAPXUL_ERROR_CODES, gn as ORGANIZATION_SETUP_STATUSES, hn as ORGANIZATION_SETUP_REASONS, pn as isCapxulOperation, vn as redactUrlSecrets, xn as FAILURE_MODES, yn as isCredentialField } from "./src-BPQVVRCG.mjs";
|
|
2
2
|
import { Cause, Clock, Context, Deferred, Duration, Effect, Exit, FiberSet, Layer, LogLevel, Logger, Metric, Option, References, Schedule, Stream, Tracer } from "effect";
|
|
3
3
|
import { FetchHttpClient, Headers, HttpBody, HttpClient, HttpClientError, HttpClientResponse } from "effect/http";
|
|
4
4
|
import { OtlpExporter, OtlpLogger, OtlpMetrics, OtlpSerialization, OtlpTracer } from "effect/observability";
|
|
@@ -75,6 +75,123 @@ const attributes = (input, limit = 32) => {
|
|
|
75
75
|
};
|
|
76
76
|
const terminalName = (name) => name === "cli.command.completed" || name === "cli.wallet.step" || CLI_COMMAND_NAMES.some((command) => name === `cli.command.${command}`);
|
|
77
77
|
//#endregion
|
|
78
|
+
//#region src/engineering/tracer.ts
|
|
79
|
+
const failureText = (failure, key, limit, source) => {
|
|
80
|
+
if (failure === null || typeof failure !== "object") return void 0;
|
|
81
|
+
try {
|
|
82
|
+
let owner = failure;
|
|
83
|
+
let descriptor;
|
|
84
|
+
for (let depth = 0; owner !== null && depth < 4; depth += 1) {
|
|
85
|
+
descriptor = Object.getOwnPropertyDescriptor(owner, key);
|
|
86
|
+
if (descriptor !== void 0 || key !== "name") break;
|
|
87
|
+
owner = Object.getPrototypeOf(owner);
|
|
88
|
+
}
|
|
89
|
+
const value = descriptor?.value;
|
|
90
|
+
return typeof value === "string" || key === "code" && typeof value === "number" ? redactSecrets(String(value), source).slice(0, limit) : void 0;
|
|
91
|
+
} catch {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const exportFailure = (failure, source) => {
|
|
96
|
+
const message = failureText(failure, "message", 2048, source) ?? (typeof failure === "string" ? redactSecrets(failure, source).slice(0, 2048) : "Engineering operation failed");
|
|
97
|
+
const code = failureText(failure, "code", 128);
|
|
98
|
+
const error = new Error((code === void 0 ? message : `${message} [code=${code}]`).slice(0, 2048));
|
|
99
|
+
error.name = failureText(failure, "_tag", 128) ?? failureText(failure, "name", 128) ?? "Error";
|
|
100
|
+
error.stack = failureText(failure, "stack", 8192, source) ?? `${error.name}: ${error.message}`;
|
|
101
|
+
return error;
|
|
102
|
+
};
|
|
103
|
+
const exportFailureExit = (cause, source) => Exit.failCause(Cause.fromReasons(cause.reasons.filter((reason) => !Cause.isInterruptReason(reason)).slice(0, 8).map((reason) => Cause.isFailReason(reason) ? Cause.makeFailReason(exportFailure(reason.error, source)) : Cause.makeDieReason(exportFailure(reason.defect, source)))));
|
|
104
|
+
const BROWSER_KEEPALIVE_BYTES = 65536;
|
|
105
|
+
let unfinishedBrowserExportBytes = 0;
|
|
106
|
+
const hasBrowserDocument = () => typeof window !== "undefined" && typeof document !== "undefined";
|
|
107
|
+
const browserExportClient = (client) => HttpClient.transform(client, (response, request) => Effect.acquireUseRelease(Effect.sync(() => {
|
|
108
|
+
const bytes = "contentLength" in request.body ? request.body.contentLength : void 0;
|
|
109
|
+
if (request.body._tag === "Stream" || request.body._tag === "FormData" || bytes === void 0 || !Number.isSafeInteger(bytes) || bytes < 0 || unfinishedBrowserExportBytes + bytes > BROWSER_KEEPALIVE_BYTES) return;
|
|
110
|
+
unfinishedBrowserExportBytes += bytes;
|
|
111
|
+
return bytes;
|
|
112
|
+
}), (bytes) => response.pipe(Effect.provideService(FetchHttpClient.RequestInit, { keepalive: bytes !== void 0 }), Effect.tap((result) => bytes === void 0 ? Effect.void : Stream.runDrain(result.stream).pipe(Effect.catchIf((error) => error.reason._tag === "EmptyBodyError", () => Effect.void)))), (bytes) => Effect.sync(() => {
|
|
113
|
+
if (bytes !== void 0) unfinishedBrowserExportBytes -= bytes;
|
|
114
|
+
})));
|
|
115
|
+
const spanUpstream = (span) => {
|
|
116
|
+
let current = span;
|
|
117
|
+
while (current?._tag === "Span") {
|
|
118
|
+
const upstream = current.attributes.get("chain.upstream");
|
|
119
|
+
if (upstream === "alchemy" || upstream === "infura" || upstream === "gateway") return upstream;
|
|
120
|
+
current = current.parent._tag === "Some" ? current.parent.value : void 0;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
function redactHttpPath(path, fullUrl, source) {
|
|
124
|
+
let origin = "https://redaction.invalid";
|
|
125
|
+
try {
|
|
126
|
+
const url = new URL(String(fullUrl));
|
|
127
|
+
if (url.protocol === "https:" || url.protocol === "http:") origin = url.origin;
|
|
128
|
+
} catch {}
|
|
129
|
+
const prefix = path.startsWith("/") ? origin : "";
|
|
130
|
+
return redactUrlSecrets(`${prefix}${path}`, source).slice(prefix.length, prefix.length + 2048);
|
|
131
|
+
}
|
|
132
|
+
/** A span whose prototype is `span`: it answers every Span member until an own property overrides it. */
|
|
133
|
+
function inheritSpan(span) {
|
|
134
|
+
const wrapped = Object.create(span);
|
|
135
|
+
Object.defineProperties(wrapped, {
|
|
136
|
+
traceId: { get: () => span.traceId },
|
|
137
|
+
spanId: { get: () => span.spanId },
|
|
138
|
+
attributes: { get: () => span.attributes },
|
|
139
|
+
event: {
|
|
140
|
+
value: span.event.bind(span),
|
|
141
|
+
configurable: true
|
|
142
|
+
},
|
|
143
|
+
addLinks: {
|
|
144
|
+
value: span.addLinks.bind(span),
|
|
145
|
+
configurable: true
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
return wrapped;
|
|
149
|
+
}
|
|
150
|
+
/** Preserve domain exits while preventing the OTLP serializer from seeing raw causes. */
|
|
151
|
+
const makeLeakSafeEngineeringTracer = (delegate, enabled = () => true) => Tracer.make({
|
|
152
|
+
span(options) {
|
|
153
|
+
const span = enabled() ? delegate.span(options) : new Tracer.NativeSpan(options);
|
|
154
|
+
const wrapped = inheritSpan(span);
|
|
155
|
+
Object.defineProperty(wrapped, "attribute", { value: (name, value) => {
|
|
156
|
+
const source = spanUpstream(span);
|
|
157
|
+
const header = /^http\.(?:request|response)\.header\.(.+)$/u.exec(name)?.[1];
|
|
158
|
+
if (header !== void 0 && isCredentialField(header, "header")) span.attribute(name, "[REDACTED]");
|
|
159
|
+
else if (typeof value === "string" && name === "url.query") span.attribute(name, redactUrlSecrets(`?${value}`).slice(1, 2049));
|
|
160
|
+
else if (typeof value === "string" && (name === "url.path" || name === "http.target")) {
|
|
161
|
+
const fullUrl = span.attributes.get("url.full") ?? span.attributes.get("http.url");
|
|
162
|
+
const path = name === "url.path" && typeof fullUrl === "string" ? /^https?:\/\/[^/]+([^?#]*)/u.exec(fullUrl)?.[1] ?? value : value;
|
|
163
|
+
span.attribute(name, redactHttpPath(path, fullUrl, source));
|
|
164
|
+
} else if (typeof value === "string" && (name === "url.full" || name === "http.url" || header === "location" || header === "referer" || header === "referrer")) span.attribute(name, redactUrlSecrets(value, source).slice(0, 2048));
|
|
165
|
+
else if (header !== void 0 && typeof value === "string") span.attribute(name, redactSecrets(value, source).slice(0, 2048));
|
|
166
|
+
else span.attribute(name, value);
|
|
167
|
+
} });
|
|
168
|
+
Object.defineProperty(wrapped, "end", {
|
|
169
|
+
configurable: false,
|
|
170
|
+
enumerable: false,
|
|
171
|
+
value: (endTime, exit) => {
|
|
172
|
+
if (!enabled()) {
|
|
173
|
+
Object.defineProperty(wrapped, "status", { value: {
|
|
174
|
+
_tag: "Ended",
|
|
175
|
+
startTime: span.status.startTime,
|
|
176
|
+
endTime,
|
|
177
|
+
exit
|
|
178
|
+
} });
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause)) {
|
|
182
|
+
const first = exit.cause.reasons.find((reason) => !Cause.isInterruptReason(reason));
|
|
183
|
+
const code = failureText(first === void 0 ? void 0 : Cause.isFailReason(first) ? first.error : first.defect, "code", 128);
|
|
184
|
+
if (code !== void 0) span.attribute("error.code", code);
|
|
185
|
+
span.end(endTime, exportFailureExit(exit.cause, spanUpstream(span)));
|
|
186
|
+
} else span.end(endTime, exit);
|
|
187
|
+
},
|
|
188
|
+
writable: false
|
|
189
|
+
});
|
|
190
|
+
return wrapped;
|
|
191
|
+
},
|
|
192
|
+
...delegate.context === void 0 ? {} : { context: delegate.context.bind(delegate) }
|
|
193
|
+
});
|
|
194
|
+
//#endregion
|
|
78
195
|
//#region src/delivery/records.ts
|
|
79
196
|
function admittedLogger(state, delegate) {
|
|
80
197
|
return Logger.make((options) => {
|
|
@@ -130,7 +247,7 @@ function admittedTracer(state, delegate) {
|
|
|
130
247
|
/** The span as a producer sees it: at most 32 fields and 2000 attribute bytes, 2 events, 2 links. */
|
|
131
248
|
function boundedSpan(state, span) {
|
|
132
249
|
const { budget } = state;
|
|
133
|
-
const wrapped =
|
|
250
|
+
const wrapped = inheritSpan(span);
|
|
134
251
|
let fields = 0, events = 0, links = 0, attributeBytes = 0;
|
|
135
252
|
let ended = false;
|
|
136
253
|
Object.defineProperties(wrapped, {
|
|
@@ -466,109 +583,6 @@ const validateEngineeringTelemetryConfig = (config) => {
|
|
|
466
583
|
};
|
|
467
584
|
};
|
|
468
585
|
//#endregion
|
|
469
|
-
//#region src/engineering/tracer.ts
|
|
470
|
-
const failureText = (failure, key, limit, source) => {
|
|
471
|
-
if (failure === null || typeof failure !== "object") return void 0;
|
|
472
|
-
try {
|
|
473
|
-
let owner = failure;
|
|
474
|
-
let descriptor;
|
|
475
|
-
for (let depth = 0; owner !== null && depth < 4; depth += 1) {
|
|
476
|
-
descriptor = Object.getOwnPropertyDescriptor(owner, key);
|
|
477
|
-
if (descriptor !== void 0 || key !== "name") break;
|
|
478
|
-
owner = Object.getPrototypeOf(owner);
|
|
479
|
-
}
|
|
480
|
-
const value = descriptor?.value;
|
|
481
|
-
return typeof value === "string" || key === "code" && typeof value === "number" ? redactSecrets(String(value), source).slice(0, limit) : void 0;
|
|
482
|
-
} catch {
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
};
|
|
486
|
-
const exportFailure = (failure, source) => {
|
|
487
|
-
const message = failureText(failure, "message", 2048, source) ?? (typeof failure === "string" ? redactSecrets(failure, source).slice(0, 2048) : "Engineering operation failed");
|
|
488
|
-
const code = failureText(failure, "code", 128);
|
|
489
|
-
const error = new Error((code === void 0 ? message : `${message} [code=${code}]`).slice(0, 2048));
|
|
490
|
-
error.name = failureText(failure, "_tag", 128) ?? failureText(failure, "name", 128) ?? "Error";
|
|
491
|
-
error.stack = failureText(failure, "stack", 8192, source) ?? `${error.name}: ${error.message}`;
|
|
492
|
-
return error;
|
|
493
|
-
};
|
|
494
|
-
const exportFailureExit = (cause, source) => Exit.failCause(Cause.fromReasons(cause.reasons.filter((reason) => !Cause.isInterruptReason(reason)).slice(0, 8).map((reason) => Cause.isFailReason(reason) ? Cause.makeFailReason(exportFailure(reason.error, source)) : Cause.makeDieReason(exportFailure(reason.defect, source)))));
|
|
495
|
-
const BROWSER_KEEPALIVE_BYTES = 65536;
|
|
496
|
-
let unfinishedBrowserExportBytes = 0;
|
|
497
|
-
const hasBrowserDocument = () => typeof window !== "undefined" && typeof document !== "undefined";
|
|
498
|
-
const browserExportClient = (client) => HttpClient.transform(client, (response, request) => Effect.acquireUseRelease(Effect.sync(() => {
|
|
499
|
-
const bytes = "contentLength" in request.body ? request.body.contentLength : void 0;
|
|
500
|
-
if (request.body._tag === "Stream" || request.body._tag === "FormData" || bytes === void 0 || !Number.isSafeInteger(bytes) || bytes < 0 || unfinishedBrowserExportBytes + bytes > BROWSER_KEEPALIVE_BYTES) return;
|
|
501
|
-
unfinishedBrowserExportBytes += bytes;
|
|
502
|
-
return bytes;
|
|
503
|
-
}), (bytes) => response.pipe(Effect.provideService(FetchHttpClient.RequestInit, { keepalive: bytes !== void 0 }), Effect.tap((result) => bytes === void 0 ? Effect.void : Stream.runDrain(result.stream).pipe(Effect.catchIf((error) => error.reason._tag === "EmptyBodyError", () => Effect.void)))), (bytes) => Effect.sync(() => {
|
|
504
|
-
if (bytes !== void 0) unfinishedBrowserExportBytes -= bytes;
|
|
505
|
-
})));
|
|
506
|
-
const spanUpstream = (span) => {
|
|
507
|
-
let current = span;
|
|
508
|
-
while (current?._tag === "Span") {
|
|
509
|
-
const upstream = current.attributes.get("chain.upstream");
|
|
510
|
-
if (upstream === "alchemy" || upstream === "infura" || upstream === "gateway") return upstream;
|
|
511
|
-
current = current.parent._tag === "Some" ? current.parent.value : void 0;
|
|
512
|
-
}
|
|
513
|
-
};
|
|
514
|
-
function redactHttpPath(path, fullUrl, source) {
|
|
515
|
-
let origin = "https://redaction.invalid";
|
|
516
|
-
try {
|
|
517
|
-
const url = new URL(String(fullUrl));
|
|
518
|
-
if (url.protocol === "https:" || url.protocol === "http:") origin = url.origin;
|
|
519
|
-
} catch {}
|
|
520
|
-
const prefix = path.startsWith("/") ? origin : "";
|
|
521
|
-
return redactUrlSecrets(`${prefix}${path}`, source).slice(prefix.length, prefix.length + 2048);
|
|
522
|
-
}
|
|
523
|
-
/** A span whose prototype is `span`: it answers every Span member until an own property overrides it. */
|
|
524
|
-
function inheritSpan(span) {
|
|
525
|
-
return Object.create(span);
|
|
526
|
-
}
|
|
527
|
-
/** Preserve domain exits while preventing the OTLP serializer from seeing raw causes. */
|
|
528
|
-
const makeLeakSafeEngineeringTracer = (delegate, enabled = () => true) => Tracer.make({
|
|
529
|
-
span(options) {
|
|
530
|
-
const span = enabled() ? delegate.span(options) : new Tracer.NativeSpan(options);
|
|
531
|
-
const wrapped = inheritSpan(span);
|
|
532
|
-
Object.defineProperty(wrapped, "attribute", { value: (name, value) => {
|
|
533
|
-
const source = spanUpstream(span);
|
|
534
|
-
const header = /^http\.(?:request|response)\.header\.(.+)$/u.exec(name)?.[1];
|
|
535
|
-
if (header !== void 0 && isCredentialField(header, "header")) span.attribute(name, "[REDACTED]");
|
|
536
|
-
else if (typeof value === "string" && name === "url.query") span.attribute(name, redactUrlSecrets(`?${value}`).slice(1, 2049));
|
|
537
|
-
else if (typeof value === "string" && (name === "url.path" || name === "http.target")) {
|
|
538
|
-
const fullUrl = span.attributes.get("url.full") ?? span.attributes.get("http.url");
|
|
539
|
-
const path = name === "url.path" && typeof fullUrl === "string" ? /^https?:\/\/[^/]+([^?#]*)/u.exec(fullUrl)?.[1] ?? value : value;
|
|
540
|
-
span.attribute(name, redactHttpPath(path, fullUrl, source));
|
|
541
|
-
} else if (typeof value === "string" && (name === "url.full" || name === "http.url" || header === "location" || header === "referer" || header === "referrer")) span.attribute(name, redactUrlSecrets(value, source).slice(0, 2048));
|
|
542
|
-
else if (header !== void 0 && typeof value === "string") span.attribute(name, redactSecrets(value, source).slice(0, 2048));
|
|
543
|
-
else span.attribute(name, value);
|
|
544
|
-
} });
|
|
545
|
-
Object.defineProperty(wrapped, "end", {
|
|
546
|
-
configurable: false,
|
|
547
|
-
enumerable: false,
|
|
548
|
-
value: (endTime, exit) => {
|
|
549
|
-
if (!enabled()) {
|
|
550
|
-
Object.defineProperty(wrapped, "status", { value: {
|
|
551
|
-
_tag: "Ended",
|
|
552
|
-
startTime: span.status.startTime,
|
|
553
|
-
endTime,
|
|
554
|
-
exit
|
|
555
|
-
} });
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
if (Exit.isFailure(exit) && !Cause.hasInterruptsOnly(exit.cause)) {
|
|
559
|
-
const first = exit.cause.reasons.find((reason) => !Cause.isInterruptReason(reason));
|
|
560
|
-
const code = failureText(first === void 0 ? void 0 : Cause.isFailReason(first) ? first.error : first.defect, "code", 128);
|
|
561
|
-
if (code !== void 0) span.attribute("error.code", code);
|
|
562
|
-
span.end(endTime, exportFailureExit(exit.cause, spanUpstream(span)));
|
|
563
|
-
} else span.end(endTime, exit);
|
|
564
|
-
},
|
|
565
|
-
writable: false
|
|
566
|
-
});
|
|
567
|
-
return wrapped;
|
|
568
|
-
},
|
|
569
|
-
...delegate.context === void 0 ? {} : { context: delegate.context.bind(delegate) }
|
|
570
|
-
});
|
|
571
|
-
//#endregion
|
|
572
586
|
//#region src/engineering/minimal.ts
|
|
573
587
|
const MINIMAL_LOG_NAMES = /* @__PURE__ */ new Set([
|
|
574
588
|
"capxul_sdk_operation",
|