@vymalo/opencode-otel 0.12.0 → 0.14.1
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 +20 -1
- package/dist/config.d.ts +29 -17
- package/dist/config.js +210 -197
- package/dist/config.js.map +1 -1
- package/dist/deferred.d.ts +22 -0
- package/dist/deferred.js +29 -0
- package/dist/deferred.js.map +1 -0
- package/dist/export-logging.d.ts +28 -0
- package/dist/export-logging.js +74 -0
- package/dist/export-logging.js.map +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/instruments.d.ts +22 -22
- package/dist/instruments.js +95 -94
- package/dist/instruments.js.map +1 -1
- package/dist/lib.d.ts +5 -1
- package/dist/lib.js +6 -1
- package/dist/lib.js.map +1 -1
- package/dist/logging.d.ts +6 -6
- package/dist/logging.js +59 -62
- package/dist/logging.js.map +1 -1
- package/dist/opencode.d.ts +16 -14
- package/dist/opencode.js +165 -122
- package/dist/opencode.js.map +1 -1
- package/dist/propagation.d.ts +13 -13
- package/dist/propagation.js +50 -48
- package/dist/propagation.js.map +1 -1
- package/dist/providers.d.ts +46 -35
- package/dist/providers.js +217 -158
- package/dist/providers.js.map +1 -1
- package/dist/recorder.d.ts +150 -69
- package/dist/recorder.js +788 -539
- package/dist/recorder.js.map +1 -1
- package/dist/token-source.d.ts +59 -0
- package/dist/token-source.js +125 -0
- package/dist/token-source.js.map +1 -0
- package/dist/types.d.ts +92 -64
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/dist/vcs.d.ts +63 -0
- package/dist/vcs.js +188 -0
- package/dist/vcs.js.map +1 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -47,7 +47,10 @@ same dashboards. What it adds:
|
|
|
47
47
|
- **All five token types** — `input`, `output`, `reasoning`, `cache_read`, `cache_write`. On a
|
|
48
48
|
cached agentic session cache-read is routinely the majority of tokens, so summing input+output
|
|
49
49
|
alone measures a different quantity.
|
|
50
|
-
- **Permission decisions**,
|
|
50
|
+
- **Permission decisions**, including ones a config auto-resolved without asking (`permission.ask`
|
|
51
|
+
covers both; `opencode.permission.source` distinguishes `user` from `auto`).
|
|
52
|
+
- **Repository identity** — `vcs.repository.url.full`, `vcs.repository.name`, `vcs.owner.name`,
|
|
53
|
+
`vcs.provider.name`, `vcs.ref.head.*` — read straight off disk, credentials stripped.
|
|
51
54
|
- **`opencode.json` configuration**, not just environment variables — required for
|
|
52
55
|
`.well-known/opencode` distribution.
|
|
53
56
|
|
|
@@ -79,6 +82,22 @@ under Bun as well as Node, and `@grpc/grpc-js` is unreliable there. Put a collec
|
|
|
79
82
|
backend needs gRPC. See
|
|
80
83
|
[ADR-0009](https://github.com/ADORSYS-GIS/lightbridge-opencode-toolbeit/blob/main/docs/adr/0009-otel-otlp-http-not-grpc.md).
|
|
81
84
|
|
|
85
|
+
## Short-lived credentials
|
|
86
|
+
|
|
87
|
+
A static `Authorization` header is read once at plugin load and never refreshed — fine for a
|
|
88
|
+
long-lived API key, wrong for a collector behind a short OIDC token. Set `tokenCommand` to an
|
|
89
|
+
executable that prints a fresh token on stdout; it is re-run before the token's `exp` claim (or
|
|
90
|
+
`tokenRefreshMs`, when there is none) expires. See
|
|
91
|
+
[docs/otel.md → Short-lived credentials](https://github.com/ADORSYS-GIS/lightbridge-opencode-toolbeit/blob/main/docs/otel.md#short-lived-credentials).
|
|
92
|
+
|
|
93
|
+
## When exports fail
|
|
94
|
+
|
|
95
|
+
A rejected OTLP request — an expired credential, an unreachable collector — reaches the host log
|
|
96
|
+
stream as `otel_export_failed` (signal, HTTP status where known, `consecutiveFailures`); recovery is
|
|
97
|
+
reported once as `otel_export_recovered`. Previously this only went to the OTel SDK's own `diag`
|
|
98
|
+
channel, which nothing subscribed to, so telemetry could stop silently. See
|
|
99
|
+
[docs/otel.md → Troubleshooting](https://github.com/ADORSYS-GIS/lightbridge-opencode-toolbeit/blob/main/docs/otel.md#troubleshooting).
|
|
100
|
+
|
|
82
101
|
## Full reference
|
|
83
102
|
|
|
84
103
|
- [`docs/otel.md`](https://github.com/ADORSYS-GIS/lightbridge-opencode-toolbeit/blob/main/docs/otel.md)
|
package/dist/config.d.ts
CHANGED
|
@@ -3,25 +3,37 @@ export declare const SIGNALS: readonly SignalName[];
|
|
|
3
3
|
/** Env source, injectable so tests never touch `process.env`. */
|
|
4
4
|
export type EnvSource = Record<string, string | undefined>;
|
|
5
5
|
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
* Parse the OTel `key=value,key2=value2` list format used by both
|
|
7
|
+
* `OTEL_EXPORTER_OTLP_HEADERS` and `OTEL_RESOURCE_ATTRIBUTES`. Values are
|
|
8
|
+
* percent-decoded per spec; an undecodable value is kept verbatim rather than
|
|
9
|
+
* dropping the whole pair.
|
|
10
|
+
*/
|
|
11
11
|
export declare function parseKeyValueList(raw: string | undefined): Record<string, string>;
|
|
12
12
|
/**
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
* Normalise a command to argv. An array is taken verbatim — that is the form to
|
|
14
|
+
* use when a path contains spaces. A string is split on whitespace, with **no
|
|
15
|
+
* shell**: no quoting, no substitution, no injection surface.
|
|
16
|
+
*
|
|
17
|
+
* The split is decided by the type of the value actually supplied, not by the
|
|
18
|
+
* type of some other candidate. Keying it on the wrong source silently produced
|
|
19
|
+
* a single argv element like `"governance-auth token"` whenever an environment
|
|
20
|
+
* override sat on top of an array in config — which `execFile` then failed to
|
|
21
|
+
* spawn, so every export went out unauthenticated.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseCommand(raw: unknown): string[];
|
|
24
|
+
/**
|
|
25
|
+
* Resolve plugin options against the environment.
|
|
26
|
+
*
|
|
27
|
+
* **Precedence: environment overrides plugin options.** Options are the base
|
|
28
|
+
* layer so a `.well-known/opencode` document can ship a working default for a
|
|
29
|
+
* whole organization; `OTEL_*` variables override per machine so a developer
|
|
30
|
+
* can point at a local collector without editing served config. See
|
|
31
|
+
* `plans/otel.md`.
|
|
32
|
+
*/
|
|
21
33
|
export declare function resolveOtelConfig(raw: unknown, env?: EnvSource): ResolvedOtelConfig;
|
|
22
34
|
/**
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
* Resolve the OTLP URL for one signal. A per-signal endpoint is used verbatim
|
|
36
|
+
* (spec: it already includes the path); the base endpoint gets the signal path
|
|
37
|
+
* appended.
|
|
38
|
+
*/
|
|
27
39
|
export declare function signalUrl(config: ResolvedOtelConfig, signal: SignalName): string | undefined;
|
package/dist/config.js
CHANGED
|
@@ -1,224 +1,237 @@
|
|
|
1
|
-
|
|
1
|
+
import { DEFAULT_REFRESH_MS } from "./token-source.js";
|
|
2
|
+
export const SIGNALS = [
|
|
3
|
+
"traces",
|
|
4
|
+
"metrics",
|
|
5
|
+
"logs"
|
|
6
|
+
];
|
|
2
7
|
const DEFAULTS = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
serviceName: "opencode",
|
|
9
|
+
metricExportIntervalMs: 6e4,
|
|
10
|
+
logExportIntervalMs: 5e3,
|
|
11
|
+
traceExportIntervalMs: 5e3,
|
|
12
|
+
metricTemporality: "delta"
|
|
8
13
|
};
|
|
9
14
|
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
* The `OTEL_*` variable names read per signal. The first entry of each tuple is
|
|
16
|
+
* the OTel-spec name; the second (where present) is the Claude-Code-compatible
|
|
17
|
+
* alias, accepted so an operator can move a working env block across tools.
|
|
18
|
+
*/
|
|
14
19
|
const SIGNAL_ENV = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
traces: {
|
|
21
|
+
exporter: "OTEL_TRACES_EXPORTER",
|
|
22
|
+
endpoint: "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
|
|
23
|
+
interval: ["OTEL_BSP_SCHEDULE_DELAY", "OTEL_TRACES_EXPORT_INTERVAL"]
|
|
24
|
+
},
|
|
25
|
+
metrics: {
|
|
26
|
+
exporter: "OTEL_METRICS_EXPORTER",
|
|
27
|
+
endpoint: "OTEL_EXPORTER_OTLP_METRICS_ENDPOINT",
|
|
28
|
+
interval: ["OTEL_METRIC_EXPORT_INTERVAL"]
|
|
29
|
+
},
|
|
30
|
+
logs: {
|
|
31
|
+
exporter: "OTEL_LOGS_EXPORTER",
|
|
32
|
+
endpoint: "OTEL_EXPORTER_OTLP_LOGS_ENDPOINT",
|
|
33
|
+
interval: ["OTEL_BLRP_SCHEDULE_DELAY", "OTEL_LOGS_EXPORT_INTERVAL"]
|
|
34
|
+
}
|
|
30
35
|
};
|
|
31
36
|
function parseBool(value) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
if (value === undefined) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
if (/^(1|true|yes|on)$/i.test(value)) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (/^(0|false|no|off)$/i.test(value)) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
42
47
|
}
|
|
43
48
|
function parsePositiveInt(value) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
if (value === undefined) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const n = Number.parseInt(value.trim(), 10);
|
|
53
|
+
return Number.isFinite(n) && n > 0 ? n : undefined;
|
|
49
54
|
}
|
|
50
55
|
/**
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
* Parse the OTel `key=value,key2=value2` list format used by both
|
|
57
|
+
* `OTEL_EXPORTER_OTLP_HEADERS` and `OTEL_RESOURCE_ATTRIBUTES`. Values are
|
|
58
|
+
* percent-decoded per spec; an undecodable value is kept verbatim rather than
|
|
59
|
+
* dropping the whole pair.
|
|
60
|
+
*/
|
|
56
61
|
export function parseKeyValueList(raw) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return out;
|
|
62
|
+
if (!raw) {
|
|
63
|
+
return {};
|
|
64
|
+
}
|
|
65
|
+
const out = {};
|
|
66
|
+
for (const pair of raw.split(",")) {
|
|
67
|
+
const eq = pair.indexOf("=");
|
|
68
|
+
if (eq <= 0) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const key = pair.slice(0, eq).trim();
|
|
72
|
+
const rawValue = pair.slice(eq + 1).trim();
|
|
73
|
+
if (!key) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
out[key] = decodeURIComponent(rawValue);
|
|
78
|
+
} catch {
|
|
79
|
+
out[key] = rawValue;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
79
83
|
}
|
|
80
84
|
function parseExporter(value) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
85
|
+
if (value === undefined) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
// The spec allows a comma-separated list; we honour the first recognised
|
|
89
|
+
// entry rather than fanning out to multiple exporters.
|
|
90
|
+
for (const candidate of value.split(",").map((v) => v.trim().toLowerCase())) {
|
|
91
|
+
if (candidate === "otlp" || candidate === "console" || candidate === "none") {
|
|
92
|
+
return candidate;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
92
96
|
}
|
|
93
97
|
function firstDefined(env, keys) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
for (const key of keys) {
|
|
99
|
+
const value = env[key];
|
|
100
|
+
if (value !== undefined && value !== "") {
|
|
101
|
+
return value;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return undefined;
|
|
101
105
|
}
|
|
102
106
|
function stringRecord(raw) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return out;
|
|
107
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
108
|
+
return {};
|
|
109
|
+
}
|
|
110
|
+
const out = {};
|
|
111
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
112
|
+
if (typeof value === "string") {
|
|
113
|
+
out[key] = value;
|
|
114
|
+
} else if (typeof value === "number" || typeof value === "boolean") {
|
|
115
|
+
out[key] = String(value);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
116
119
|
}
|
|
117
120
|
function stringList(raw) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
.filter((v) => v !== "");
|
|
126
|
-
}
|
|
127
|
-
return [];
|
|
121
|
+
if (Array.isArray(raw)) {
|
|
122
|
+
return raw.filter((v) => typeof v === "string" && v.trim() !== "");
|
|
123
|
+
}
|
|
124
|
+
if (typeof raw === "string") {
|
|
125
|
+
return raw.split(",").map((v) => v.trim()).filter((v) => v !== "");
|
|
126
|
+
}
|
|
127
|
+
return [];
|
|
128
128
|
}
|
|
129
129
|
/**
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
* Normalise a command to argv. An array is taken verbatim — that is the form to
|
|
131
|
+
* use when a path contains spaces. A string is split on whitespace, with **no
|
|
132
|
+
* shell**: no quoting, no substitution, no injection surface.
|
|
133
|
+
*
|
|
134
|
+
* The split is decided by the type of the value actually supplied, not by the
|
|
135
|
+
* type of some other candidate. Keying it on the wrong source silently produced
|
|
136
|
+
* a single argv element like `"governance-auth token"` whenever an environment
|
|
137
|
+
* override sat on top of an array in config — which `execFile` then failed to
|
|
138
|
+
* spawn, so every export went out unauthenticated.
|
|
139
|
+
*/
|
|
140
|
+
export function parseCommand(raw) {
|
|
141
|
+
if (Array.isArray(raw)) {
|
|
142
|
+
return raw.filter((part) => typeof part === "string" && part.trim() !== "");
|
|
143
|
+
}
|
|
144
|
+
if (typeof raw === "string") {
|
|
145
|
+
return raw.split(/\s+/).filter((part) => part !== "");
|
|
146
|
+
}
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Resolve plugin options against the environment.
|
|
151
|
+
*
|
|
152
|
+
* **Precedence: environment overrides plugin options.** Options are the base
|
|
153
|
+
* layer so a `.well-known/opencode` document can ship a working default for a
|
|
154
|
+
* whole organization; `OTEL_*` variables override per machine so a developer
|
|
155
|
+
* can point at a local collector without editing served config. See
|
|
156
|
+
* `plans/otel.md`.
|
|
157
|
+
*/
|
|
138
158
|
export function resolveOtelConfig(raw, env = process.env) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
? opts.traceExportIntervalMs
|
|
199
|
-
: DEFAULTS.traceExportIntervalMs),
|
|
200
|
-
metricTemporality: temporality,
|
|
201
|
-
includeSessionId: parseBool(env.OTEL_METRICS_INCLUDE_SESSION_ID) ?? opts.includeSessionId === true,
|
|
202
|
-
filteredTools,
|
|
203
|
-
propagateTraceContext: parseBool(env.OPENCODE_OTEL_PROPAGATE_TRACE_CONTEXT) ??
|
|
204
|
-
(opts.propagateTraceContext !== false && exporters.traces !== "none")
|
|
205
|
-
};
|
|
159
|
+
const opts = raw ?? {};
|
|
160
|
+
const enabled = parseBool(env.OPENCODE_OTEL_ENABLED) ?? opts.enabled !== false;
|
|
161
|
+
const endpoint = env.OTEL_EXPORTER_OTLP_ENDPOINT || opts.endpoint || undefined;
|
|
162
|
+
const endpoints = {};
|
|
163
|
+
for (const signal of SIGNALS) {
|
|
164
|
+
const value = env[SIGNAL_ENV[signal].endpoint] || opts.endpoints?.[signal];
|
|
165
|
+
if (value) {
|
|
166
|
+
endpoints[signal] = value;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// Env headers merge over option headers key-by-key rather than replacing the
|
|
170
|
+
// map, so a machine can override just its auth token without restating the
|
|
171
|
+
// whole set the served config provided.
|
|
172
|
+
const headers = {
|
|
173
|
+
...stringRecord(opts.headers),
|
|
174
|
+
...parseKeyValueList(env.OTEL_EXPORTER_OTLP_HEADERS)
|
|
175
|
+
};
|
|
176
|
+
// An endpoint anywhere is what makes OTLP the implicit default; with none
|
|
177
|
+
// configured the plugin stays completely inert.
|
|
178
|
+
const hasEndpoint = Boolean(endpoint) || SIGNALS.some((s) => Boolean(endpoints[s]));
|
|
179
|
+
const fallback = hasEndpoint ? "otlp" : "none";
|
|
180
|
+
const exporters = {};
|
|
181
|
+
for (const signal of SIGNALS) {
|
|
182
|
+
exporters[signal] = parseExporter(env[SIGNAL_ENV[signal].exporter]) ?? opts.exporters?.[signal] ?? fallback;
|
|
183
|
+
}
|
|
184
|
+
const resourceAttributes = {
|
|
185
|
+
...stringRecord(opts.resourceAttributes),
|
|
186
|
+
...parseKeyValueList(env.OTEL_RESOURCE_ATTRIBUTES)
|
|
187
|
+
};
|
|
188
|
+
const temporality = env.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE?.trim().toLowerCase() === "cumulative" ? "cumulative" : env.OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE?.trim().toLowerCase() === "delta" ? "delta" : opts.metricTemporality ?? DEFAULTS.metricTemporality;
|
|
189
|
+
const filteredTools = new Set(env.OTEL_OPENCODE_FILTERED_TOOLS !== undefined ? stringList(env.OTEL_OPENCODE_FILTERED_TOOLS) : stringList(opts.filteredTools));
|
|
190
|
+
// Resolve the source first, then normalise based on *its* own type — see
|
|
191
|
+
// `parseCommand` for why keying the split on anything else is a trap.
|
|
192
|
+
const tokenCommand = parseCommand(env.OPENCODE_OTEL_TOKEN_COMMAND ?? opts.tokenCommand);
|
|
193
|
+
const enabledSignals = SIGNALS.filter((s) => exporters[s] !== "none");
|
|
194
|
+
return {
|
|
195
|
+
enabled,
|
|
196
|
+
active: enabled && enabledSignals.length > 0,
|
|
197
|
+
endpoint,
|
|
198
|
+
endpoints,
|
|
199
|
+
headers,
|
|
200
|
+
tokenCommand,
|
|
201
|
+
tokenHeader: env.OPENCODE_OTEL_TOKEN_HEADER || opts.tokenHeader || "Authorization",
|
|
202
|
+
tokenPrefix: env.OPENCODE_OTEL_TOKEN_PREFIX ?? opts.tokenPrefix ?? "Bearer ",
|
|
203
|
+
tokenRefreshMs: parsePositiveInt(env.OPENCODE_OTEL_TOKEN_REFRESH_MS) ?? (opts.tokenRefreshMs && opts.tokenRefreshMs > 0 ? opts.tokenRefreshMs : DEFAULT_REFRESH_MS),
|
|
204
|
+
tokenTimeoutMs: parsePositiveInt(env.OPENCODE_OTEL_TOKEN_TIMEOUT_MS) ?? (opts.tokenTimeoutMs && opts.tokenTimeoutMs > 0 ? opts.tokenTimeoutMs : 1e4),
|
|
205
|
+
exporters,
|
|
206
|
+
serviceName: env.OTEL_SERVICE_NAME || opts.serviceName || DEFAULTS.serviceName,
|
|
207
|
+
environment: env.OPENCODE_OTEL_ENVIRONMENT || opts.environment || undefined,
|
|
208
|
+
resourceAttributes,
|
|
209
|
+
collectVcs: parseBool(env.OPENCODE_OTEL_COLLECT_VCS) ?? opts.collectVcs !== false,
|
|
210
|
+
metricExportIntervalMs: parsePositiveInt(firstDefined(env, SIGNAL_ENV.metrics.interval)) ?? (opts.metricExportIntervalMs && opts.metricExportIntervalMs > 0 ? opts.metricExportIntervalMs : DEFAULTS.metricExportIntervalMs),
|
|
211
|
+
logExportIntervalMs: parsePositiveInt(firstDefined(env, SIGNAL_ENV.logs.interval)) ?? (opts.logExportIntervalMs && opts.logExportIntervalMs > 0 ? opts.logExportIntervalMs : DEFAULTS.logExportIntervalMs),
|
|
212
|
+
traceExportIntervalMs: parsePositiveInt(firstDefined(env, SIGNAL_ENV.traces.interval)) ?? (opts.traceExportIntervalMs && opts.traceExportIntervalMs > 0 ? opts.traceExportIntervalMs : DEFAULTS.traceExportIntervalMs),
|
|
213
|
+
metricTemporality: temporality,
|
|
214
|
+
includeSessionId: parseBool(env.OTEL_METRICS_INCLUDE_SESSION_ID) ?? opts.includeSessionId === true,
|
|
215
|
+
filteredTools,
|
|
216
|
+
propagateTraceContext: parseBool(env.OPENCODE_OTEL_PROPAGATE_TRACE_CONTEXT) ?? (opts.propagateTraceContext !== false && exporters.traces !== "none")
|
|
217
|
+
};
|
|
206
218
|
}
|
|
207
219
|
/**
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
220
|
+
* Resolve the OTLP URL for one signal. A per-signal endpoint is used verbatim
|
|
221
|
+
* (spec: it already includes the path); the base endpoint gets the signal path
|
|
222
|
+
* appended.
|
|
223
|
+
*/
|
|
212
224
|
export function signalUrl(config, signal) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
225
|
+
const explicit = config.endpoints[signal];
|
|
226
|
+
if (explicit) {
|
|
227
|
+
return explicit;
|
|
228
|
+
}
|
|
229
|
+
if (!config.endpoint) {
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
const base = config.endpoint.replace(/\/+$/, "");
|
|
233
|
+
const path = signal === "traces" ? "v1/traces" : signal === "metrics" ? "v1/metrics" : "v1/logs";
|
|
234
|
+
return `${base}/${path}`;
|
|
223
235
|
}
|
|
236
|
+
|
|
224
237
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"
|
|
1
|
+
{"mappings":"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","names":[],"sources":["../src/config.ts"],"version":3,"file":"config.js","sourceRoot":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A resource attribute whose value only becomes known after the plugin has
|
|
3
|
+
* already started — OpenCode reports the host version and the git branch as
|
|
4
|
+
* *events*, not as plugin input, but an OTel `Resource` is fixed at provider
|
|
5
|
+
* construction.
|
|
6
|
+
*
|
|
7
|
+
* The OTel resource API accepts promise-valued attributes and exporters await
|
|
8
|
+
* them before the first export, so a deferred value is the supported way to
|
|
9
|
+
* bridge that gap. The timeout is not optional: a promise that never settles
|
|
10
|
+
* would block every export forever, so an attribute that has not arrived in
|
|
11
|
+
* time resolves to `undefined` and is dropped from the resource.
|
|
12
|
+
*/
|
|
13
|
+
export interface DeferredAttribute {
|
|
14
|
+
/** Hand this to `resourceFromAttributes`. */
|
|
15
|
+
readonly value: Promise<string | undefined>;
|
|
16
|
+
/** Settle it with the real value. Later calls are ignored. */
|
|
17
|
+
settle(value: string | undefined): void;
|
|
18
|
+
/** Give up and settle as absent. Idempotent. */
|
|
19
|
+
abandon(): void;
|
|
20
|
+
}
|
|
21
|
+
export declare const DEFAULT_DEFERRED_TIMEOUT_MS = 2e3;
|
|
22
|
+
export declare function deferredAttribute(timeoutMs?: number, schedule?: typeof setTimeout): DeferredAttribute;
|