vorner / pyo3-log

Logging bridge from pyo3 native extension to python

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`log_enabled!` macro behavior

gephaistos opened this issue · comments

Hello!
I've encountered some strange behavior regarding log_enabled! macro that seems like a bug.
If it called before any call of another level-logging macros (except 'trace!'), it does not set the check properly: it always returns true no matter what logging settings are enabled.
Here is a patch with modified example that produces this issue.
It looks like there is no such a problem in flexi_logger, for example.

diff --git a/examples/hello_world/hw.py b/examples/hello_world/hw.py
index c45c67a..f10136b 100755
--- a/examples/hello_world/hw.py
+++ b/examples/hello_world/hw.py
@@ -5,6 +5,6 @@ import hello_world
 
 FORMAT = '%(levelname)s %(name)s %(asctime)-15s %(filename)s:%(lineno)d %(message)s'
 logging.basicConfig(format=FORMAT)
-logging.getLogger().setLevel(logging.INFO)
+logging.getLogger().setLevel(logging.CRITICAL)
 logging.info("Test 1")
 hello_world.log_hello()
diff --git a/examples/hello_world/src/lib.rs b/examples/hello_world/src/lib.rs
index bec87c7..11c31b7 100644
--- a/examples/hello_world/src/lib.rs
+++ b/examples/hello_world/src/lib.rs
@@ -1,12 +1,15 @@
-use log::{debug, trace, info};
+use log::{debug, trace, info, log_enabled, Level};
 use pyo3::prelude::*;
 use pyo3::wrap_pyfunction;
 use pyo3_log::{Caching, Logger};
 
 #[pyfunction]
 fn log_hello() {
+    println!("First call {}", log_enabled!(Level::Info));
     trace!("xyz");
+    println!("Second call {}", log_enabled!(Level::Info));
     debug!("stuff2");
+    println!("Third call {}", log_enabled!(Level::Info));
     debug!("Stuff");
     info!("Hello {}", "world");
     info!("Hello 2{}", "world");

Hello

Let me first provide some background for how it behaves now and discuss if you think it is a bug or a feature 😇.

I agree with you that in the ideal world, log_enabled would fully correspond to the fact the message gets or doesn't get logged. And for the flexi_logger you mention has everything under its control, so it „knows“ all the details.

This is a bit harder here, since all the details about what gets logged and what not is hidden somewhere in the intestines of python. Some guessing is possible from several observable things (like the log level of a certain logger), but it definitely is not 100% reliable ‒ there can be more filtering on the Python side we know nothing of and python is so flexible that it's probably impossible to discover all the ways how and where things may get filtered. Therefore, the log_enabled will always be somewhat of an approximation, erring on the safe side (that is preferring to create a message and throw it away over losing it).

Now, going over into Python is potentially expensive operation (it needs to lock the interpreter and that might become a bottleneck in multithreaded application ‒ and one of the good reasons to use Rust alongside with Python is to gain some performance or better multithreading support). Therefore, there's a cache of loggers so we don't have to lock if a message wouldn't get logged. This gets filled while sending a log message into Python.

Considering the motivation for log_enabled is to avoid doing extra work, it must be cheap to call. Therefore, it only looks into the cache without locking the interpreter. The situation where it wrongly answers true seemed acceptable (since it can't be precise anyway and since it'll get fixed the next time when a log message is created and thrown away, so if some part of code gets executed often and performance matters there, it gets slowed down only once).

That being said, if you still considers it a big enough issue to care and fix and come up with a patch that looks into the Python the first time log_enabled is called (and caches it for the next time) without introducing too much complexity to the code, I'll be happy to review & accept it.

I see, I guess that performance is more important here. I am not familiar with the crate source code and I don't think that fixing this issue would be an easy task. This is definitely out of my knowledge scope, so I am fine with how it works. Just noticed this behavior and thought that it could be an undetected bug... But since you are aware of it and it is expected, I'll close the issue. Anyway thanks for your time and detailed explanation.