Skip to content

Commit

Permalink
ensure Redactable works with Console.log
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart committed Dec 18, 2024
1 parent e9049ea commit 939f93f
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 46 deletions.
6 changes: 6 additions & 0 deletions .changeset/rare-icons-hear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"effect": minor
"@effect/platform": patch
---

ensure Redactable works with Console.log
31 changes: 8 additions & 23 deletions packages/effect/src/Inspectable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"

/**
Expand Down Expand Up @@ -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
)
Expand Down Expand Up @@ -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 = <A>(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<any, any> | undefined
if (fiber !== undefined) {
return u[symbolRedactable](fiber.getFiberRefs())
}
}
return u
}
26 changes: 12 additions & 14 deletions packages/effect/src/internal/fiberRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -859,20 +859,18 @@ export class FiberRuntime<in out A, in out E = never> extends Effectable.Class<A
if (HashSet.size(loggers) > 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
})
}
}
}

Expand Down
9 changes: 6 additions & 3 deletions packages/platform/src/Headers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<string, string | Redacted.Redacted<string>> {
return redact(this, FiberRefs.getOrDefault(fiberRefs, currentRedactedNames))
},
[Inspectable.NodeInspectSymbol]() {
return Inspectable.redact(this)
}
})

Expand Down
17 changes: 12 additions & 5 deletions packages/platform/test/Headers.test.ts
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -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",
Expand All @@ -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, {
Expand All @@ -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")
Expand Down
5 changes: 4 additions & 1 deletion packages/platform/test/HttpClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, {
Expand Down

0 comments on commit 939f93f

Please sign in to comment.