From 1f74b0a133119703673aa129d85a1db335b905b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Dr=C3=B6nner?= Date: Wed, 29 Jul 2026 15:02:44 +0200 Subject: [PATCH 1/3] fix(python): y_pixel_size may be positive --- python/geoengine/types.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/geoengine/types.py b/python/geoengine/types.py index 7d32ac9a3c..e621a4e916 100644 --- a/python/geoengine/types.py +++ b/python/geoengine/types.py @@ -1751,8 +1751,12 @@ class GeoTransform: def __init__(self, x_min: float, y_max: float, x_pixel_size: float, y_pixel_size: float): """Initialize a new `GeoTransform`""" + # Note: We use the GeoTransform in API to adress two types in the backend. + # The first type is the backend GeoTransform. In this case, the x_pixel_size is always positive and the y_pixel_size is always negative. + # The second type is the GdalGeoTransform. In this case, the x_pixel_size is always positive and the y_pixel_size is in most cases negative. + # BUT there are cases where y_pixel_size is positive. Therefore, we only check that x_pixel_size is positive and y_pixel_size is not zero. assert x_pixel_size > 0, "In Geo Engine, x_pixel_size is always positive." - assert y_pixel_size < 0, "In Geo Engine, y_pixel_size is always negative." + assert y_pixel_size != 0, "y_pixel_size must not be zero." self.x_min = x_min self.y_max = y_max From 0e44489fc2a1be5e26dbbbd3a7be8287326a30f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Dr=C3=B6nner?= Date: Wed, 29 Jul 2026 15:19:13 +0200 Subject: [PATCH 2/3] ruff ruff --- python/geoengine/types.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/python/geoengine/types.py b/python/geoengine/types.py index e621a4e916..67cb26691e 100644 --- a/python/geoengine/types.py +++ b/python/geoengine/types.py @@ -1752,9 +1752,11 @@ def __init__(self, x_min: float, y_max: float, x_pixel_size: float, y_pixel_size """Initialize a new `GeoTransform`""" # Note: We use the GeoTransform in API to adress two types in the backend. - # The first type is the backend GeoTransform. In this case, the x_pixel_size is always positive and the y_pixel_size is always negative. - # The second type is the GdalGeoTransform. In this case, the x_pixel_size is always positive and the y_pixel_size is in most cases negative. - # BUT there are cases where y_pixel_size is positive. Therefore, we only check that x_pixel_size is positive and y_pixel_size is not zero. + # The first type is the backend GeoTransform. In this case, the x_pixel_size is always positive \ + # and the y_pixel_size is always negative. + # The second type is the GdalGeoTransform. In this case, the x_pixel_size is always positive \ + # and the y_pixel_size is in most cases negative. + # BUT there are cases where y_pixel_size is positive. Therefore, we only check that y_pixel_size is not zero. assert x_pixel_size > 0, "In Geo Engine, x_pixel_size is always positive." assert y_pixel_size != 0, "y_pixel_size must not be zero." From a35887bc9a171c4234f92e6b9cf6c064dc5edfd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Dr=C3=B6nner?= Date: Fri, 31 Jul 2026 19:01:04 +0200 Subject: [PATCH 3/3] fix: console logging not really async --- .../operators/src/bin/gdalsource_process_main.rs | 13 ++++++++----- geoengine/services/src/bin/geoengine-server.rs | 16 +++++++++++----- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/geoengine/operators/src/bin/gdalsource_process_main.rs b/geoengine/operators/src/bin/gdalsource_process_main.rs index 0415e12277..bfd0264d4d 100644 --- a/geoengine/operators/src/bin/gdalsource_process_main.rs +++ b/geoengine/operators/src/bin/gdalsource_process_main.rs @@ -108,13 +108,16 @@ fn init_subscriber( logging_config: &WorkerLoggingConfig, open_telemetry_config: &OpenTelemetryConfig, token: &str, -) -> (Option, Option) { +) -> (Option, WorkerGuard, Option) { + // ponytail: reuse the same non-blocking writer pattern as the file layer to avoid + // blocking the event thread when the PTY can't keep up; lines are dropped when full + let (non_blocking_writer, stderr_guard) = tracing_appender::non_blocking(std::io::stderr()); let stderr_layer = tracing_subscriber::fmt::layer() .pretty() .with_file(false) .with_target(true) .with_ansi(true) - .with_writer(std::io::stderr) + .with_writer(non_blocking_writer) .with_filter(EnvFilter::new(&logging_config.log_spec)); let (file_layer, file_guard) = if logging_config.log_to_file { @@ -162,14 +165,14 @@ fn init_subscriber( .with(opentelemetry) .init(); - return (Some(provider), file_guard); + return (Some(provider), stderr_guard, file_guard); } tracing_subscriber::registry() .with(stderr_layer) .with(file_layer) .init(); - (None, file_guard) + (None, stderr_guard, file_guard) } // We use a custom formatter because there are still format flags within spans even when @@ -227,7 +230,7 @@ fn main() { .expect("Failed to create tokio runtime for telemetry"); let runtime_guard = runtime.enter(); - let (provider, _file_guard) = init_subscriber( + let (provider, _stderr_guard, _file_guard) = init_subscriber( &worker_config.logging, &worker_config.open_telemetry, &token, diff --git a/geoengine/services/src/bin/geoengine-server.rs b/geoengine/services/src/bin/geoengine-server.rs index c1c624ec59..1eabeec87b 100644 --- a/geoengine/services/src/bin/geoengine-server.rs +++ b/geoengine/services/src/bin/geoengine-server.rs @@ -38,7 +38,8 @@ pub async fn start_server() -> Result<()> { EnvFilter::try_new(&logging_config.log_spec).expect("to have a valid log spec"); // create a log layer for output to the console and add it to the registry - let registry = registry.with(console_layer_with_filter(console_filter)); + let (console_layer, _console_guard) = console_layer_with_filter(console_filter); + let registry = registry.with(console_layer); // create a filter for the log message level in file output. Since the console_filter is not copy or clone, we have to create a new one. TODO: allow a different log level for file output. let file_filter = @@ -111,18 +112,23 @@ where Ok(opentelemetry) } -fn console_layer_with_filter + 'static>(filter: F) -> impl Layer +fn console_layer_with_filter + 'static>( + filter: F, +) -> (impl Layer + use, WorkerGuard) where S: Subscriber, for<'a> S: LookupSpan<'a>, { - tracing_subscriber::fmt::layer() + // blocking the event thread when the PTY can't keep up; lines are dropped when full + let (non_blocking_writer, guard) = tracing_appender::non_blocking(std::io::stderr()); + let layer = tracing_subscriber::fmt::layer() .pretty() .with_file(false) .with_target(true) .with_ansi(true) - .with_writer(std::io::stderr) - .with_filter(filter) + .with_writer(non_blocking_writer) + .with_filter(filter); + (layer, guard) } // we use a custom formatter because there are still format flags within spans even when `with_ansi` is false due to bug: https://github.com/tokio-rs/tracing/issues/1817