From a7087025e51a1f6a314481c7e78786546fca7d93 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 24 May 2024 12:17:42 +1200 Subject: [PATCH] add Layer.annotateLogs & Layer.annotateSpans (#2836) --- .changeset/purple-mangos-grin.md | 17 ++++++++ packages/effect/src/Layer.ts | 22 ++++++++++ packages/effect/src/internal/layer.ts | 63 +++++++++++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 .changeset/purple-mangos-grin.md diff --git a/.changeset/purple-mangos-grin.md b/.changeset/purple-mangos-grin.md new file mode 100644 index 0000000000..1e4f640331 --- /dev/null +++ b/.changeset/purple-mangos-grin.md @@ -0,0 +1,17 @@ +--- +"effect": minor +--- + +add Layer.annotateLogs & Layer.annotateSpans + +This allows you to add log & span annotation to a Layer. + +```ts +import { Effect, Layer } from "effect"; + +Layer.effectDiscard(Effect.log("hello")).pipe( + Layer.annotateLogs({ + service: "my-service", + }), +); +``` diff --git a/packages/effect/src/Layer.ts b/packages/effect/src/Layer.ts index e18181a1a8..0e6a1ebfe4 100644 --- a/packages/effect/src/Layer.ts +++ b/packages/effect/src/Layer.ts @@ -139,6 +139,28 @@ export const isLayer: (u: unknown) => u is Layer = in */ export const isFresh: (self: Layer) => boolean = internal.isFresh +/** + * @since 3.3.0 + * @category tracing + */ +export const annotateLogs: { + (key: string, value: unknown): (self: Layer) => Layer + (values: Record): (self: Layer) => Layer + (self: Layer, key: string, value: unknown): Layer + (self: Layer, values: Record): Layer +} = internal.annotateLogs + +/** + * @since 3.3.0 + * @category tracing + */ +export const annotateSpans: { + (key: string, value: unknown): (self: Layer) => Layer + (values: Record): (self: Layer) => Layer + (self: Layer, key: string, value: unknown): Layer + (self: Layer, values: Record): Layer +} = internal.annotateSpans + /** * Builds a layer into a scoped value. * diff --git a/packages/effect/src/internal/layer.ts b/packages/effect/src/internal/layer.ts index aec5500891..a1c61b6dba 100644 --- a/packages/effect/src/internal/layer.ts +++ b/packages/effect/src/internal/layer.ts @@ -8,6 +8,7 @@ import type { FiberRef } from "../FiberRef.js" import * as FiberRefsPatch from "../FiberRefsPatch.js" import type { LazyArg } from "../Function.js" import { dual, pipe } from "../Function.js" +import * as HashMap from "../HashMap.js" import type * as Layer from "../Layer.js" import { pipeArguments } from "../Pipeable.js" import { hasProperty } from "../Predicate.js" @@ -1108,10 +1109,72 @@ export const unwrapScoped = ( return flatMap(scoped(tag, self), (context) => Context.get(context, tag)) } +// ----------------------------------------------------------------------------- +// logging +// ----------------------------------------------------------------------------- + +export const annotateLogs = dual< + { + (key: string, value: unknown): (self: Layer.Layer) => Layer.Layer + ( + values: Record + ): (self: Layer.Layer) => Layer.Layer + }, + { + (self: Layer.Layer, key: string, value: unknown): Layer.Layer + (self: Layer.Layer, values: Record): Layer.Layer + } +>( + (args) => isLayer(args[0]), + function() { + const args = arguments + return fiberRefLocallyWith( + args[0] as Layer.Layer, + core.currentLogAnnotations, + typeof args[1] === "string" + ? HashMap.set(args[1], args[2]) + : (annotations) => + Object.entries(args[1] as Record).reduce( + (acc, [key, value]) => HashMap.set(acc, key, value), + annotations + ) + ) + } +) + // ----------------------------------------------------------------------------- // tracing // ----------------------------------------------------------------------------- +export const annotateSpans = dual< + { + (key: string, value: unknown): (self: Layer.Layer) => Layer.Layer + ( + values: Record + ): (self: Layer.Layer) => Layer.Layer + }, + { + (self: Layer.Layer, key: string, value: unknown): Layer.Layer + (self: Layer.Layer, values: Record): Layer.Layer + } +>( + (args) => isLayer(args[0]), + function() { + const args = arguments + return fiberRefLocallyWith( + args[0] as Layer.Layer, + core.currentTracerSpanAnnotations, + typeof args[1] === "string" + ? HashMap.set(args[1], args[2]) + : (annotations) => + Object.entries(args[1] as Record).reduce( + (acc, [key, value]) => HashMap.set(acc, key, value), + annotations + ) + ) + } +) + /** @internal */ export const withSpan: { (