# Logging

SGN uses Python's standard `logging` module with a logger hierarchy rooted at
`sgn`. Each element gets its own child logger named `sgn.<element_name>`,
enabling fine-grained control over log output.

## Enable Logging

Set the `SGNLOGLEVEL` environment variable to activate logging. The simplest
form sets the level for all SGN loggers:

```bash
SGNLOGLEVEL=INFO python my_pipeline.py
```

## Per-Element Logging

To set different log levels for specific elements, use `name:LEVEL` pairs
separated by spaces:

```bash
SGNLOGLEVEL="WARNING my_source:DEBUG" python my_pipeline.py
```

This sets the root `sgn` logger to `WARNING` while setting
`sgn.my_source` to `DEBUG`. Only the element named `"my_source"` will
produce debug output — all other elements log at `WARNING` or above.

Multiple elements can be configured independently:

```bash
SGNLOGLEVEL="WARNING my_source:DEBUG my_transform:INFO" python my_pipeline.py
```

## Available Log Levels

| Level      | Value | Description                          |
|------------|-------|--------------------------------------|
| `MEMPROF`  | 5     | Memory profiling (see [Profile Memory](profile-memory.md)) |
| `DEBUG`    | 10    | Pad-level frame details              |
| `INFO`     | 20    | Pipeline iteration progress          |
| `WARNING`  | 30    | Default — only warnings and errors   |
| `ERROR`    | 40    | Error conditions                     |
| `CRITICAL` | 50    | Fatal errors                         |

## Using the Element Logger

Every element has a `logger` property that returns a logger scoped to that
element. Use it inside your element methods for structured logging:

```{.python notest}
from dataclasses import dataclass
from sgn import TransformElement, Frame, SinkPad, SourcePad

@dataclass
class MyTransform(TransformElement):
    def pull(self, pad: SinkPad, frame: Frame) -> None:
        self.logger.debug("Received frame on %s: %s", pad.pad_name, frame.data)
        self.in_frame = frame

    def new(self, pad: SourcePad) -> Frame:
        result = process(self.in_frame.data)
        self.logger.info("Produced result: %s", result)
        return Frame(data=result)
```

The logger name follows the pattern `sgn.<element_name>`, so an element with
`name="my_transform"` logs under `sgn.my_transform`. This is the same name
used in the `SGNLOGLEVEL` configuration.

## Built-in Debug Logging

At `DEBUG` level, SGN automatically logs every frame as it passes through each
pad. This is handled internally — you don't need to add any logging code to see
frame flow through your pipeline.
