hydra-structlog 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hydra_plugins/hydra_structlog/__init__.py +5 -0
- hydra_plugins/hydra_structlog/py.typed +0 -0
- hydra_structlog/__init__.py +1 -0
- hydra_structlog/conf/__init__.py +0 -0
- hydra_structlog/conf/hydra/job_logging/structlog.yaml +102 -0
- hydra_structlog/formatters.py +12 -0
- hydra_structlog/handlers.py +34 -0
- hydra_structlog/init.py +90 -0
- hydra_structlog/plugin.py +7 -0
- hydra_structlog/processors.py +43 -0
- hydra_structlog/py.typed +0 -0
- hydra_structlog-0.1.0.dist-info/METADATA +112 -0
- hydra_structlog-0.1.0.dist-info/RECORD +15 -0
- hydra_structlog-0.1.0.dist-info/WHEEL +4 -0
- hydra_structlog-0.1.0.dist-info/licenses/LICENSE +21 -0
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
File without changes
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# @package hydra.job_logging
|
|
2
|
+
# python logging configuration for tasks
|
|
3
|
+
version: 1
|
|
4
|
+
formatters:
|
|
5
|
+
console:
|
|
6
|
+
"()": hydra_structlog.formatters.build_processor_formatter
|
|
7
|
+
foreign_pre_chain: ${hydra.job_logging.formatters.json.foreign_pre_chain}
|
|
8
|
+
processors:
|
|
9
|
+
_target_: hydra_structlog.processors.named_processor_chain
|
|
10
|
+
remove_processors_meta:
|
|
11
|
+
_target_: structlog.stdlib.ProcessorFormatter.remove_processors_meta
|
|
12
|
+
_partial_: true
|
|
13
|
+
time_stamper:
|
|
14
|
+
_target_: structlog.processors.TimeStamper
|
|
15
|
+
fmt: "%Y-%m-%d %H:%M:%S"
|
|
16
|
+
utc: false
|
|
17
|
+
console_renderer:
|
|
18
|
+
_target_: structlog.dev.ConsoleRenderer
|
|
19
|
+
json:
|
|
20
|
+
"()": hydra_structlog.formatters.build_processor_formatter
|
|
21
|
+
foreign_pre_chain:
|
|
22
|
+
_target_: hydra_structlog.processors.named_processor_chain
|
|
23
|
+
merge_contextvars:
|
|
24
|
+
_target_: structlog.contextvars.merge_contextvars
|
|
25
|
+
_partial_: true
|
|
26
|
+
add_logger_name:
|
|
27
|
+
_target_: structlog.stdlib.add_logger_name
|
|
28
|
+
_partial_: true
|
|
29
|
+
add_log_level:
|
|
30
|
+
_target_: structlog.stdlib.add_log_level
|
|
31
|
+
_partial_: true
|
|
32
|
+
positional_arguments_formatter:
|
|
33
|
+
_target_: structlog.stdlib.PositionalArgumentsFormatter
|
|
34
|
+
extra_adder:
|
|
35
|
+
_target_: structlog.stdlib.ExtraAdder
|
|
36
|
+
stack_info_renderer:
|
|
37
|
+
_target_: structlog.processors.StackInfoRenderer
|
|
38
|
+
processors:
|
|
39
|
+
_target_: hydra_structlog.processors.named_processor_chain
|
|
40
|
+
remove_processors_meta:
|
|
41
|
+
_target_: structlog.stdlib.ProcessorFormatter.remove_processors_meta
|
|
42
|
+
_partial_: true
|
|
43
|
+
static_field_adder:
|
|
44
|
+
_target_: hydra_structlog.processors.StaticFieldAdder
|
|
45
|
+
service: ${oc.env:SERVICE,null}
|
|
46
|
+
version: ${oc.env:VERSION,null}
|
|
47
|
+
env: ${oc.env:ENV,dev}
|
|
48
|
+
task: ${hydra.job.name}
|
|
49
|
+
callsite_parameter_adder:
|
|
50
|
+
_target_: structlog.processors.CallsiteParameterAdder
|
|
51
|
+
parameters:
|
|
52
|
+
- _target_: structlog.processors.CallsiteParameter
|
|
53
|
+
_args_:
|
|
54
|
+
- lineno
|
|
55
|
+
- _target_: structlog.processors.CallsiteParameter
|
|
56
|
+
_args_:
|
|
57
|
+
- func_name
|
|
58
|
+
additional_ignores:
|
|
59
|
+
- warnings
|
|
60
|
+
- hydra_structlog
|
|
61
|
+
time_stamper:
|
|
62
|
+
_target_: structlog.processors.TimeStamper
|
|
63
|
+
fmt: iso
|
|
64
|
+
field_renamer:
|
|
65
|
+
_target_: hydra_structlog.processors.FieldRenamer
|
|
66
|
+
level: status
|
|
67
|
+
event: message
|
|
68
|
+
format_exc_info:
|
|
69
|
+
_target_: structlog.processors.format_exc_info
|
|
70
|
+
_partial_: true
|
|
71
|
+
json_renderer:
|
|
72
|
+
_target_: structlog.processors.JSONRenderer
|
|
73
|
+
sort_keys: true
|
|
74
|
+
handlers:
|
|
75
|
+
console:
|
|
76
|
+
class: hydra_structlog.handlers.TqdmStreamHandler
|
|
77
|
+
formatter: console
|
|
78
|
+
stream: ext://sys.stdout
|
|
79
|
+
file:
|
|
80
|
+
# Run-local copy of the log
|
|
81
|
+
class: logging.FileHandler
|
|
82
|
+
formatter: json
|
|
83
|
+
filename: ${hydra.runtime.output_dir}/${hydra.job.name}.log
|
|
84
|
+
encoding: utf-8
|
|
85
|
+
json:
|
|
86
|
+
# Global structured log for monitoring or similar
|
|
87
|
+
class: logging.handlers.RotatingFileHandler
|
|
88
|
+
formatter: json
|
|
89
|
+
level: INFO
|
|
90
|
+
# Fixed location for all runs
|
|
91
|
+
filename: ${hydra.runtime.cwd}/structured.log
|
|
92
|
+
encoding: utf-8
|
|
93
|
+
# 1024**2 = 1 MB
|
|
94
|
+
maxBytes: 1048576
|
|
95
|
+
# Important for safe rotation (structured.log.1)
|
|
96
|
+
backupCount: 1
|
|
97
|
+
|
|
98
|
+
root:
|
|
99
|
+
level: INFO
|
|
100
|
+
handlers: [console, file, json]
|
|
101
|
+
|
|
102
|
+
disable_existing_loggers: false
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from hydra.utils import instantiate
|
|
2
|
+
from structlog.stdlib import ProcessorFormatter
|
|
3
|
+
|
|
4
|
+
from .init import init_plugin
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def build_processor_formatter(**kwargs) -> ProcessorFormatter:
|
|
8
|
+
"""Dynamically instantiate the processor chain from plain logging config."""
|
|
9
|
+
kwargs.setdefault("_target_", "structlog.stdlib.ProcessorFormatter")
|
|
10
|
+
processor = instantiate(kwargs)
|
|
11
|
+
init_plugin(processor.foreign_pre_chain)
|
|
12
|
+
return processor
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any, TextIO
|
|
3
|
+
|
|
4
|
+
try:
|
|
5
|
+
from tqdm.std import tqdm as std_tqdm # type: ignore[ty:unresolved-import]
|
|
6
|
+
|
|
7
|
+
TqdmClass = type[std_tqdm]
|
|
8
|
+
except ImportError:
|
|
9
|
+
std_tqdm: Any = None
|
|
10
|
+
TqdmClass = None
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TqdmStreamHandler(logging.StreamHandler):
|
|
14
|
+
"""Handler inheriting from StreamHandler to route logging stream through tqdm."""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
stream: TextIO | None = None,
|
|
19
|
+
tqdm_class: TqdmClass = std_tqdm,
|
|
20
|
+
):
|
|
21
|
+
super().__init__(stream=stream)
|
|
22
|
+
self.tqdm_class = tqdm_class
|
|
23
|
+
|
|
24
|
+
if std_tqdm is not None:
|
|
25
|
+
|
|
26
|
+
def emit(self, record: logging.LogRecord):
|
|
27
|
+
try:
|
|
28
|
+
msg = self.format(record)
|
|
29
|
+
self.tqdm_class.write(msg, end=self.terminator, file=self.stream) # type: ignore
|
|
30
|
+
self.flush()
|
|
31
|
+
except (KeyboardInterrupt, RecursionError, SystemExit):
|
|
32
|
+
raise
|
|
33
|
+
except Exception:
|
|
34
|
+
self.handleError(record)
|
hydra_structlog/init.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import warnings
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
from types import TracebackType
|
|
7
|
+
from typing import Any, TextIO
|
|
8
|
+
|
|
9
|
+
import structlog
|
|
10
|
+
|
|
11
|
+
# Original warnings.showwarning and sys.excepthook
|
|
12
|
+
_showwarning = None
|
|
13
|
+
_excepthook = None
|
|
14
|
+
_configured_once = False
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def warning_logger(
|
|
18
|
+
message: Warning | str,
|
|
19
|
+
category: type[Warning],
|
|
20
|
+
filename: str,
|
|
21
|
+
lineno: int,
|
|
22
|
+
file: TextIO | None = None,
|
|
23
|
+
line: str | None = None,
|
|
24
|
+
) -> None:
|
|
25
|
+
"""Emit Python-native warnings as logging warnings."""
|
|
26
|
+
frame = sys._getframe(2)
|
|
27
|
+
module = frame.f_globals.get("__name__")
|
|
28
|
+
logger = logging.getLogger(module)
|
|
29
|
+
logger.warning("%s: %s", category.__name__, f"{message} (line {lineno})")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def exception_logger(
|
|
33
|
+
exc_type: type[BaseException],
|
|
34
|
+
exc_value: BaseException,
|
|
35
|
+
exc_traceback: TracebackType | None,
|
|
36
|
+
) -> Any:
|
|
37
|
+
"""Exception hook to log uncaught exceptions."""
|
|
38
|
+
logger = logging.getLogger("exception")
|
|
39
|
+
|
|
40
|
+
if issubclass(exc_type, KeyboardInterrupt):
|
|
41
|
+
logger.error("User interrupt")
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
# Skip Hydra frames in stack trace (see hydra._internal.utils.run_and_report)
|
|
45
|
+
skip_files = (
|
|
46
|
+
"hydra/core/utils.py", # hydra
|
|
47
|
+
"hydra_zen/wrapper/_implementations.py", # hydra-zen
|
|
48
|
+
"hydra/main.py", # hydra through hydra-zen
|
|
49
|
+
"pydantic/_internal/_validate_call.py", # hydra-zen with pydantic wrapper
|
|
50
|
+
)
|
|
51
|
+
try:
|
|
52
|
+
tb = exc_traceback
|
|
53
|
+
while tb is not None:
|
|
54
|
+
frame = tb.tb_frame
|
|
55
|
+
tb = tb.tb_next
|
|
56
|
+
filename = frame.f_code.co_filename.replace(os.sep, "/")
|
|
57
|
+
if filename.endswith(skip_files) and tb:
|
|
58
|
+
exc_traceback = tb
|
|
59
|
+
except Exception:
|
|
60
|
+
pass
|
|
61
|
+
|
|
62
|
+
message = getattr(exc_value, "message", str(exc_value))
|
|
63
|
+
exc_info = exc_type, exc_value, exc_traceback
|
|
64
|
+
logger.critical(message, exc_info=exc_info)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def init_plugin(foreign_pre_chain: Sequence[structlog.typing.Processor]) -> None:
|
|
68
|
+
"""Configure structlog and warning and exception hooks."""
|
|
69
|
+
global _excepthook, _showwarning, _configured_once
|
|
70
|
+
|
|
71
|
+
if _showwarning is None:
|
|
72
|
+
_showwarning = warnings.showwarning
|
|
73
|
+
warnings.showwarning = warning_logger # type: ignore[ty:invalid-assignment]
|
|
74
|
+
|
|
75
|
+
if _excepthook is None:
|
|
76
|
+
os.environ["HYDRA_FULL_ERROR"] = "1" # Suppress Hydra's exception hook
|
|
77
|
+
_excepthook = sys.excepthook
|
|
78
|
+
sys.excepthook = exception_logger
|
|
79
|
+
|
|
80
|
+
if _configured_once is False:
|
|
81
|
+
structlog.configure(
|
|
82
|
+
processors=(
|
|
83
|
+
list(foreign_pre_chain)
|
|
84
|
+
+ [structlog.stdlib.ProcessorFormatter.wrap_for_formatter]
|
|
85
|
+
),
|
|
86
|
+
logger_factory=structlog.stdlib.LoggerFactory(),
|
|
87
|
+
wrapper_class=structlog.stdlib.BoundLogger,
|
|
88
|
+
cache_logger_on_first_use=True,
|
|
89
|
+
)
|
|
90
|
+
_configured_once = True
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from hydra.core.config_search_path import ConfigSearchPath
|
|
2
|
+
from hydra.plugins.search_path_plugin import SearchPathPlugin
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class HydraStructlogSearchPathPlugin(SearchPathPlugin):
|
|
6
|
+
def manipulate_search_path(self, search_path: ConfigSearchPath) -> None:
|
|
7
|
+
search_path.append("hydra-structlog", "pkg://hydra_structlog.conf")
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from collections.abc import Callable, MutableMapping
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from structlog.typing import EventDict, WrappedLogger
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class StaticFieldAdder:
|
|
8
|
+
"""Structlog processor to add static fields to all logs."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, **fields: str):
|
|
11
|
+
self.fields = fields
|
|
12
|
+
|
|
13
|
+
def __call__(
|
|
14
|
+
self, logger: WrappedLogger, name: str, event_dict: EventDict
|
|
15
|
+
) -> EventDict:
|
|
16
|
+
for field, value in self.fields.items():
|
|
17
|
+
event_dict.setdefault(field, value)
|
|
18
|
+
return event_dict
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class FieldRenamer:
|
|
22
|
+
"""Structlog processor to rename fields. Existing fields of the new name are
|
|
23
|
+
overwritten.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, **mapping: str):
|
|
27
|
+
self.mapping = mapping
|
|
28
|
+
|
|
29
|
+
def __call__(
|
|
30
|
+
self, logger: WrappedLogger, name: str, event_dict: EventDict
|
|
31
|
+
) -> EventDict:
|
|
32
|
+
for field, replace in self.mapping.items():
|
|
33
|
+
if field in event_dict:
|
|
34
|
+
event_dict[replace] = event_dict.pop(field)
|
|
35
|
+
return event_dict
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
Processor = Callable[[Any, str, MutableMapping], MutableMapping]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def named_processor_chain(**processors: Processor) -> list[Processor]:
|
|
42
|
+
"""Convert a mapping of named processors into list. Skip None"""
|
|
43
|
+
return [p for p in processors.values() if p is not None]
|
hydra_structlog/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hydra-structlog
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An opinionated hydra plugin to configure logging with structlog
|
|
5
|
+
Keywords: hydra,structlog,plugin,hydra-zen
|
|
6
|
+
Author: Sören Zapp
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Programming Language :: Python
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Intended Audience :: Information Technology
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering
|
|
20
|
+
Requires-Dist: hydra-core>=1.3.2
|
|
21
|
+
Requires-Dist: structlog>=25.5.0
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Project-URL: Source, https://github.com/szapp/hydra-structlog
|
|
24
|
+
Project-URL: Issues, https://github.com/szapp/hydra-structlog/issues
|
|
25
|
+
Project-URL: Funding, https://ko-fi.com/szapp
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# Hydra-Structlog
|
|
29
|
+
|
|
30
|
+
An opinionated hydra plugin to configure logging with structlog.
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
Structlog is fully integrated in Hydra through a config group named `structlog` for `hydra.job_logging`.
|
|
35
|
+
|
|
36
|
+
1. Install the plugin.
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
uv add hydra-structlog
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
2. Override the job logging with a default in your config.
|
|
43
|
+
|
|
44
|
+
```yaml
|
|
45
|
+
defaults:
|
|
46
|
+
- override hydra/job_logging=structlog
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
3. Hydra will now emit JSON logs (by default to `structured.log`) and print human readably logs to the console.
|
|
50
|
+
|
|
51
|
+
## Customization
|
|
52
|
+
|
|
53
|
+
Structlog comes configured with opinionated defaults.
|
|
54
|
+
|
|
55
|
+
To adjust the processors, use the hydra defaults as outlined above and overwrite individual config entries afterwards.
|
|
56
|
+
For example:
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
defaults:
|
|
60
|
+
- override hydra/job_logging=structlog
|
|
61
|
+
|
|
62
|
+
# Change the storage location
|
|
63
|
+
hydra:
|
|
64
|
+
job_logging:
|
|
65
|
+
handlers:
|
|
66
|
+
json:
|
|
67
|
+
filename: ${hydra.runtime.cwd}/logs/structured.log
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Defaults
|
|
71
|
+
|
|
72
|
+
The configuration runs structlog through the standard library logging.
|
|
73
|
+
That has several advantages.
|
|
74
|
+
|
|
75
|
+
The use of structlog and logging, e.g. by third-party packages, are recorded and both exhibit structlog's bound contextvars.
|
|
76
|
+
|
|
77
|
+
The processor chain is conveniently exposed in the job_logging configuration and adjustable through hydra's config interface.
|
|
78
|
+
|
|
79
|
+
Because lists are not easily manipulated in hydra configs, the processor chains are defined as dictionaries.
|
|
80
|
+
The name of each processor does not matter as long as its unique in the chain.
|
|
81
|
+
The default processor chain can then be extended more comfortably.
|
|
82
|
+
|
|
83
|
+
To remove a processor set it to `null`. See example below.
|
|
84
|
+
|
|
85
|
+
Because structlog's ProcessorFormatter does not accept the processors as strings, the logging config contains `_target_` instantiation.
|
|
86
|
+
|
|
87
|
+
```yaml
|
|
88
|
+
defaults:
|
|
89
|
+
- override hydra/job_logging=structlog
|
|
90
|
+
|
|
91
|
+
# Remove a processor from the default chain and add another one
|
|
92
|
+
hydra:
|
|
93
|
+
job_logging:
|
|
94
|
+
formatters:
|
|
95
|
+
json:
|
|
96
|
+
foreign_pre_chain:
|
|
97
|
+
# Remove the add-log-level processor
|
|
98
|
+
add_logger_name: null
|
|
99
|
+
# Append a new processor
|
|
100
|
+
arbitrary_name:
|
|
101
|
+
# Follow hydra's instantiate syntax
|
|
102
|
+
_target_: structlog.stdlib.add_log_level_number
|
|
103
|
+
_partial_: true
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Notes
|
|
107
|
+
|
|
108
|
+
Python 3.14 is currently not supported as `hydra.main` causes a ValueError on argparse-validation, see <https://github.com/facebookresearch/hydra/issues/3121>.
|
|
109
|
+
It is recommended to use `hydra-zen` which does not have that problem and works well with Python 3.14.
|
|
110
|
+
|
|
111
|
+
Tracer injection is not implemented here as data science projects using hydra typically do not implement web apps.
|
|
112
|
+
Nevertheless, an appropriate structlog processor can be added to the job_logging config.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
hydra_plugins/hydra_structlog/__init__.py,sha256=b8nxszR3JwULO_rfmSkOs27b1QwJPM_dOHpmiRTXIP0,119
|
|
2
|
+
hydra_plugins/hydra_structlog/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
hydra_structlog/__init__.py,sha256=kUR5RAFc7HCeiqdlX36dZOHkUI5wI6V_43RpEcD8b-0,22
|
|
4
|
+
hydra_structlog/conf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
hydra_structlog/conf/hydra/job_logging/structlog.yaml,sha256=3U247Abw0ca6wN3END6ZFl8STk1-P7Wa_C6HKrJvBhk,3372
|
|
6
|
+
hydra_structlog/formatters.py,sha256=Tff7FtD9CQFHxhobGMrD2I94R8sldCIaL4Nng_zuvOc,436
|
|
7
|
+
hydra_structlog/handlers.py,sha256=2jR9CNCKPpFBpiN9fcUwza5VvRB-k1Fazyi60_jKVr4,992
|
|
8
|
+
hydra_structlog/init.py,sha256=xgz375XzRfcZ-8CFe4ewCKRp88ShRdnt6ax4zw2do2s,2856
|
|
9
|
+
hydra_structlog/plugin.py,sha256=o0QZHx2Grx8i8_LfskMrh0io4dQurvftKIpk65vuTPU,332
|
|
10
|
+
hydra_structlog/processors.py,sha256=vXW42l39Spaa32YYY2jnVJEs0R2sbsJ7oxo1vCB7nro,1275
|
|
11
|
+
hydra_structlog/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
+
hydra_structlog-0.1.0.dist-info/licenses/LICENSE,sha256=748QfVuRg6qe0w5Byrj-yYr0coH58yJGP1WinEvDVvQ,1069
|
|
13
|
+
hydra_structlog-0.1.0.dist-info/WHEEL,sha256=M4DeIjVCA49okfALADZoWX5JOGwnmHb-JOpQHtI-1c0,80
|
|
14
|
+
hydra_structlog-0.1.0.dist-info/METADATA,sha256=jCqNB3W-5Xl9JOZJQZZFcjS4ECHOaWSBVTqNDd-tD-8,3803
|
|
15
|
+
hydra_structlog-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sören Zapp
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|