# Logging

AutoGen uses Python's built-in [`logging`](https://docs.python.org/3/library/logging.html) module.

There are two kinds of logging:

- **Trace logging**: This is used for debugging and is human readable messages to indicate what is going on. This is intended for a developer to understand what is happening in the code. The content and format of these logs should not be depended on by other systems.
  - Name: {py:attr}`~autogen_core.TRACE_LOGGER_NAME`.
- **Structured logging**: This logger emits structured events that can be consumed by other systems. The content and format of these logs can be depended on by other systems.
  - Name: {py:attr}`~autogen_core.EVENT_LOGGER_NAME`.
  - See the module {py:mod}`autogen_core.logging` to see the available events.
- {py:attr}`~autogen_core.ROOT_LOGGER_NAME` can be used to enable or disable all logs.

## Enabling logging output

To enable trace logging, you can use the following code:

```python
import logging

from autogen_core import TRACE_LOGGER_NAME

logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger(TRACE_LOGGER_NAME)
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)
```

To enable structured logging, you can use the following code:

```python
import logging

from autogen_core import EVENT_LOGGER_NAME

logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger(EVENT_LOGGER_NAME)
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.INFO)
```

### Structured logging

Structured logging allows you to write handling logic that deals with the actual events including all fields rather than just a formatted string.

For example, if you had defined this custom event and were emitting it. Then you could write the following handler to receive it.

```python
import logging
from dataclasses import dataclass

@dataclass
class MyEvent:
    timestamp: str
    message: str

class MyHandler(logging.Handler):
    def __init__(self) -> None:
        super().__init__()

    def emit(self, record: logging.LogRecord) -> None:
        try:
            # Use the StructuredMessage if the message is an instance of it
            if isinstance(record.msg, MyEvent):
                print(f"Timestamp: {record.msg.timestamp}, Message: {record.msg.message}")
        except Exception:
            self.handleError(record)
```

And this is how you could use it:

```python
logger = logging.getLogger(EVENT_LOGGER_NAME)
logger.setLevel(logging.INFO)
my_handler = MyHandler()
logger.handlers = [my_handler]
```

## Emitting logs

These two names are the root loggers for these types. Code that emits logs should use a child logger of these loggers. For example, if you are writing a module `my_module` and you want to emit trace logs, you should use the logger named:

```python
import logging

from autogen_core import TRACE_LOGGER_NAME
logger = logging.getLogger(f"{TRACE_LOGGER_NAME}.my_module")
```

### Emitting structured logs

If your event is a dataclass, then it could be emitted in code like this:

```python
import logging
from dataclasses import dataclass
from autogen_core import EVENT_LOGGER_NAME

@dataclass
class MyEvent:
    timestamp: str
    message: str

logger = logging.getLogger(EVENT_LOGGER_NAME + ".my_module")
logger.info(MyEvent("timestamp", "message"))
```
