1/**
2 * @title Customizing logging
3 *
4 * Configure loggers & log-level filtering for production applications.
5 */
6import { NodeFileSystem } from "@effect/platform-node"
7import { Config, Effect, Layer, Logger, References } from "effect"
8
9// Build a logger layer that emits one JSON line per log entry.
10export const JsonLoggerLayer = Logger.layer([Logger.consoleJson])
11
12// Raise the minimum level to "Warn" to skip debug/info logs.
13export const WarnAndAbove = Layer.succeed(References.MinimumLogLevel, "Warn")
14
15// There is a built-in logger for writing to a file
16export const FileLoggerLayer = Logger.layer([
17 Logger.toFile(Logger.formatSimple, "app.log")
18]).pipe(
19 Layer.provide(NodeFileSystem.layer)
20)
21
22// Define a custom logger for app-specific formatting and routing.
23export const appLogger = Effect.gen(function*() {
24 // Here you could initialize a connection to an external logging service, set
25 // up log file rotation, etc.
26 yield* Effect.logDebug("initializing app logger")
27
28 return yield* Logger.batched(Logger.formatStructured, {
29 window: "1 second",
30 flush: Effect.fn(function*(batch) {
31 // In a real implementation, this is where you would send the batch of log entries to an external logging service or write them to a file.
32 console.log(`Flushing ${batch.length} log entries`)
33 })
34 })
35})
36
37export const AppLoggerLayer = Logger.layer([appLogger]).pipe(
38 Layer.provideMerge(WarnAndAbove) // Start with "Warn" level for the app logger.
39)
40
41// Create a logger layer that uses the default logger for development, and the
42// custom logger for production
43export const LoggerLayer = Layer.unwrap(Effect.gen(function*() {
44 const env = yield* Config.String("NODE_ENV").pipe(Config.withDefault("development"))
45 if (env === "production") {
46 return AppLoggerLayer
47 }
48 return Logger.layer([Logger.defaultLogger])
49}))
50
51// Example effect that logs at various levels during a checkout flow.
52export const logCheckoutFlow = Effect.gen(function*() {
53 yield* Effect.logDebug("loading checkout state")
54
55 yield* Effect.logInfo("validating cart")
56 yield* Effect.logWarning("inventory is low for one line item")
57 yield* Effect.logError("payment provider timeout")
58}).pipe(
59 // Attach structured metadata to all log lines emitted by this effect.
60 Effect.annotateLogs({
61 service: "checkout-api",
62 route: "POST /checkout"
63 }),
64 // Add a duration span so each log line includes checkout=<N>ms metadata.
65 Effect.withLogSpan("checkout")
66)