New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Filter log levels by target #10729
Filter log levels by target #10729
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
set_max_level(level); | ||
// TODO this should be whatever the most verbose log level specified in log_domain_levels - | ||
// but I'm not sure if it's actually much of a gain over just setting this to Trace. | ||
set_max_level(LevelFilter::Trace); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean we would be formatting the strings for log messages only to discard them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tdyas with this change we would execute format strings in Rust log!
macros (and debug!
, etc.), but we wouldn't generate the final format string in PantsLogger::log
since that only gets executed if PantsLogger::enabled
is true. If the performance hit from doing too much trace-level string formatting is too bad, we could probably hook into whatever system the log macros are using to know whether they need to print, and make that aware of this option too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat!
@@ -112,13 +146,26 @@ impl PantsLogger { | |||
|
|||
impl Log for PantsLogger { | |||
fn enabled(&self, metadata: &Metadata) -> bool { | |||
metadata.level() <= max_level() | |||
let global_level: LevelFilter = { *self.global_level.lock().borrow() }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is calling *foo.borrow()
the same thing as *&foo
, which I would expect to be the same thing as foo
but I think isn't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
borrow
is a method defined on RefCell
(https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.borrow). However, I don't think I actually need Mutex<RefCell<T>>
, just a Mutex
should be fine here, so I'm removing this call.
let global_level: LevelFilter = { *self.global_level.lock().borrow() }; | ||
let enabled_globally = metadata.level() <= global_level; | ||
let log_level_filters_lock = self.log_level_filters.lock(); | ||
let log_level_filters = log_level_filters_lock.borrow(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same thing as &log_level_filters_lock
? (I'm trying to understand .borrow()
)
type=bool, | ||
default=False, | ||
advanced=True, | ||
help="Display the target where a log message originates in that log message's output.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add: "This can be helpful when paired with the option --log-levels-by-target
"
help="Set a more specific logging level for one or more logging targets. " | ||
"The logging levels are one of: " | ||
'"error", "warn", "info", "debug", "trace".', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It'd be good to give an example. Maybe something like:
Set a more specific logging level for one or more logging targets. You can find the target names by enabling
--log-levels-by-target
. The logging levels are one of "error", "warn", "info", "debug", "trace". All unspecified targets use the global level set by-l
/--level
. For example, you can set{"workunit_store": "info", "pants.engine.rules": "warn"}
src/python/pants/init/logging.py
Outdated
raise ValueError("keys for log_domain_levels must be strings") | ||
if not isinstance(value, str): | ||
raise ValueError("values for log_domain_levels must be strings") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be good to include the bad value.
"Keys for log_domain_levels must be strings, but was given the key 1232 with type 'int'."
log_show_rust_3rdparty: bool, | ||
use_color: bool, | ||
show_target: bool, | ||
log_levels_by_target: Dict[str, LogLevel], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: the type hint for log_levels_by_target
everywhere can be Mapping
, given that you convert it into a dict on the next line.
Not a big deal, but can be useful given how frequently we use FrozenDict
.
self.native.write_log( | ||
msg=self.format(record), level=record.levelno, target=f"{record.name}:pid={os.getpid()}" | ||
) | ||
self.native.write_log(msg=self.format(record), level=record.levelno, target=record.name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to getting rid of the PID.
sources = { | ||
"src/python/project/__init__.py": "", | ||
"src/python/project/lib.py": dedent( | ||
"""\ | ||
def add(x: int, y: int) -> int: | ||
return x + y | ||
""" | ||
), | ||
"src/python/project/BUILD": "python_library()", | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than copying and pasting, can you please either use a @pytest.fixture
or make this value be a module-level constant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I don't think there's any need for this source file, if all you're running is list
. It's fine to have no tmpdir afaict.
ce5df2a
to
2e8cbb1
Compare
36fe18d
to
d7d48f0
Compare
Also remove PID in log target, explicitly log pantsd PID one time at startup [ci skip-build-wheels]
[ci skip-build-wheels]
# Building wheels and fs_util will be skipped. Delete if not intended. [ci skip-build-wheels]
# Building wheels and fs_util will be skipped. Delete if not intended. [ci skip-build-wheels]
d7d48f0
to
69b56db
Compare
(Large?) nit: "target" already has a pretty specific meaning in pants: https://www.pantsbuild.org/docs/target-api |
Problem
Pants's logging, particularly on the DEBUG and TRACE levels, is too verbose to make effective use of. We would like to be able to selectively enable more verbose logging for specific areas of the pants codebase where we think a problem we're trying to debug might lie, while leaving others at the default logging level.
Solution
The Rust and Python logging frameworks that Pants uses already have the concept of a target, that is, a name associated with a log object that comes from the area of the codebase where that log is emitted. For Python logs, that target name is a fully-qualified Python module (e.g.
pants.pantsd.service.pants_service
) and for Rust logs it is the name of the Rust module (e.g.workunit_store
).This commit adds a new global option
--log-levels-by-target
that expects a dictionary mapping strings representing these target names to the string representation of a Pants log level. By this mechanism, a user can specify that logs originating in a given part of the pants codebase will be subject to less filtering than other logs. Log targets not explicitly specified in this option are filtered according to the global log level specified with--level
.This commit also adds another new global option
--show-log-target
that simply adds the target name to log messages without doing any filtering, to make it easier for users casually inspecting logs to see what log targets might be relevant for further debugging.