Skip to content

Commit 29cab0b

Browse files
authored
Merge pull request #67 from bcdev/forman-64-console_logging
Simplify logging configuration
2 parents eb62368 + 6fa9dd9 commit 29cab0b

File tree

5 files changed

+112
-24
lines changed

5 files changed

+112
-24
lines changed

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
### Enhancements
44

5+
* Simplified logging to console. You can now set configuration setting `logging`
6+
to a log level which will implicitly enable console logging with given log
7+
level. [#64]
8+
59
* Added a section in the notebook `examples/zappend-demo.ipynb`
610
that demonstrates transaction rollbacks.
711

docs/guide.md

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -691,14 +691,28 @@ the [Configuration Reference](config.md) for more details.
691691
## Logging
692692

693693
The `zappend` logging output is configured using the `logging` setting.
694-
Its configuration follows exactly the
695-
[dictionary schema](https://docs.python.org/3/library/logging.config.html#logging-config-dictschema)
696-
of the Python module `logging.config`. The logger used by the `zappend` tool is named
697-
`zappend`. Note that you can also configure the logger of other Python modules, e.g.,
698-
`xarray` or `dask` using an entry in the `loggers` setting.
694+
In the simplest case, if you just want logging output from `zappend` to the console:
699695

696+
```json
697+
{
698+
"logging": true
699+
}
700+
```
701+
702+
The above uses log level `INFO`. If you want a different log level,
703+
just provide its name:
704+
705+
```json
706+
{
707+
"logging": "DEBUG"
708+
}
709+
```
710+
711+
If you also want logging output in a file or using a different format or if you want to
712+
see logging output of other Python modules, you can configure Python's logging
713+
system following the [logging dictionary schema](https://docs.python.org/3/library/logging.config.html#logging-config-dictschema).
700714
Given here is an example that logs `zappend`'s output to the console using
701-
the INFO level:
715+
the `INFO` level (same as `"logging": true`):
702716

703717
```json
704718
{
@@ -726,3 +740,5 @@ the INFO level:
726740
}
727741
```
728742

743+
Using the `loggers` entry you can configure the logger of other Python modules, e.g.,
744+
`xarray` or `dask`. The logger used by the `zappend` tool is named `zappend`.

tests/test_log.py

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,27 @@
1111

1212

1313
class LogTest(unittest.TestCase):
14+
old_level = None
15+
old_handlers = None
16+
17+
@classmethod
18+
def setUpClass(cls):
19+
cls.old_level = logger.level
20+
cls.old_handlers = list(logger.handlers)
21+
for h in cls.old_handlers:
22+
logger.removeHandler(h)
23+
24+
def tearDown(self):
25+
logger.setLevel(self.old_level)
26+
for h in self.old_handlers:
27+
logger.addHandler(h)
28+
1429
def test_logger(self):
1530
self.assertIsInstance(logger, logging.Logger)
1631
self.assertEqual(logging.NOTSET, logger.level)
1732
self.assertEqual(1, len(logger.handlers))
1833

19-
def test_configure_logging(self):
34+
def test_configure_logging_dict(self):
2035
logging_config = {
2136
"version": 1,
2237
"formatters": {
@@ -31,19 +46,31 @@ def test_configure_logging(self):
3146
"loggers": {"zappend": {"level": "INFO", "handlers": ["console"]}},
3247
}
3348

34-
old_level = logger.level
35-
old_handlers = list(logger.handlers)
36-
for h in old_handlers:
37-
logger.removeHandler(h)
49+
configure_logging(logging_config)
50+
self.assertEqual(logging.INFO, logger.level)
51+
self.assertEqual(1, len(logger.handlers))
52+
self.assertIsInstance(logger.handlers[0], logging.StreamHandler)
3853

39-
try:
40-
configure_logging(logging_config)
41-
self.assertEqual(logging.INFO, logger.level)
42-
self.assertEqual(1, len(logger.handlers))
43-
finally:
44-
logger.setLevel(old_level)
45-
for h in old_handlers:
46-
logger.addHandler(h)
54+
def test_configure_logging_false(self):
55+
logging_config = False
56+
configure_logging(logging_config)
57+
self.assertEqual(logging.NOTSET, logger.level)
58+
self.assertEqual(1, len(logger.handlers))
59+
self.assertIsInstance(logger.handlers[0], logging.StreamHandler)
60+
61+
def test_configure_logging_true(self):
62+
logging_config = True
63+
configure_logging(logging_config)
64+
self.assertEqual(logging.INFO, logger.level)
65+
self.assertEqual(1, len(logger.handlers))
66+
self.assertIsInstance(logger.handlers[0], logging.StreamHandler)
67+
68+
def test_configure_logging_level(self):
69+
logging_config = "WARNING"
70+
configure_logging(logging_config)
71+
self.assertEqual(logging.WARNING, logger.level)
72+
self.assertEqual(1, len(logger.handlers))
73+
self.assertIsInstance(logger.handlers[0], logging.StreamHandler)
4774

4875
def test_get_log_level(self):
4976
self.assertEqual(logging.DEBUG, get_log_level("DEBUG"))

zappend/config/schema.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,9 @@
297297
}
298298

299299

300-
LOGGING_SCHEMA = {
300+
DETAILED_LOGGING_SCHEMA = {
301301
"description": (
302-
f"Logging configuration. For details refer to the"
302+
f"Detailed logging configuration. For details refer to the"
303303
f" [dictionary schema]({LOG_REF_URL})"
304304
f" of the Python module `logging.config`."
305305
),
@@ -441,6 +441,27 @@
441441
"additionalProperties": True,
442442
}
443443

444+
LOGGING_SCHEMA = {
445+
"description": "Logging configuration.",
446+
"oneOf": [
447+
{
448+
"description": (
449+
"Shortform that enables logging to the console"
450+
' using log level `"INFO"`.'
451+
),
452+
"type": "boolean",
453+
},
454+
{
455+
"description": (
456+
"Shortform that enables logging to the console"
457+
" using the specified log level."
458+
),
459+
"enum": LOG_LEVELS,
460+
},
461+
DETAILED_LOGGING_SCHEMA,
462+
],
463+
}
464+
444465
CONFIG_SCHEMA_V1 = {
445466
"title": "Configuration Reference",
446467
"type": "object",

zappend/log.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,26 @@ def get_log_level(level_name: str) -> int:
2525
return _nameToLevel.get(level_name, logging.NOTSET)
2626

2727

28-
def configure_logging(logging_config: dict[str, Any] | None):
29-
if logging_config:
30-
logging.config.dictConfig(logging_config)
28+
def configure_logging(logging_config: dict[str, Any] | str | bool | None):
29+
if not logging_config:
30+
return
31+
if isinstance(logging_config, (str, bool)):
32+
logging_config = {
33+
"version": 1,
34+
"formatters": {
35+
"normal": {
36+
"format": "%(asctime)s %(levelname)s %(message)s",
37+
"style": "%",
38+
}
39+
},
40+
"handlers": {
41+
"console": {"class": "logging.StreamHandler", "formatter": "normal"}
42+
},
43+
"loggers": {
44+
"zappend": {
45+
"level": _nameToLevel.get(logging_config, logging.INFO),
46+
"handlers": ["console"],
47+
}
48+
},
49+
}
50+
logging.config.dictConfig(logging_config)

0 commit comments

Comments
 (0)