brass-runtime 1.18.0 → 1.18.2

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.
Files changed (84) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/agent/cli/main.cjs +31 -31
  3. package/dist/agent/cli/main.js +3 -3
  4. package/dist/agent/cli/main.mjs +3 -3
  5. package/dist/agent/index.cjs +4 -4
  6. package/dist/agent/index.d.ts +1 -1
  7. package/dist/agent/index.js +3 -3
  8. package/dist/agent/index.mjs +3 -3
  9. package/dist/{chunk-PSEU65ND.js → chunk-2R3RVNS2.js} +6 -6
  10. package/dist/{chunk-ITZQ526U.mjs → chunk-3NKXUX4T.mjs} +2 -2
  11. package/dist/{chunk-JH4GI3DW.js → chunk-4PKBNG2H.js} +38 -18
  12. package/dist/{chunk-Z3PSSXP3.mjs → chunk-5RVHSBJ6.mjs} +292 -36
  13. package/dist/{chunk-QZ6QFJNM.mjs → chunk-5UBJT4RW.mjs} +4 -4
  14. package/dist/{chunk-7TXQJFZX.cjs → chunk-6STX4PS3.cjs} +13 -13
  15. package/dist/{chunk-VIFA4DPN.cjs → chunk-7FZUTJM3.cjs} +508 -252
  16. package/dist/{chunk-4YQHPIWJ.js → chunk-A6EG5WRL.js} +3 -3
  17. package/dist/{chunk-XSAHV5HQ.js → chunk-APQBU7TM.js} +264 -133
  18. package/dist/{chunk-RREBJX2S.mjs → chunk-AQQQFNYD.mjs} +38 -18
  19. package/dist/{chunk-AADFFVYS.js → chunk-B2VXVNIS.js} +1 -1
  20. package/dist/{chunk-R6WDSZA6.mjs → chunk-BLXBZ6RE.mjs} +1 -1
  21. package/dist/{chunk-ITG6I7ZS.js → chunk-C3CWI42G.js} +1 -1
  22. package/dist/{chunk-LXBU5E77.cjs → chunk-DV644N7P.cjs} +85 -85
  23. package/dist/{chunk-G5JTCFMI.mjs → chunk-EKLEDIVJ.mjs} +2 -2
  24. package/dist/{chunk-IBRHSH5H.js → chunk-EXBGIC66.js} +1 -1
  25. package/dist/{chunk-W6WR37HN.js → chunk-FC5N5QHJ.js} +2 -2
  26. package/dist/{chunk-6MLAZPBL.mjs → chunk-FNWOH2T2.js} +18 -6
  27. package/dist/{chunk-AJMKZXRB.cjs → chunk-FYWWU3Z7.cjs} +2 -2
  28. package/dist/{chunk-IFRBVMWJ.cjs → chunk-GOEO763K.cjs} +21 -21
  29. package/dist/{chunk-S4HHFUYP.js → chunk-GXOIUBKE.js} +2 -2
  30. package/dist/{chunk-BG5RNEA2.js → chunk-H4ZRUQZL.js} +4 -4
  31. package/dist/{chunk-OI4ESUMC.mjs → chunk-HW2CLRJ3.mjs} +6 -6
  32. package/dist/{chunk-3PHU7FWS.js → chunk-JWFOWPMB.js} +163 -155
  33. package/dist/{chunk-OT2TESZU.mjs → chunk-KAPZHDO4.mjs} +1 -1
  34. package/dist/{chunk-ELLF55ER.mjs → chunk-KDXNWGPB.mjs} +1 -1
  35. package/dist/{chunk-UUMKZJRJ.cjs → chunk-KPOL2YEO.cjs} +18 -6
  36. package/dist/{chunk-2SLT3X6G.cjs → chunk-MA74OYCI.cjs} +6 -6
  37. package/dist/{chunk-2QNREG6K.mjs → chunk-MUMBUXU6.mjs} +264 -133
  38. package/dist/{chunk-YTX2JYYP.cjs → chunk-NQW3YUFN.cjs} +18 -18
  39. package/dist/{chunk-3PFZGP23.cjs → chunk-OO7BGCC3.cjs} +54 -34
  40. package/dist/{chunk-QCOLAHU3.mjs → chunk-OX6MF7SZ.mjs} +163 -155
  41. package/dist/{chunk-KHACHFBQ.cjs → chunk-QBVS3UYN.cjs} +245 -237
  42. package/dist/{chunk-H5GYX7RZ.js → chunk-RZGB3DXR.js} +292 -36
  43. package/dist/{chunk-KRYP6CAE.mjs → chunk-URVS2OE2.mjs} +3 -3
  44. package/dist/{chunk-HCJ4S3YB.js → chunk-UZQ3BB6W.mjs} +18 -6
  45. package/dist/{chunk-N6QNSTWD.cjs → chunk-YQWZ7FZX.cjs} +5 -5
  46. package/dist/{chunk-5XADBMSU.cjs → chunk-Z2YIDHRI.cjs} +5 -5
  47. package/dist/{chunk-SSQJKDN3.cjs → chunk-ZDZNV6NA.cjs} +286 -155
  48. package/dist/core/index.cjs +14 -8
  49. package/dist/core/index.d.ts +6 -6
  50. package/dist/core/index.js +13 -7
  51. package/dist/core/index.mjs +13 -7
  52. package/dist/{defaultClient-DhpCQW9m.d.ts → defaultClient-Cid0JoUR.d.ts} +29 -4
  53. package/dist/{effect-CtUDl5M5.d.ts → effect-DnGUuhw6.d.ts} +22 -1
  54. package/dist/http/index.cjs +58 -54
  55. package/dist/http/index.d.ts +8 -8
  56. package/dist/http/index.js +11 -7
  57. package/dist/http/index.mjs +11 -7
  58. package/dist/http/testing.cjs +9 -9
  59. package/dist/http/testing.d.ts +4 -4
  60. package/dist/http/testing.js +5 -5
  61. package/dist/http/testing.mjs +5 -5
  62. package/dist/index.cjs +92 -86
  63. package/dist/index.d.ts +7 -7
  64. package/dist/index.js +14 -8
  65. package/dist/index.mjs +14 -8
  66. package/dist/{layer-BalPI6cN.d.ts → layer-D2LFcBVx.d.ts} +1 -1
  67. package/dist/observability/index.cjs +10 -10
  68. package/dist/observability/index.d.ts +7 -7
  69. package/dist/observability/index.js +9 -9
  70. package/dist/observability/index.mjs +9 -9
  71. package/dist/perf/cli.cjs +26 -26
  72. package/dist/perf/cli.js +11 -11
  73. package/dist/perf/cli.mjs +11 -11
  74. package/dist/perf/index.cjs +13 -13
  75. package/dist/perf/index.js +11 -11
  76. package/dist/perf/index.mjs +11 -11
  77. package/dist/schema/index.cjs +2 -2
  78. package/dist/schema/index.js +1 -1
  79. package/dist/schema/index.mjs +1 -1
  80. package/dist/{server-C1zVmqE6.d.ts → server-Bf1zNYZk.d.ts} +4 -4
  81. package/dist/{stream-Bb4FTejt.d.ts → stream-I7bkvF7a.d.ts} +1 -1
  82. package/dist/{tracer-DzfuE6um.d.ts → tracer-DF83nLn6.d.ts} +2 -2
  83. package/dist/{tracing-BABA5arE.d.ts → tracing-CWV4gT0u.d.ts} +1 -1
  84. package/package.json +3 -2
@@ -6,7 +6,7 @@ var _chunkSA6HUJVIcjs = require('./chunk-SA6HUJVI.cjs');
6
6
 
7
7
 
8
8
 
9
- var _chunkSSQJKDN3cjs = require('./chunk-SSQJKDN3.cjs');
9
+ var _chunkZDZNV6NAcjs = require('./chunk-ZDZNV6NA.cjs');
10
10
 
11
11
 
12
12
 
@@ -99,8 +99,8 @@ function makeMergePull(onLeft, onRight, flip, mergePullId) {
99
99
  const onLeftHandler = streamToRaceWithHandler("L", onLeft, onRight, flip, id);
100
100
  const onRightHandler = streamToRaceWithHandler("R", onLeft, onRight, flip, id);
101
101
  return _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (_env, cb) => {
102
- const runtime = _chunkSSQJKDN3cjs.unsafeGetCurrentRuntime.call(void 0, );
103
- const scope = new (0, _chunkSSQJKDN3cjs.Scope)(runtime);
102
+ const runtime = _chunkZDZNV6NAcjs.unsafeGetCurrentRuntime.call(void 0, );
103
+ const scope = new (0, _chunkZDZNV6NAcjs.Scope)(runtime);
104
104
  const handler = _chunkSA6HUJVIcjs.raceWith.call(void 0,
105
105
  uncons(onLeft),
106
106
  uncons(onRight),
@@ -160,9 +160,9 @@ function uncons(self) {
160
160
  return makeMergePull(self.left, self.right, self.flip, 0);
161
161
  case "Scoped":
162
162
  return _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (env, cb) => {
163
- const runtime = _chunkSSQJKDN3cjs.unsafeGetCurrentRuntime.call(void 0, );
164
- const scope = new (0, _chunkSSQJKDN3cjs.Scope)(runtime);
165
- const fiber = _chunkSSQJKDN3cjs.getCurrentFiber.call(void 0, );
163
+ const runtime = _chunkZDZNV6NAcjs.unsafeGetCurrentRuntime.call(void 0, );
164
+ const scope = new (0, _chunkZDZNV6NAcjs.Scope)(runtime);
165
+ const fiber = _chunkZDZNV6NAcjs.getCurrentFiber.call(void 0, );
166
166
  _optionalChain([fiber, 'optionalAccess', _2 => _2.addFinalizer, 'call', _3 => _3((exit) => {
167
167
  try {
168
168
  scope.close(exit);
@@ -183,7 +183,7 @@ function uncons(self) {
183
183
  const wrap = (s) => fromPull(
184
184
  _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (env2, cb2) => {
185
185
  const pull = uncons(s);
186
- _chunkSSQJKDN3cjs.unsafeRunFoldWithEnv.call(void 0,
186
+ _chunkZDZNV6NAcjs.unsafeRunFoldWithEnv.call(void 0,
187
187
  pull,
188
188
  env2,
189
189
  (cause) => {
@@ -206,14 +206,14 @@ function uncons(self) {
206
206
  }
207
207
  scope.addFinalizer((exit) => self.release(exit));
208
208
  const inner = ex.value;
209
- _chunkSSQJKDN3cjs.unsafeGetCurrentRuntime.call(void 0, ).fork(uncons(wrap(inner))).join(cb);
209
+ _chunkZDZNV6NAcjs.unsafeGetCurrentRuntime.call(void 0, ).fork(uncons(wrap(inner))).join(cb);
210
210
  });
211
211
  });
212
212
  case "Managed":
213
213
  return _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (env, cb) => {
214
- const runtime = _chunkSSQJKDN3cjs.unsafeGetCurrentRuntime.call(void 0, );
215
- const scope = new (0, _chunkSSQJKDN3cjs.Scope)(runtime);
216
- _optionalChain([_chunkSSQJKDN3cjs.getCurrentFiber.call(void 0, ), 'optionalAccess', _4 => _4.addFinalizer, 'call', _5 => _5((exit) => {
214
+ const runtime = _chunkZDZNV6NAcjs.unsafeGetCurrentRuntime.call(void 0, );
215
+ const scope = new (0, _chunkZDZNV6NAcjs.Scope)(runtime);
216
+ _optionalChain([_chunkZDZNV6NAcjs.getCurrentFiber.call(void 0, ), 'optionalAccess', _4 => _4.addFinalizer, 'call', _5 => _5((exit) => {
217
217
  try {
218
218
  scope.close(exit);
219
219
  } catch (e4) {
@@ -241,7 +241,7 @@ function uncons(self) {
241
241
  scope.addFinalizer((exit) => release(exit));
242
242
  const wrap = (s) => fromPull(
243
243
  _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (env2, cb2) => {
244
- _chunkSSQJKDN3cjs.unsafeRunFoldWithEnv.call(void 0,
244
+ _chunkZDZNV6NAcjs.unsafeRunFoldWithEnv.call(void 0,
245
245
  uncons(s),
246
246
  env2,
247
247
  (cause) => {
@@ -255,7 +255,7 @@ function uncons(self) {
255
255
  );
256
256
  })
257
257
  );
258
- _chunkSSQJKDN3cjs.unsafeGetCurrentRuntime.call(void 0, ).fork(uncons(wrap(inner))).join(cb);
258
+ _chunkZDZNV6NAcjs.unsafeGetCurrentRuntime.call(void 0, ).fork(uncons(wrap(inner))).join(cb);
259
259
  });
260
260
  });
261
261
  }
@@ -412,31 +412,49 @@ function drainStreamSyncFull(stream) {
412
412
  }
413
413
  }
414
414
  }
415
+ var ABORTED_ERROR = (() => {
416
+ if (typeof DOMException === "function") {
417
+ try {
418
+ return new DOMException("aborted", "AbortError");
419
+ } catch (e5) {
420
+ }
421
+ }
422
+ const e = new Error("aborted");
423
+ e.name = "AbortError";
424
+ return e;
425
+ })();
415
426
  function readerStream(reader, normalizeError, signal) {
427
+ const noopSignal = globalThis.__brassNoopSignal;
428
+ const needsSignalListener = signal !== void 0 && signal !== noopSignal;
416
429
  const pull = _chunkMVGUEJ5Zcjs.asyncEffect.call(void 0, (_, cb) => {
417
430
  let done = false;
418
- const cleanup = () => _optionalChain([signal, 'optionalAccess', _6 => _6.removeEventListener, 'call', _7 => _7("abort", abort)]);
431
+ let abortFn;
419
432
  const finish = (exit) => {
420
433
  if (done) return;
421
434
  done = true;
422
- cleanup();
435
+ if (needsSignalListener && abortFn) signal.removeEventListener("abort", abortFn);
423
436
  cb(exit);
424
437
  };
425
- const abort = () => {
426
- try {
427
- reader.cancel();
428
- } catch (e5) {
438
+ if (needsSignalListener) {
439
+ if (signal.aborted) {
440
+ try {
441
+ reader.cancel();
442
+ } catch (e6) {
443
+ }
444
+ finish({ _tag: "Failure", cause: { _tag: "Fail", error: _chunkMVGUEJ5Zcjs.some.call(void 0, normalizeError(ABORTED_ERROR)) } });
445
+ return;
429
446
  }
430
- const error = typeof DOMException === "function" ? new DOMException("aborted", "AbortError") : new Error("aborted");
431
- finish({ _tag: "Failure", cause: { _tag: "Fail", error: _chunkMVGUEJ5Zcjs.some.call(void 0, normalizeError(error)) } });
432
- };
433
- if (_optionalChain([signal, 'optionalAccess', _8 => _8.aborted])) {
434
- abort();
435
- return;
447
+ abortFn = () => {
448
+ try {
449
+ reader.cancel();
450
+ } catch (e7) {
451
+ }
452
+ finish({ _tag: "Failure", cause: { _tag: "Fail", error: _chunkMVGUEJ5Zcjs.some.call(void 0, normalizeError(ABORTED_ERROR)) } });
453
+ };
454
+ signal.addEventListener("abort", abortFn, { once: true });
436
455
  }
437
- _optionalChain([signal, 'optionalAccess', _9 => _9.addEventListener, 'call', _10 => _10("abort", abort, { once: true })]);
438
- reader.read().then(({ done: done2, value }) => {
439
- if (done2) {
456
+ reader.read().then(({ done: readDone, value }) => {
457
+ if (readDone) {
440
458
  finish({ _tag: "Failure", cause: { _tag: "Fail", error: _chunkMVGUEJ5Zcjs.none } });
441
459
  return;
442
460
  }
@@ -444,14 +462,16 @@ function readerStream(reader, normalizeError, signal) {
444
462
  _tag: "Success",
445
463
  value: [value, fromPull(pull)]
446
464
  });
447
- }).catch((e) => {
465
+ }, (e) => {
448
466
  finish({ _tag: "Failure", cause: { _tag: "Fail", error: _chunkMVGUEJ5Zcjs.some.call(void 0, normalizeError(e)) } });
449
467
  });
450
468
  return () => {
451
- cleanup();
469
+ if (done) return;
470
+ done = true;
471
+ if (needsSignalListener && abortFn) signal.removeEventListener("abort", abortFn);
452
472
  try {
453
473
  reader.cancel();
454
- } catch (e6) {
474
+ } catch (e8) {
455
475
  }
456
476
  };
457
477
  });
@@ -469,10 +489,10 @@ function streamFromReadableStream(body, normalizeError, options = {}) {
469
489
  // release: se corre en fin / error / interrupción
470
490
  () => _chunkMVGUEJ5Zcjs.asyncSync.call(void 0, () => {
471
491
  try {
472
- _optionalChain([reader, 'optionalAccess', _11 => _11.cancel, 'call', _12 => _12()]);
473
- } catch (e7) {
492
+ _optionalChain([reader, 'optionalAccess', _6 => _6.cancel, 'call', _7 => _7()]);
493
+ } catch (e9) {
474
494
  } finally {
475
- _optionalChain([options, 'access', _13 => _13.onRelease, 'optionalCall', _14 => _14()]);
495
+ _optionalChain([options, 'access', _8 => _8.onRelease, 'optionalCall', _9 => _9()]);
476
496
  }
477
497
  })
478
498
  );
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  RuntimeService
3
- } from "./chunk-ITZQ526U.mjs";
3
+ } from "./chunk-3NKXUX4T.mjs";
4
4
  import {
5
5
  exemplarFromTraceContext,
6
6
  injectTraceContext,
@@ -13,33 +13,29 @@ import {
13
13
  spanEvent,
14
14
  validateHttpObservabilityOptions,
15
15
  withSpan
16
- } from "./chunk-KRYP6CAE.mjs";
16
+ } from "./chunk-URVS2OE2.mjs";
17
17
  import {
18
18
  HttpClientService,
19
19
  getHttpRequestPolicy,
20
20
  httpErrorStatus,
21
21
  isRetryableHttpError,
22
22
  makeDefaultHttpClient
23
- } from "./chunk-Z3PSSXP3.mjs";
23
+ } from "./chunk-5RVHSBJ6.mjs";
24
24
  import {
25
25
  registerHttpEffect
26
26
  } from "./chunk-MOO4L7F4.mjs";
27
27
  import {
28
28
  layerEffect,
29
29
  makeServiceTag
30
- } from "./chunk-ELLF55ER.mjs";
30
+ } from "./chunk-KDXNWGPB.mjs";
31
31
  import {
32
32
  Runtime,
33
33
  fromPromiseAbortable,
34
34
  getCurrentFiber
35
- } from "./chunk-2QNREG6K.mjs";
35
+ } from "./chunk-MUMBUXU6.mjs";
36
36
  import {
37
37
  Cause,
38
38
  asyncEffect,
39
- asyncFail,
40
- asyncFlatMap,
41
- asyncFold,
42
- asyncSucceed,
43
39
  asyncSync
44
40
  } from "./chunk-36I3M4UC.mjs";
45
41
 
@@ -134,43 +130,147 @@ function withHttpObservability(options) {
134
130
  return withLeanHttpSampledSpanObservability(next, resolved, metricCache);
135
131
  }
136
132
  return (req) => {
137
- const run = asyncFlatMap(
138
- beginHttpObservation(req, resolved, metricCache),
139
- (state) => asyncFlatMap(
140
- logHttpRequest(req, resolved),
141
- () => asyncFlatMap(
142
- prepareHttpRequest(req, resolved),
143
- (wireReq) => asyncFold(
144
- next(wireReq),
145
- (error) => {
146
- const finish = state.finishWithError(error);
147
- const adaptiveLimiterAttrs = observeAdaptiveLimiter(wireReq, next, resolved);
148
- const traceEvent = !shouldEmitHttpSpanEvents(resolved) ? asyncSucceed(void 0) : spanEvent("http.client.error", {
149
- ...finish.spanAttributes,
150
- ...adaptiveLimiterAttrs,
151
- "error.type": error._tag
152
- });
153
- return asyncFlatMap(
154
- traceEvent,
155
- () => asyncFlatMap(logHttpError(req, error, finish, resolved), () => asyncFail(error))
156
- );
157
- },
158
- (res) => {
159
- const finish = state.finishWithResponse(res);
160
- const adaptiveLimiterAttrs = observeAdaptiveLimiter(wireReq, next, resolved);
161
- const traceEvent = !shouldEmitHttpSpanEvents(resolved) ? asyncSucceed(void 0) : spanEvent("http.client.response", {
162
- ...finish.spanAttributes,
163
- ...adaptiveLimiterAttrs
164
- });
165
- return asyncFlatMap(
166
- traceEvent,
167
- () => asyncFlatMap(logHttpResponse(req, res, finish, resolved), () => asyncSucceed(res))
168
- );
169
- }
170
- )
171
- )
172
- )
173
- );
133
+ const run = asyncEffect((env, cb) => {
134
+ const startedAt = resolved.clock();
135
+ const baseLabels = getCachedBaseLabels(req, resolved, metricCache);
136
+ const inFlight = resolved.metrics ? getCachedMetric(
137
+ metricCache,
138
+ metricCache.inFlightGauges,
139
+ metricCacheKey("brass_http_client_in_flight", baseLabels),
140
+ () => resolved.metrics.gauge("brass_http_client_in_flight", baseLabels)
141
+ ) : void 0;
142
+ inFlight?.increment();
143
+ let finished = false;
144
+ let cancelInner;
145
+ const completeFinish = (outcome, status, extra) => {
146
+ const durationMs = Math.max(0, resolved.clock() - startedAt);
147
+ const labels = requestFinishLabelsFromBase(baseLabels, outcome, status);
148
+ if (!finished) {
149
+ finished = true;
150
+ if (inFlight && inFlight.value() > 0) inFlight.decrement();
151
+ if (resolved.metrics) {
152
+ getCachedMetric(
153
+ metricCache,
154
+ metricCache.requestCounters,
155
+ metricCacheKey("brass_http_client_requests_total", labels),
156
+ () => resolved.metrics.counter("brass_http_client_requests_total", labels)
157
+ ).increment();
158
+ getCachedMetric(
159
+ metricCache,
160
+ metricCache.durationHistograms,
161
+ metricCacheKey("brass_http_client_duration_ms", labels),
162
+ () => resolved.metrics.histogram(
163
+ "brass_http_client_duration_ms",
164
+ [...resolved.durationBuckets ?? DEFAULT_DURATION_BUCKETS],
165
+ labels
166
+ )
167
+ ).observe(
168
+ durationMs,
169
+ resolved.spans === false ? void 0 : currentTraceExemplar(durationMs, startedAt + durationMs)
170
+ );
171
+ }
172
+ }
173
+ return {
174
+ durationMs,
175
+ outcome,
176
+ labels,
177
+ spanAttributes: resolved.spans === false ? EMPTY_SPAN_ATTRIBUTES : {
178
+ "http.duration_ms": durationMs,
179
+ "http.outcome": outcome,
180
+ ...status ? { "http.status_code": Number(status) } : {},
181
+ ...status ? { "http.response.status_code": Number(status) } : {},
182
+ ...extra
183
+ }
184
+ };
185
+ };
186
+ const fiber = getCurrentFiber();
187
+ fiber?.addFinalizer?.(() => {
188
+ completeFinish("abort", void 0, { "http.cancelled": true });
189
+ });
190
+ const reqLogLevel = resolved.logs === false ? false : resolved.logs.requestLevel ?? false;
191
+ if (reqLogLevel) {
192
+ const logEff = logEffect(reqLogLevel, "http.client.request", requestLogFields(req, resolved));
193
+ registerHttpEffect(logEff, env, () => void 0);
194
+ }
195
+ const wireReq = resolved.injectTraceHeaders ? injectCurrentTraceContext(req) : req;
196
+ const onSuccess = (res) => {
197
+ const finish = completeFinish(httpStatusOutcome(res.status), String(res.status), {});
198
+ const adaptiveAttrs = observeAdaptiveLimiter(wireReq, next, resolved);
199
+ if (shouldEmitHttpSpanEvents(resolved)) {
200
+ const ev = spanEvent("http.client.response", {
201
+ ...finish.spanAttributes,
202
+ ...adaptiveAttrs
203
+ });
204
+ registerHttpEffect(ev, env, () => void 0);
205
+ }
206
+ const respLevel = resolved.logs === false ? false : (resolved.logs.responseLevel ?? false) || (finish.outcome === "error" ? resolved.logs.errorLevel ?? "warn" : false);
207
+ if (respLevel) {
208
+ const logEff = logEffect(respLevel, "http.client.response", {
209
+ ...requestLogFields(req, resolved),
210
+ status: res.status,
211
+ statusText: res.statusText,
212
+ outcome: finish.outcome,
213
+ durationMs: finish.durationMs
214
+ });
215
+ registerHttpEffect(logEff, env, () => void 0);
216
+ }
217
+ cb({ _tag: "Success", value: res });
218
+ };
219
+ const onError = (error) => {
220
+ const status = httpErrorStatus(error);
221
+ const finish = completeFinish(
222
+ httpErrorOutcome(error),
223
+ status !== void 0 ? String(status) : void 0,
224
+ {
225
+ "error.type": error._tag,
226
+ "http.retryable": isRetryableHttpError(error)
227
+ }
228
+ );
229
+ const adaptiveAttrs = observeAdaptiveLimiter(wireReq, next, resolved);
230
+ if (shouldEmitHttpSpanEvents(resolved)) {
231
+ const ev = spanEvent("http.client.error", {
232
+ ...finish.spanAttributes,
233
+ ...adaptiveAttrs,
234
+ "error.type": error._tag
235
+ });
236
+ registerHttpEffect(ev, env, () => void 0);
237
+ }
238
+ const errLevel = resolved.logs === false ? false : resolved.logs.errorLevel ?? "error";
239
+ if (errLevel) {
240
+ const statusText = httpErrorStatusText(error);
241
+ const logEff = logEffect(errLevel, "http.client.error", {
242
+ ...requestLogFields(req, resolved),
243
+ outcome: finish.outcome,
244
+ durationMs: finish.durationMs,
245
+ ...status !== void 0 ? { status } : {},
246
+ ...statusText ? { statusText } : {},
247
+ retryable: isRetryableHttpError(error),
248
+ errorTag: error._tag,
249
+ message: httpErrorMessage(error)
250
+ });
251
+ registerHttpEffect(logEff, env, () => void 0);
252
+ }
253
+ cb({ _tag: "Failure", cause: Cause.fail(error) });
254
+ };
255
+ try {
256
+ cancelInner = registerHttpEffect(next(wireReq), env, (exit) => {
257
+ cancelInner = void 0;
258
+ if (exit._tag === "Success") onSuccess(exit.value);
259
+ else {
260
+ const failure = Cause.firstFailure(exit.cause);
261
+ if (failure._tag === "Some") onError(failure.value);
262
+ else cb(exit);
263
+ }
264
+ });
265
+ } catch (error) {
266
+ cb({ _tag: "Failure", cause: Cause.die(error) });
267
+ }
268
+ return () => {
269
+ const cancel = cancelInner;
270
+ cancelInner = void 0;
271
+ cancel?.();
272
+ };
273
+ });
174
274
  if (resolved.spans === false) return run;
175
275
  return withSpan(spanName(req, resolved.spans), run, spanStartAttributes(req, resolved));
176
276
  };
@@ -191,7 +291,7 @@ function canUseLeanHttpSampledSpanPath(options, adaptiveLimiter) {
191
291
  function withLeanHttpSampledSpanObservability(next, options, metricCache) {
192
292
  return (req) => asyncEffect((env, cb) => {
193
293
  const startedAt = options.clock();
194
- const baseLabels = requestBaseLabels(req, options);
294
+ const baseLabels = getCachedBaseLabels(req, options, metricCache);
195
295
  const handles = beginLeanHttpMetricsObservation(baseLabels, options, metricCache);
196
296
  const span = startLeanHttpSpan(req, options);
197
297
  let finished = false;
@@ -256,7 +356,7 @@ function withLeanHttpSampledSpanObservability(next, options, metricCache) {
256
356
  function withLeanHttpMetricsObservability(next, options, metricCache) {
257
357
  return (req) => asyncEffect((env, cb) => {
258
358
  const startedAt = options.clock();
259
- const baseLabels = requestBaseLabels(req, options);
359
+ const baseLabels = getCachedBaseLabels(req, options, metricCache);
260
360
  const handles = beginLeanHttpMetricsObservation(baseLabels, options, metricCache);
261
361
  let finished = false;
262
362
  let cancelInner;
@@ -486,9 +586,23 @@ function makeHttpMetricCache() {
486
586
  leanEntries: /* @__PURE__ */ new Map(),
487
587
  inFlightGauges: /* @__PURE__ */ new Map(),
488
588
  requestCounters: /* @__PURE__ */ new Map(),
489
- durationHistograms: /* @__PURE__ */ new Map()
589
+ durationHistograms: /* @__PURE__ */ new Map(),
590
+ baseLabelsCache: /* @__PURE__ */ new Map()
490
591
  };
491
592
  }
593
+ function getCachedBaseLabels(req, options, cache) {
594
+ if (cache.disabled) return requestBaseLabels(req, options);
595
+ const route = requestRoute(req, options);
596
+ const host = options.includeHostLabel ? requestHost(req) : void 0;
597
+ const policy = getHttpRequestPolicy(req);
598
+ const preset = typeof policy === "string" ? policy : policy?.preset;
599
+ const key = `${req.method}|${host ?? ""}|${route ?? ""}|${preset ?? ""}`;
600
+ const existing = cache.baseLabelsCache.get(key);
601
+ if (existing) return existing;
602
+ const fresh = requestBaseLabels(req, options);
603
+ cache.baseLabelsCache.set(key, fresh);
604
+ return fresh;
605
+ }
492
606
  function attachMetricCache(metrics, cache) {
493
607
  if (!metrics) return;
494
608
  const existing = metricResetRegistry.get(metrics);
@@ -536,112 +650,6 @@ function metricCacheKey(name, labels) {
536
650
  }
537
651
  return key;
538
652
  }
539
- function beginHttpObservation(req, options, metricCache) {
540
- return asyncSync(() => {
541
- const startedAt = options.clock();
542
- let finished = false;
543
- const baseLabels = requestBaseLabels(req, options);
544
- const inFlight = options.metrics ? getCachedMetric(
545
- metricCache,
546
- metricCache.inFlightGauges,
547
- metricCacheKey("brass_http_client_in_flight", baseLabels),
548
- () => options.metrics.gauge("brass_http_client_in_flight", baseLabels)
549
- ) : void 0;
550
- inFlight?.increment();
551
- const finish = (outcome, status, extra = {}) => {
552
- const durationMs = Math.max(0, options.clock() - startedAt);
553
- const labels = requestFinishLabelsFromBase(baseLabels, outcome, status);
554
- if (!finished) {
555
- finished = true;
556
- if (inFlight && inFlight.value() > 0) inFlight.decrement();
557
- if (options.metrics) {
558
- getCachedMetric(
559
- metricCache,
560
- metricCache.requestCounters,
561
- metricCacheKey("brass_http_client_requests_total", labels),
562
- () => options.metrics.counter("brass_http_client_requests_total", labels)
563
- ).increment();
564
- getCachedMetric(
565
- metricCache,
566
- metricCache.durationHistograms,
567
- metricCacheKey("brass_http_client_duration_ms", labels),
568
- () => options.metrics.histogram(
569
- "brass_http_client_duration_ms",
570
- [...options.durationBuckets ?? DEFAULT_DURATION_BUCKETS],
571
- labels
572
- )
573
- ).observe(
574
- durationMs,
575
- options.spans === false ? void 0 : currentTraceExemplar(durationMs, startedAt + durationMs)
576
- );
577
- }
578
- }
579
- return {
580
- durationMs,
581
- outcome,
582
- labels,
583
- spanAttributes: options.spans === false ? EMPTY_SPAN_ATTRIBUTES : {
584
- "http.duration_ms": durationMs,
585
- "http.outcome": outcome,
586
- ...status ? { "http.status_code": Number(status) } : {},
587
- ...status ? { "http.response.status_code": Number(status) } : {},
588
- ...extra
589
- }
590
- };
591
- };
592
- const fiber = getCurrentFiber();
593
- fiber?.addFinalizer?.(() => {
594
- finish("abort", void 0, { "http.cancelled": true });
595
- });
596
- return {
597
- finishWithResponse: (res) => finish(httpStatusOutcome(res.status), String(res.status)),
598
- finishWithError: (error) => {
599
- const status = httpErrorStatus(error);
600
- return finish(httpErrorOutcome(error), status !== void 0 ? String(status) : void 0, {
601
- "error.type": error._tag,
602
- "http.retryable": isRetryableHttpError(error)
603
- });
604
- }
605
- };
606
- });
607
- }
608
- function prepareHttpRequest(req, options) {
609
- if (!options.injectTraceHeaders) return asyncSucceed(req);
610
- return asyncSync(() => injectCurrentTraceContext(req));
611
- }
612
- function logHttpRequest(req, options) {
613
- const level = options.logs === false ? false : options.logs.requestLevel ?? false;
614
- if (!level) return asyncSucceed(void 0);
615
- return logEffect(level, "http.client.request", requestLogFields(req, options));
616
- }
617
- function logHttpResponse(req, res, finish, options) {
618
- const configured = options.logs === false ? false : options.logs.responseLevel ?? false;
619
- const level = configured || (finish.outcome === "error" ? options.logs !== false ? options.logs.errorLevel ?? "warn" : false : false);
620
- if (!level) return asyncSucceed(void 0);
621
- return logEffect(level, "http.client.response", {
622
- ...requestLogFields(req, options),
623
- status: res.status,
624
- statusText: res.statusText,
625
- outcome: finish.outcome,
626
- durationMs: finish.durationMs
627
- });
628
- }
629
- function logHttpError(req, error, finish, options) {
630
- const level = options.logs === false ? false : options.logs.errorLevel ?? "error";
631
- if (!level) return asyncSucceed(void 0);
632
- const status = httpErrorStatus(error);
633
- const statusText = httpErrorStatusText(error);
634
- return logEffect(level, "http.client.error", {
635
- ...requestLogFields(req, options),
636
- outcome: finish.outcome,
637
- durationMs: finish.durationMs,
638
- ...status !== void 0 ? { status } : {},
639
- ...statusText ? { statusText } : {},
640
- retryable: isRetryableHttpError(error),
641
- errorTag: error._tag,
642
- message: httpErrorMessage(error)
643
- });
644
- }
645
653
  function resolveHttpObservabilityOptions(options) {
646
654
  const maybeObservability = isObservabilityInstance(options) ? options : void 0;
647
655
  const raw = maybeObservability ? { metrics: maybeObservability.metrics } : options;