diff --git a/.changeset/rare-icons-hear.md b/.changeset/rare-icons-hear.md new file mode 100644 index 00000000000..227bd7dcebc --- /dev/null +++ b/.changeset/rare-icons-hear.md @@ -0,0 +1,6 @@ +--- +"effect": minor +"@effect/platform": patch +--- + +ensure Redactable works with Console.log diff --git a/packages/effect/src/Inspectable.ts b/packages/effect/src/Inspectable.ts index 0116aaf3b0b..7d99db7b189 100644 --- a/packages/effect/src/Inspectable.ts +++ b/packages/effect/src/Inspectable.ts @@ -2,8 +2,8 @@ * @since 2.0.0 */ +import type { RuntimeFiber } from "./Fiber.js" import type * as FiberRefs from "./FiberRefs.js" -import { globalValue } from "./GlobalValue.js" import { hasProperty, isFunction } from "./Predicate.js" /** @@ -114,9 +114,7 @@ export const stringifyCircular = (obj: unknown, whitespace?: number | string | u typeof value === "object" && value !== null ? cache.includes(value) ? undefined // circular reference - : cache.push(value) && (redactableState.fiberRefs !== undefined && isRedactable(value) - ? value[symbolRedactable](redactableState.fiberRefs) - : value) + : cache.push(value) && (isRedactable(value) ? redact(value) : value) : value, whitespace ) @@ -145,31 +143,18 @@ export const symbolRedactable: unique symbol = Symbol.for("effect/Inspectable/Re export const isRedactable = (u: unknown): u is Redactable => typeof u === "object" && u !== null && symbolRedactable in u -const redactableState = globalValue("effect/Inspectable/redactableState", () => ({ - fiberRefs: undefined as FiberRefs.FiberRefs | undefined -})) - -/** - * @since 3.10.0 - * @category redactable - */ -export const withRedactableContext = (context: FiberRefs.FiberRefs, f: () => A): A => { - const prev = redactableState.fiberRefs - redactableState.fiberRefs = context - try { - return f() - } finally { - redactableState.fiberRefs = prev - } -} +const currentFiberURI = "effect/FiberCurrent" /** * @since 3.10.0 * @category redactable */ export const redact = (u: unknown): unknown => { - if (isRedactable(u) && redactableState.fiberRefs !== undefined) { - return u[symbolRedactable](redactableState.fiberRefs) + if (isRedactable(u)) { + const fiber = (globalThis as any)[currentFiberURI] as RuntimeFiber | undefined + if (fiber !== undefined) { + return u[symbolRedactable](fiber.getFiberRefs()) + } } return u } diff --git a/packages/effect/src/internal/fiberRuntime.ts b/packages/effect/src/internal/fiberRuntime.ts index af4564c312a..466707c7bda 100644 --- a/packages/effect/src/internal/fiberRuntime.ts +++ b/packages/effect/src/internal/fiberRuntime.ts @@ -859,20 +859,18 @@ export class FiberRuntime extends Effectable.Class 0) { const clockService = Context.get(this.getFiberRef(defaultServices.currentServices), clock.clockTag) const date = new Date(clockService.unsafeCurrentTimeMillis()) - Inspectable.withRedactableContext(contextMap, () => { - for (const logger of loggers) { - logger.log({ - fiberId: this.id(), - logLevel, - message, - cause, - context: contextMap, - spans, - annotations, - date - }) - } - }) + for (const logger of loggers) { + logger.log({ + fiberId: this.id(), + logLevel, + message, + cause, + context: contextMap, + spans, + annotations, + date + }) + } } } diff --git a/packages/platform/src/Headers.ts b/packages/platform/src/Headers.ts index 830e713665d..83c27d96efd 100644 --- a/packages/platform/src/Headers.ts +++ b/packages/platform/src/Headers.ts @@ -5,7 +5,7 @@ import { FiberRefs } from "effect" import * as FiberRef from "effect/FiberRef" import { dual, identity } from "effect/Function" import { globalValue } from "effect/GlobalValue" -import { type Redactable, symbolRedactable } from "effect/Inspectable" +import * as Inspectable from "effect/Inspectable" import type * as Option from "effect/Option" import * as Predicate from "effect/Predicate" import * as Record from "effect/Record" @@ -36,18 +36,21 @@ export const isHeaders = (u: unknown): u is Headers => Predicate.hasProperty(u, * @since 1.0.0 * @category models */ -export interface Headers extends Redactable { +export interface Headers extends Inspectable.Redactable { readonly [HeadersTypeId]: HeadersTypeId readonly [key: string]: string } const Proto = Object.assign(Object.create(null), { [HeadersTypeId]: HeadersTypeId, - [symbolRedactable]( + [Inspectable.symbolRedactable]( this: Headers, fiberRefs: FiberRefs.FiberRefs ): Record> { return redact(this, FiberRefs.getOrDefault(fiberRefs, currentRedactedNames)) + }, + [Inspectable.NodeInspectSymbol]() { + return Inspectable.redact(this) } }) diff --git a/packages/platform/test/Headers.test.ts b/packages/platform/test/Headers.test.ts index 95abe753c67..aea0a4745e3 100644 --- a/packages/platform/test/Headers.test.ts +++ b/packages/platform/test/Headers.test.ts @@ -1,11 +1,11 @@ import * as Headers from "@effect/platform/Headers" import { assert, describe, it } from "@effect/vitest" -import { Effect, FiberId, FiberRef, FiberRefs, HashSet, Inspectable, Logger } from "effect" +import { Console, Effect, FiberId, FiberRef, FiberRefs, HashSet, Inspectable, Logger } from "effect" import * as Redacted from "effect/Redacted" describe("Headers", () => { describe("Redactable", () => { - it("one key", () => { + it("one key", async () => { const headers = Headers.fromInput({ "Content-Type": "application/json", "Authorization": "Bearer some-token", @@ -20,8 +20,11 @@ describe("Headers", () => { ] as const ]) ) - const r = Inspectable.withRedactableContext(fiberRefs, () => Inspectable.toStringUnknown(headers)) - const redacted = JSON.parse(r) + const r = Effect.gen(function*() { + yield* Effect.setFiberRefs(fiberRefs) + return Inspectable.toStringUnknown(headers) + }).pipe(Effect.runSync) + const redacted = JSON.parse(r) as any assert.deepEqual(redacted, { "content-type": "application/json", @@ -45,7 +48,10 @@ describe("Headers", () => { ] as const ]) ) - const r = Inspectable.withRedactableContext(fiberRefs, () => Inspectable.toStringUnknown({ headers })) + const r = Effect.gen(function*() { + yield* Effect.setFiberRefs(fiberRefs) + return Inspectable.toStringUnknown({ headers }) + }).pipe(Effect.runSync) const redacted = JSON.parse(r) as { headers: unknown } assert.deepEqual(redacted.headers, { @@ -72,6 +78,7 @@ describe("Headers", () => { yield* Effect.log(headers).pipe( Effect.annotateLogs({ headers }) ) + yield* Console.log(headers) assert.include(messages[0], "application/json") assert.notInclude(messages[0], "some-token") assert.notInclude(messages[0], "some-key") diff --git a/packages/platform/test/HttpClient.test.ts b/packages/platform/test/HttpClient.test.ts index a3adc1f94e0..d6993f9fd22 100644 --- a/packages/platform/test/HttpClient.test.ts +++ b/packages/platform/test/HttpClient.test.ts @@ -208,7 +208,10 @@ describe("HttpClient", () => { ] as const ]) ) - const r = Inspectable.withRedactableContext(fiberRefs, () => Inspectable.toStringUnknown(request)) + const r = Effect.gen(function*() { + yield* Effect.setFiberRefs(fiberRefs) + return Inspectable.toStringUnknown(request) + }).pipe(Effect.runSync) const redacted = JSON.parse(r) assert.deepStrictEqual(redacted, {