> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ooneex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Logger

> Write structured logs through a single ILogger interface with terminal and database backends.

The `@ooneex/logger` component is a multi-backend logging layer. Every logger implements the same `ILogger` interface — `init`, `error`, `warn`, `info`, `debug`, `log`, `success` — so you can write to the terminal in development and ship to a database in production without changing a single call site. Each method takes a message, an optional structured `data` object, and per-call display `options`, and `error` additionally accepts an `IException` to log its name, status, and stack trace.

## Why this component

* **One interface, many backends.** `TerminalLogger` and `DatabaseLogger` both implement `ILogger` — swap backends without touching callers.
* **Six log levels.** `error`, `warn`, `info`, `debug`, `log`, and `success` map to the `ELogLevel` enum, each with its own color and symbol in the terminal.
* **Structured data.** Pass a typed `data` object alongside the message; backends serialize it for you.
* **Exception-aware.** `error()` accepts a string or an `IException` and records its name, status, and structured stack trace.
* **Container-managed.** Register a logger class with a decorator and resolve it from the container.

## How it works

You pick (or implement) a backend and register it. Calls go through the `ILogger` methods; the backend handles formatting, serialization, and transport.

| Method                              | Purpose                                                                                    |
| ----------------------------------- | ------------------------------------------------------------------------------------------ |
| `init()`                            | Set up the logger (open handles, configure transports). Returns `void` or `Promise<void>`. |
| `error(message, data?, options?)`   | Log an error. `message` may be a `string` or an `IException`.                              |
| `warn(message, data?, options?)`    | Log a warning.                                                                             |
| `info(message, data?, options?)`    | Log informational output.                                                                  |
| `debug(message, data?, options?)`   | Log debug detail.                                                                          |
| `log(message, data?, options?)`     | Log a general message.                                                                     |
| `success(message, data?, options?)` | Log a success message.                                                                     |

Every method shares the same `ELogLevel` levels — `ERROR`, `WARN`, `INFO`, `DEBUG`, `LOG`, `SUCCESS`. The built-in backends differ in where logs go, not in how you call them:

| Backend          | Destination                     | Best for                                |
| ---------------- | ------------------------------- | --------------------------------------- |
| `TerminalLogger` | `stdout` / `stderr`             | Local development and CLI output        |
| `DatabaseLogger` | PostgreSQL via `LogsRepository` | Persisting application and request logs |

`TerminalLogger` accepts `LoggerOptionsType` per call — `showArrow`, `showTimestamp`, `showLevel`, and `useSymbol` — to control how each line is rendered. Error and `ERROR`-level lines go to `stderr`; everything else goes to `stdout`.

## Environment variables

Only the production backends need configuration. `TerminalLogger` needs none.

| Variable            | Backend          | Required | Purpose                                             |
| ------------------- | ---------------- | -------- | --------------------------------------------------- |
| `LOGS_DATABASE_URL` | `DatabaseLogger` | Yes      | PostgreSQL connection string for the logs database. |

```bash theme={null}
LOGS_DATABASE_URL=postgres://user:password@localhost:5432/logs
```

## Decorator and usage

### `@decorator.logger()`

Registers a logger class with the container. It accepts an optional scope (defaults to `EContainerScope.Singleton`). All built-in loggers are decorated, and you use it to register custom loggers that implement `ILogger`.

```typescript theme={null}
import { decorator } from "@ooneex/logger";
import type { ILogger } from "@ooneex/logger";

@decorator.logger()
export class AuditLogger implements ILogger {
  // ...implement init, error, warn, info, debug, log, success
}
```

Resolve a logger from the container and call its level methods:

```typescript theme={null}
import { TerminalLogger } from "@ooneex/logger";
import { container } from "@ooneex/container";

const logger = container.get(TerminalLogger);

logger.info("User signed in", { userId: "123", email: "john@example.com" });
logger.success("Payment captured", { orderId: "ord_456", amount: 4999 });
logger.warn("Rate limit approaching", { remaining: 5 });

// Control terminal rendering per call
logger.debug("Cache miss", { key: "user:123" }, { useSymbol: true, showTimestamp: false });
```

`error()` accepts a plain message or an `IException` — when given an exception it records the name, status, and stack trace automatically:

```typescript theme={null}
import { TerminalLogger } from "@ooneex/logger";
import { container } from "@ooneex/container";

const logger = container.get(TerminalLogger);

try {
  await processPayment(order);
} catch (error) {
  // Logs the exception name, status, and structured stack trace
  logger.error(error as IException, { orderId: order.id });
}
```

Inject a logger where you need it:

```typescript theme={null}
import { inject } from "@ooneex/container";
import { TerminalLogger } from "@ooneex/logger";

export class PaymentService {
  constructor(@inject(TerminalLogger) private readonly logger: TerminalLogger) {}
}
```

## Exceptions

The component throws `LoggerException` when a backend is misconfigured. It carries a machine-readable `key`, a human-readable `message`, a `data` object, and an `InternalServerError` status.

```typescript theme={null}
import { LoggerException } from "@ooneex/logger";

try {
  const logger = container.get(DatabaseLogger);
} catch (error) {
  if (error instanceof LoggerException) {
    console.error(`Logger error [${error.key}]: ${error.message}`, error.data);
  } else {
    throw error;
  }
}
```

## Best practices

* **Pick the backend per environment.** `TerminalLogger` for local/dev and `DatabaseLogger` for production — the call sites stay identical.
* **Pass structured data, not interpolated strings.** Keep the message stable and put variable detail in the `data` object so logs stay searchable.
* **Match the level to the meaning.** Reserve `error` for failures, `warn` for recoverable issues, `success` for completed operations, and `debug` for diagnostics.
* **Log exceptions as exceptions.** Pass the `IException` to `error()` rather than its `message` string so the name, status, and stack trace are captured.
* **Keep `data` serializable.** Backends serialize values; avoid class instances, functions, and circular references.
* **Throw `LoggerException` with a stable `key`.** In custom backends, keep keys constant and put variable detail in `data`.

## CLI command

Scaffold a logger class and its test file with the generator. It writes the class under `modules/<module>/src/loggers/<Name>Logger.ts` and installs `@ooneex/logger` if it is missing.

```bash theme={null}
# Interactive: prompts for the name
ooneex logger:create

# Provide the name
ooneex logger:create --name=Audit

# Target a module and overwrite
ooneex logger:create --name=Audit --module=auth --override
```

| Option       | Description                                                       | Default             |
| ------------ | ----------------------------------------------------------------- | ------------------- |
| `--name`     | Logger class name. The `Logger` suffix is appended automatically. | Prompted if omitted |
| `--module`   | Target module the class is generated into.                        | `shared`            |
| `--override` | Overwrite an existing class without prompting.                    | `false`             |

The generated class starts as an `ILogger` stub, ready for you to implement each level method:

```typescript theme={null}
import type { IException } from "@ooneex/exception";
import type { ILogger } from "@ooneex/logger";
import type { ScalarType } from "@ooneex/types";
import { decorator } from "@ooneex/logger";

@decorator.logger()
export class AuditLogger implements ILogger {
  public async init(): Promise<void> {
    // Initialize your logger here
  }

  public log(message: string, data?: Record<string, ScalarType>): void {
    // Handle general logging
  }

  public debug(message: string, data?: Record<string, ScalarType>): void {
    // Handle debug logging
  }

  public info(message: string, data?: Record<string, ScalarType>): void {
    // Handle info logging
  }

  public success(message: string, data?: Record<string, ScalarType>): void {
    // Handle success logging
  }

  public warn(message: string, data?: Record<string, ScalarType>): void {
    // Handle warning logging
  }

  public error(message: string | IException, data?: Record<string, ScalarType>): void {
    // Handle error logging
  }
}
```

See [logger:create](/cli/commands/logger-create) for the full command reference.

## Use with Claude and Codex

The generator ships a matching `logger:create` skill. It runs the scaffold and then guides your AI agent through completing the logger — implementing `init`, `log`, `debug`, `info`, `success`, `warn`, and `error` against a real transport and wiring up its dependencies. Initialize the skills once for your agent:

<Tabs>
  <Tab title="Claude">
    ```bash theme={null}
    ooneex claude:init
    ```

    Then ask Claude in natural language — it maps the request to the generator, runs it, and fills in the implementation:

    ```text Prompt icon="terminal" wrap theme={null}
    Create a logger that writes structured logs for the payments module.
    ```
  </Tab>

  <Tab title="Codex">
    ```bash theme={null}
    ooneex codex:init
    ```

    Then ask Codex in natural language — it maps the request to the generator, runs it, and fills in the implementation:

    ```text Prompt icon="terminal" wrap theme={null}
    Create a logger that writes structured logs for the payments module.
    ```
  </Tab>
</Tabs>

For example, the prompt above maps to `logger:create --name=Payments --module=payments`, then implements the `ILogger` methods against your chosen transport.
