Skip to content

Commit

Permalink
Add Effect.whenLogLevel (#4342)
Browse files Browse the repository at this point in the history
  • Loading branch information
indietyp authored Jan 30, 2025
1 parent d425963 commit e1b3701
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/dirty-ways-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": minor
---

Add `Effect.whenLogLevel`, which conditionally executes an effect if the specified log level is enabled
44 changes: 40 additions & 4 deletions packages/effect/src/Effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import * as runtime_ from "./internal/runtime.js"
import * as schedule_ from "./internal/schedule.js"
import * as internalTracer from "./internal/tracer.js"
import type * as Layer from "./Layer.js"
import type { LogLevel } from "./LogLevel.js"
import type * as LogLevel from "./LogLevel.js"
import type * as ManagedRuntime from "./ManagedRuntime.js"
import type * as Metric from "./Metric.js"
import type * as MetricLabel from "./MetricLabel.js"
Expand Down Expand Up @@ -10680,7 +10680,7 @@ export const log: (...message: ReadonlyArray<any>) => Effect<void, never, never>
* @category Logging
*/
export const logWithLevel = (
level: LogLevel,
level: LogLevel.LogLevel,
...message: ReadonlyArray<any>
): Effect<void> => effect.logWithLevel(level)(...message)

Expand Down Expand Up @@ -10974,10 +10974,46 @@ export const logAnnotations: Effect<HashMap.HashMap<string, unknown>> = effect.l
* @category Logging
*/
export const withUnhandledErrorLogLevel: {
(level: Option.Option<LogLevel>): <A, E, R>(self: Effect<A, E, R>) => Effect<A, E, R>
<A, E, R>(self: Effect<A, E, R>, level: Option.Option<LogLevel>): Effect<A, E, R>
(level: Option.Option<LogLevel.LogLevel>): <A, E, R>(self: Effect<A, E, R>) => Effect<A, E, R>
<A, E, R>(self: Effect<A, E, R>, level: Option.Option<LogLevel.LogLevel>): Effect<A, E, R>
} = core.withUnhandledErrorLogLevel

/**
* Conditionally executes an effect based on the specified log level and currently enabled log level.
*
* **Details**
*
* This function runs the provided effect only if the specified log level is
* enabled. If the log level is enabled, the effect is executed and its result
* is wrapped in `Some`. If the log level is not enabled, the effect is not
* executed and `None` is returned.
*
* This function is useful for conditionally executing logging-related effects
* or other operations that depend on the current log level configuration.
*
* @example
* ```ts
* import { Effect, Logger, LogLevel } from "effect"
*
* const program = Effect.gen(function* () {
* yield* Effect.whenLogLevel(Effect.logTrace("message1"), LogLevel.Trace); // returns `None`
* yield* Effect.whenLogLevel(Effect.logDebug("message2"), LogLevel.Debug); // returns `Some`
* }).pipe(Logger.withMinimumLogLevel(LogLevel.Debug));
*
* // Effect.runFork(program)
* // timestamp=... level=DEBUG fiber=#0 message=message2
* ```
*
* @see {@link FiberRef.minimumLogLevel} to retrieve the current minimum log level.
*
* @since 3.13.0
* @category Logging
*/
export const whenLogLevel: {
(level: LogLevel.LogLevel | LogLevel.Literal): <A, E, R>(self: Effect<A, E, R>) => Effect<Option.Option<A>, E, R>
<A, E, R>(self: Effect<A, E, R>, level: LogLevel.LogLevel | LogLevel.Literal): Effect<Option.Option<A>, E, R>
} = fiberRuntime.whenLogLevel

/**
* Converts an effect's failure into a fiber termination, removing the error
* from the effect's type.
Expand Down
24 changes: 24 additions & 0 deletions packages/effect/src/internal/fiberRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,30 @@ export const annotateLogsScoped: {
)
}

/** @internal */
export const whenLogLevel = dual<
(
level: LogLevel.LogLevel | LogLevel.Literal
) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<Option.Option<A>, E, R>,
<A, E, R>(
effect: Effect.Effect<A, E, R>,
level: LogLevel.LogLevel | LogLevel.Literal
) => Effect.Effect<Option.Option<A>, E, R>
>(2, (effect, level) => {
const requiredLogLevel = typeof level === "string" ? LogLevel.fromLiteral(level) : level

return core.withFiberRuntime((fiberState) => {
const minimumLogLevel = fiberState.getFiberRef(currentMinimumLogLevel)

// Imitate the behaviour of `FiberRuntime.log`
if (LogLevel.greaterThan(minimumLogLevel, requiredLogLevel)) {
return core.succeed(Option.none())
}

return core.map(effect, Option.some)
})
})

// circular with Effect

/* @internal */
Expand Down

0 comments on commit e1b3701

Please sign in to comment.