# PlatformLogger

Effect's logging system generally writes messages to the console by default. However, you might prefer to store logs in a file for easier debugging or archiving. The `Logger.toFile` function creates a logger that sends log messages to a file on disk.

### toFile

Creates a new logger from an existing string-based logger, writing its output to the specified file.

If you include a `batchWindow` duration when calling `toFile`, logs are batched for that period before being written. This can reduce overhead if your application produces many log entries. Without a `batchWindow`, logs are written as they arrive.

Note that `toFile` returns an `Effect` that may fail with a `PlatformError` if the file cannot be opened or written to. Be sure to handle this possibility if you need to react to file I/O issues.

**Example** (Directing Logs to a File)

This logger requires a `FileSystem` implementation to open and write to the file. For Node.js, you can use `NodeFileSystem.layer`.

```ts
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
```

In the following example, logs are written to both the console and a file. The console uses the pretty logger, while the file uses the logfmt format.

**Example** (Directing Logs to Both a File and the Console)

```ts
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
```
