Metadata-Version: 2.4
Name: simpac-logger
Version: 0.2.0
Summary: Colored console + daily file logger for Python, zero dependencies
Author: SIMPAC AI LAB
Keywords: logging,logger,color,ansi,daily,file
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Logging
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: build; extra == "dev"
Dynamic: license-file

# simpac-logger

[![PyPI](https://img.shields.io/pypi/v/simpac-logger)](https://pypi.org/project/simpac-logger/)
[![Python](https://img.shields.io/pypi/pyversions/simpac-logger)](https://pypi.org/project/simpac-logger/)
![License](https://img.shields.io/badge/license-MIT-green)

A Python logger you set up in one line: **colored console output by level** plus a
**daily log file under `logs/`**, with optional size-based rotation. Standard library only,
no dependencies. Maintained by the SIMPAC AI Lab.

```python
from simpac_logger import get_logger

log = get_logger(__name__)

log.debug("detailed information")   # blue
log.info("general information")
log.success("task completed")        # green
log.warning("something to watch")    # orange
log.error("something failed")        # red
log.critical("fatal error")          # bold white on red
```

Console:

```
15:04:12 | DEBUG    | myapp | detailed information
15:04:12 | INFO     | myapp | general information
15:04:12 | SUCCESS  | myapp | task completed
15:04:12 | WARNING  | myapp | something to watch
15:04:12 | ERROR    | myapp | something failed
15:04:12 | CRITICAL | myapp | fatal error
```

`logs/2026-09-07.log` (no color codes):

```
2026-09-07 15:04:12.031 | DEBUG    | myapp | detailed information
2026-09-07 15:04:12.031 | INFO     | myapp | general information
2026-09-07 15:04:12.032 | SUCCESS  | myapp | task completed
...
```

## Installation

```bash
pip install simpac-logger
```

In `requirements.txt`:

```
simpac-logger>=0.2.0
```

## Usage

### `get_logger()` arguments

| Argument | Default | Description |
|---|---|---|
| `name` | `"simpac"` | Logger name, usually `__name__`. Calling again with the same name does not add handlers; it only updates the levels |
| `level` | `"DEBUG"` | Minimum level for console output, as a string or an int |
| `log_dir` | `"logs"` | Directory for log files, created if missing. Relative paths are resolved against the current working directory. Can also be set with the `SIMPAC_LOG_DIR` environment variable |
| `to_file` | `True` | `False` disables the file handler |
| `file_level` | `"DEBUG"` | Minimum level written to the file |
| `color` | `None` | `None` auto-detects; `True`/`False` forces the choice |
| `stream` | `sys.stdout` | Console output stream; pass `sys.stderr` to switch |
| `max_bytes` | `0` | Start a new part when the day's file would grow past this many bytes; `0` disables size rotation |
| `backup_count` | `0` | Rotated parts to keep per day when `max_bytes` is set; `0` keeps all of them |

```python
# INFO and above on the console, everything in the file, custom directory
log = get_logger("crawler", level="INFO", log_dir="output/logs")

# console only
log = get_logger("quick", to_file=False)

# cap each file at 10 MB and keep at most 5 rotated parts per day
log = get_logger("worker", max_bytes=10 * 1024 * 1024, backup_count=5)
```

### Levels

| Level | Value | Color |
|---|---|---|
| DEBUG | 10 | blue |
| INFO | 20 | default |
| **SUCCESS** | **25** | green |
| WARNING | 30 | orange |
| ERROR | 40 | red |
| CRITICAL | 50 | bold white on red |

`SUCCESS` is added by this package. Use `level="SUCCESS"` to hide INFO messages while
keeping success messages visible.

### Color detection

1. `NO_COLOR` is set: always off
2. `FORCE_COLOR` is set: always on
3. `TERM=dumb`: off
4. Jupyter (ipykernel) output stream: on
5. Otherwise on only when the stream is a TTY, so colors disappear automatically when piped or redirected

On Windows 10 and later the console's ANSI mode is enabled automatically.

### Daily files and size rotation

- File names follow `logs/YYYY-MM-DD.log` in local time.
- A process running past midnight writes subsequent records to the new day's file.
- Multiple runs on the same day append to the same file.
- With `max_bytes` set, a file that would grow past the limit is renamed to
  `YYYY-MM-DD.001.log` (then `.002.log` and so on) and a fresh `YYYY-MM-DD.log` is started.
  The live file always keeps the plain date name, and the numbered parts sort in
  chronological order, oldest first.
- `backup_count` limits how many numbered parts are kept for each day; the oldest are deleted
  first. Files from previous days are never deleted.
- Add `logs/` to your `.gitignore`.

A busy day with `max_bytes` set looks like this:

```
logs/
├── 2026-09-06.log
├── 2026-09-07.001.log   # oldest part of the day
├── 2026-09-07.002.log
└── 2026-09-07.log       # live file
```

### Working with existing `logging` code

`get_logger()` returns a subclass of the standard `logging.Logger`, so `exception()`, `log()`,
filters and extra handlers work as usual. If a logger with the same name was already created
with `logging.getLogger(__name__)`, `get_logger(__name__)` attaches the handlers and a
`success()` method to that existing logger. Propagation to the root logger is turned off, so
records are not printed twice when the root logger has handlers of its own.

### Limitations

- `log_dir` is relative to the current working directory, not to the script. Scripts started
  from cron or from another directory should pass an absolute path, for example
  `Path(__file__).resolve().parent / "logs"`.
- Old daily files are never deleted. `backup_count` only limits size-rotated parts within a
  day; use a scheduled job or `logrotate` for long-term retention.
- Several processes writing to the same file are not coordinated: lines may interleave, and a
  size rotation done by one process is not seen by the others. Give each process its own
  `log_dir`.
- Handlers are the standard blocking ones from `logging`; there is no asynchronous mode.

## Development

```bash
python -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
pytest
python examples/demo.py
```

Release steps for maintainers are in `CONTRIBUTING.md`.

## License

MIT
