---
jupyter:
  jupytext:
    formats: ipynb,md
    text_representation:
      extension: .md
      format_name: markdown
      format_version: '1.3'
      jupytext_version: 1.18.1
  kernelspec:
    display_name: Python 3 (ipykernel)
    language: python
    name: python3
---

# Configuring Logging in gdptools

`gdptools` uses Python's standard `logging` module for all diagnostic output.
By default the library emits **no messages** because it registers a
[`NullHandler`](https://docs.python.org/3/howto/logging.html#configuring-logging-for-a-library).
This notebook shows how to enable and customize logging so you can monitor
progress, debug issues, and control verbosity.

> **Note:** This notebook uses `zonal_engine="serial"` for logging demonstration
> purposes. The `serial`, `parallel`, and `dask` engines are deprecated — use
> `zonal_engine="exactextract"` for new work. See the
> [zonal statistics notebook](zonal_stats.ipynb) for details.


## Setup

We use the same local test data as the [zonal statistics notebook](zonal_stats.ipynb)
so this notebook works fully offline.

```python
import logging

import geopandas as gpd
import rioxarray as rxr

from gdptools import ZonalGen
from gdptools.data.user_data import UserTiffData
```

```python
rds = rxr.open_rasterio("../../../tests/data/rasters/slope/slope.tif")
gdf = gpd.read_file("../../../tests/data/Oahu.shp")

data = UserTiffData(
    source_var="slope",
    source_ds=rds,
    source_crs=26904,
    source_x_coord="x",
    source_y_coord="y",
    band=1,
    bname="band",
    target_gdf=gdf,
    target_id="fid",
)
```

## Enabling INFO-level logging

The simplest way to see `gdptools` output is to call `logging.basicConfig`.
At `INFO` level you get workflow milestones, timing summaries, and data
dimensions — enough to confirm things are progressing.

```python
logging.basicConfig(
    level=logging.INFO,
    format="%(name)s | %(levelname)s | %(message)s",
    force=True,
)

zg = ZonalGen(
    user_data=data,
    zonal_engine="serial",
    zonal_writer="csv",
    out_path=".",
    file_prefix="logging_demo",
)
stats = zg.calculate_zonal(categorical=False)
stats.head()
```

## Switching to DEBUG level

At `DEBUG` level `gdptools` logs internal state: geometry validation details,
intersection data, and spatial-index timing. This is useful when diagnosing
unexpected results.

```python
logging.basicConfig(
    level=logging.DEBUG,
    format="%(name)s | %(levelname)s | %(message)s",
    force=True,
)

stats = zg.calculate_zonal(categorical=False)
stats.head()
```

## Selective logging: gdptools only

Setting the root logger to `DEBUG` can produce a flood of output from
third-party libraries (rasterio, fiona, urllib3, etc.). A better approach is
to keep the root level at `WARNING` and lower only the `gdptools` logger.

```python
logging.basicConfig(
    level=logging.WARNING,
    format="%(name)s | %(levelname)s | %(message)s",
    force=True,
)
logging.getLogger("gdptools").setLevel(logging.DEBUG)

stats = zg.calculate_zonal(categorical=False)
stats.head()
```

## Logging to a file

For long-running jobs you may want to send log output to a file while keeping
the console quiet. Add a `FileHandler` to the `gdptools` logger:

```python
# Reset root logger to suppress console output
logging.basicConfig(level=logging.WARNING, force=True)

gdp_logger = logging.getLogger("gdptools")
gdp_logger.setLevel(logging.DEBUG)

fh = logging.FileHandler("gdptools_debug.log", mode="w")
fh.setFormatter(logging.Formatter("%(asctime)s | %(name)s | %(levelname)s | %(message)s"))
gdp_logger.addHandler(fh)

stats = zg.calculate_zonal(categorical=False)

# Show the first few lines of the log file
with open("gdptools_debug.log") as f:
    for line in f.readlines()[:10]:
        print(line, end="")

# Clean up the handler so it doesn't persist into later cells
gdp_logger.removeHandler(fh)
fh.close()
```

<!-- #region -->
## Quick reference

| Level     | What gdptools emits                                                          |
| :-------- | :--------------------------------------------------------------------------- |
| `DEBUG`   | Internal state, geometry validation details, intersection data               |
| `INFO`    | Workflow milestones, timing summaries, data dimensions, weight-gen progress   |
| `WARNING` | Recoverable issues (e.g., antimeridian wrapping, CRS validation fallbacks)   |
| `ERROR`   | Failures that precede an exception being raised                              |

### Common patterns

```python
import logging

# Quick: see everything
logging.basicConfig(level=logging.DEBUG)

# Recommended: gdptools detail, quiet third-party
logging.basicConfig(level=logging.WARNING)
logging.getLogger("gdptools").setLevel(logging.INFO)

# Production: log to file
fh = logging.FileHandler("gdp.log")
logging.getLogger("gdptools").addHandler(fh)
```
<!-- #endregion -->
