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.
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. Theserial,parallel, anddaskengines are deprecated — usezonal_engine="exactextract"for new work. See the zonal statistics notebook for details.
Setup#
We use the same local test data as the zonal statistics notebook so this notebook works fully offline.
import logging
import geopandas as gpd
import rioxarray as rxr
from gdptools import ZonalGen
from gdptools.data.user_data import UserTiffData
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.
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.
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.
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:
# 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()
Quick reference#
Level |
What gdptools emits |
|---|---|
|
Internal state, geometry validation details, intersection data |
|
Workflow milestones, timing summaries, data dimensions, weight-gen progress |
|
Recoverable issues (e.g., antimeridian wrapping, CRS validation fallbacks) |
|
Failures that precede an exception being raised |
Common patterns#
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)