import * as Context from "effect/Context";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as Option from "effect/Option";import * as Tracer from "effect/Tracer";import type { HttpClient } from "effect/unstable/http";import { OtlpSerialization, OtlpTracer } from "effect/unstable/observability"; export interface RelayClientTracingConfig { readonly tracesUrl: string; readonly tracesDataset: string; readonly tracesToken: string;} export interface RelayClientTracingResource { readonly serviceName: string; readonly serviceVersion?: string; readonly runtime: string; readonly client: string; readonly component?: string;} export class RelayClientTracer extends Context.Reference( "@t3tools/shared/relayTracing/RelayClientTracer", { defaultValue: () => Option.none<Tracer.Tracer>(), },) {} export const withRelayClientTracing = <A, E, R>( effect: Effect.Effect<A, E, R>,): Effect.Effect<A, E, R> => RelayClientTracer.pipe( Effect.flatMap( Option.match({ onNone: () => effect, onSome: (tracer) => effect.pipe(Effect.provideService(Tracer.Tracer, tracer)), }), ), ); export function makeRelayClientTracingLayer( config: RelayClientTracingConfig | null, resource: RelayClientTracingResource,): Layer.Layer<never, never, HttpClient.HttpClient> { if (config === null) { return Layer.succeed(RelayClientTracer, Option.none()); } const tracerLayer = OtlpTracer.layer({ url: config.tracesUrl, headers: { Authorization: `Bearer ${config.tracesToken}`, "X-Axiom-Dataset": config.tracesDataset, }, resource: { serviceName: resource.serviceName, serviceVersion: resource.serviceVersion, attributes: { "service.runtime": resource.runtime, "service.component": resource.component ?? "relay-client", "t3.client.surface": resource.client, }, }, }).pipe(Layer.provide(OtlpSerialization.layerJson)); return Layer.effect(RelayClientTracer, Tracer.Tracer.pipe(Effect.map(Option.some))).pipe( Layer.provide(tracerLayer), );}
import * as Context from "effect/Context";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import * as Option from "effect/Option";
import * as Tracer from "effect/Tracer";
import type { HttpClient } from "effect/unstable/http";
import { OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
export interface RelayClientTracingConfig {
readonly tracesUrl: string;
readonly tracesDataset: string;
readonly tracesToken: string;
}
export interface RelayClientTracingResource {
readonly serviceName: string;
readonly serviceVersion?: string;
readonly runtime: string;
readonly client: string;
readonly component?: string;
}
export class RelayClientTracer extends Context.Reference(
"@t3tools/shared/relayTracing/RelayClientTracer",
{
defaultValue: () => Option.none<Tracer.Tracer>(),
},
) {}
export const withRelayClientTracing = <A, E, R>(
effect: Effect.Effect<A, E, R>,
): Effect.Effect<A, E, R> =>
RelayClientTracer.pipe(
Effect.flatMap(
Option.match({
onNone: () => effect,
onSome: (tracer) => effect.pipe(Effect.provideService(Tracer.Tracer, tracer)),
}),
),
);
export function makeRelayClientTracingLayer(
config: RelayClientTracingConfig | null,
resource: RelayClientTracingResource,
): Layer.Layer<never, never, HttpClient.HttpClient> {
if (config === null) {
return Layer.succeed(RelayClientTracer, Option.none());
}
const tracerLayer = OtlpTracer.layer({
url: config.tracesUrl,
headers: {
Authorization: `Bearer ${config.tracesToken}`,
"X-Axiom-Dataset": config.tracesDataset,
},
resource: {
serviceName: resource.serviceName,
serviceVersion: resource.serviceVersion,
attributes: {
"service.runtime": resource.runtime,
"service.component": resource.component ?? "relay-client",
"t3.client.surface": resource.client,
},
},
}).pipe(Layer.provide(OtlpSerialization.layerJson));
return Layer.effect(RelayClientTracer, Tracer.Tracer.pipe(Effect.map(Option.some))).pipe(
Layer.provide(tracerLayer),
);
}