| /** | |
| * Shared batch exporter for OTLP/HTTP observability modules. | |
| * | |
| * Signal modules use this exporter to buffer already-encoded telemetry and post | |
| * it to a configured OTLP endpoint. It owns the scoped transport loop, batching, | |
| * retry behavior, temporary disabling after repeated failures, and final flush | |
| * during shutdown. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| import { Clock } from "../../Clock.js"; | |
| import * as Context from "../../Context.js"; | |
| import * as Duration from "../../Duration.js"; | |
| import * as Effect from "../../Effect.js"; | |
| import * as Fiber from "../../Fiber.js"; | |
| import * as Num from "../../Number.js"; | |
| import * as Option from "../../Option.js"; | |
| import * as Schedule from "../../Schedule.js"; | |
| import * as Scope from "../../Scope.js"; | |
| import * as Headers from "../../unstable/http/Headers.js"; | |
| import * as HttpClient from "../../unstable/http/HttpClient.js"; | |
| import * as HttpClientError from "../../unstable/http/HttpClientError.js"; | |
| import * as HttpClientRequest from "../../unstable/http/HttpClientRequest.js"; | |
| const policy = /*#__PURE__*/Schedule.forever.pipe(Schedule.passthrough, /*#__PURE__*/Schedule.addDelay(error => { | |
| if (HttpClientError.isHttpClientError(error) && error.reason._tag === "StatusCodeError" && error.reason.response.status === 429) { | |
| const retryAfter = Option.fromUndefinedOr(error.reason.response.headers["retry-after"]).pipe(Option.flatMap(Num.parse), Option.getOrElse(() => 5)); | |
| return Effect.succeed(Duration.seconds(retryAfter)); | |
| } | |
| return Effect.succeed(Duration.seconds(1)); | |
| })); | |
| /** | |
| * Creates a scoped OTLP batch exporter. | |
| * | |
| * **Details** | |
| * | |
| * The exporter buffers pushed data, periodically posts encoded batches to the | |
| * configured URL, retries transient failures, temporarily disables exporting | |
| * after unhandled failures, and flushes during scope finalization up to | |
| * `shutdownTimeout`. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const make = /*#__PURE__*/Effect.fnUntraced(function* (options) { | |
| const services = yield* Effect.context(); | |
| const clock = Context.get(services, Clock); | |
| const scope = Context.get(services, Scope.Scope); | |
| const runFork = Effect.runForkWith(services); | |
| const exportInterval = Duration.max(Duration.fromInputUnsafe(options.exportInterval), Duration.zero); | |
| let disabledUntil = undefined; | |
| const client = HttpClient.filterStatusOk(Context.get(services, HttpClient.HttpClient)).pipe(HttpClient.transformResponse(Effect.provideService(HttpClient.TracerPropagationEnabled, false)), HttpClient.retryTransient({ | |
| schedule: policy, | |
| times: 3 | |
| })); | |
| let headers = Headers.fromRecordUnsafe({ | |
| "user-agent": `effect-opentelemetry-${options.label}/0.0.0` | |
| }); | |
| if (options.headers) { | |
| headers = Headers.merge(Headers.fromInput(options.headers), headers); | |
| } | |
| const request = HttpClientRequest.post(options.url, { | |
| headers | |
| }); | |
| let buffer = []; | |
| const runExport = Effect.suspend(() => { | |
| if (disabledUntil !== undefined && clock.currentTimeMillisUnsafe() < disabledUntil) { | |
| return Effect.void; | |
| } else if (disabledUntil !== undefined) { | |
| disabledUntil = undefined; | |
| } | |
| const items = buffer; | |
| if (options.maxBatchSize !== "disabled") { | |
| if (buffer.length === 0) { | |
| return Effect.void; | |
| } | |
| buffer = []; | |
| } | |
| return client.execute(HttpClientRequest.setBody(request, options.body(items))).pipe(Effect.asVoid, Effect.withTracerEnabled(false)); | |
| }).pipe(Effect.catchCause(cause => { | |
| if (disabledUntil !== undefined) return Effect.void; | |
| disabledUntil = clock.currentTimeMillisUnsafe() + 60_000; | |
| buffer = []; | |
| return Effect.logDebug("Disabling exporter for 60 seconds", cause); | |
| }), Effect.annotateLogs({ | |
| package: "@effect/opentelemetry", | |
| module: options.label | |
| })); | |
| yield* Scope.addFinalizer(scope, runExport.pipe(Effect.ignore, Effect.interruptible, Effect.timeoutOption(options.shutdownTimeout))); | |
| yield* Effect.sleep(exportInterval).pipe(Effect.andThen(runExport), Effect.forever, Effect.forkIn(scope)); | |
| return { | |
| push(data) { | |
| if (disabledUntil !== undefined) return; | |
| buffer.push(data); | |
| if (options.maxBatchSize !== "disabled" && buffer.length >= options.maxBatchSize) { | |
| Fiber.runIn(runFork(runExport), scope); | |
| } | |
| } | |
| }; | |
| }); | |
| //# sourceMappingURL=OtlpExporter.js.map |
Xet Storage Details
- Size:
- 4.31 kB
- Xet hash:
- 34525a9aa1f9728ab13b30611c3fca3d361328f8a6358b32b67487b5a3e99348
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.