Skip to content

Commit

Permalink
configuration: add log_level to configuration_opts
Browse files Browse the repository at this point in the history
Add `CollectorBase.setLoggers(logger_names)` as a means for collectors
derived from `CollectorBase` to easily configure logging-levels. The new
method uses the `collector_opts.logging_level` value (if set in the
configuration) to set the logging-level of any loggers given to it.
  • Loading branch information
olaf-mandel committed Oct 6, 2024
1 parent 62b6e3b commit 6cbc257
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](http://semver.org/) and [Keep a Ch
### New
* Fix \#47 - add environment variables for fundamental parameters
* configuration: add logging section
* configuration: add log_level to configuration_opts

### Changes

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ collectors:
- netdev
collector_opts:
netdev:
log_level: DEBUG
whitelist:
blacklist:
- docker0
Expand All @@ -121,6 +122,10 @@ logging:
target: /path/to/my/collector/logfile.log
```
The `collector_opts` can optionally contain a `log_level` entry which
will configure the logging-level for that specific collector. Note that
support for this must be implemented by each individual collector.

Logging can optionally be configured for any logger. The entries must
specify the name of the logger and can optionally specify a
logging-level (default: stay at whatever the default logging-level for
Expand Down
19 changes: 19 additions & 0 deletions p3exporter/collector/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,25 @@ def collector_name_from_class(self):

return '_'.join(class_name_parts)

def setLoggers(self, logger_names: list | str):
"""Configure the provided logger(s) according to the CollectorConfig
It is recommended to call this method from the constructor of any
deriving class. Either bump the required p3exporter version or check
dynamically if the method is supported.
:param logger_names: Name or names of loggers to configure.
:type logger_names: list or str
"""
if not isinstance(logger_names, list):
logger_names = [logger_names]
if "log_level" not in self.opts:
return
level = self.opts["log_level"]
for name in logger_names:
logger = logging.getLogger(name)
logger.setLevel(level)


class Collector(object):
"""Base class to load collectors.
Expand Down
49 changes: 49 additions & 0 deletions tests/test_cases/logging_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from p3exporter import setup_logging
from p3exporter.collector import CollectorBase, CollectorConfig
import logging
import os.path
import pytest
Expand Down Expand Up @@ -105,3 +106,51 @@ def test_logging_levels(cfg_logging, levels, targets):
handler = added_handlers[0]
assert isinstance(handler, logging.FileHandler)
assert handler.baseFilename == os.path.abspath(targets[i])


class FooCollector(CollectorBase):
pass

data_collectorbase_setloggers = [
pytest.param(None,
["foo", "bar"],
[logging.WARNING, logging.NOTSET, logging.NOTSET],
id="no log_level setting"),
pytest.param("CRITICAL",
"foo",
[logging.WARNING, logging.CRITICAL, logging.NOTSET],
id="single logger-name"),
pytest.param("ERROR",
["foo", "bar"],
[logging.WARNING, logging.ERROR, logging.ERROR],
id="list of loggers"),
pytest.param(20,
["", "foo"],
[logging.INFO, logging.INFO, logging.NOTSET],
id="numeric log_level"),
]

@pytest.mark.parametrize("cfg_log_level,logger_names,expected",
data_collectorbase_setloggers)
def test_collectorbase_setloggers(cfg_log_level, logger_names, expected):
# GIVEN an input config-dictionary
cfg = {
"exporter_name": "Test only",
"collectors": ["foo"],
"collector_opts": {
"foo": {}
},
}
if cfg_log_level is not None:
cfg["collector_opts"]["foo"]["log_level"] = cfg_log_level

# AND a collector-base using this config
collector = FooCollector(CollectorConfig(**cfg))

# WHEN the setLoggers() method is called
collector.setLoggers(logger_names)

# THEN the logging-levels should get changed to the expected
for i, name in enumerate(loggers):
logger = logging.getLogger(name)
assert logger.level == expected[i]

0 comments on commit 6cbc257

Please sign in to comment.