provide-foundation 0.0.0.dev0__py3-none-any.whl → 0.0.0.dev2__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.
- provide/foundation/__init__.py +41 -23
- provide/foundation/archive/__init__.py +23 -0
- provide/foundation/archive/base.py +70 -0
- provide/foundation/archive/bzip2.py +157 -0
- provide/foundation/archive/gzip.py +159 -0
- provide/foundation/archive/operations.py +334 -0
- provide/foundation/archive/tar.py +164 -0
- provide/foundation/archive/zip.py +203 -0
- provide/foundation/cli/__init__.py +2 -2
- provide/foundation/cli/commands/deps.py +13 -7
- provide/foundation/cli/commands/logs/__init__.py +1 -1
- provide/foundation/cli/commands/logs/query.py +1 -1
- provide/foundation/cli/commands/logs/send.py +1 -1
- provide/foundation/cli/commands/logs/tail.py +1 -1
- provide/foundation/cli/decorators.py +11 -10
- provide/foundation/cli/main.py +1 -1
- provide/foundation/cli/testing.py +2 -35
- provide/foundation/cli/utils.py +21 -17
- provide/foundation/config/__init__.py +35 -2
- provide/foundation/config/base.py +2 -2
- provide/foundation/config/converters.py +479 -0
- provide/foundation/config/defaults.py +67 -0
- provide/foundation/config/env.py +4 -19
- provide/foundation/config/loader.py +9 -3
- provide/foundation/config/sync.py +19 -4
- provide/foundation/console/input.py +5 -5
- provide/foundation/console/output.py +35 -13
- provide/foundation/context/__init__.py +8 -4
- provide/foundation/context/core.py +85 -109
- provide/foundation/core.py +1 -2
- provide/foundation/crypto/__init__.py +2 -0
- provide/foundation/crypto/certificates/__init__.py +34 -0
- provide/foundation/crypto/certificates/base.py +173 -0
- provide/foundation/crypto/certificates/certificate.py +290 -0
- provide/foundation/crypto/certificates/factory.py +213 -0
- provide/foundation/crypto/certificates/generator.py +138 -0
- provide/foundation/crypto/certificates/loader.py +130 -0
- provide/foundation/crypto/certificates/operations.py +198 -0
- provide/foundation/crypto/certificates/trust.py +107 -0
- provide/foundation/errors/__init__.py +2 -3
- provide/foundation/errors/decorators.py +0 -231
- provide/foundation/errors/types.py +0 -97
- provide/foundation/eventsets/__init__.py +0 -0
- provide/foundation/eventsets/display.py +84 -0
- provide/foundation/eventsets/registry.py +160 -0
- provide/foundation/eventsets/resolver.py +192 -0
- provide/foundation/eventsets/sets/das.py +128 -0
- provide/foundation/eventsets/sets/database.py +125 -0
- provide/foundation/eventsets/sets/http.py +153 -0
- provide/foundation/eventsets/sets/llm.py +139 -0
- provide/foundation/eventsets/sets/task_queue.py +107 -0
- provide/foundation/eventsets/types.py +70 -0
- provide/foundation/file/directory.py +13 -22
- provide/foundation/file/lock.py +3 -1
- provide/foundation/hub/components.py +77 -515
- provide/foundation/hub/config.py +151 -0
- provide/foundation/hub/discovery.py +62 -0
- provide/foundation/hub/handlers.py +81 -0
- provide/foundation/hub/lifecycle.py +194 -0
- provide/foundation/hub/manager.py +4 -4
- provide/foundation/hub/processors.py +44 -0
- provide/foundation/integrations/__init__.py +11 -0
- provide/foundation/{observability → integrations}/openobserve/__init__.py +10 -7
- provide/foundation/{observability → integrations}/openobserve/auth.py +1 -1
- provide/foundation/{observability → integrations}/openobserve/client.py +12 -12
- provide/foundation/{observability → integrations}/openobserve/commands.py +3 -3
- provide/foundation/integrations/openobserve/config.py +37 -0
- provide/foundation/{observability → integrations}/openobserve/formatters.py +1 -1
- provide/foundation/{observability → integrations}/openobserve/otlp.py +1 -1
- provide/foundation/{observability → integrations}/openobserve/search.py +2 -2
- provide/foundation/{observability → integrations}/openobserve/streaming.py +4 -4
- provide/foundation/logger/__init__.py +3 -10
- provide/foundation/logger/config/logging.py +68 -298
- provide/foundation/logger/config/telemetry.py +41 -121
- provide/foundation/logger/core.py +0 -2
- provide/foundation/logger/custom_processors.py +1 -0
- provide/foundation/logger/factories.py +11 -2
- provide/foundation/logger/processors/main.py +20 -84
- provide/foundation/logger/setup/__init__.py +5 -1
- provide/foundation/logger/setup/coordinator.py +76 -24
- provide/foundation/logger/setup/processors.py +2 -9
- provide/foundation/logger/trace.py +27 -0
- provide/foundation/metrics/otel.py +10 -10
- provide/foundation/observability/__init__.py +2 -2
- provide/foundation/process/__init__.py +9 -0
- provide/foundation/process/exit.py +47 -0
- provide/foundation/process/lifecycle.py +115 -59
- provide/foundation/resilience/__init__.py +35 -0
- provide/foundation/resilience/circuit.py +164 -0
- provide/foundation/resilience/decorators.py +220 -0
- provide/foundation/resilience/fallback.py +193 -0
- provide/foundation/resilience/retry.py +325 -0
- provide/foundation/streams/config.py +79 -0
- provide/foundation/streams/console.py +7 -8
- provide/foundation/streams/core.py +6 -3
- provide/foundation/streams/file.py +12 -2
- provide/foundation/testing/__init__.py +84 -2
- provide/foundation/testing/archive/__init__.py +24 -0
- provide/foundation/testing/archive/fixtures.py +217 -0
- provide/foundation/testing/cli.py +30 -17
- provide/foundation/testing/common/__init__.py +32 -0
- provide/foundation/testing/common/fixtures.py +236 -0
- provide/foundation/testing/file/__init__.py +40 -0
- provide/foundation/testing/file/content_fixtures.py +316 -0
- provide/foundation/testing/file/directory_fixtures.py +107 -0
- provide/foundation/testing/file/fixtures.py +52 -0
- provide/foundation/testing/file/special_fixtures.py +153 -0
- provide/foundation/testing/logger.py +117 -11
- provide/foundation/testing/mocking/__init__.py +46 -0
- provide/foundation/testing/mocking/fixtures.py +331 -0
- provide/foundation/testing/process/__init__.py +48 -0
- provide/foundation/testing/process/async_fixtures.py +405 -0
- provide/foundation/testing/process/fixtures.py +56 -0
- provide/foundation/testing/process/subprocess_fixtures.py +209 -0
- provide/foundation/testing/threading/__init__.py +38 -0
- provide/foundation/testing/threading/basic_fixtures.py +101 -0
- provide/foundation/testing/threading/data_fixtures.py +99 -0
- provide/foundation/testing/threading/execution_fixtures.py +263 -0
- provide/foundation/testing/threading/fixtures.py +54 -0
- provide/foundation/testing/threading/sync_fixtures.py +97 -0
- provide/foundation/testing/time/__init__.py +32 -0
- provide/foundation/testing/time/fixtures.py +409 -0
- provide/foundation/testing/transport/__init__.py +30 -0
- provide/foundation/testing/transport/fixtures.py +280 -0
- provide/foundation/tools/__init__.py +58 -0
- provide/foundation/tools/base.py +348 -0
- provide/foundation/tools/cache.py +268 -0
- provide/foundation/tools/downloader.py +224 -0
- provide/foundation/tools/installer.py +254 -0
- provide/foundation/tools/registry.py +223 -0
- provide/foundation/tools/resolver.py +321 -0
- provide/foundation/tools/verifier.py +186 -0
- provide/foundation/tracer/otel.py +7 -11
- provide/foundation/tracer/spans.py +2 -2
- provide/foundation/transport/__init__.py +155 -0
- provide/foundation/transport/base.py +171 -0
- provide/foundation/transport/client.py +266 -0
- provide/foundation/transport/config.py +140 -0
- provide/foundation/transport/errors.py +79 -0
- provide/foundation/transport/http.py +232 -0
- provide/foundation/transport/middleware.py +360 -0
- provide/foundation/transport/registry.py +167 -0
- provide/foundation/transport/types.py +45 -0
- provide/foundation/utils/deps.py +14 -12
- provide/foundation/utils/parsing.py +49 -4
- {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/METADATA +5 -28
- provide_foundation-0.0.0.dev2.dist-info/RECORD +225 -0
- provide/foundation/cli/commands/logs/generate_old.py +0 -569
- provide/foundation/crypto/certificates.py +0 -896
- provide/foundation/logger/emoji/__init__.py +0 -44
- provide/foundation/logger/emoji/matrix.py +0 -209
- provide/foundation/logger/emoji/sets.py +0 -458
- provide/foundation/logger/emoji/types.py +0 -56
- provide/foundation/logger/setup/emoji_resolver.py +0 -64
- provide_foundation-0.0.0.dev0.dist-info/RECORD +0 -149
- /provide/foundation/{observability → integrations}/openobserve/exceptions.py +0 -0
- /provide/foundation/{observability → integrations}/openobserve/models.py +0 -0
- {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/WHEEL +0 -0
- {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/entry_points.txt +0 -0
- {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/licenses/LICENSE +0 -0
- {provide_foundation-0.0.0.dev0.dist-info → provide_foundation-0.0.0.dev2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,151 @@
|
|
1
|
+
"""
|
2
|
+
Hub configuration management utilities.
|
3
|
+
|
4
|
+
Provides functions for resolving configuration values from registered sources,
|
5
|
+
loading configurations, and managing the configuration chain.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import asyncio
|
9
|
+
import inspect
|
10
|
+
from typing import Any, TypeVar
|
11
|
+
|
12
|
+
from provide.foundation.errors.decorators import with_error_handling
|
13
|
+
from provide.foundation.hub.registry import RegistryEntry
|
14
|
+
from provide.foundation.logger import get_logger
|
15
|
+
|
16
|
+
T = TypeVar("T")
|
17
|
+
|
18
|
+
log = get_logger(__name__)
|
19
|
+
|
20
|
+
|
21
|
+
def _get_registry_and_lock():
|
22
|
+
"""Get registry and lock from components module."""
|
23
|
+
from provide.foundation.hub.components import get_component_registry, _registry_lock, ComponentCategory
|
24
|
+
return get_component_registry(), _registry_lock, ComponentCategory
|
25
|
+
|
26
|
+
|
27
|
+
@with_error_handling(fallback=None, suppress=(Exception,))
|
28
|
+
def resolve_config_value(key: str) -> Any:
|
29
|
+
"""Resolve configuration value using priority-ordered sources."""
|
30
|
+
registry, registry_lock, ComponentCategory = _get_registry_and_lock()
|
31
|
+
|
32
|
+
with registry_lock:
|
33
|
+
# Get all config sources
|
34
|
+
all_entries = list(registry)
|
35
|
+
config_sources = [
|
36
|
+
entry
|
37
|
+
for entry in all_entries
|
38
|
+
if entry.dimension == ComponentCategory.CONFIG_SOURCE.value
|
39
|
+
]
|
40
|
+
|
41
|
+
# Sort by priority (highest first)
|
42
|
+
config_sources.sort(key=lambda e: e.metadata.get("priority", 0), reverse=True)
|
43
|
+
|
44
|
+
# Try each source
|
45
|
+
for entry in config_sources:
|
46
|
+
source = entry.value
|
47
|
+
if hasattr(source, "get_value"):
|
48
|
+
# Try to get value, continue on error
|
49
|
+
try:
|
50
|
+
value = source.get_value(key)
|
51
|
+
if value is not None:
|
52
|
+
return value
|
53
|
+
except Exception:
|
54
|
+
continue
|
55
|
+
|
56
|
+
return None
|
57
|
+
|
58
|
+
|
59
|
+
def get_config_chain() -> list[RegistryEntry]:
|
60
|
+
"""Get configuration sources ordered by priority."""
|
61
|
+
registry, registry_lock, ComponentCategory = _get_registry_and_lock()
|
62
|
+
|
63
|
+
with registry_lock:
|
64
|
+
# Get all config sources
|
65
|
+
all_entries = list(registry)
|
66
|
+
config_sources = [
|
67
|
+
entry
|
68
|
+
for entry in all_entries
|
69
|
+
if entry.dimension == ComponentCategory.CONFIG_SOURCE.value
|
70
|
+
]
|
71
|
+
|
72
|
+
# Sort by priority (highest first)
|
73
|
+
config_sources.sort(key=lambda e: e.metadata.get("priority", 0), reverse=True)
|
74
|
+
return config_sources
|
75
|
+
|
76
|
+
|
77
|
+
@with_error_handling(
|
78
|
+
fallback={},
|
79
|
+
context_provider=lambda: {"function": "load_all_configs"}
|
80
|
+
)
|
81
|
+
async def load_all_configs() -> dict[str, Any]:
|
82
|
+
"""Load configurations from all registered sources."""
|
83
|
+
configs = {}
|
84
|
+
chain = get_config_chain()
|
85
|
+
|
86
|
+
for entry in chain:
|
87
|
+
source = entry.value
|
88
|
+
if hasattr(source, "load_config"):
|
89
|
+
try:
|
90
|
+
if inspect.iscoroutinefunction(source.load_config):
|
91
|
+
source_config = await source.load_config()
|
92
|
+
else:
|
93
|
+
source_config = source.load_config()
|
94
|
+
|
95
|
+
if source_config:
|
96
|
+
configs.update(source_config)
|
97
|
+
except Exception as e:
|
98
|
+
log.warning(
|
99
|
+
"Config source failed to load", source=entry.name, error=str(e)
|
100
|
+
)
|
101
|
+
|
102
|
+
return configs
|
103
|
+
|
104
|
+
|
105
|
+
def load_config_from_registry(config_class: type[T]) -> T:
|
106
|
+
"""
|
107
|
+
Load configuration from registry sources.
|
108
|
+
|
109
|
+
Args:
|
110
|
+
config_class: Configuration class to instantiate
|
111
|
+
|
112
|
+
Returns:
|
113
|
+
Configuration instance loaded from registry sources
|
114
|
+
"""
|
115
|
+
registry, registry_lock, ComponentCategory = _get_registry_and_lock()
|
116
|
+
|
117
|
+
with registry_lock:
|
118
|
+
# Get configuration data from registry
|
119
|
+
config_data = {}
|
120
|
+
|
121
|
+
# Load from all config sources
|
122
|
+
chain = get_config_chain()
|
123
|
+
for entry in chain:
|
124
|
+
source = entry.value
|
125
|
+
if hasattr(source, "load_config"):
|
126
|
+
try:
|
127
|
+
# Skip async sources in sync context
|
128
|
+
if inspect.iscoroutinefunction(source.load_config):
|
129
|
+
log.debug("Skipping async config source in sync context", source=entry.name)
|
130
|
+
continue
|
131
|
+
|
132
|
+
source_data = source.load_config()
|
133
|
+
if source_data:
|
134
|
+
config_data.update(source_data)
|
135
|
+
except Exception as e:
|
136
|
+
log.warning(
|
137
|
+
"Failed to load config from source",
|
138
|
+
source=entry.name,
|
139
|
+
error=str(e)
|
140
|
+
)
|
141
|
+
|
142
|
+
# Create config instance
|
143
|
+
return config_class.from_dict(config_data)
|
144
|
+
|
145
|
+
|
146
|
+
__all__ = [
|
147
|
+
"resolve_config_value",
|
148
|
+
"get_config_chain",
|
149
|
+
"load_all_configs",
|
150
|
+
"load_config_from_registry",
|
151
|
+
]
|
@@ -0,0 +1,62 @@
|
|
1
|
+
"""
|
2
|
+
Hub component discovery and dependency resolution utilities.
|
3
|
+
|
4
|
+
Provides functions for discovering components and resolving their dependencies
|
5
|
+
in the Hub registry system.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from typing import Any
|
9
|
+
|
10
|
+
from provide.foundation.hub.registry import Registry
|
11
|
+
|
12
|
+
|
13
|
+
def _get_registry_and_lock():
|
14
|
+
"""Get registry and lock from components module."""
|
15
|
+
from provide.foundation.hub.components import get_component_registry, _registry_lock
|
16
|
+
return get_component_registry(), _registry_lock
|
17
|
+
|
18
|
+
|
19
|
+
def resolve_component_dependencies(name: str, dimension: str) -> dict[str, Any]:
|
20
|
+
"""Resolve component dependencies recursively."""
|
21
|
+
registry, registry_lock = _get_registry_and_lock()
|
22
|
+
|
23
|
+
with registry_lock:
|
24
|
+
entry = registry.get_entry(name, dimension)
|
25
|
+
|
26
|
+
if not entry:
|
27
|
+
return {}
|
28
|
+
|
29
|
+
dependencies = {}
|
30
|
+
dep_names = entry.metadata.get("dependencies", [])
|
31
|
+
|
32
|
+
for dep_name in dep_names:
|
33
|
+
# Try same dimension first
|
34
|
+
dep_component = registry.get(dep_name, dimension)
|
35
|
+
if dep_component is not None:
|
36
|
+
dependencies[dep_name] = dep_component
|
37
|
+
else:
|
38
|
+
# Search across dimensions
|
39
|
+
dep_component = registry.get(dep_name)
|
40
|
+
if dep_component is not None:
|
41
|
+
dependencies[dep_name] = dep_component
|
42
|
+
|
43
|
+
return dependencies
|
44
|
+
|
45
|
+
|
46
|
+
def discover_components(
|
47
|
+
group: str,
|
48
|
+
dimension: str = "component",
|
49
|
+
registry: Registry | None = None,
|
50
|
+
) -> dict[str, type[Any]]:
|
51
|
+
"""
|
52
|
+
Discover and register components from entry points.
|
53
|
+
|
54
|
+
This is a stub for the TDD implementation.
|
55
|
+
"""
|
56
|
+
return {}
|
57
|
+
|
58
|
+
|
59
|
+
__all__ = [
|
60
|
+
"resolve_component_dependencies",
|
61
|
+
"discover_components",
|
62
|
+
]
|
@@ -0,0 +1,81 @@
|
|
1
|
+
"""
|
2
|
+
Hub error handler management utilities.
|
3
|
+
|
4
|
+
Provides functions for discovering and executing error handlers from the registry.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from typing import Any
|
8
|
+
|
9
|
+
from provide.foundation.errors.decorators import with_error_handling
|
10
|
+
from provide.foundation.hub.registry import RegistryEntry
|
11
|
+
from provide.foundation.logger import get_logger
|
12
|
+
|
13
|
+
log = get_logger(__name__)
|
14
|
+
|
15
|
+
|
16
|
+
def _get_registry_and_lock():
|
17
|
+
"""Get registry and lock from components module."""
|
18
|
+
from provide.foundation.hub.components import get_component_registry, _registry_lock, ComponentCategory
|
19
|
+
return get_component_registry(), _registry_lock, ComponentCategory
|
20
|
+
|
21
|
+
|
22
|
+
def get_handlers_for_exception(exception: Exception) -> list[RegistryEntry]:
|
23
|
+
"""Get error handlers that can handle the given exception type."""
|
24
|
+
registry, registry_lock, ComponentCategory = _get_registry_and_lock()
|
25
|
+
|
26
|
+
with registry_lock:
|
27
|
+
# Get all error handlers
|
28
|
+
all_entries = list(registry)
|
29
|
+
handlers = [
|
30
|
+
entry
|
31
|
+
for entry in all_entries
|
32
|
+
if entry.dimension == ComponentCategory.ERROR_HANDLER.value
|
33
|
+
]
|
34
|
+
|
35
|
+
# Filter by exception type
|
36
|
+
exception_type_name = type(exception).__name__
|
37
|
+
matching_handlers = []
|
38
|
+
|
39
|
+
for entry in handlers:
|
40
|
+
exception_types = entry.metadata.get("exception_types", [])
|
41
|
+
if any(
|
42
|
+
exc_type in exception_type_name or exception_type_name in exc_type
|
43
|
+
for exc_type in exception_types
|
44
|
+
):
|
45
|
+
matching_handlers.append(entry)
|
46
|
+
|
47
|
+
# Sort by priority (highest first)
|
48
|
+
matching_handlers.sort(
|
49
|
+
key=lambda e: e.metadata.get("priority", 0), reverse=True
|
50
|
+
)
|
51
|
+
return matching_handlers
|
52
|
+
|
53
|
+
|
54
|
+
@with_error_handling(
|
55
|
+
fallback=None,
|
56
|
+
context_provider=lambda: {"function": "execute_error_handlers", "module": "hub.handlers"}
|
57
|
+
)
|
58
|
+
def execute_error_handlers(
|
59
|
+
exception: Exception, context: dict[str, Any]
|
60
|
+
) -> dict[str, Any] | None:
|
61
|
+
"""Execute error handlers until one handles the exception."""
|
62
|
+
handlers = get_handlers_for_exception(exception)
|
63
|
+
|
64
|
+
for entry in handlers:
|
65
|
+
handler = entry.value
|
66
|
+
try:
|
67
|
+
result = handler(exception, context)
|
68
|
+
if result is not None:
|
69
|
+
return result
|
70
|
+
except Exception as handler_error:
|
71
|
+
log.error(
|
72
|
+
"Error handler failed", handler=entry.name, error=str(handler_error)
|
73
|
+
)
|
74
|
+
|
75
|
+
return None
|
76
|
+
|
77
|
+
|
78
|
+
__all__ = [
|
79
|
+
"get_handlers_for_exception",
|
80
|
+
"execute_error_handlers",
|
81
|
+
]
|
@@ -0,0 +1,194 @@
|
|
1
|
+
"""
|
2
|
+
Hub component lifecycle management utilities.
|
3
|
+
|
4
|
+
Provides functions for initializing, managing, and cleaning up components
|
5
|
+
registered in the Hub registry system.
|
6
|
+
"""
|
7
|
+
|
8
|
+
import asyncio
|
9
|
+
import inspect
|
10
|
+
from typing import Any
|
11
|
+
|
12
|
+
from provide.foundation.logger import get_logger
|
13
|
+
|
14
|
+
log = get_logger(__name__)
|
15
|
+
|
16
|
+
|
17
|
+
def _get_registry_and_globals():
|
18
|
+
"""Get registry, lock, and initialized components from components module."""
|
19
|
+
from provide.foundation.hub.components import (
|
20
|
+
get_component_registry,
|
21
|
+
_registry_lock,
|
22
|
+
_initialized_components
|
23
|
+
)
|
24
|
+
return get_component_registry(), _registry_lock, _initialized_components
|
25
|
+
|
26
|
+
|
27
|
+
def get_or_initialize_component(name: str, dimension: str) -> Any:
|
28
|
+
"""Get component, initializing lazily if needed."""
|
29
|
+
registry, registry_lock, initialized_components = _get_registry_and_globals()
|
30
|
+
|
31
|
+
with registry_lock:
|
32
|
+
key = (name, dimension)
|
33
|
+
|
34
|
+
# Return already initialized component
|
35
|
+
if key in initialized_components:
|
36
|
+
return initialized_components[key]
|
37
|
+
|
38
|
+
entry = registry.get_entry(name, dimension)
|
39
|
+
|
40
|
+
if not entry:
|
41
|
+
return None
|
42
|
+
|
43
|
+
# If already initialized, return it
|
44
|
+
if entry.value is not None:
|
45
|
+
initialized_components[key] = entry.value
|
46
|
+
return entry.value
|
47
|
+
|
48
|
+
# Initialize lazily
|
49
|
+
if entry.metadata.get("lazy", False):
|
50
|
+
factory = entry.metadata.get("factory")
|
51
|
+
if factory:
|
52
|
+
try:
|
53
|
+
component = factory()
|
54
|
+
# Update registry with initialized component
|
55
|
+
registry.register(
|
56
|
+
name=name,
|
57
|
+
value=component,
|
58
|
+
dimension=dimension,
|
59
|
+
metadata=entry.metadata,
|
60
|
+
replace=True,
|
61
|
+
)
|
62
|
+
initialized_components[key] = component
|
63
|
+
return component
|
64
|
+
except Exception as e:
|
65
|
+
log.error(
|
66
|
+
"Component initialization failed",
|
67
|
+
component=name,
|
68
|
+
dimension=dimension,
|
69
|
+
error=str(e),
|
70
|
+
)
|
71
|
+
|
72
|
+
return entry.value
|
73
|
+
|
74
|
+
|
75
|
+
async def initialize_async_component(name: str, dimension: str) -> Any:
|
76
|
+
"""Initialize component asynchronously."""
|
77
|
+
registry, registry_lock, initialized_components = _get_registry_and_globals()
|
78
|
+
|
79
|
+
with registry_lock:
|
80
|
+
key = (name, dimension)
|
81
|
+
|
82
|
+
# Return already initialized component
|
83
|
+
if key in initialized_components:
|
84
|
+
return initialized_components[key]
|
85
|
+
|
86
|
+
entry = registry.get_entry(name, dimension)
|
87
|
+
|
88
|
+
if not entry:
|
89
|
+
return None
|
90
|
+
|
91
|
+
# Initialize with async factory
|
92
|
+
if entry.metadata.get("async", False):
|
93
|
+
factory = entry.metadata.get("factory")
|
94
|
+
if factory:
|
95
|
+
try:
|
96
|
+
if inspect.iscoroutinefunction(factory):
|
97
|
+
component = await factory()
|
98
|
+
else:
|
99
|
+
component = factory()
|
100
|
+
|
101
|
+
# Update registry
|
102
|
+
registry.register(
|
103
|
+
name=name,
|
104
|
+
value=component,
|
105
|
+
dimension=dimension,
|
106
|
+
metadata=entry.metadata,
|
107
|
+
replace=True,
|
108
|
+
)
|
109
|
+
initialized_components[key] = component
|
110
|
+
return component
|
111
|
+
except Exception as e:
|
112
|
+
log.error(
|
113
|
+
"Async component initialization failed",
|
114
|
+
component=name,
|
115
|
+
dimension=dimension,
|
116
|
+
error=str(e),
|
117
|
+
)
|
118
|
+
|
119
|
+
return entry.value
|
120
|
+
|
121
|
+
|
122
|
+
def cleanup_all_components(dimension: str | None = None) -> None:
|
123
|
+
"""Clean up all components in dimension."""
|
124
|
+
registry, registry_lock, _ = _get_registry_and_globals()
|
125
|
+
|
126
|
+
with registry_lock:
|
127
|
+
if dimension:
|
128
|
+
entries = [entry for entry in registry if entry.dimension == dimension]
|
129
|
+
else:
|
130
|
+
entries = list(registry)
|
131
|
+
|
132
|
+
for entry in entries:
|
133
|
+
if entry.metadata.get("supports_cleanup", False):
|
134
|
+
component = entry.value
|
135
|
+
if hasattr(component, "cleanup"):
|
136
|
+
try:
|
137
|
+
cleanup_func = component.cleanup
|
138
|
+
if inspect.iscoroutinefunction(cleanup_func):
|
139
|
+
# Run async cleanup
|
140
|
+
loop = None
|
141
|
+
try:
|
142
|
+
loop = asyncio.get_event_loop()
|
143
|
+
if loop.is_running():
|
144
|
+
# Create task if loop is running
|
145
|
+
loop.create_task(cleanup_func())
|
146
|
+
else:
|
147
|
+
loop.run_until_complete(cleanup_func())
|
148
|
+
except RuntimeError:
|
149
|
+
# Create new loop if none exists
|
150
|
+
loop = asyncio.new_event_loop()
|
151
|
+
loop.run_until_complete(cleanup_func())
|
152
|
+
loop.close()
|
153
|
+
else:
|
154
|
+
cleanup_func()
|
155
|
+
except Exception as e:
|
156
|
+
log.error(
|
157
|
+
"Component cleanup failed",
|
158
|
+
component=entry.name,
|
159
|
+
dimension=entry.dimension,
|
160
|
+
error=str(e),
|
161
|
+
)
|
162
|
+
|
163
|
+
|
164
|
+
async def initialize_all_async_components() -> None:
|
165
|
+
"""Initialize all async components in dependency order."""
|
166
|
+
registry, _, _ = _get_registry_and_globals()
|
167
|
+
|
168
|
+
# Get all async components
|
169
|
+
async_components = [
|
170
|
+
entry for entry in registry if entry.metadata.get("async", False)
|
171
|
+
]
|
172
|
+
|
173
|
+
# Sort by priority for initialization order
|
174
|
+
async_components.sort(key=lambda e: e.metadata.get("priority", 0), reverse=True)
|
175
|
+
|
176
|
+
# Initialize each component
|
177
|
+
for entry in async_components:
|
178
|
+
try:
|
179
|
+
await initialize_async_component(entry.name, entry.dimension)
|
180
|
+
except Exception as e:
|
181
|
+
log.error(
|
182
|
+
"Failed to initialize async component",
|
183
|
+
component=entry.name,
|
184
|
+
dimension=entry.dimension,
|
185
|
+
error=str(e),
|
186
|
+
)
|
187
|
+
|
188
|
+
|
189
|
+
__all__ = [
|
190
|
+
"get_or_initialize_component",
|
191
|
+
"initialize_async_component",
|
192
|
+
"cleanup_all_components",
|
193
|
+
"initialize_all_async_components",
|
194
|
+
]
|
@@ -19,7 +19,7 @@ except ImportError:
|
|
19
19
|
click = None
|
20
20
|
_HAS_CLICK = False
|
21
21
|
|
22
|
-
from provide.foundation.context import
|
22
|
+
from provide.foundation.context import CLIContext
|
23
23
|
from provide.foundation.errors.config import ValidationError
|
24
24
|
from provide.foundation.errors.decorators import with_error_handling
|
25
25
|
from provide.foundation.errors.resources import AlreadyExistsError
|
@@ -60,7 +60,7 @@ class Hub:
|
|
60
60
|
|
61
61
|
def __init__(
|
62
62
|
self,
|
63
|
-
context:
|
63
|
+
context: CLIContext | None = None,
|
64
64
|
component_registry: Registry | None = None,
|
65
65
|
command_registry: Registry | None = None,
|
66
66
|
) -> None:
|
@@ -68,11 +68,11 @@ class Hub:
|
|
68
68
|
Initialize the hub.
|
69
69
|
|
70
70
|
Args:
|
71
|
-
context: Foundation
|
71
|
+
context: Foundation CLIContext for configuration
|
72
72
|
component_registry: Custom component registry
|
73
73
|
command_registry: Custom command registry
|
74
74
|
"""
|
75
|
-
self.context = context or
|
75
|
+
self.context = context or CLIContext()
|
76
76
|
self._component_registry = component_registry or get_component_registry()
|
77
77
|
self._command_registry = command_registry or get_command_registry()
|
78
78
|
self._cli_group: click.Group | None = None
|
@@ -0,0 +1,44 @@
|
|
1
|
+
"""
|
2
|
+
Hub processor pipeline management utilities.
|
3
|
+
|
4
|
+
Provides functions for managing log processors and processing stages
|
5
|
+
in the Hub registry system.
|
6
|
+
"""
|
7
|
+
|
8
|
+
from provide.foundation.hub.registry import RegistryEntry
|
9
|
+
|
10
|
+
|
11
|
+
def _get_registry_and_lock():
|
12
|
+
"""Get registry and lock from components module."""
|
13
|
+
from provide.foundation.hub.components import get_component_registry, _registry_lock, ComponentCategory
|
14
|
+
return get_component_registry(), _registry_lock, ComponentCategory
|
15
|
+
|
16
|
+
|
17
|
+
def get_processor_pipeline() -> list[RegistryEntry]:
|
18
|
+
"""Get log processors ordered by priority."""
|
19
|
+
registry, registry_lock, ComponentCategory = _get_registry_and_lock()
|
20
|
+
|
21
|
+
with registry_lock:
|
22
|
+
# Get all processors
|
23
|
+
all_entries = list(registry)
|
24
|
+
processors = [
|
25
|
+
entry
|
26
|
+
for entry in all_entries
|
27
|
+
if entry.dimension == ComponentCategory.PROCESSOR.value
|
28
|
+
]
|
29
|
+
|
30
|
+
# Sort by priority (highest first)
|
31
|
+
processors.sort(key=lambda e: e.metadata.get("priority", 0), reverse=True)
|
32
|
+
return processors
|
33
|
+
|
34
|
+
|
35
|
+
def get_processors_for_stage(stage: str) -> list[RegistryEntry]:
|
36
|
+
"""Get processors for a specific processing stage."""
|
37
|
+
pipeline = get_processor_pipeline()
|
38
|
+
return [entry for entry in pipeline if entry.metadata.get("stage") == stage]
|
39
|
+
|
40
|
+
|
41
|
+
__all__ = [
|
42
|
+
"get_processor_pipeline",
|
43
|
+
"get_processors_for_stage",
|
44
|
+
]
|
@@ -0,0 +1,11 @@
|
|
1
|
+
"""
|
2
|
+
Optional integrations for Foundation.
|
3
|
+
|
4
|
+
This module contains integrations with external services and tools
|
5
|
+
that are not part of the core foundation library.
|
6
|
+
"""
|
7
|
+
|
8
|
+
__all__ = [
|
9
|
+
# Available integrations (import on demand)
|
10
|
+
# "openobserve",
|
11
|
+
]
|
@@ -1,11 +1,12 @@
|
|
1
1
|
"""
|
2
2
|
OpenObserve integration for Foundation.
|
3
3
|
|
4
|
-
Provides log querying and streaming capabilities
|
4
|
+
Provides log querying and streaming capabilities as an optional integration.
|
5
5
|
"""
|
6
6
|
|
7
|
-
from provide.foundation.
|
8
|
-
from provide.foundation.
|
7
|
+
from provide.foundation.integrations.openobserve.client import OpenObserveClient
|
8
|
+
from provide.foundation.integrations.openobserve.config import OpenObserveConfig
|
9
|
+
from provide.foundation.integrations.openobserve.exceptions import (
|
9
10
|
OpenObserveAuthenticationError,
|
10
11
|
OpenObserveConfigError,
|
11
12
|
OpenObserveConnectionError,
|
@@ -13,7 +14,7 @@ from provide.foundation.observability.openobserve.exceptions import (
|
|
13
14
|
OpenObserveQueryError,
|
14
15
|
OpenObserveStreamingError,
|
15
16
|
)
|
16
|
-
from provide.foundation.
|
17
|
+
from provide.foundation.integrations.openobserve.formatters import (
|
17
18
|
format_csv,
|
18
19
|
format_json,
|
19
20
|
format_log_line,
|
@@ -21,13 +22,13 @@ from provide.foundation.observability.openobserve.formatters import (
|
|
21
22
|
format_summary,
|
22
23
|
format_table,
|
23
24
|
)
|
24
|
-
from provide.foundation.
|
25
|
+
from provide.foundation.integrations.openobserve.models import (
|
25
26
|
SearchQuery,
|
26
27
|
SearchResponse,
|
27
28
|
StreamInfo,
|
28
29
|
parse_relative_time,
|
29
30
|
)
|
30
|
-
from provide.foundation.
|
31
|
+
from provide.foundation.integrations.openobserve.search import (
|
31
32
|
aggregate_by_level,
|
32
33
|
get_current_trace_logs,
|
33
34
|
search_by_level,
|
@@ -36,13 +37,15 @@ from provide.foundation.observability.openobserve.search import (
|
|
36
37
|
search_errors,
|
37
38
|
search_logs,
|
38
39
|
)
|
39
|
-
from provide.foundation.
|
40
|
+
from provide.foundation.integrations.openobserve.streaming import (
|
40
41
|
stream_logs,
|
41
42
|
stream_search_http2,
|
42
43
|
tail_logs,
|
43
44
|
)
|
44
45
|
|
45
46
|
__all__ = [
|
47
|
+
# Configuration
|
48
|
+
"OpenObserveConfig",
|
46
49
|
# Client
|
47
50
|
"OpenObserveClient",
|
48
51
|
# Search functions
|