import {
Array,
Config,
Duration,
Effect,
Number,
pipe,
Runtime,
String,
} from "effect";
export const withSpanProcessorLive = Effect.fn(function* (
effect: Effect.Effect,
) {
const enabled = yield* Config.boolean("LOG_SPAN").pipe(
Config.withDefault(false),
);
if (!enabled) {
return yield* effect;
}
const NodeSdk = yield* Effect.promise(
() => import("@effect/opentelemetry/NodeSdk"),
);
const { SpanStatusCode } = yield* Effect.promise(
() => import("@opentelemetry/api"),
);
const runtime = yield* Effect.runtime();
const layer = NodeSdk.layer(() => ({
resource: { serviceName: "nodecg" },
spanProcessor: {
forceFlush: () => Promise.resolve(),
onStart: (span) => {
Runtime.runSync(runtime, Effect.logTrace(`▶️ ${span.name}`));
},
onEnd: (span) => {
const formattedDuration = pipe(
span.duration,
Duration.toMillis,
Number.round(0),
Duration.millis,
Duration.format,
String.split(" "),
Array.take(2),
Array.join(" "),
);
const status = span.status.code === SpanStatusCode.ERROR ? "❌" : "✅";
let log = `${status} ${span.name} (${formattedDuration})`;
if (span.status.code === SpanStatusCode.ERROR) {
log += ` ${span.status.message}`;
}
Runtime.runSync(runtime, Effect.logTrace(log));
},
shutdown: () => Promise.resolve(),
},
}));
return yield* Effect.provide(effect, layer);
});