@xeonr/telemetry 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -2
- package/dist/baggage.d.ts +21 -0
- package/dist/baggage.d.ts.map +1 -0
- package/dist/baggage.js +117 -0
- package/dist/baggage.js.map +1 -0
- package/dist/boot.d.ts +7 -0
- package/dist/boot.d.ts.map +1 -0
- package/dist/boot.js +10 -0
- package/dist/boot.js.map +1 -0
- package/dist/connect.d.ts +63 -0
- package/dist/connect.d.ts.map +1 -0
- package/dist/connect.js +200 -0
- package/dist/connect.js.map +1 -0
- package/dist/fetch.d.ts +19 -0
- package/dist/fetch.d.ts.map +1 -0
- package/dist/fetch.js +41 -0
- package/dist/fetch.js.map +1 -0
- package/dist/identity.d.ts +79 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +173 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/job.d.ts +38 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +107 -0
- package/dist/job.js.map +1 -0
- package/dist/keys.d.ts +80 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +90 -0
- package/dist/keys.js.map +1 -0
- package/dist/keys.json +127 -0
- package/dist/log.d.ts +43 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +139 -0
- package/dist/log.js.map +1 -0
- package/dist/processor.d.ts +76 -0
- package/dist/processor.d.ts.map +1 -0
- package/dist/processor.js +160 -0
- package/dist/processor.js.map +1 -0
- package/dist/register.d.ts +2 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +34 -0
- package/dist/register.js.map +1 -0
- package/dist/sanitize.d.ts +17 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +52 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/sdk.d.ts +50 -0
- package/dist/sdk.d.ts.map +1 -0
- package/dist/sdk.js +207 -0
- package/dist/sdk.js.map +1 -0
- package/package.json +97 -3
- package/register.cjs +3 -0
package/README.md
CHANGED
|
@@ -1,3 +1,129 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @xeonr/telemetry
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Telemetry for Xeonr's Node services: the Node mirror of go-platform's
|
|
4
|
+
`telemetry` package, and the way a Node service meets Plumb's
|
|
5
|
+
`obs.node-telemetry`.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
node --import @xeonr/telemetry/register dist/server.js # ES modules
|
|
9
|
+
node --require @xeonr/telemetry/register dist/server.cjs # CommonJS
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`register` starts OpenTelemetry before the app loads. The SDK itself is
|
|
13
|
+
[`@lntrn/otel`](https://www.npmjs.com/package/@lntrn/otel), Lantern's add-on
|
|
14
|
+
for the stock `NodeSDK`. This package makes the Xeonr choices on top:
|
|
15
|
+
|
|
16
|
+
- **OTLP gRPC** to the cluster collector, from `OTEL_EXPORTER_OTLP_ENDPOINT`
|
|
17
|
+
(Go-style `host:port` or a URL). In-cluster hosts and
|
|
18
|
+
`OTEL_EXPORTER_OTLP_INSECURE=true` are cleartext. With no endpoint nothing
|
|
19
|
+
is sent: one `telemetry export disabled` line, and spans still get ids so
|
|
20
|
+
log lines still carry them.
|
|
21
|
+
- **Resource** from `OTEL_SERVICE_NAME`, `OTEL_SERVICE_NAMESPACE`,
|
|
22
|
+
`OTEL_SERVICE_VERSION`, `ENV` (else `NODE_ENV`, as `prod`/`dev`) as
|
|
23
|
+
`deployment.environment`, and the pod name as `service.instance.id`.
|
|
24
|
+
- **AlwaysOn** sampling. **W3C trace context** is the only propagator:
|
|
25
|
+
baggage is sent only by this package's in-cluster helpers.
|
|
26
|
+
- **A fixed instrumentation list**, never `auto-instrumentations-node`: http,
|
|
27
|
+
undici (fetch), ioredis, mysql2 (statements masked), pg, aws-sdk,
|
|
28
|
+
runtime-node, and pino (trace ids on lines, never log export). `/healthz`
|
|
29
|
+
is not traced. Client spans need a parent: one without becomes nothing
|
|
30
|
+
rather than a root (`xeonr_telemetry_rootless_client_spans_total` counts
|
|
31
|
+
the ones dropped).
|
|
32
|
+
- **Runtime metrics**: runtime-node's event loop, heap and GC, and
|
|
33
|
+
host-metrics' `process.cpu.*` and `process.memory.*` (the pod, not the node).
|
|
34
|
+
- **No log export**: logs go to stdout for the Lantern agent. No HTTP RED
|
|
35
|
+
histograms: spanmetrics derives RED from the spans.
|
|
36
|
+
- **Identity on every span**, from the request or job it belongs to; URL
|
|
37
|
+
queries and credentials stripped from URL attributes.
|
|
38
|
+
|
|
39
|
+
## Identity (§4.2)
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { setIdentity, setTeam, setResource } from "@xeonr/telemetry";
|
|
43
|
+
|
|
44
|
+
// where the service verifies a Xeonr caller itself (its auth interceptor)
|
|
45
|
+
setIdentity({ subject: principal.sub, orgId, clientId, authMethod: "bearer", scopes });
|
|
46
|
+
// in a handler acting on an owned resource
|
|
47
|
+
setTeam(bucket.teamUrn);
|
|
48
|
+
setResource("bucket", bucket.id, bucket.urn);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The keys are generated from go-platform's `telemetry/keys.json`
|
|
52
|
+
(`src/keys.json`, copied byte for byte; `pnpm gen-keys`).
|
|
53
|
+
|
|
54
|
+
## Connect
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { clientInterceptor, peerContextValues, serverInterceptor } from "@xeonr/telemetry/connect";
|
|
58
|
+
|
|
59
|
+
app.register(fastifyConnectPlugin, {
|
|
60
|
+
routes,
|
|
61
|
+
interceptors: [serverInterceptor(), authInterceptor], // telemetry first
|
|
62
|
+
contextValues: peerContextValues, // the TCP peer, for trust
|
|
63
|
+
});
|
|
64
|
+
const transport = createConnectTransport({ baseUrl, interceptors: [clientInterceptor({ peer: "upl-im-api" })] });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The server continues a caller's `traceparent` and honours its origin baggage
|
|
68
|
+
only from a trusted peer (`TRUSTED_PROXY_CIDR`, default `10.0.0.0/8`, as
|
|
69
|
+
go-platform); anyone else's trace becomes a link. Status follows otelconnect:
|
|
70
|
+
only a server-class code is an error.
|
|
71
|
+
|
|
72
|
+
## Jobs
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { runJob, startJob, detach } from "@xeonr/telemetry";
|
|
76
|
+
|
|
77
|
+
await runJob("upl.trace.reconcile", () => reconcile(), { trigger: "cron" });
|
|
78
|
+
const job = startJob("upl.parse_upload", { trigger: "queue", links });
|
|
79
|
+
// … context.with(job.ctx, …) …
|
|
80
|
+
job.end(err);
|
|
81
|
+
void runJob("upl.index", () => index(id), { ctx: detach(), trigger: "request" }); // from a handler
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
A job is a root span with `xeonr.job.*` and system identity (or the caller's,
|
|
85
|
+
when started from a request), and counts `xeonr_job_runs_total` and
|
|
86
|
+
`xeonr_job_duration_seconds`.
|
|
87
|
+
|
|
88
|
+
## Outbound HTTP
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { fetchWith, withPeer, baggageFor } from "@xeonr/telemetry";
|
|
92
|
+
|
|
93
|
+
const discord = fetchWith({ peer: "discord" }); // fetch with peer.service, no baggage
|
|
94
|
+
const api = fetchWith({ peer: "upl-im-api" }); // in-cluster: origin baggage too
|
|
95
|
+
await withPeer("s3", () => s3.send(cmd)); // any other client
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Logging
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { logger, withContext } from "@xeonr/telemetry/log";
|
|
102
|
+
|
|
103
|
+
logger.info({ upload_id }, "parsed");
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
pino, JSON on stdout as logrus writes it (`level`, `time`, `msg`), with
|
|
107
|
+
`trace_id`, `span_id`, `trace_flags`, the §4.2 fields, `procedure` and `ip`
|
|
108
|
+
from the active context; credentials redacted by key; errors as
|
|
109
|
+
`{type, message, stack, code}` with tokens, emails and URL queries removed.
|
|
110
|
+
An Error line inside a span is mirrored as a span event.
|
|
111
|
+
|
|
112
|
+
## Shutting down
|
|
113
|
+
|
|
114
|
+
`register` flushes when the event loop empties. A service that handles
|
|
115
|
+
SIGTERM itself calls `shutdown()` last, after its servers and workers have
|
|
116
|
+
drained; one that does not gets a flush and the signal re-raised.
|
|
117
|
+
|
|
118
|
+
## Run-time span processors
|
|
119
|
+
|
|
120
|
+
`addSpanProcessor(p)` adds a processor after boot (the upl-im pipeline's
|
|
121
|
+
run-trace store). It sees the spans started after it. A span event made with
|
|
122
|
+
`localEvent(attrs)` reaches those processors but is never exported: for
|
|
123
|
+
payloads a product shows its own users, which must not reach Lantern.
|
|
124
|
+
|
|
125
|
+
## Releasing
|
|
126
|
+
|
|
127
|
+
Bump `"version"` and merge to main: CI (`.xeonr-ci.yaml`, app `telemetry`)
|
|
128
|
+
tests, builds and publishes any version the registry hasn't got, and tags it
|
|
129
|
+
`telemetry-vX.Y.Z`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type Context } from "@opentelemetry/api";
|
|
2
|
+
export declare const HEADER_BAGGAGE = "baggage";
|
|
3
|
+
/** go-platform's connectmw.DefaultTrustedProxyCIDR. */
|
|
4
|
+
export declare const DEFAULT_TRUSTED_PROXY_CIDR = "10.0.0.0/8";
|
|
5
|
+
/** Whether `host` (a host or host:port) is a cluster-internal name: `*.svc`, `*.cluster.local`, or a bare single-label name. IPs and localhost are not. */
|
|
6
|
+
export declare function inCluster(host: string): boolean;
|
|
7
|
+
/** The `baggage` header value for the origin members of `ctx`'s identity, or "" when there are none. */
|
|
8
|
+
export declare function originBaggage(ctx?: Context): string;
|
|
9
|
+
/** Parses a `baggage` header into the origin members, ignoring every other member. */
|
|
10
|
+
export declare function parseOriginBaggage(header: string | null | undefined): Record<string, string>;
|
|
11
|
+
/** Decides peer trust from CIDRs, like go-platform's ClientIPResolver.PeerTrusted. */
|
|
12
|
+
export declare class PeerTrust {
|
|
13
|
+
#private;
|
|
14
|
+
/** No CIDRs → DEFAULT_TRUSTED_PROXY_CIDR. An invalid entry throws: a bad trust range must fail at boot. */
|
|
15
|
+
constructor(cidrs?: readonly string[]);
|
|
16
|
+
/** From TRUSTED_PROXY_CIDR (comma-separated), as the Go services read it. */
|
|
17
|
+
static fromEnv(env?: Record<string, string | undefined>): PeerTrust;
|
|
18
|
+
/** Whether the TCP peer (an IP, "ip:port" or "[v6]:port") is trusted. An unparseable address is not. */
|
|
19
|
+
trusted(remoteAddress: string | undefined): boolean;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=baggage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baggage.d.ts","sourceRoot":"","sources":["../src/baggage.ts"],"names":[],"mappings":"AAWA,OAAO,EAAW,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAI3D,eAAO,MAAM,cAAc,YAAY,CAAC;AAExC,uDAAuD;AACvD,eAAO,MAAM,0BAA0B,eAAe,CAAC;AAEvD,2JAA2J;AAC3J,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAQ/C;AAED,wGAAwG;AACxG,wBAAgB,aAAa,CAAC,GAAG,GAAE,OAA0B,GAAG,MAAM,CAmBrE;AAED,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiB5F;AAED,sFAAsF;AACtF,qBAAa,SAAS;;IAGrB,2GAA2G;gBAC/F,KAAK,GAAE,SAAS,MAAM,EAAO;IAazC,6EAA6E;IAC7E,MAAM,CAAC,OAAO,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,SAAS;IAIhF,wGAAwG;IACxG,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO;CAUnD"}
|
package/dist/baggage.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Origin baggage and peer trust (observability plan §5.4), as go-platform's
|
|
3
|
+
* telemetry/baggage.go and connectmw.ClientIPResolver decide them.
|
|
4
|
+
*
|
|
5
|
+
* - Members: xeonr.origin.subject, xeonr.origin.service, xeonr.org.id. Nothing else.
|
|
6
|
+
* - Sent only toward in-cluster hosts; any other destination gets none.
|
|
7
|
+
* - Honoured only from a trusted TCP peer (TRUSTED_PROXY_CIDR, default
|
|
8
|
+
* 10.0.0.0/8: the edge and in-cluster callers). From anyone else it is
|
|
9
|
+
* ignored, and so is their traceparent.
|
|
10
|
+
*/
|
|
11
|
+
import { BlockList, isIP } from "node:net";
|
|
12
|
+
import { context } from "@opentelemetry/api";
|
|
13
|
+
import { stateFrom } from "./identity.js";
|
|
14
|
+
import { BAGGAGE_KEYS } from "./keys.js";
|
|
15
|
+
export const HEADER_BAGGAGE = "baggage";
|
|
16
|
+
/** go-platform's connectmw.DefaultTrustedProxyCIDR. */
|
|
17
|
+
export const DEFAULT_TRUSTED_PROXY_CIDR = "10.0.0.0/8";
|
|
18
|
+
/** Whether `host` (a host or host:port) is a cluster-internal name: `*.svc`, `*.cluster.local`, or a bare single-label name. IPs and localhost are not. */
|
|
19
|
+
export function inCluster(host) {
|
|
20
|
+
let h = host.trim().toLowerCase();
|
|
21
|
+
if (h.startsWith("["))
|
|
22
|
+
h = h.slice(1, h.indexOf("]"));
|
|
23
|
+
else if (h.split(":").length === 2)
|
|
24
|
+
h = h.split(":")[0] ?? "";
|
|
25
|
+
h = h.replace(/\.$/, "");
|
|
26
|
+
if (!h || h === "localhost" || isIP(h))
|
|
27
|
+
return false;
|
|
28
|
+
if (h.endsWith(".svc") || h.endsWith(".svc.cluster.local") || h.endsWith(".cluster.local"))
|
|
29
|
+
return true;
|
|
30
|
+
return !h.includes(".");
|
|
31
|
+
}
|
|
32
|
+
/** The `baggage` header value for the origin members of `ctx`'s identity, or "" when there are none. */
|
|
33
|
+
export function originBaggage(ctx = context.active()) {
|
|
34
|
+
const id = stateFrom(ctx)?.identity();
|
|
35
|
+
if (!id)
|
|
36
|
+
return "";
|
|
37
|
+
const values = {
|
|
38
|
+
"xeonr.origin.subject": id.originSubject,
|
|
39
|
+
"xeonr.origin.service": id.originService,
|
|
40
|
+
"xeonr.org.id": id.orgId,
|
|
41
|
+
};
|
|
42
|
+
const entries = {};
|
|
43
|
+
for (const k of BAGGAGE_KEYS) {
|
|
44
|
+
const v = values[k];
|
|
45
|
+
if (v)
|
|
46
|
+
entries[k] = { value: v };
|
|
47
|
+
}
|
|
48
|
+
if (Object.keys(entries).length === 0)
|
|
49
|
+
return "";
|
|
50
|
+
// The global propagator is W3C trace context only (§5.4): baggage is never
|
|
51
|
+
// injected by an instrumentation, only by these helpers.
|
|
52
|
+
return Object.entries(entries)
|
|
53
|
+
.map(([k, { value }]) => `${k}=${encodeURIComponent(value)}`)
|
|
54
|
+
.join(",");
|
|
55
|
+
}
|
|
56
|
+
/** Parses a `baggage` header into the origin members, ignoring every other member. */
|
|
57
|
+
export function parseOriginBaggage(header) {
|
|
58
|
+
const out = {};
|
|
59
|
+
if (!header)
|
|
60
|
+
return out;
|
|
61
|
+
for (const part of header.split(",")) {
|
|
62
|
+
const [kv] = part.split(";");
|
|
63
|
+
const i = kv?.indexOf("=") ?? -1;
|
|
64
|
+
if (!kv || i < 0)
|
|
65
|
+
continue;
|
|
66
|
+
const k = kv.slice(0, i).trim();
|
|
67
|
+
if (!BAGGAGE_KEYS.includes(k))
|
|
68
|
+
continue;
|
|
69
|
+
try {
|
|
70
|
+
const v = decodeURIComponent(kv.slice(i + 1).trim());
|
|
71
|
+
if (v)
|
|
72
|
+
out[k] = v;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// A malformed member is dropped, as Go's baggage.Parse would drop the header.
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
/** Decides peer trust from CIDRs, like go-platform's ClientIPResolver.PeerTrusted. */
|
|
81
|
+
export class PeerTrust {
|
|
82
|
+
#list = new BlockList();
|
|
83
|
+
/** No CIDRs → DEFAULT_TRUSTED_PROXY_CIDR. An invalid entry throws: a bad trust range must fail at boot. */
|
|
84
|
+
constructor(cidrs = []) {
|
|
85
|
+
const valid = cidrs.map((c) => c.trim()).filter(Boolean);
|
|
86
|
+
for (const c of valid.length ? valid : [DEFAULT_TRUSTED_PROXY_CIDR]) {
|
|
87
|
+
const [addr, bits] = c.split("/");
|
|
88
|
+
const family = addr && isIP(addr);
|
|
89
|
+
const prefix = Number(bits);
|
|
90
|
+
if (!addr || !family || bits === undefined || !Number.isInteger(prefix) || prefix < 0 || prefix > (family === 4 ? 32 : 128)) {
|
|
91
|
+
throw new Error(`@xeonr/telemetry: trusted proxy CIDR ${JSON.stringify(c)} is invalid`);
|
|
92
|
+
}
|
|
93
|
+
this.#list.addSubnet(addr, prefix, family === 4 ? "ipv4" : "ipv6");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** From TRUSTED_PROXY_CIDR (comma-separated), as the Go services read it. */
|
|
97
|
+
static fromEnv(env = process.env) {
|
|
98
|
+
return new PeerTrust((env.TRUSTED_PROXY_CIDR ?? "").split(","));
|
|
99
|
+
}
|
|
100
|
+
/** Whether the TCP peer (an IP, "ip:port" or "[v6]:port") is trusted. An unparseable address is not. */
|
|
101
|
+
trusted(remoteAddress) {
|
|
102
|
+
if (!remoteAddress)
|
|
103
|
+
return false;
|
|
104
|
+
let ip = remoteAddress.trim();
|
|
105
|
+
if (ip.startsWith("["))
|
|
106
|
+
ip = ip.slice(1, ip.indexOf("]"));
|
|
107
|
+
else if (!isIP(ip) && ip.split(":").length === 2)
|
|
108
|
+
ip = ip.split(":")[0] ?? "";
|
|
109
|
+
if (ip.startsWith("::ffff:") && isIP(ip.slice(7)) === 4)
|
|
110
|
+
ip = ip.slice(7);
|
|
111
|
+
const family = isIP(ip);
|
|
112
|
+
if (!family)
|
|
113
|
+
return false;
|
|
114
|
+
return this.#list.check(ip, family === 4 ? "ipv4" : "ipv6");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=baggage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baggage.js","sourceRoot":"","sources":["../src/baggage.ts"],"names":[],"mappings":"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"}
|
package/dist/boot.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The boot lines `init` writes, in the logger's shape, without loading pino:
|
|
3
|
+
* `register` runs before the app, and pino must be imported after the
|
|
4
|
+
* instrumentations are enabled for the pino instrumentation to see it.
|
|
5
|
+
*/
|
|
6
|
+
export declare function bootLine(level: "info" | "warn" | "error", msg: string, fields?: Record<string, unknown>): void;
|
|
7
|
+
//# sourceMappingURL=boot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot.d.ts","sourceRoot":"","sources":["../src/boot.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI,CAGlH"}
|
package/dist/boot.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The boot lines `init` writes, in the logger's shape, without loading pino:
|
|
3
|
+
* `register` runs before the app, and pino must be imported after the
|
|
4
|
+
* instrumentations are enabled for the pino instrumentation to see it.
|
|
5
|
+
*/
|
|
6
|
+
export function bootLine(level, msg, fields = {}) {
|
|
7
|
+
const clean = Object.fromEntries(Object.entries(fields).filter(([, v]) => v !== undefined && v !== ""));
|
|
8
|
+
process.stdout.write(JSON.stringify({ level, time: new Date().toISOString(), msg, ...clean }) + "\n");
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=boot.js.map
|
package/dist/boot.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boot.js","sourceRoot":"","sources":["../src/boot.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAgC,EAAE,GAAW,EAAE,SAAkC,EAAE;IAC3G,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACxG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;AACvG,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@xeonr/telemetry/connect`: Connect ^2 interceptors, the Node counterparts
|
|
3
|
+
* of go-platform's telemetry.ServerInterceptor (with otelconnect and
|
|
4
|
+
* RemoteParent) and telemetry.ClientInterceptor.
|
|
5
|
+
*
|
|
6
|
+
* Server: one SERVER span per call named `pkg.Service/Method`, with
|
|
7
|
+
* `rpc.system=connect_rpc`, `rpc.service` and `rpc.method` = the full
|
|
8
|
+
* procedure (as Lantern shows `rpc.method` for the Go services, and what
|
|
9
|
+
* dashboards and monitors filter on), and otelconnect's status rule (only a server-class code is an error; the code is in
|
|
10
|
+
* `rpc.connect_rpc.error_code`). A remote traceparent is continued only from a
|
|
11
|
+
* trusted peer (TRUSTED_PROXY_CIDR, default 10.0.0.0/8); anyone else's becomes
|
|
12
|
+
* a link. Origin baggage is honoured only from a trusted peer too. The call
|
|
13
|
+
* runs with a fresh identity record: the service's auth layer fills it with
|
|
14
|
+
* `setIdentity`, and it is stamped on the server span when the call ends.
|
|
15
|
+
*
|
|
16
|
+
* Client: one CLIENT span per call, `traceparent` on the request, origin
|
|
17
|
+
* baggage only toward an in-cluster host, `peer.service` from the option.
|
|
18
|
+
*
|
|
19
|
+
* Put the server interceptor first, ahead of auth, so a refused call is still
|
|
20
|
+
* a span with `subject.kind=anonymous`.
|
|
21
|
+
*/
|
|
22
|
+
import { type ContextValues, type Interceptor } from "@connectrpc/connect";
|
|
23
|
+
import { PeerTrust } from "./baggage.ts";
|
|
24
|
+
/** The TCP peer of the call, for the trust decision. Set it with `peerContextValues`. */
|
|
25
|
+
export declare const kPeerAddress: import("@connectrpc/connect").ContextKey<string | undefined>;
|
|
26
|
+
type RequestLike = {
|
|
27
|
+
socket?: {
|
|
28
|
+
remoteAddress?: string | undefined;
|
|
29
|
+
} | undefined;
|
|
30
|
+
raw?: {
|
|
31
|
+
socket?: {
|
|
32
|
+
remoteAddress?: string | undefined;
|
|
33
|
+
} | undefined;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Context values carrying the TCP peer, for the Connect adapter's
|
|
38
|
+
* `contextValues` option (`@connectrpc/connect-fastify`, `connect-node`,
|
|
39
|
+
* `connect-express` all pass the request):
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* app.register(fastifyConnectPlugin, { routes, interceptors, contextValues: peerContextValues });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function peerContextValues(req: RequestLike): ContextValues;
|
|
46
|
+
export interface ServerInterceptorOptions {
|
|
47
|
+
/** Who may continue a trace and send baggage. Default: TRUSTED_PROXY_CIDR, else 10.0.0.0/8. */
|
|
48
|
+
trust?: PeerTrust;
|
|
49
|
+
/** `service.name` for the origin of a trace this service starts. Default OTEL_SERVICE_NAME. */
|
|
50
|
+
serviceName?: string;
|
|
51
|
+
}
|
|
52
|
+
export declare function serverInterceptor(opts?: ServerInterceptorOptions): Interceptor;
|
|
53
|
+
export interface ClientInterceptorOptions {
|
|
54
|
+
/** `peer.service`: the service being called (`upl-im-api`). */
|
|
55
|
+
peer?: string;
|
|
56
|
+
/** Which hosts are in-cluster and get origin baggage. Default `inCluster`. */
|
|
57
|
+
inCluster?: (host: string) => boolean;
|
|
58
|
+
}
|
|
59
|
+
export declare function clientInterceptor(opts?: ClientInterceptorOptions): Interceptor;
|
|
60
|
+
/** For tests and adapters without `contextValues`: values carrying a given peer. */
|
|
61
|
+
export declare function contextValuesWithPeer(peer: string): ContextValues;
|
|
62
|
+
export {};
|
|
63
|
+
//# sourceMappingURL=connect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAKN,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAgE,SAAS,EAAE,MAAM,cAAc,CAAC;AAWvG,yFAAyF;AACzF,eAAO,MAAM,YAAY,8DAA0G,CAAC;AAEpI,KAAK,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,SAAS,CAAC;IAAC,GAAG,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE;YAAE,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE,GAAG,SAAS,CAAA;KAAE,CAAA;CAAE,CAAC;AAE1J;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,CAIjE;AAED,MAAM,WAAW,wBAAwB;IACxC,+FAA+F;IAC/F,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+FAA+F;IAC/F,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,wBAA6B,GAAG,WAAW,CA2DlF;AAED,MAAM,WAAW,wBAAwB;IACxC,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACtC;AAED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,wBAA6B,GAAG,WAAW,CAsClF;AA4CD,oFAAoF;AACpF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAIjE"}
|
package/dist/connect.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@xeonr/telemetry/connect`: Connect ^2 interceptors, the Node counterparts
|
|
3
|
+
* of go-platform's telemetry.ServerInterceptor (with otelconnect and
|
|
4
|
+
* RemoteParent) and telemetry.ClientInterceptor.
|
|
5
|
+
*
|
|
6
|
+
* Server: one SERVER span per call named `pkg.Service/Method`, with
|
|
7
|
+
* `rpc.system=connect_rpc`, `rpc.service` and `rpc.method` = the full
|
|
8
|
+
* procedure (as Lantern shows `rpc.method` for the Go services, and what
|
|
9
|
+
* dashboards and monitors filter on), and otelconnect's status rule (only a server-class code is an error; the code is in
|
|
10
|
+
* `rpc.connect_rpc.error_code`). A remote traceparent is continued only from a
|
|
11
|
+
* trusted peer (TRUSTED_PROXY_CIDR, default 10.0.0.0/8); anyone else's becomes
|
|
12
|
+
* a link. Origin baggage is honoured only from a trusted peer too. The call
|
|
13
|
+
* runs with a fresh identity record: the service's auth layer fills it with
|
|
14
|
+
* `setIdentity`, and it is stamped on the server span when the call ends.
|
|
15
|
+
*
|
|
16
|
+
* Client: one CLIENT span per call, `traceparent` on the request, origin
|
|
17
|
+
* baggage only toward an in-cluster host, `peer.service` from the option.
|
|
18
|
+
*
|
|
19
|
+
* Put the server interceptor first, ahead of auth, so a refused call is still
|
|
20
|
+
* a span with `subject.kind=anonymous`.
|
|
21
|
+
*/
|
|
22
|
+
import { Code, ConnectError, createContextKey as createConnectContextKey, createContextValues, } from "@connectrpc/connect";
|
|
23
|
+
import { context, propagation, ROOT_CONTEXT, SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
24
|
+
import { HEADER_BAGGAGE, inCluster, originBaggage, parseOriginBaggage, PeerTrust } from "./baggage.js";
|
|
25
|
+
import { attributes, State, withState } from "./identity.js";
|
|
26
|
+
import { KeyScopes } from "./keys.js";
|
|
27
|
+
import { KEY_PEER_SERVICE } from "./processor.js";
|
|
28
|
+
import { sanitize } from "./sanitize.js";
|
|
29
|
+
const TRACER = "@xeonr/telemetry/connect";
|
|
30
|
+
/** otelconnect's server-class codes: only these mark a server span as an error. */
|
|
31
|
+
const SERVER_ERROR_CODES = new Set([Code.Unknown, Code.DeadlineExceeded, Code.Unimplemented, Code.Internal, Code.Unavailable, Code.DataLoss]);
|
|
32
|
+
/** The TCP peer of the call, for the trust decision. Set it with `peerContextValues`. */
|
|
33
|
+
export const kPeerAddress = createConnectContextKey(undefined, { description: "xeonr.telemetry.peer_address" });
|
|
34
|
+
/**
|
|
35
|
+
* Context values carrying the TCP peer, for the Connect adapter's
|
|
36
|
+
* `contextValues` option (`@connectrpc/connect-fastify`, `connect-node`,
|
|
37
|
+
* `connect-express` all pass the request):
|
|
38
|
+
*
|
|
39
|
+
* ```ts
|
|
40
|
+
* app.register(fastifyConnectPlugin, { routes, interceptors, contextValues: peerContextValues });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function peerContextValues(req) {
|
|
44
|
+
const values = createContextValues();
|
|
45
|
+
values.set(kPeerAddress, req.socket?.remoteAddress ?? req.raw?.socket?.remoteAddress);
|
|
46
|
+
return values;
|
|
47
|
+
}
|
|
48
|
+
export function serverInterceptor(opts = {}) {
|
|
49
|
+
const trust = opts.trust ?? PeerTrust.fromEnv();
|
|
50
|
+
const service = opts.serviceName ?? process.env.OTEL_SERVICE_NAME?.trim() ?? "";
|
|
51
|
+
return (next) => async (req) => {
|
|
52
|
+
const procedure = `${req.service.typeName}/${req.method.name}`;
|
|
53
|
+
const peer = req.contextValues.get(kPeerAddress);
|
|
54
|
+
const trusted = trust.trusted(peer);
|
|
55
|
+
const s = new State();
|
|
56
|
+
s.service = service;
|
|
57
|
+
s.procedure = procedure;
|
|
58
|
+
s.ip = (trusted ? req.header.get("x-real-ip")?.trim() : stripPort(peer)) ?? "";
|
|
59
|
+
decideOrigin(s, req.header.get(HEADER_BAGGAGE), trusted);
|
|
60
|
+
// Under an HTTP server span (connect-node on HTTP/1.1, which the http
|
|
61
|
+
// instrumentation sees), the call is its child. Otherwise (HTTP/2, which
|
|
62
|
+
// it does not see) the remote parent is decided here.
|
|
63
|
+
const links = [];
|
|
64
|
+
let parent = context.active();
|
|
65
|
+
const local = trace.getSpanContext(parent);
|
|
66
|
+
if (!local || !trace.isSpanContextValid(local)) {
|
|
67
|
+
const getter = { get: (h, k) => h.get(k) ?? undefined, keys: (h) => [...h.keys()] };
|
|
68
|
+
const remoteSc = trace.getSpanContext(propagation.extract(ROOT_CONTEXT, req.header, getter));
|
|
69
|
+
if (remoteSc && trace.isSpanContextValid(remoteSc)) {
|
|
70
|
+
if (trusted)
|
|
71
|
+
parent = trace.setSpanContext(parent, remoteSc);
|
|
72
|
+
else
|
|
73
|
+
links.push({ context: remoteSc });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
parent = withState(parent, s);
|
|
77
|
+
const span = trace.getTracer(TRACER).startSpan(procedure, {
|
|
78
|
+
kind: SpanKind.SERVER,
|
|
79
|
+
links,
|
|
80
|
+
attributes: { "rpc.system": "connect_rpc", "rpc.service": req.service.typeName, "rpc.method": procedure },
|
|
81
|
+
}, parent);
|
|
82
|
+
s.root = span;
|
|
83
|
+
const ctx = trace.setSpan(parent, span);
|
|
84
|
+
const finish = (err) => {
|
|
85
|
+
const id = s.identity();
|
|
86
|
+
span.setAttributes(attributes(id));
|
|
87
|
+
if (id.scopes?.length)
|
|
88
|
+
span.setAttribute(KeyScopes, id.scopes);
|
|
89
|
+
if (err !== undefined)
|
|
90
|
+
serverError(span, err);
|
|
91
|
+
span.end();
|
|
92
|
+
};
|
|
93
|
+
try {
|
|
94
|
+
const res = await context.with(ctx, () => next(req));
|
|
95
|
+
if (res.stream)
|
|
96
|
+
return { ...res, message: endWhenDone(res.message, finish) };
|
|
97
|
+
finish();
|
|
98
|
+
return res;
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
finish(err);
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
export function clientInterceptor(opts = {}) {
|
|
107
|
+
const isInCluster = opts.inCluster ?? inCluster;
|
|
108
|
+
return (next) => async (req) => {
|
|
109
|
+
const procedure = `${req.service.typeName}/${req.method.name}`;
|
|
110
|
+
const attrs = { "rpc.system": "connect_rpc", "rpc.service": req.service.typeName, "rpc.method": procedure };
|
|
111
|
+
if (opts.peer)
|
|
112
|
+
attrs[KEY_PEER_SERVICE] = opts.peer;
|
|
113
|
+
const span = trace.getTracer(TRACER).startSpan(procedure, { kind: SpanKind.CLIENT, attributes: attrs });
|
|
114
|
+
const ctx = trace.setSpan(context.active(), span);
|
|
115
|
+
propagation.inject(ctx, req.header, { set: (h, k, v) => h.set(k, v) });
|
|
116
|
+
let host = "";
|
|
117
|
+
try {
|
|
118
|
+
host = new URL(req.url).host;
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
// An unparseable URL is not in-cluster.
|
|
122
|
+
}
|
|
123
|
+
const b = isInCluster(host) ? originBaggage(ctx) : "";
|
|
124
|
+
if (b)
|
|
125
|
+
req.header.set(HEADER_BAGGAGE, b);
|
|
126
|
+
else
|
|
127
|
+
req.header.delete(HEADER_BAGGAGE);
|
|
128
|
+
const finish = (err) => {
|
|
129
|
+
if (err !== undefined) {
|
|
130
|
+
const ce = ConnectError.from(err);
|
|
131
|
+
span.setAttribute("rpc.connect_rpc.error_code", Code[ce.code]);
|
|
132
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: sanitize(ce.rawMessage) });
|
|
133
|
+
}
|
|
134
|
+
span.end();
|
|
135
|
+
};
|
|
136
|
+
try {
|
|
137
|
+
const res = await context.with(ctx, () => next(req));
|
|
138
|
+
if (res.stream)
|
|
139
|
+
return { ...res, message: endWhenDone(res.message, finish) };
|
|
140
|
+
finish();
|
|
141
|
+
return res;
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
finish(err);
|
|
145
|
+
throw err;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function serverError(span, err) {
|
|
150
|
+
// What the client sees: anything not a ConnectError goes out as internal.
|
|
151
|
+
const ce = err instanceof ConnectError ? err : ConnectError.from(err, Code.Internal);
|
|
152
|
+
span.setAttribute("rpc.connect_rpc.error_code", Code[ce.code]);
|
|
153
|
+
if (!SERVER_ERROR_CODES.has(ce.code))
|
|
154
|
+
return;
|
|
155
|
+
const message = sanitize(ce.rawMessage);
|
|
156
|
+
span.addEvent("exception", { "exception.type": err instanceof Error ? err.name : "ConnectError", "exception.message": message });
|
|
157
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
158
|
+
}
|
|
159
|
+
async function* endWhenDone(messages, finish) {
|
|
160
|
+
try {
|
|
161
|
+
yield* messages;
|
|
162
|
+
finish();
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
finish(err);
|
|
166
|
+
throw err;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/** go-platform's state.decideOrigin: the first hop with no trusted origin baggage is the entry. */
|
|
170
|
+
function decideOrigin(s, header, trusted) {
|
|
171
|
+
s.originDecided = true;
|
|
172
|
+
s.entry = true;
|
|
173
|
+
if (!trusted || !header)
|
|
174
|
+
return;
|
|
175
|
+
const b = parseOriginBaggage(header);
|
|
176
|
+
const subject = b["xeonr.origin.subject"];
|
|
177
|
+
const service = b["xeonr.origin.service"];
|
|
178
|
+
if (subject || service) {
|
|
179
|
+
s.entry = false;
|
|
180
|
+
if (subject)
|
|
181
|
+
s.id.originSubject = subject;
|
|
182
|
+
if (service)
|
|
183
|
+
s.id.originService = service;
|
|
184
|
+
}
|
|
185
|
+
s.baggageOrgId = b["xeonr.org.id"] ?? "";
|
|
186
|
+
}
|
|
187
|
+
function stripPort(addr) {
|
|
188
|
+
if (!addr)
|
|
189
|
+
return undefined;
|
|
190
|
+
if (addr.startsWith("["))
|
|
191
|
+
return addr.slice(1, addr.indexOf("]"));
|
|
192
|
+
return addr.split(":").length === 2 ? addr.split(":")[0] : addr;
|
|
193
|
+
}
|
|
194
|
+
/** For tests and adapters without `contextValues`: values carrying a given peer. */
|
|
195
|
+
export function contextValuesWithPeer(peer) {
|
|
196
|
+
const values = createContextValues();
|
|
197
|
+
values.set(kPeerAddress, peer);
|
|
198
|
+
return values;
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=connect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"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"}
|
package/dist/fetch.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface FetchOptions {
|
|
2
|
+
/** `peer.service`: who is being called (`discord`, `upl-im-api`). */
|
|
3
|
+
peer?: string;
|
|
4
|
+
/** Send origin baggage when the host is in-cluster (go-platform's WithOriginBaggage). Default true. */
|
|
5
|
+
baggage?: boolean;
|
|
6
|
+
/** Which hosts are in-cluster. Default `inCluster`. */
|
|
7
|
+
inCluster?: (host: string) => boolean;
|
|
8
|
+
/** The fetch to wrap. Default `globalThis.fetch`. */
|
|
9
|
+
fetch?: typeof fetch;
|
|
10
|
+
}
|
|
11
|
+
/** A `fetch` for one peer. */
|
|
12
|
+
export declare function fetchWith(opts?: FetchOptions): typeof fetch;
|
|
13
|
+
/**
|
|
14
|
+
* The `baggage` header for a request to `url`: the origin members when the
|
|
15
|
+
* host is in-cluster, else "". For HTTP clients other than fetch (axios,
|
|
16
|
+
* got): set it when non-empty, and run the call inside `withPeer`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function baggageFor(url: string, isInCluster?: (host: string) => boolean): string;
|
|
19
|
+
//# sourceMappingURL=fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,YAAY;IAC5B,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uGAAuG;IACvG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uDAAuD;IACvD,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACtC,qDAAqD;IACrD,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACrB;AAED,8BAA8B;AAC9B,wBAAgB,SAAS,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,KAAK,CAW/D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,GAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAmB,GAAG,MAAM,CAQlG"}
|