Skip to content

Commit 705793f

Browse files
committed
Added logging configuration
1 parent cf3a5ca commit 705793f

File tree

8 files changed

+359
-73
lines changed

8 files changed

+359
-73
lines changed

CONFIG.md

Lines changed: 90 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
Configuration for the zappend tool.
1+
## Configuration for the `zappend` tool
2+
23

34
### `version`
45

5-
Configuration version.
6+
Configuration schema version. Allows the schema to evolve while still preserving backwards compatibility.
67
It's value is `1`.
78

89
### `target_uri`
@@ -35,11 +36,12 @@ Must be one of the following:
3536
It's value is `true`.
3637
* Type _object_.
3738
Polling parameters.
39+
The keys `interval`, `timeout` are required.
40+
3841
* `interval`:
3942
Type _number_.
4043
Polling interval in seconds.
4144
Defaults to `2`.
42-
4345
* `timeout`:
4446
Type _number_.
4547
Polling timeout in seconds.
@@ -66,7 +68,6 @@ It's value is `2`.
6668
Type _object_.
6769
Specifies the fixed dimensions of the target dataset. Keys are dimension names, values are dimension sizes.
6870
Object values are:
69-
7071
Type _integer_.
7172

7273
### `append_dim`
@@ -80,28 +81,26 @@ Defaults to `"time"`.
8081
Type _object_.
8182
Defines dimensions, encoding, and attributes for variables in the target dataset. Object property names refer to variable names. The special name `*` refers to all variables, which is useful for defining common values.
8283
Object values are:
83-
8484
Type _object_.
85-
Variable metadata
85+
Variable metadata.
86+
8687
* `dims`:
8788
Type _array_.
8889
The names of the variable's dimensions in the given order. Each dimension must exist in contributing datasets.
89-
9090
* `encoding`:
9191
Type _object_.
9292
Variable storage encoding. Settings given here overwrite the encoding settings of the first contributing dataset.
93+
9394
* `dtype`:
9495
Storage data type
9596
Must be one of `"int8", "uint8", "int16", "uint16", "int32", "uint32", "int64", "uint64", "float32", "float64"`.
96-
9797
* `chunks`:
9898
Storage chunking.
9999
Must be one of the following:
100100
* Type _array_.
101101
Chunk sizes in the order of the dimensions.
102102
* Disable chunking.
103103
It's value is `null`.
104-
105104
* `fill_value`:
106105
Storage fill value.
107106
Must be one of the following:
@@ -111,36 +110,30 @@ Variable metadata
111110
It's value is `"NaN"`.
112111
* No fill value.
113112
It's value is `null`.
114-
115113
* `scale_factor`:
116114
Type _number_.
117115
Scale factor for computing the in-memory value: `memory_value = scale_factor * storage_value + add_offset`.
118-
119116
* `add_offset`:
120117
Type _number_.
121118
Add offset for computing the in-memory value: `memory_value = scale_factor * storage_value + add_offset`.
122-
123119
* `units`:
124120
Type _string_.
125121
Units of the storage data type if memory data type is date/time.
126-
127122
* `calendar`:
128123
Type _string_.
129124
The calendar to be used if memory data type is date/time.
130-
131125
* `compressor`:
132126
Type _array_ | _null_.
133127
Compressor. Set to `null` to disable data compression.
128+
The key `id` is required.
129+
134130
* `id`:
135131
Type _string_.
136132

137-
$`$id` are required.
138-
139133
* `filters`:
140134
Type _array_ | _null_.
141135
Filters. Set to `null` to not use filters.
142136

143-
144137
* `attrs`:
145138
Type _object_.
146139
Arbitrary variable metadata attributes.
@@ -160,4 +153,83 @@ Specifies the names of individual variables to be excluded from all contributin
160153

161154
Type _boolean_.
162155
If 'true', log only what would have been done, but don't apply any changes.
163-
Defaults to `false`.
156+
Defaults to `false`.
157+
158+
### `logging`
159+
160+
Type _object_.
161+
Logging configuration. For details refer to the [dictionary schema](https://docs.python.org/3/library/logging.config.html#logging-config-dictschema) of the Python module `logging.config`.
162+
The key `version` is required.
163+
164+
* `version`:
165+
Logging schema version.
166+
It's value is `1`.
167+
* `formatters`:
168+
Type _object_.
169+
Formatter definitions. Each key is a formatter id and each value is an object describing how to configure the corresponding formatter.
170+
Object values are:
171+
Type _object_.
172+
Formatter configuration.
173+
174+
* `format`:
175+
Type _string_.
176+
Format string in the given `style`.
177+
Defaults to `"%(message)s"`.
178+
* `datefmt`:
179+
Type _string_.
180+
Format string in the given `style` for the date/time portion.
181+
Defaults to `"%Y-%m-%d %H:%M:%S,uuu"`.
182+
* `style`:
183+
Determines how the format string will be merged with its data.
184+
Must be one of `"%", "{", "$"`.
185+
186+
* `filters`:
187+
Type _object_.
188+
Filter definitions. Each key is a filter id and each value is a dict describing how to configure the corresponding filter.
189+
Object values are:
190+
Type _object_.
191+
Filter configuration.
192+
* `handlers`:
193+
Type _object_.
194+
Handler definitions. Each key is a handler id and each value is an object describing how to configure the corresponding handler.
195+
Object values are:
196+
Type _object_.
197+
Handler configuration. All keys other than the following are passed through as keyword arguments to the handler's constructor.
198+
The key `class` is required.
199+
200+
* `class`:
201+
Type _string_.
202+
The fully qualified name of the handler class. See [logging handlers](https://docs.python.org/3/library/logging.handlers.html).
203+
* `level`:
204+
The level of the handler.
205+
Must be one of `"CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "NOTSET"`.
206+
* `formatter `:
207+
Type _string_.
208+
The id of the formatter for this handler.
209+
* `filters`:
210+
Type _array_.
211+
A list of ids of the filters for this logger.
212+
213+
* `loggers`:
214+
Type _object_.
215+
Logger definitions. Each key is a logger name and each value is an object describing how to configure the corresponding logger. The tool's logger has the id `'zappend'`.
216+
Object values are:
217+
Type _object_.
218+
Logger configuration.
219+
220+
* `level`:
221+
The level of the logger.
222+
Must be one of `"CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "NOTSET"`.
223+
* `propagate `:
224+
Type _boolean_.
225+
The propagation setting of the logger.
226+
* `filters`:
227+
Type _array_.
228+
A list of ids of the filters for this logger.
229+
* `handlers`:
230+
Type _array_.
231+
A list of ids of the handlers for this logger.
232+
233+
234+
235+

tests/test_cli.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
1818
Options:
1919
-c, --config CONFIG Configuration JSON or YAML file. If multiple are
20-
passed, they will be deeply merged into one.
20+
passed, subsequent configurations are incremental to
21+
the previous ones.
2122
-t, --target TARGET Target Zarr dataset path or URI. Overrides the
2223
'target_uri' configuration field.
2324
--dry-run Run the tool without creating, changing, or deleting

tests/test_config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ def test_schema(self):
213213
'excluded_variables',
214214
'fixed_dims',
215215
'included_variables',
216+
'logging',
216217
'slice_engine',
217218
'slice_polling',
218219
'slice_storage_options',

tests/test_log.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Copyright © 2024 Norman Fomferra
2+
# Permissions are hereby granted under the terms of the MIT License:
3+
# https://opensource.org/licenses/MIT.
4+
import logging
5+
import unittest
6+
from click.testing import CliRunner
7+
8+
from zappend.log import logger
9+
from zappend.log import configure_logging
10+
11+
12+
class LogTest(unittest.TestCase):
13+
14+
def test_logger(self):
15+
self.assertIsInstance(logger, logging.Logger)
16+
self.assertEqual(logging.NOTSET, logger.level)
17+
self.assertEqual(1, len(logger.handlers))
18+
19+
def test_configure_logging(self):
20+
logging_config = {
21+
"version": 1,
22+
"formatters": {
23+
"normal": {
24+
"format": "%(asctime)s %(levelname)s %(message)s",
25+
"style": "%"
26+
}
27+
},
28+
"handlers": {
29+
"console": {
30+
"class": "logging.StreamHandler",
31+
"formatter": "normal"
32+
}
33+
},
34+
"loggers": {
35+
"zappend": {
36+
"level": "INFO",
37+
"handlers": ["console"]
38+
}
39+
}
40+
}
41+
42+
old_level = logger.level
43+
old_handlers = list(logger.handlers)
44+
for h in old_handlers:
45+
logger.removeHandler(h)
46+
47+
try:
48+
configure_logging(logging_config)
49+
self.assertEqual(logging.INFO, logger.level)
50+
self.assertEqual(1, len(logger.handlers))
51+
finally:
52+
logger.setLevel(old_level)
53+
for h in old_handlers:
54+
logger.addHandler(h)

zappend/cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
metavar="CONFIG",
1212
multiple=True,
1313
help="Configuration JSON or YAML file."
14-
" If multiple are passed,"
15-
" they will be deeply merged into one.")
14+
" If multiple are passed, subsequent configurations"
15+
" are incremental to the previous ones.")
1616
@click.option("--target", "-t",
1717
metavar="TARGET",
1818
help="Target Zarr dataset path or URI."

0 commit comments

Comments
 (0)