# Console

The `Console` module is the effectful mirror of the global `console`. Every
method you know from `console` — `log`, `error`, `table`, `group`, `time`, and
friends — has an Effect-returning counterpart that you `yield*` inside
`Effect.gen` (or `pipe` through `Effect.tap`). The output goes wherever the
active **Console reference** points, which by default is `globalThis.console`.

```ts
import { Console, Effect } from "effect"

const program = Effect.gen(function*() {
  yield* Console.log("Hello, world!")
  yield* Console.info("server starting", { port: 3000 })
  yield* Console.warn("inventory is low")
  yield* Console.error("checkout failed", { code: 500 })
})
```
**Console vs. Logger:** `Console` is for direct, unstructured terminal output — the kind you'd reach
for `console.log` for. For application logging with levels, annotations,
spans, and swappable backends (pretty / JSON / remote), use the
[Logging](https://effect.plants.sh/observability/logging/) APIs (`Effect.logInfo` and friends)
instead. Reach for `Console` when you specifically want the browser/Node
console's own features such as `table`, `group`, `dir`, or `count`.

## Swapping the Console for tests

Because the console is held as a [`Context.Reference`](https://effect.plants.sh/services-and-layers/),
you can substitute your own implementation with `Effect.provideService`. This
makes console output capturable and assertable in tests, with no global
patching.

```ts
import { Console, Effect } from "effect"

// A minimal capturing console. Only implement the methods you exercise;
// cast through the Console interface for the rest.
const makeCapture = () => {
  const lines: Array<string> = []
  const capture = {
    ...globalThis.console,
    log: (...args: Array<any>) => lines.push(args.join(" ")),
    error: (...args: Array<any>) => lines.push(`ERROR ${args.join(" ")}`)
  } as Console.Console
  return { capture, lines }
}

const program = Effect.gen(function*() {
  yield* Console.log("hello")
  yield* Console.error("boom")
})

const { capture, lines } = makeCapture()

Effect.runSync(program.pipe(Effect.provideService(Console.Console, capture)))

console.log(lines)
// => ["hello", "ERROR boom"]
```

## Reference

### Console (interface)

The shape of a console implementation: the methods `assert`, `clear`, `count`,
`countReset`, `debug`, `dir`, `dirxml`, `error`, `group`, `groupCollapsed`,
`groupEnd`, `info`, `log`, `table`, `time`, `timeEnd`, `timeLog`, `trace`, and
`warn`. The browser/Node `console` already satisfies it, which is why it is the
default.

```ts
import { Console } from "effect"

// Provide your own implementation by satisfying this interface.
const silent: Console.Console = {
  ...globalThis.console,
  log: () => {},
  error: () => {}
}
```

### Console (reference)

`Console.Console` is the `Context.Reference` holding the active console. It
resolves to `globalThis.console` unless overridden. Override it with
`Effect.provideService(Console.Console, impl)` to redirect output.

```ts
import { Console, Effect } from "effect"

const program = Console.log("written to the overridden console")

const myConsole = { ...globalThis.console } as Console.Console

Effect.runSync(program.pipe(Effect.provideService(Console.Console, myConsole)))
```

### consoleWith

Accesses the current console and lets you build an Effect from it directly —
useful when you want to call several methods on the raw console in one
synchronous block.

```ts
import { Console, Effect } from "effect"

const program = Console.consoleWith((console) =>
  Effect.sync(() => {
    console.log("Hello, world!")
    console.error("This is an error message")
  })
)
```

## Output

### log

Logs a general-purpose message. Accepts any number of arguments.

```ts
import { Console, Effect } from "effect"

const program = Console.log("User data:", { name: "John", age: 30 })
// => User data: { name: 'John', age: 30 }
```

### error

Writes an error-level message, typically styled as an error by the host
console.

```ts
import { Console } from "effect"

const program = Console.error("Error details:", { code: 500 })
// => Error details: { code: 500 }
```

### warn

Writes a warning-level message.

```ts
import { Console } from "effect"

const program = Console.warn("This feature is deprecated")
// => This feature is deprecated
```

### info

Writes an informational message.

```ts
import { Console } from "effect"

const program = Console.info("Server configuration:", { port: 3000 })
// => Server configuration: { port: 3000 }
```

### debug

Writes a debug-level message. Visibility depends on the host console's level
filtering.

```ts
import { Console } from "effect"

const program = Console.debug("Debug info:", { userId: 123, action: "login" })
// => Debug info: { userId: 123, action: 'login' }
```

### trace

Writes the current stack trace alongside the supplied arguments, showing how
the current point in the code was reached.

```ts
import { Console } from "effect"

const program = Console.trace("Debug trace point")
// => Trace: Debug trace point
// =>     at ...
```

### dir

Displays an interactive list of an object's properties. The optional second
argument forwards inspection options (e.g. `{ depth, colors }`) to the host
console.

```ts
import { Console } from "effect"

const obj = { name: "John", nested: { city: "New York" } }

const program = Console.dir(obj, { depth: 2 })
// => { name: 'John', nested: { city: 'New York' } }
```

### dirxml

Displays an interactive tree of descendant XML/HTML elements, primarily useful
for inspecting DOM nodes in the browser. Falls back to `dir`-like output
elsewhere.

```ts
import { Console } from "effect"

const program = Console.dirxml("<user id=\"1\">Ada</user>")
// => <user id="1">Ada</user>
```

## Tables and inspection

### table

Renders an array or object as a formatted table. The optional second argument
restricts the table to the listed property names.

```ts
import { Console, Effect } from "effect"

const program = Effect.gen(function*() {
  const users = [
    { name: "John", age: 30, city: "New York" },
    { name: "Jane", age: 25, city: "London" }
  ]
  yield* Console.table(users)
  yield* Console.table(users, ["name", "age"]) // only these columns
})
// => ┌─────────┬────────┬─────┬────────────┐
// => │ (index) │ name   │ age │ city       │
// => ├─────────┼────────┼─────┼────────────┤
// => │ 0       │ 'John' │ 30  │ 'New York' │
// => │ 1       │ 'Jane' │ 25  │ 'London'   │
// => └─────────┴────────┴─────┴────────────┘
```

### assert

Writes an assertion error to the console when `condition` is `false`; produces
no output when it is `true`.

```ts
import { Console, Effect } from "effect"

const program = Effect.gen(function*() {
  yield* Console.assert(2 + 2 === 4, "Math is working") // no output
  yield* Console.assert(2 + 2 === 5, "This is logged as an error")
})
// => Assertion failed: This is logged as an error
```

## Counters

### count

Logs and increments a named counter. With no label it uses the console's
default counter.

```ts
import { Console, Effect } from "effect"

const program = Effect.gen(function*() {
  yield* Console.count("hits")
  yield* Console.count("hits")
})
// => hits: 1
// => hits: 2
```

### countReset

Resets the named counter back to zero.

```ts
import { Console, Effect } from "effect"

const program = Effect.gen(function*() {
  yield* Console.count("hits") // => hits: 1
  yield* Console.count("hits") // => hits: 2
  yield* Console.countReset("hits")
  yield* Console.count("hits") // => hits: 1
})
```

## Timing

`Console.time` and `Console.group` are *scoped*: they require a `Scope` and end
the timer / close the group automatically when the scope is finalized. Run them
under `Effect.scoped`. For the common "time/group exactly this effect" case,
prefer the `withTime` / `withGroup` combinators below, which manage the scope
for you.

### time

Starts a console timer for `label`, ending it automatically when the
surrounding scope closes. Returns `Effect<void, never, Scope>`.

```ts
import { Console, Effect } from "effect"

const program = Effect.scoped(
  Effect.gen(function*() {
    yield* Console.time("operation")
    yield* Effect.sleep("1 second")
    yield* Console.log("done")
    // timer ends here, when the scope closes
  })
)
// => done
// => operation: 1004.218ms
```

### timeLog

Logs the elapsed time of an existing timer without stopping it — handy for
progress reports inside a `time` scope.

```ts
import { Console, Effect } from "effect"

const program = Effect.scoped(
  Effect.gen(function*() {
    yield* Console.time("job")
    yield* Effect.sleep("500 millis")
    yield* Console.timeLog("job", "halfway")
    yield* Effect.sleep("500 millis")
  })
)
// => job: 503.91ms halfway
// => job: 1006.77ms   (emitted when the scope closes)
```

### withTime

Runs an Effect with a console timer wrapped around it: starts the timer before
the effect and ends it after. Dual — data-first `(self, label?)` or data-last
`(label?)` for piping. No explicit `Scope` needed.

```ts
import { Console, Effect } from "effect"

const work = Effect.sleep("1 second")

// data-first
const a = Console.withTime(work, "my-operation")

// data-last (pipeable)
const b = work.pipe(Console.withTime("my-operation"))
// => my-operation: 1003.12ms
```

## Grouping

### group

Opens a console group (indenting subsequent output), closing it automatically
when the scope is finalized. Pass `{ collapsed: true }` for a collapsed group in
the browser. Returns `Effect<void, never, Scope>`.

```ts
import { Console, Effect } from "effect"

const program = Effect.scoped(
  Effect.gen(function*() {
    yield* Console.group({ label: "User Processing" })
    yield* Console.log("Loading user data...")
    yield* Console.log("Validating user...")
    // group closes here, when the scope closes
  })
)
// => User Processing
// =>   Loading user data...
// =>   Validating user...
```

### withGroup

Runs an Effect inside a console group, opening it before and closing it after
the effect completes. Dual — data-first `(self, options?)` or data-last
`(options?)`. No explicit `Scope` needed.

```ts
import { Console, Effect } from "effect"

const steps = Effect.gen(function*() {
  yield* Console.log("Step 1: Initialize")
  yield* Console.log("Step 2: Process")
})

const program = Console.withGroup(steps, {
  label: "Processing Steps",
  collapsed: false
})
// => Processing Steps
// =>   Step 1: Initialize
// =>   Step 2: Process
```

### clear

Requests that the active console clear its visible output. The exact behavior
depends on the host environment.

```ts
import { Console, Effect } from "effect"

const program = Effect.gen(function*() {
  yield* Console.log("This will be cleared")
  yield* Console.clear
  yield* Console.log("This appears after clearing")
})
```