已发布 上游基线 bf46254 原文 ↗ 在 GitHub 编辑

PlatformLogger

使用 FileSystem API 将日志消息写入文件。

Effect 的日志系统默认通常会把消息写入控制台。不过,你可能更希望把日志存到文件里,以便调试或归档。Logger.toFile 函数会创建一个 logger,把日志消息写入磁盘上的文件。

toFile

基于已有的字符串 logger 创建一个新的 logger,并把它的输出写入指定文件。

如果在调用 toFile 时传入一个 batchWindow 时长,日志会先在该时间窗口内批量累积,然后再写入。当你的应用产生大量日志条目时,这可以降低开销。若不设置 batchWindow,日志会在到达时立即写入。

请注意,toFile 返回一个 Effect,如果文件无法打开或写入,它可能以 PlatformError 失败。如果你需要对文件 I/O 问题作出反应,请务必处理这种可能性。

示例(将日志写入文件)

这个 logger 需要一个 FileSystem 实现来打开并写入文件。在 Node.js 上,你可以使用 NodeFileSystem.layer

import { NodeFileSystem } from "@effect/platform-node"
import { Effect, FileSystem, Layer, Logger } from "effect"

// Create a string-based logger (formatLogFmt in this case)
const myStringLogger = Logger.formatLogFmt

// Apply toFile to write logs to "/tmp/log.txt"
const fileLogger = myStringLogger.pipe(Logger.toFile("/tmp/log.txt"))

// Replace the default logger, providing NodeFileSystem
// to access the file system
const LoggerLive = Logger.layer([fileLogger]).pipe(
  Layer.provide(NodeFileSystem.layer),
)

const program = Effect.log("Hello")

// Run the program, writing logs to /tmp/log.txt
await Effect.runPromise(program.pipe(Effect.provide(LoggerLive)))
/*
Logs will be written to "/tmp/log.txt" in the logfmt format,
and won't appear on the console.
*/

// Read back the file to verify the log entry was written
// (the timestamp is omitted from the assertion since it varies)
const content = await Effect.runPromise(
  Effect.gen(function* () {
    const fs = yield* FileSystem.FileSystem
    return yield* fs.readFileString("/tmp/log.txt")
  }).pipe(Effect.provide(NodeFileSystem.layer)),
)

content.includes("level=Info") // => true
content.includes("message=Hello") // => true

在下面的示例中,日志会同时写入控制台和文件。控制台使用 pretty logger,而文件使用 logfmt 格式。

示例(同时将日志写入文件和控制台)

import { NodeFileSystem } from "@effect/platform-node"
import { Effect, FileSystem, Layer, Logger } from "effect"

const fileLogger = Logger.formatLogFmt.pipe(Logger.toFile("/tmp/log.txt"))

// Combine the pretty logger for console output with the file logger
const LoggerLive = Logger.layer([Logger.consolePretty(), fileLogger]).pipe(
  Layer.provide(NodeFileSystem.layer),
)

const program = Effect.log("Hello")

// Run the program, writing logs to both the console (pretty format)
// and "/tmp/log.txt" (logfmt)
await Effect.runPromise(program.pipe(Effect.provide(LoggerLive)))

// The console output includes ANSI styling and a wall-clock timestamp,
// so only the file (logfmt) output is asserted here
const content = await Effect.runPromise(
  Effect.gen(function* () {
    const fs = yield* FileSystem.FileSystem
    return yield* fs.readFileString("/tmp/log.txt")
  }).pipe(Effect.provide(NodeFileSystem.layer)),
)

content.includes("message=Hello") // => true