Skip to content

Commit b695007

Browse files
authored
Merge branch 'main' into forman-60-custom_attrs
2 parents d27b435 + 29cab0b commit b695007

File tree

5 files changed

+116
-24
lines changed

5 files changed

+116
-24
lines changed

CHANGES.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@
1717
* Introduced new configuration setting `attrs_update_mode` that controls
1818
how dataset attributes are updated. [#59]
1919

20+
* Simplified logging to console. You can now set configuration setting `logging`
21+
to a log level which will implicitly enable console logging with given log
22+
level. [#64]
23+
24+
* Added a section in the notebook `examples/zappend-demo.ipynb`
25+
that demonstrates transaction rollbacks.
26+
27+
2028
* Added CLI option `--traceback`. [#57]
2129

2230
* Added a section in the notebook `examples/zappend-demo.ipynb`

docs/guide.md

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

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

777+
```json
778+
{
779+
"logging": true
780+
}
781+
```
782+
783+
The above uses log level `INFO`. If you want a different log level,
784+
just provide its name:
785+
786+
```json
787+
{
788+
"logging": "DEBUG"
789+
}
790+
```
791+
792+
If you also want logging output in a file or using a different format or if you want to
793+
see logging output of other Python modules, you can configure Python's logging
794+
system following the [logging dictionary schema](https://docs.python.org/3/library/logging.config.html#logging-config-dictschema).
781795
Given here is an example that logs `zappend`'s output to the console using
782-
the INFO level:
796+
the `INFO` level (same as `"logging": true`):
783797

784798
```json
785799
{
@@ -807,3 +821,5 @@ the INFO level:
807821
}
808822
```
809823

824+
Using the `loggers` entry you can configure the logger of other Python modules, e.g.,
825+
`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
@@ -298,9 +298,9 @@
298298
}
299299

300300

301-
LOGGING_SCHEMA = {
301+
DETAILED_LOGGING_SCHEMA = {
302302
"description": (
303-
f"Logging configuration. For details refer to the"
303+
f"Detailed logging configuration. For details refer to the"
304304
f" [dictionary schema]({LOG_REF_URL})"
305305
f" of the Python module `logging.config`."
306306
),
@@ -442,6 +442,27 @@
442442
"additionalProperties": True,
443443
}
444444

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