@krak-stack/registry 0.1.34 → 0.1.35

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.
@@ -1,5 +1,5 @@
1
1
  // ../../src/services/opentelemetry/api.ts
2
- import { Config, Effect, Layer } from "effect";
2
+ import { Config, Effect, Layer, Schema } from "effect";
3
3
  import {
4
4
  FetchHttpClient,
5
5
  HttpClient,
@@ -17,6 +17,7 @@ var otlpProxyPaths = [
17
17
  "/api/otel/v1/metrics",
18
18
  "/api/otel/v1/logs"
19
19
  ];
20
+ var exporterConfig = (signal) => Config.schema(Config.Array(Schema.String), `OTEL_${signal}_EXPORTER`).pipe(Config.map((exporters) => exporters.map((exporter) => exporter.toLowerCase().trim())), Config.withDefault([]));
20
21
  var proxyOtlp = (baseUrl, signal) => Effect.gen(function* () {
21
22
  const incoming = yield* HttpServerRequest.HttpServerRequest;
22
23
  const client = yield* HttpClient.HttpClient;
@@ -33,7 +34,15 @@ var proxyOtlp = (baseUrl, signal) => Effect.gen(function* () {
33
34
  }
34
35
  });
35
36
  }).pipe(Effect.withTracerEnabled(false), HttpMiddleware.withLoggerDisabled, Effect.catch((error) => Effect.logError("Failed to proxy browser telemetry", error).pipe(Effect.as(HttpServerResponse.empty({ status: 502 })))), Effect.provide(FetchHttpClient.layer));
36
- var otlpProxyLayer = Layer.unwrap(Effect.map(Config.url("OTEL_COLLECTOR_PROXY_URL").pipe(Config.withDefault(new URL("http://localhost:4318"))), (baseUrl) => Layer.mergeAll(HttpRouter.add("POST", otlpProxyPaths[0], proxyOtlp(baseUrl, "traces")), HttpRouter.add("POST", otlpProxyPaths[1], proxyOtlp(baseUrl, "metrics")), HttpRouter.add("POST", otlpProxyPaths[2], proxyOtlp(baseUrl, "logs")))));
37
+ var otlpProxyLayer = Layer.unwrap(Effect.gen(function* () {
38
+ const baseUrl = yield* Config.url("OTEL_EXPORTER_OTLP_ENDPOINT");
39
+ const exporters = yield* Config.all({
40
+ logs: exporterConfig("LOGS"),
41
+ metrics: exporterConfig("METRICS"),
42
+ traces: exporterConfig("TRACES")
43
+ });
44
+ return Layer.mergeAll(exporters.traces.includes("otlp") ? HttpRouter.add("POST", otlpProxyPaths[0], proxyOtlp(baseUrl, "traces")) : Layer.empty, exporters.metrics.includes("otlp") ? HttpRouter.add("POST", otlpProxyPaths[1], proxyOtlp(baseUrl, "metrics")) : Layer.empty, exporters.logs.includes("otlp") ? HttpRouter.add("POST", otlpProxyPaths[2], proxyOtlp(baseUrl, "logs")) : Layer.empty);
45
+ }));
37
46
  var serverServices = HttpServer.layerServices.pipe(Layer.provideMerge(HttpMiddleware.layerTracerDisabledForUrls(otlpProxyPaths)));
38
47
 
39
48
  class HttpApiOtlp {
@@ -1,10 +1,18 @@
1
1
  import { Layer } from "effect";
2
- import { Otlp } from "effect/unstable/observability";
2
+ import { type Otlp, OtlpExporter, OtlpLogger, OtlpMetrics, OtlpTracer } from "effect/unstable/observability";
3
+ type OtlpOptions = Parameters<typeof Otlp.layerJson>[0];
4
+ type SignalOptions<Options> = Omit<Options, "url" | "resource" | "headers">;
5
+ export interface BrowserOtlpOptions {
6
+ readonly serviceName: string;
7
+ readonly serviceVersion?: string;
8
+ readonly attributes?: NonNullable<OtlpOptions["resource"]>["attributes"];
9
+ readonly baseUrl?: string;
10
+ readonly headers?: OtlpOptions["headers"];
11
+ readonly traces?: false | SignalOptions<Parameters<typeof OtlpTracer.layer>[0]>;
12
+ readonly metrics?: false | SignalOptions<Parameters<typeof OtlpMetrics.layer>[0]>;
13
+ readonly logs?: false | SignalOptions<Parameters<typeof OtlpLogger.layer>[0]>;
14
+ }
3
15
  export declare class BrowserOtlp {
4
- static readonly layer: ({ attributes, baseUrl, serviceName, serviceVersion, ...options }: Omit<Parameters<typeof Otlp.layerJson>[0], "baseUrl" | "resource"> & {
5
- readonly serviceName: string;
6
- readonly serviceVersion?: string;
7
- readonly attributes?: NonNullable<Parameters<typeof Otlp.layerJson>[0]["resource"]>["attributes"];
8
- readonly baseUrl?: string;
9
- }) => Layer.Layer<never, never, never>;
16
+ static readonly layer: ({ attributes, baseUrl, logs, metrics, serviceName, serviceVersion, traces, headers, }: BrowserOtlpOptions) => Layer.Layer<OtlpExporter.Flusher, never, never>;
10
17
  }
18
+ export {};
@@ -1,7 +1,13 @@
1
1
  // ../../src/services/opentelemetry/browser.ts
2
- import { Effect, Layer, Predicate, Schema, Stream } from "effect";
3
- import { FetchHttpClient } from "effect/unstable/http";
4
- import { Otlp } from "effect/unstable/observability";
2
+ import { Effect, FiberSet, Layer, Predicate, Schema, Stream } from "effect";
3
+ import { FetchHttpClient, HttpClientRequest } from "effect/unstable/http";
4
+ import {
5
+ OtlpExporter,
6
+ OtlpLogger,
7
+ OtlpMetrics,
8
+ OtlpSerialization,
9
+ OtlpTracer
10
+ } from "effect/unstable/observability";
5
11
 
6
12
  class BrowserReportedError extends Schema.TaggedError()("BrowserReportedError", {
7
13
  type: Schema.Literals(["window.error", "unhandledrejection"]),
@@ -10,6 +16,8 @@ class BrowserReportedError extends Schema.TaggedError()("BrowserReportedError",
10
16
  }) {
11
17
  }
12
18
  var reportBrowserException = (exception) => Effect.fail(exception).pipe(Effect.withSpan("browser.exception", {
19
+ root: true,
20
+ sampled: true,
13
21
  attributes: {
14
22
  "exception.type": exception.type,
15
23
  "exception.message": exception.message,
@@ -36,23 +44,64 @@ var BrowserExceptionTrackingLive = Layer.effectDiscard(Stream.merge(Stream.fromE
36
44
  message: "Unhandled promise rejection"
37
45
  });
38
46
  }))).pipe(Stream.runForEach(reportBrowserException), Effect.forkScoped));
47
+ var BrowserLifecycleFlushingLive = Layer.effectDiscard(Effect.gen(function* () {
48
+ const flusher = yield* OtlpExporter.Flusher;
49
+ const fibers = yield* FiberSet.make();
50
+ const run = yield* FiberSet.runtime(fibers)();
51
+ const flush = () => {
52
+ run(flusher.flush.pipe(Effect.provideService(FetchHttpClient.RequestInit, {
53
+ keepalive: true
54
+ })));
55
+ };
56
+ const onVisibilityChange = () => {
57
+ if (document.visibilityState === "hidden")
58
+ flush();
59
+ };
60
+ yield* Effect.acquireRelease(Effect.sync(() => {
61
+ document.addEventListener("visibilitychange", onVisibilityChange);
62
+ globalThis.addEventListener("pagehide", flush);
63
+ }), () => Effect.sync(() => {
64
+ document.removeEventListener("visibilitychange", onVisibilityChange);
65
+ globalThis.removeEventListener("pagehide", flush);
66
+ }));
67
+ }));
39
68
 
40
69
  class BrowserOtlp {
41
70
  static layer = ({
42
71
  attributes,
43
72
  baseUrl = "/api/otel",
73
+ logs = false,
74
+ metrics = false,
44
75
  serviceName,
45
76
  serviceVersion,
46
- ...options
47
- }) => BrowserExceptionTrackingLive.pipe(Layer.provideMerge(Otlp.layerJson({
48
- tracerExportInterval: "5 seconds",
49
- metricsExportInterval: "30 seconds",
50
- loggerExcludeLogSpans: true,
51
- loggerMergeWithExisting: true,
52
- ...options,
53
- baseUrl,
54
- resource: { attributes, serviceName, serviceVersion }
55
- }).pipe(Layer.provide(FetchHttpClient.layer))));
77
+ traces = {},
78
+ headers
79
+ }) => {
80
+ const resource = { attributes, serviceName, serviceVersion };
81
+ const request = HttpClientRequest.get(baseUrl);
82
+ const signalUrl = (signal) => HttpClientRequest.appendUrl(request, `/v1/${signal}`).url;
83
+ const exporters = Layer.mergeAll(OtlpExporter.layerFlusher, traces !== false ? OtlpTracer.layer({
84
+ exportInterval: "30 seconds",
85
+ ...traces,
86
+ url: signalUrl("traces"),
87
+ resource,
88
+ headers
89
+ }) : Layer.empty, metrics !== false ? OtlpMetrics.layer({
90
+ exportInterval: "60 seconds",
91
+ ...metrics,
92
+ url: signalUrl("metrics"),
93
+ resource,
94
+ headers
95
+ }) : Layer.empty, logs !== false ? OtlpLogger.layer({
96
+ excludeLogSpans: true,
97
+ mergeWithExisting: true,
98
+ ...logs,
99
+ url: signalUrl("logs"),
100
+ resource,
101
+ headers
102
+ }) : Layer.empty).pipe(Layer.provide(OtlpSerialization.layerJson), Layer.provide(FetchHttpClient.layer));
103
+ return Layer.mergeAll(BrowserLifecycleFlushingLive, traces !== false ? BrowserExceptionTrackingLive : Layer.empty).pipe(Layer.provideMerge(exporters));
104
+ };
56
105
  }
57
106
  export {
58
107
  BrowserOtlp
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@krak-stack/registry",
3
- "version": "0.1.34",
3
+ "version": "0.1.35",
4
4
  "description": "Tree-shakable KrakStack components and Effect services.",
5
5
  "license": "MIT",
6
6
  "repository": {