provide-foundation 0.0.0.dev1__py3-none-any.whl → 0.0.0.dev3__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.
Files changed (163) hide show
  1. provide/foundation/__init__.py +36 -10
  2. provide/foundation/archive/__init__.py +1 -1
  3. provide/foundation/archive/base.py +15 -14
  4. provide/foundation/archive/bzip2.py +40 -40
  5. provide/foundation/archive/gzip.py +42 -42
  6. provide/foundation/archive/operations.py +93 -96
  7. provide/foundation/archive/tar.py +33 -31
  8. provide/foundation/archive/zip.py +52 -50
  9. provide/foundation/asynctools/__init__.py +20 -0
  10. provide/foundation/asynctools/core.py +126 -0
  11. provide/foundation/cli/__init__.py +2 -2
  12. provide/foundation/cli/commands/deps.py +15 -9
  13. provide/foundation/cli/commands/logs/__init__.py +3 -3
  14. provide/foundation/cli/commands/logs/generate.py +2 -2
  15. provide/foundation/cli/commands/logs/query.py +4 -4
  16. provide/foundation/cli/commands/logs/send.py +3 -3
  17. provide/foundation/cli/commands/logs/tail.py +3 -3
  18. provide/foundation/cli/decorators.py +11 -11
  19. provide/foundation/cli/main.py +1 -1
  20. provide/foundation/cli/testing.py +2 -40
  21. provide/foundation/cli/utils.py +21 -18
  22. provide/foundation/config/__init__.py +35 -2
  23. provide/foundation/config/base.py +2 -2
  24. provide/foundation/config/converters.py +477 -0
  25. provide/foundation/config/defaults.py +67 -0
  26. provide/foundation/config/env.py +6 -20
  27. provide/foundation/config/loader.py +10 -4
  28. provide/foundation/config/sync.py +8 -6
  29. provide/foundation/config/types.py +5 -5
  30. provide/foundation/config/validators.py +4 -4
  31. provide/foundation/console/input.py +5 -5
  32. provide/foundation/console/output.py +36 -14
  33. provide/foundation/context/__init__.py +8 -4
  34. provide/foundation/context/core.py +88 -110
  35. provide/foundation/crypto/certificates/__init__.py +9 -5
  36. provide/foundation/crypto/certificates/base.py +2 -2
  37. provide/foundation/crypto/certificates/certificate.py +48 -19
  38. provide/foundation/crypto/certificates/factory.py +26 -18
  39. provide/foundation/crypto/certificates/generator.py +24 -23
  40. provide/foundation/crypto/certificates/loader.py +24 -16
  41. provide/foundation/crypto/certificates/operations.py +17 -10
  42. provide/foundation/crypto/certificates/trust.py +21 -21
  43. provide/foundation/env/__init__.py +28 -0
  44. provide/foundation/env/core.py +218 -0
  45. provide/foundation/errors/__init__.py +3 -3
  46. provide/foundation/errors/decorators.py +0 -234
  47. provide/foundation/errors/types.py +0 -98
  48. provide/foundation/eventsets/display.py +13 -14
  49. provide/foundation/eventsets/registry.py +61 -31
  50. provide/foundation/eventsets/resolver.py +50 -46
  51. provide/foundation/eventsets/sets/das.py +8 -8
  52. provide/foundation/eventsets/sets/database.py +14 -14
  53. provide/foundation/eventsets/sets/http.py +21 -21
  54. provide/foundation/eventsets/sets/llm.py +16 -16
  55. provide/foundation/eventsets/sets/task_queue.py +13 -13
  56. provide/foundation/eventsets/types.py +7 -7
  57. provide/foundation/file/directory.py +14 -23
  58. provide/foundation/file/lock.py +4 -3
  59. provide/foundation/hub/components.py +75 -389
  60. provide/foundation/hub/config.py +157 -0
  61. provide/foundation/hub/discovery.py +63 -0
  62. provide/foundation/hub/handlers.py +89 -0
  63. provide/foundation/hub/lifecycle.py +195 -0
  64. provide/foundation/hub/manager.py +7 -4
  65. provide/foundation/hub/processors.py +49 -0
  66. provide/foundation/integrations/__init__.py +11 -0
  67. provide/foundation/{observability → integrations}/openobserve/__init__.py +10 -7
  68. provide/foundation/{observability → integrations}/openobserve/auth.py +1 -1
  69. provide/foundation/{observability → integrations}/openobserve/client.py +14 -14
  70. provide/foundation/{observability → integrations}/openobserve/commands.py +12 -12
  71. provide/foundation/integrations/openobserve/config.py +37 -0
  72. provide/foundation/{observability → integrations}/openobserve/formatters.py +1 -1
  73. provide/foundation/{observability → integrations}/openobserve/otlp.py +2 -2
  74. provide/foundation/{observability → integrations}/openobserve/search.py +2 -3
  75. provide/foundation/{observability → integrations}/openobserve/streaming.py +5 -5
  76. provide/foundation/logger/__init__.py +0 -1
  77. provide/foundation/logger/config/base.py +1 -1
  78. provide/foundation/logger/config/logging.py +69 -299
  79. provide/foundation/logger/config/telemetry.py +39 -121
  80. provide/foundation/logger/factories.py +2 -2
  81. provide/foundation/logger/processors/main.py +12 -10
  82. provide/foundation/logger/ratelimit/limiters.py +4 -4
  83. provide/foundation/logger/ratelimit/processor.py +1 -1
  84. provide/foundation/logger/setup/coordinator.py +39 -25
  85. provide/foundation/logger/setup/processors.py +3 -3
  86. provide/foundation/logger/setup/testing.py +14 -0
  87. provide/foundation/logger/trace.py +5 -5
  88. provide/foundation/metrics/__init__.py +1 -1
  89. provide/foundation/metrics/otel.py +3 -1
  90. provide/foundation/observability/__init__.py +3 -3
  91. provide/foundation/process/__init__.py +9 -0
  92. provide/foundation/process/exit.py +48 -0
  93. provide/foundation/process/lifecycle.py +69 -46
  94. provide/foundation/resilience/__init__.py +36 -0
  95. provide/foundation/resilience/circuit.py +166 -0
  96. provide/foundation/resilience/decorators.py +236 -0
  97. provide/foundation/resilience/fallback.py +208 -0
  98. provide/foundation/resilience/retry.py +327 -0
  99. provide/foundation/serialization/__init__.py +16 -0
  100. provide/foundation/serialization/core.py +70 -0
  101. provide/foundation/streams/config.py +78 -0
  102. provide/foundation/streams/console.py +4 -5
  103. provide/foundation/streams/core.py +5 -2
  104. provide/foundation/streams/file.py +12 -2
  105. provide/foundation/testing/__init__.py +29 -9
  106. provide/foundation/testing/archive/__init__.py +7 -7
  107. provide/foundation/testing/archive/fixtures.py +58 -54
  108. provide/foundation/testing/cli.py +30 -20
  109. provide/foundation/testing/common/__init__.py +13 -15
  110. provide/foundation/testing/common/fixtures.py +27 -57
  111. provide/foundation/testing/file/__init__.py +15 -15
  112. provide/foundation/testing/file/content_fixtures.py +289 -0
  113. provide/foundation/testing/file/directory_fixtures.py +107 -0
  114. provide/foundation/testing/file/fixtures.py +42 -516
  115. provide/foundation/testing/file/special_fixtures.py +145 -0
  116. provide/foundation/testing/logger.py +89 -8
  117. provide/foundation/testing/mocking/__init__.py +21 -21
  118. provide/foundation/testing/mocking/fixtures.py +80 -67
  119. provide/foundation/testing/process/__init__.py +23 -23
  120. provide/foundation/testing/process/async_fixtures.py +414 -0
  121. provide/foundation/testing/process/fixtures.py +48 -571
  122. provide/foundation/testing/process/subprocess_fixtures.py +210 -0
  123. provide/foundation/testing/threading/__init__.py +17 -17
  124. provide/foundation/testing/threading/basic_fixtures.py +105 -0
  125. provide/foundation/testing/threading/data_fixtures.py +101 -0
  126. provide/foundation/testing/threading/execution_fixtures.py +278 -0
  127. provide/foundation/testing/threading/fixtures.py +32 -502
  128. provide/foundation/testing/threading/sync_fixtures.py +100 -0
  129. provide/foundation/testing/time/__init__.py +11 -11
  130. provide/foundation/testing/time/fixtures.py +95 -83
  131. provide/foundation/testing/transport/__init__.py +9 -9
  132. provide/foundation/testing/transport/fixtures.py +54 -54
  133. provide/foundation/time/__init__.py +18 -0
  134. provide/foundation/time/core.py +63 -0
  135. provide/foundation/tools/__init__.py +2 -2
  136. provide/foundation/tools/base.py +68 -67
  137. provide/foundation/tools/cache.py +69 -74
  138. provide/foundation/tools/downloader.py +68 -62
  139. provide/foundation/tools/installer.py +51 -57
  140. provide/foundation/tools/registry.py +38 -45
  141. provide/foundation/tools/resolver.py +70 -68
  142. provide/foundation/tools/verifier.py +39 -50
  143. provide/foundation/tracer/spans.py +2 -14
  144. provide/foundation/transport/__init__.py +26 -33
  145. provide/foundation/transport/base.py +32 -30
  146. provide/foundation/transport/client.py +44 -49
  147. provide/foundation/transport/config.py +36 -107
  148. provide/foundation/transport/errors.py +13 -27
  149. provide/foundation/transport/http.py +69 -55
  150. provide/foundation/transport/middleware.py +113 -114
  151. provide/foundation/transport/registry.py +29 -27
  152. provide/foundation/transport/types.py +6 -6
  153. provide/foundation/utils/deps.py +17 -14
  154. provide/foundation/utils/parsing.py +49 -4
  155. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/METADATA +2 -2
  156. provide_foundation-0.0.0.dev3.dist-info/RECORD +233 -0
  157. provide_foundation-0.0.0.dev1.dist-info/RECORD +0 -200
  158. /provide/foundation/{observability → integrations}/openobserve/exceptions.py +0 -0
  159. /provide/foundation/{observability → integrations}/openobserve/models.py +0 -0
  160. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/WHEEL +0 -0
  161. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/entry_points.txt +0 -0
  162. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/licenses/LICENSE +0 -0
  163. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,63 @@
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 _registry_lock, get_component_registry
16
+
17
+ return get_component_registry(), _registry_lock
18
+
19
+
20
+ def resolve_component_dependencies(name: str, dimension: str) -> dict[str, Any]:
21
+ """Resolve component dependencies recursively."""
22
+ registry, registry_lock = _get_registry_and_lock()
23
+
24
+ with registry_lock:
25
+ entry = registry.get_entry(name, dimension)
26
+
27
+ if not entry:
28
+ return {}
29
+
30
+ dependencies = {}
31
+ dep_names = entry.metadata.get("dependencies", [])
32
+
33
+ for dep_name in dep_names:
34
+ # Try same dimension first
35
+ dep_component = registry.get(dep_name, dimension)
36
+ if dep_component is not None:
37
+ dependencies[dep_name] = dep_component
38
+ else:
39
+ # Search across dimensions
40
+ dep_component = registry.get(dep_name)
41
+ if dep_component is not None:
42
+ dependencies[dep_name] = dep_component
43
+
44
+ return dependencies
45
+
46
+
47
+ def discover_components(
48
+ group: str,
49
+ dimension: str = "component",
50
+ registry: Registry | None = None,
51
+ ) -> dict[str, type[Any]]:
52
+ """
53
+ Discover and register components from entry points.
54
+
55
+ This is a stub for the TDD implementation.
56
+ """
57
+ return {}
58
+
59
+
60
+ __all__ = [
61
+ "discover_components",
62
+ "resolve_component_dependencies",
63
+ ]
@@ -0,0 +1,89 @@
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 (
19
+ ComponentCategory,
20
+ _registry_lock,
21
+ get_component_registry,
22
+ )
23
+
24
+ return get_component_registry(), _registry_lock, ComponentCategory
25
+
26
+
27
+ def get_handlers_for_exception(exception: Exception) -> list[RegistryEntry]:
28
+ """Get error handlers that can handle the given exception type."""
29
+ registry, registry_lock, ComponentCategory = _get_registry_and_lock()
30
+
31
+ with registry_lock:
32
+ # Get all error handlers
33
+ all_entries = list(registry)
34
+ handlers = [
35
+ entry
36
+ for entry in all_entries
37
+ if entry.dimension == ComponentCategory.ERROR_HANDLER.value
38
+ ]
39
+
40
+ # Filter by exception type
41
+ exception_type_name = type(exception).__name__
42
+ matching_handlers = []
43
+
44
+ for entry in handlers:
45
+ exception_types = entry.metadata.get("exception_types", [])
46
+ if any(
47
+ exc_type in exception_type_name or exception_type_name in exc_type
48
+ for exc_type in exception_types
49
+ ):
50
+ matching_handlers.append(entry)
51
+
52
+ # Sort by priority (highest first)
53
+ matching_handlers.sort(
54
+ key=lambda e: e.metadata.get("priority", 0), reverse=True
55
+ )
56
+ return matching_handlers
57
+
58
+
59
+ @with_error_handling(
60
+ fallback=None,
61
+ context_provider=lambda: {
62
+ "function": "execute_error_handlers",
63
+ "module": "hub.handlers",
64
+ },
65
+ )
66
+ def execute_error_handlers(
67
+ exception: Exception, context: dict[str, Any]
68
+ ) -> dict[str, Any] | None:
69
+ """Execute error handlers until one handles the exception."""
70
+ handlers = get_handlers_for_exception(exception)
71
+
72
+ for entry in handlers:
73
+ handler = entry.value
74
+ try:
75
+ result = handler(exception, context)
76
+ if result is not None:
77
+ return result
78
+ except Exception as handler_error:
79
+ log.error(
80
+ "Error handler failed", handler=entry.name, error=str(handler_error)
81
+ )
82
+
83
+ return None
84
+
85
+
86
+ __all__ = [
87
+ "execute_error_handlers",
88
+ "get_handlers_for_exception",
89
+ ]
@@ -0,0 +1,195 @@
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
+ _initialized_components,
21
+ _registry_lock,
22
+ get_component_registry,
23
+ )
24
+
25
+ return get_component_registry(), _registry_lock, _initialized_components
26
+
27
+
28
+ def get_or_initialize_component(name: str, dimension: str) -> Any:
29
+ """Get component, initializing lazily if needed."""
30
+ registry, registry_lock, initialized_components = _get_registry_and_globals()
31
+
32
+ with registry_lock:
33
+ key = (name, dimension)
34
+
35
+ # Return already initialized component
36
+ if key in initialized_components:
37
+ return initialized_components[key]
38
+
39
+ entry = registry.get_entry(name, dimension)
40
+
41
+ if not entry:
42
+ return None
43
+
44
+ # If already initialized, return it
45
+ if entry.value is not None:
46
+ initialized_components[key] = entry.value
47
+ return entry.value
48
+
49
+ # Initialize lazily
50
+ if entry.metadata.get("lazy", False):
51
+ factory = entry.metadata.get("factory")
52
+ if factory:
53
+ try:
54
+ component = factory()
55
+ # Update registry with initialized component
56
+ registry.register(
57
+ name=name,
58
+ value=component,
59
+ dimension=dimension,
60
+ metadata=entry.metadata,
61
+ replace=True,
62
+ )
63
+ initialized_components[key] = component
64
+ return component
65
+ except Exception as e:
66
+ log.error(
67
+ "Component initialization failed",
68
+ component=name,
69
+ dimension=dimension,
70
+ error=str(e),
71
+ )
72
+
73
+ return entry.value
74
+
75
+
76
+ async def initialize_async_component(name: str, dimension: str) -> Any:
77
+ """Initialize component asynchronously."""
78
+ registry, registry_lock, initialized_components = _get_registry_and_globals()
79
+
80
+ with registry_lock:
81
+ key = (name, dimension)
82
+
83
+ # Return already initialized component
84
+ if key in initialized_components:
85
+ return initialized_components[key]
86
+
87
+ entry = registry.get_entry(name, dimension)
88
+
89
+ if not entry:
90
+ return None
91
+
92
+ # Initialize with async factory
93
+ if entry.metadata.get("async", False):
94
+ factory = entry.metadata.get("factory")
95
+ if factory:
96
+ try:
97
+ if inspect.iscoroutinefunction(factory):
98
+ component = await factory()
99
+ else:
100
+ component = factory()
101
+
102
+ # Update registry
103
+ registry.register(
104
+ name=name,
105
+ value=component,
106
+ dimension=dimension,
107
+ metadata=entry.metadata,
108
+ replace=True,
109
+ )
110
+ initialized_components[key] = component
111
+ return component
112
+ except Exception as e:
113
+ log.error(
114
+ "Async component initialization failed",
115
+ component=name,
116
+ dimension=dimension,
117
+ error=str(e),
118
+ )
119
+
120
+ return entry.value
121
+
122
+
123
+ def cleanup_all_components(dimension: str | None = None) -> None:
124
+ """Clean up all components in dimension."""
125
+ registry, registry_lock, _ = _get_registry_and_globals()
126
+
127
+ with registry_lock:
128
+ if dimension:
129
+ entries = [entry for entry in registry if entry.dimension == dimension]
130
+ else:
131
+ entries = list(registry)
132
+
133
+ for entry in entries:
134
+ if entry.metadata.get("supports_cleanup", False):
135
+ component = entry.value
136
+ if hasattr(component, "cleanup"):
137
+ try:
138
+ cleanup_func = component.cleanup
139
+ if inspect.iscoroutinefunction(cleanup_func):
140
+ # Run async cleanup
141
+ loop = None
142
+ try:
143
+ loop = asyncio.get_event_loop()
144
+ if loop.is_running():
145
+ # Create task if loop is running
146
+ loop.create_task(cleanup_func())
147
+ else:
148
+ loop.run_until_complete(cleanup_func())
149
+ except RuntimeError:
150
+ # Create new loop if none exists
151
+ loop = asyncio.new_event_loop()
152
+ loop.run_until_complete(cleanup_func())
153
+ loop.close()
154
+ else:
155
+ cleanup_func()
156
+ except Exception as e:
157
+ log.error(
158
+ "Component cleanup failed",
159
+ component=entry.name,
160
+ dimension=entry.dimension,
161
+ error=str(e),
162
+ )
163
+
164
+
165
+ async def initialize_all_async_components() -> None:
166
+ """Initialize all async components in dependency order."""
167
+ registry, _, _ = _get_registry_and_globals()
168
+
169
+ # Get all async components
170
+ async_components = [
171
+ entry for entry in registry if entry.metadata.get("async", False)
172
+ ]
173
+
174
+ # Sort by priority for initialization order
175
+ async_components.sort(key=lambda e: e.metadata.get("priority", 0), reverse=True)
176
+
177
+ # Initialize each component
178
+ for entry in async_components:
179
+ try:
180
+ await initialize_async_component(entry.name, entry.dimension)
181
+ except Exception as e:
182
+ log.error(
183
+ "Failed to initialize async component",
184
+ component=entry.name,
185
+ dimension=entry.dimension,
186
+ error=str(e),
187
+ )
188
+
189
+
190
+ __all__ = [
191
+ "cleanup_all_components",
192
+ "get_or_initialize_component",
193
+ "initialize_all_async_components",
194
+ "initialize_async_component",
195
+ ]
@@ -19,7 +19,7 @@ except ImportError:
19
19
  click = None
20
20
  _HAS_CLICK = False
21
21
 
22
- from provide.foundation.context import Context
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: Context | None = None,
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 context for configuration
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 Context()
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
@@ -433,6 +433,9 @@ def get_hub() -> Hub:
433
433
  # Double-check after acquiring lock
434
434
  if _global_hub is None:
435
435
  _global_hub = Hub()
436
+ # Bootstrap foundation components now that hub is ready
437
+ from provide.foundation.hub.components import bootstrap_foundation
438
+ bootstrap_foundation()
436
439
 
437
440
  return _global_hub
438
441
 
@@ -0,0 +1,49 @@
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 (
14
+ ComponentCategory,
15
+ _registry_lock,
16
+ get_component_registry,
17
+ )
18
+
19
+ return get_component_registry(), _registry_lock, ComponentCategory
20
+
21
+
22
+ def get_processor_pipeline() -> list[RegistryEntry]:
23
+ """Get log processors ordered by priority."""
24
+ registry, registry_lock, ComponentCategory = _get_registry_and_lock()
25
+
26
+ with registry_lock:
27
+ # Get all processors
28
+ all_entries = list(registry)
29
+ processors = [
30
+ entry
31
+ for entry in all_entries
32
+ if entry.dimension == ComponentCategory.PROCESSOR.value
33
+ ]
34
+
35
+ # Sort by priority (highest first)
36
+ processors.sort(key=lambda e: e.metadata.get("priority", 0), reverse=True)
37
+ return processors
38
+
39
+
40
+ def get_processors_for_stage(stage: str) -> list[RegistryEntry]:
41
+ """Get processors for a specific processing stage."""
42
+ pipeline = get_processor_pipeline()
43
+ return [entry for entry in pipeline if entry.metadata.get("stage") == stage]
44
+
45
+
46
+ __all__ = [
47
+ "get_processor_pipeline",
48
+ "get_processors_for_stage",
49
+ ]
@@ -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 when OpenTelemetry is available.
4
+ Provides log querying and streaming capabilities as an optional integration.
5
5
  """
6
6
 
7
- from provide.foundation.observability.openobserve.client import OpenObserveClient
8
- from provide.foundation.observability.openobserve.exceptions import (
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.observability.openobserve.formatters import (
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.observability.openobserve.models import (
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.observability.openobserve.search import (
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.observability.openobserve.streaming import (
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
@@ -4,7 +4,7 @@ Authentication handling for OpenObserve.
4
4
 
5
5
  import base64
6
6
 
7
- from provide.foundation.observability.openobserve.exceptions import (
7
+ from provide.foundation.integrations.openobserve.exceptions import (
8
8
  OpenObserveAuthenticationError,
9
9
  )
10
10
 
@@ -11,22 +11,22 @@ import requests
11
11
  from requests.adapters import HTTPAdapter
12
12
  from urllib3.util.retry import Retry
13
13
 
14
- from provide.foundation.logger import get_logger
15
- from provide.foundation.observability.openobserve.auth import (
14
+ from provide.foundation.integrations.openobserve.auth import (
16
15
  get_auth_headers,
17
16
  validate_credentials,
18
17
  )
19
- from provide.foundation.observability.openobserve.exceptions import (
18
+ from provide.foundation.integrations.openobserve.exceptions import (
20
19
  OpenObserveConfigError,
21
20
  OpenObserveConnectionError,
22
21
  OpenObserveQueryError,
23
22
  )
24
- from provide.foundation.observability.openobserve.models import (
23
+ from provide.foundation.integrations.openobserve.models import (
25
24
  SearchQuery,
26
25
  SearchResponse,
27
26
  StreamInfo,
28
27
  parse_relative_time,
29
28
  )
29
+ from provide.foundation.logger import get_logger
30
30
 
31
31
  log = get_logger(__name__)
32
32
 
@@ -42,7 +42,7 @@ class OpenObserveClient:
42
42
  organization: str = "default",
43
43
  timeout: int = 30,
44
44
  max_retries: int = 3,
45
- ):
45
+ ) -> None:
46
46
  """Initialize OpenObserve client.
47
47
 
48
48
  Args:
@@ -74,7 +74,7 @@ class OpenObserveClient:
74
74
 
75
75
  @classmethod
76
76
  def from_config(cls) -> "OpenObserveClient":
77
- """Create client from TelemetryConfig.
77
+ """Create client from OpenObserveConfig.
78
78
 
79
79
  Returns:
80
80
  Configured OpenObserveClient instance
@@ -82,26 +82,26 @@ class OpenObserveClient:
82
82
  Raises:
83
83
  OpenObserveConfigError: If configuration is missing
84
84
  """
85
- from provide.foundation.logger.config import TelemetryConfig
85
+ from provide.foundation.integrations.openobserve.config import OpenObserveConfig
86
86
 
87
- config = TelemetryConfig.from_env()
87
+ config = OpenObserveConfig.from_env()
88
88
 
89
- if not config.openobserve_url:
89
+ if not config.url:
90
90
  raise OpenObserveConfigError(
91
91
  "OpenObserve URL not configured. Set OPENOBSERVE_URL environment variable."
92
92
  )
93
93
 
94
- if not config.openobserve_user or not config.openobserve_password:
94
+ if not config.user or not config.password:
95
95
  raise OpenObserveConfigError(
96
96
  "OpenObserve credentials not configured. "
97
97
  "Set OPENOBSERVE_USER and OPENOBSERVE_PASSWORD environment variables."
98
98
  )
99
99
 
100
100
  return cls(
101
- url=config.openobserve_url,
102
- username=config.openobserve_user,
103
- password=config.openobserve_password,
104
- organization=config.openobserve_org,
101
+ url=config.url,
102
+ username=config.user,
103
+ password=config.password,
104
+ organization=config.org or "default",
105
105
  )
106
106
 
107
107
  def _make_request(