mvx-common 0.2.2__tar.gz → 0.2.3__tar.gz
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.
- {mvx_common-0.2.2 → mvx_common-0.2.3}/PKG-INFO +1 -1
- {mvx_common-0.2.2 → mvx_common-0.2.3}/pyproject.toml +1 -1
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/__init__.py +13 -0
- mvx_common-0.2.3/src/mvx/common/logger/pattern_event_policy/__init__.py +15 -0
- mvx_common-0.2.3/src/mvx/common/logger/pattern_event_policy/pattern_event_policy.py +338 -0
- mvx_common-0.2.3/tests/test_logger/pattern_event_policy/test_pattern_event_policy.py +830 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/.gitignore +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/LICENSE +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/NOTICE +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/README.md +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/scripts/check.sh +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/scripts/format.sh +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/__init__.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/errors/__init__.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/errors/invalid_function_argument_error.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/errors/reasoned_error.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/errors/runtime_errors.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/errors/structured_error.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/helpers/__init__.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/helpers/api_error_processor.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/helpers/document_enum.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/helpers/introspection.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/helpers/run_with_cancellation_policy.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/adapter_logging/__init__.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/adapter_logging/log_record_factory.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/adapter_logging/logging_configs.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/adapter_logging/logging_file_sink.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/adapter_logging/logging_stream_sink.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/asyncio_log_sink/__init__.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/asyncio_log_sink/common.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/asyncio_log_sink/errors.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/asyncio_log_sink/log_sink.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/errors.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/helpers.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/log_components/__init__.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/log_components/log_invocation.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/log_components/protocols.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/log_context/__init__.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/log_context/log_context.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/log_payload_processor/__init__.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/log_payload_processor/log_payload_processor.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/log_payload_processor/types.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/logger/models.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/src/mvx/common/py.typed +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_errors/test_invalid_function_argument_error.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_errors/test_reasoned_error.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_errors/test_runtime_errors.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_errors/test_structured_error.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_helpers/test_api_error_processor.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_helpers/test_run_with_cancellation_policy.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/adapter_logging/test_log_record_factory.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/adapter_logging/test_logging_configs.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/adapter_logging/test_logging_file_sink.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/adapter_logging/test_logging_stream_sink.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/asyncio_log_sink/test_asyncio_log_sink.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_components/log_invocation/doc_examples/conftest.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_components/log_invocation/doc_examples/test_awaitable_result.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_components/log_invocation/doc_examples/test_cancellation.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_components/log_invocation/doc_examples/test_context_fields.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_components/log_invocation/doc_examples/test_context_formatter.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_components/log_invocation/doc_examples/test_error_policy.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_components/log_invocation/doc_examples/test_invoke_kwargs.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_components/log_invocation/doc_examples/test_public_api_method.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_components/log_invocation/doc_examples/test_result_logging.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_components/log_invocation/doc_examples/test_standalone_function.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_components/log_invocation/doc_examples/test_verbosity.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_components/log_invocation/test_log_invocation.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_context/test_log_context.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/log_payload_processor/test_log_payload_processor.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/test_errors.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/test_manual_log_context_wiring.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/test_package_bootstrap.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/test_package_file_sink_smoke.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/test_package_internals.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/test_package_log_invocation_integration.py +0 -0
- {mvx_common-0.2.2 → mvx_common-0.2.3}/tests/test_logger/test_package_public_api.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mvx-common
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Common utilities for MVX Python packages.
|
|
5
5
|
Project-URL: Documentation, https://mvx-lib.readthedocs.io/en/latest/
|
|
6
6
|
Project-URL: Source, https://github.com/makarovvvdream-dev/mvx-lib
|
|
@@ -40,6 +40,14 @@ from .log_context import (
|
|
|
40
40
|
LogErrorHandlingPolicy,
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
+
from .pattern_event_policy import (
|
|
44
|
+
PatternLogEventPolicyAction,
|
|
45
|
+
PatternLogEventPolicyRuleConfig,
|
|
46
|
+
PatternLogEventPolicyConfig,
|
|
47
|
+
PatternLogEventPolicy,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
43
51
|
from .log_payload_processor import (
|
|
44
52
|
LogPayloadProcessor,
|
|
45
53
|
LogVerbosityLevel,
|
|
@@ -106,6 +114,11 @@ __all__ = (
|
|
|
106
114
|
# from .log_context
|
|
107
115
|
"LogContext",
|
|
108
116
|
"LogErrorHandlingPolicy",
|
|
117
|
+
# from .pattern_event_policy
|
|
118
|
+
"PatternLogEventPolicyAction",
|
|
119
|
+
"PatternLogEventPolicyRuleConfig",
|
|
120
|
+
"PatternLogEventPolicyConfig",
|
|
121
|
+
"PatternLogEventPolicy",
|
|
109
122
|
# from .log_payload_processor
|
|
110
123
|
"LogPayloadProcessor",
|
|
111
124
|
"LogVerbosityLevel",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# src/mvx/common/logger/pattern_event_policy/__init__.py
|
|
2
|
+
|
|
3
|
+
from .pattern_event_policy import (
|
|
4
|
+
PatternLogEventPolicyAction,
|
|
5
|
+
PatternLogEventPolicyRuleConfig,
|
|
6
|
+
PatternLogEventPolicyConfig,
|
|
7
|
+
PatternLogEventPolicy,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = (
|
|
11
|
+
"PatternLogEventPolicyAction",
|
|
12
|
+
"PatternLogEventPolicyRuleConfig",
|
|
13
|
+
"PatternLogEventPolicyConfig",
|
|
14
|
+
"PatternLogEventPolicy",
|
|
15
|
+
)
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
# src/mvx/common/logger/pattern_event_policy/pattern_event_policy.py
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from mvx.common.helpers.document_enum import document_enum
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from enum import StrEnum
|
|
8
|
+
from fnmatch import fnmatchcase
|
|
9
|
+
from typing import Any, Mapping, Sequence
|
|
10
|
+
|
|
11
|
+
from mvx.common.logger import LogEventMeta
|
|
12
|
+
|
|
13
|
+
__all__ = (
|
|
14
|
+
"PatternLogEventPolicyAction",
|
|
15
|
+
"PatternLogEventPolicyRuleConfig",
|
|
16
|
+
"PatternLogEventPolicyConfig",
|
|
17
|
+
"PatternLogEventPolicy",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@document_enum
|
|
22
|
+
class PatternLogEventPolicyAction(StrEnum):
|
|
23
|
+
"""Action returned by a matching pattern event policy rule."""
|
|
24
|
+
|
|
25
|
+
#: Allow the matching event
|
|
26
|
+
ALLOW = "allow"
|
|
27
|
+
|
|
28
|
+
#: Deny the matching event
|
|
29
|
+
DENY = "deny"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(frozen=True, slots=True)
|
|
33
|
+
class PatternLogEventPolicyRuleConfig:
|
|
34
|
+
"""Configuration of one ordered pattern event policy rule.
|
|
35
|
+
|
|
36
|
+
A rule contains an action and optional pattern groups used to match
|
|
37
|
+
``LogEventMeta`` fields.
|
|
38
|
+
|
|
39
|
+
Pattern groups inside one rule are combined as logical ``and``: every
|
|
40
|
+
non-empty group must match the event metadata. Patterns inside one group
|
|
41
|
+
are alternatives: at least one pattern in that group must match.
|
|
42
|
+
|
|
43
|
+
Empty pattern groups do not restrict the rule. A rule without any pattern
|
|
44
|
+
groups matches every event.
|
|
45
|
+
|
|
46
|
+
Rules are evaluated by ``PatternLogEventPolicy`` in configuration order.
|
|
47
|
+
The first matching rule decides whether the event is enabled.
|
|
48
|
+
|
|
49
|
+
:param action: action returned when the rule matches.
|
|
50
|
+
:param events: shell-style patterns matched against the composed event key.
|
|
51
|
+
:param event_namespaces: shell-style patterns matched against event namespace.
|
|
52
|
+
:param event_names: shell-style patterns matched against event name.
|
|
53
|
+
:param entity_ids: shell-style patterns matched against entity id.
|
|
54
|
+
:param source_paths: shell-style patterns matched against source path.
|
|
55
|
+
:param source_funcs: shell-style patterns matched against source function.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
action: PatternLogEventPolicyAction
|
|
59
|
+
|
|
60
|
+
events: tuple[str, ...] = field(default_factory=tuple)
|
|
61
|
+
event_namespaces: tuple[str, ...] = field(default_factory=tuple)
|
|
62
|
+
event_names: tuple[str, ...] = field(default_factory=tuple)
|
|
63
|
+
entity_ids: tuple[str, ...] = field(default_factory=tuple)
|
|
64
|
+
source_paths: tuple[str, ...] = field(default_factory=tuple)
|
|
65
|
+
source_funcs: tuple[str, ...] = field(default_factory=tuple)
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def from_mapping(cls, data: Mapping[str, Any]) -> PatternLogEventPolicyRuleConfig:
|
|
69
|
+
"""Build rule configuration from a mapping.
|
|
70
|
+
|
|
71
|
+
The mapping must contain the ``action`` field with value ``"allow"``
|
|
72
|
+
or ``"deny"``. Pattern fields are optional. Missing pattern fields and
|
|
73
|
+
fields explicitly set to ``None`` are treated as empty pattern groups.
|
|
74
|
+
|
|
75
|
+
Supported pattern fields are:
|
|
76
|
+
|
|
77
|
+
* ``events``;
|
|
78
|
+
* ``event_namespaces``;
|
|
79
|
+
* ``event_names``;
|
|
80
|
+
* ``entity_ids``;
|
|
81
|
+
* ``source_paths``;
|
|
82
|
+
* ``source_funcs``.
|
|
83
|
+
|
|
84
|
+
Pattern fields must be sequences of non-empty strings. String values
|
|
85
|
+
are stripped before they are stored in the resulting configuration.
|
|
86
|
+
|
|
87
|
+
:param data: mapping containing rule configuration.
|
|
88
|
+
:return: parsed rule configuration.
|
|
89
|
+
:raises TypeError: if a field has an invalid type.
|
|
90
|
+
:raises ValueError: if ``action`` is empty, unknown, or a pattern field
|
|
91
|
+
contains an empty string.
|
|
92
|
+
"""
|
|
93
|
+
action_raw = _get_required_str(data, "action")
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
action = PatternLogEventPolicyAction(action_raw)
|
|
97
|
+
except ValueError as exc:
|
|
98
|
+
raise ValueError(
|
|
99
|
+
"field 'action' must be one of: " f"{_enum_values(PatternLogEventPolicyAction)}"
|
|
100
|
+
) from exc
|
|
101
|
+
|
|
102
|
+
return cls(
|
|
103
|
+
action=action,
|
|
104
|
+
events=_get_str_tuple(data, "events"),
|
|
105
|
+
event_namespaces=_get_str_tuple(data, "event_namespaces"),
|
|
106
|
+
event_names=_get_str_tuple(data, "event_names"),
|
|
107
|
+
entity_ids=_get_str_tuple(data, "entity_ids"),
|
|
108
|
+
source_paths=_get_str_tuple(data, "source_paths"),
|
|
109
|
+
source_funcs=_get_str_tuple(data, "source_funcs"),
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@dataclass(frozen=True, slots=True)
|
|
114
|
+
class PatternLogEventPolicyConfig:
|
|
115
|
+
"""Configuration of ``PatternLogEventPolicy``.
|
|
116
|
+
|
|
117
|
+
The configuration defines a fallback decision and an ordered rule list.
|
|
118
|
+
|
|
119
|
+
``default_enabled`` is returned when no rule matches. ``rules`` are checked
|
|
120
|
+
from first to last. The first matching rule wins.
|
|
121
|
+
|
|
122
|
+
The configuration is immutable and can be safely shared as read-only policy
|
|
123
|
+
configuration.
|
|
124
|
+
|
|
125
|
+
:param default_enabled: fallback decision used when no rule matches.
|
|
126
|
+
:param rules: ordered sequence of pattern policy rules.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
default_enabled: bool = True
|
|
130
|
+
rules: tuple[PatternLogEventPolicyRuleConfig, ...] = field(default_factory=tuple)
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def from_mapping(cls, data: Mapping[str, Any]) -> PatternLogEventPolicyConfig:
|
|
134
|
+
"""Build pattern policy configuration from a mapping.
|
|
135
|
+
|
|
136
|
+
The mapping may contain:
|
|
137
|
+
|
|
138
|
+
* ``default_enabled``: boolean fallback decision, defaults to ``True``;
|
|
139
|
+
* ``rules``: sequence of rule mappings, defaults to an empty sequence.
|
|
140
|
+
|
|
141
|
+
Rule mappings are parsed by
|
|
142
|
+
``PatternLogEventPolicyRuleConfig.from_mapping``.
|
|
143
|
+
|
|
144
|
+
:param data: mapping containing policy configuration.
|
|
145
|
+
:return: parsed policy configuration.
|
|
146
|
+
:raises TypeError: if a field has an invalid type.
|
|
147
|
+
:raises ValueError: if a nested rule contains an invalid value.
|
|
148
|
+
"""
|
|
149
|
+
return cls(
|
|
150
|
+
default_enabled=_get_bool(data, "default_enabled", default=True),
|
|
151
|
+
rules=_get_rule_tuple(data, "rules"),
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class PatternLogEventPolicy:
|
|
156
|
+
"""Ready-to-use event policy based on ordered metadata pattern rules.
|
|
157
|
+
|
|
158
|
+
The policy implements the event policy contract used by ``LogContext``.
|
|
159
|
+
It receives ``LogEventMeta`` and returns whether the event is enabled.
|
|
160
|
+
|
|
161
|
+
Matching is based only on event metadata. The policy does not inspect
|
|
162
|
+
payload, normalized payload, logging level, event type, timestamp, sink, or
|
|
163
|
+
destination.
|
|
164
|
+
|
|
165
|
+
Rules are evaluated in the order defined by
|
|
166
|
+
``PatternLogEventPolicyConfig.rules``. The first matching rule decides the
|
|
167
|
+
result. If no rule matches, ``PatternLogEventPolicyConfig.default_enabled``
|
|
168
|
+
is returned.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
def __init__(self, config: PatternLogEventPolicyConfig) -> None:
|
|
172
|
+
"""Initialize pattern event policy.
|
|
173
|
+
|
|
174
|
+
:param config: immutable pattern policy configuration.
|
|
175
|
+
:raises TypeError: if ``config`` is not a
|
|
176
|
+
``PatternLogEventPolicyConfig`` instance.
|
|
177
|
+
"""
|
|
178
|
+
if not isinstance(config, PatternLogEventPolicyConfig):
|
|
179
|
+
raise TypeError(
|
|
180
|
+
"argument 'config' must be an instance of 'PatternLogEventPolicyConfig'"
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
self._config = config
|
|
184
|
+
|
|
185
|
+
def is_event_enabled(self, event: LogEventMeta) -> bool:
|
|
186
|
+
"""Return whether the event is enabled by this policy.
|
|
187
|
+
|
|
188
|
+
The method checks configured rules in order. The first matching rule
|
|
189
|
+
returns its action as a boolean decision. If no rule matches, the
|
|
190
|
+
configured default decision is returned.
|
|
191
|
+
|
|
192
|
+
:param event: event metadata to check.
|
|
193
|
+
:return: ``True`` if the event is enabled, ``False`` otherwise.
|
|
194
|
+
"""
|
|
195
|
+
for rule in self._config.rules:
|
|
196
|
+
if _rule_matches(rule, event):
|
|
197
|
+
return rule.action is PatternLogEventPolicyAction.ALLOW
|
|
198
|
+
|
|
199
|
+
return self._config.default_enabled
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _rule_matches(rule: PatternLogEventPolicyRuleConfig, event: LogEventMeta) -> bool:
|
|
203
|
+
event_key = _event_key(event)
|
|
204
|
+
|
|
205
|
+
if rule.events and not _matches_optional_any(event_key, rule.events):
|
|
206
|
+
return False
|
|
207
|
+
|
|
208
|
+
if rule.event_namespaces and not _matches_optional_any(
|
|
209
|
+
event.event_namespace,
|
|
210
|
+
rule.event_namespaces,
|
|
211
|
+
):
|
|
212
|
+
return False
|
|
213
|
+
|
|
214
|
+
if rule.event_names and not _matches_optional_any(
|
|
215
|
+
event.event_name,
|
|
216
|
+
rule.event_names,
|
|
217
|
+
):
|
|
218
|
+
return False
|
|
219
|
+
|
|
220
|
+
if rule.entity_ids and not _matches_optional_any(
|
|
221
|
+
event.entity_id,
|
|
222
|
+
rule.entity_ids,
|
|
223
|
+
):
|
|
224
|
+
return False
|
|
225
|
+
|
|
226
|
+
if rule.source_paths and not _matches_optional_any(
|
|
227
|
+
event.source_path,
|
|
228
|
+
rule.source_paths,
|
|
229
|
+
):
|
|
230
|
+
return False
|
|
231
|
+
|
|
232
|
+
if rule.source_funcs and not _matches_optional_any(
|
|
233
|
+
event.source_func,
|
|
234
|
+
rule.source_funcs,
|
|
235
|
+
):
|
|
236
|
+
return False
|
|
237
|
+
|
|
238
|
+
return True
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _event_key(event: LogEventMeta) -> str | None:
|
|
242
|
+
event_name = event.event_name
|
|
243
|
+
|
|
244
|
+
if event_name is None:
|
|
245
|
+
return None
|
|
246
|
+
|
|
247
|
+
event_namespace = event.event_namespace
|
|
248
|
+
|
|
249
|
+
if event_namespace:
|
|
250
|
+
return f"{event_namespace}.{event_name}"
|
|
251
|
+
|
|
252
|
+
return event_name
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def _matches_optional_any(value: str | None, patterns: Sequence[str]) -> bool:
|
|
256
|
+
if value is None:
|
|
257
|
+
return False
|
|
258
|
+
|
|
259
|
+
return _matches_any(value, patterns)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _matches_any(value: str, patterns: Sequence[str]) -> bool:
|
|
263
|
+
return any(fnmatchcase(value, pattern) for pattern in patterns)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _get_bool(data: Mapping[str, Any], key: str, *, default: bool) -> bool:
|
|
267
|
+
value = data.get(key, default)
|
|
268
|
+
|
|
269
|
+
if not isinstance(value, bool):
|
|
270
|
+
raise TypeError(f"field '{key}' must be bool")
|
|
271
|
+
|
|
272
|
+
return value
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _get_required_str(data: Mapping[str, Any], key: str) -> str:
|
|
276
|
+
value = data.get(key)
|
|
277
|
+
|
|
278
|
+
if not isinstance(value, str):
|
|
279
|
+
raise TypeError(f"field '{key}' must be string")
|
|
280
|
+
|
|
281
|
+
value = value.strip()
|
|
282
|
+
|
|
283
|
+
if not value:
|
|
284
|
+
raise ValueError(f"field '{key}' must not be empty")
|
|
285
|
+
|
|
286
|
+
return value
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def _get_str_tuple(data: Mapping[str, Any], key: str) -> tuple[str, ...]:
|
|
290
|
+
value = data.get(key, ())
|
|
291
|
+
|
|
292
|
+
if value is None:
|
|
293
|
+
return ()
|
|
294
|
+
|
|
295
|
+
if isinstance(value, (str, bytes, bytearray)) or not isinstance(value, Sequence):
|
|
296
|
+
raise TypeError(f"field '{key}' must be a sequence of strings")
|
|
297
|
+
|
|
298
|
+
result: list[str] = []
|
|
299
|
+
|
|
300
|
+
for item in value:
|
|
301
|
+
if not isinstance(item, str):
|
|
302
|
+
raise TypeError(f"field '{key}' must contain only strings")
|
|
303
|
+
|
|
304
|
+
item = item.strip()
|
|
305
|
+
|
|
306
|
+
if not item:
|
|
307
|
+
raise ValueError(f"field '{key}' must not contain empty strings")
|
|
308
|
+
|
|
309
|
+
result.append(item)
|
|
310
|
+
|
|
311
|
+
return tuple(result)
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def _get_rule_tuple(
|
|
315
|
+
data: Mapping[str, Any],
|
|
316
|
+
key: str,
|
|
317
|
+
) -> tuple[PatternLogEventPolicyRuleConfig, ...]:
|
|
318
|
+
value = data.get(key, ())
|
|
319
|
+
|
|
320
|
+
if value is None:
|
|
321
|
+
return ()
|
|
322
|
+
|
|
323
|
+
if isinstance(value, (str, bytes, bytearray)) or not isinstance(value, Sequence):
|
|
324
|
+
raise TypeError(f"field '{key}' must be a sequence of mappings")
|
|
325
|
+
|
|
326
|
+
result: list[PatternLogEventPolicyRuleConfig] = []
|
|
327
|
+
|
|
328
|
+
for item in value:
|
|
329
|
+
if not isinstance(item, Mapping):
|
|
330
|
+
raise TypeError(f"field '{key}' must contain only mappings")
|
|
331
|
+
|
|
332
|
+
result.append(PatternLogEventPolicyRuleConfig.from_mapping(item))
|
|
333
|
+
|
|
334
|
+
return tuple(result)
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
def _enum_values(enum_type: type[StrEnum]) -> str:
|
|
338
|
+
return ", ".join(repr(item.value) for item in enum_type)
|