provide-foundation 0.0.0.dev1__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.
Files changed (93) hide show
  1. provide/foundation/__init__.py +29 -3
  2. provide/foundation/archive/operations.py +4 -6
  3. provide/foundation/cli/__init__.py +2 -2
  4. provide/foundation/cli/commands/deps.py +13 -7
  5. provide/foundation/cli/commands/logs/__init__.py +1 -1
  6. provide/foundation/cli/commands/logs/query.py +1 -1
  7. provide/foundation/cli/commands/logs/send.py +1 -1
  8. provide/foundation/cli/commands/logs/tail.py +1 -1
  9. provide/foundation/cli/decorators.py +11 -10
  10. provide/foundation/cli/main.py +1 -1
  11. provide/foundation/cli/testing.py +2 -35
  12. provide/foundation/cli/utils.py +21 -17
  13. provide/foundation/config/__init__.py +35 -2
  14. provide/foundation/config/converters.py +479 -0
  15. provide/foundation/config/defaults.py +67 -0
  16. provide/foundation/config/env.py +4 -19
  17. provide/foundation/config/loader.py +9 -3
  18. provide/foundation/console/input.py +5 -5
  19. provide/foundation/console/output.py +35 -13
  20. provide/foundation/context/__init__.py +8 -4
  21. provide/foundation/context/core.py +85 -109
  22. provide/foundation/crypto/certificates/operations.py +1 -1
  23. provide/foundation/errors/__init__.py +2 -3
  24. provide/foundation/errors/decorators.py +0 -231
  25. provide/foundation/errors/types.py +0 -97
  26. provide/foundation/file/directory.py +13 -22
  27. provide/foundation/file/lock.py +3 -1
  28. provide/foundation/hub/components.py +72 -384
  29. provide/foundation/hub/config.py +151 -0
  30. provide/foundation/hub/discovery.py +62 -0
  31. provide/foundation/hub/handlers.py +81 -0
  32. provide/foundation/hub/lifecycle.py +194 -0
  33. provide/foundation/hub/manager.py +4 -4
  34. provide/foundation/hub/processors.py +44 -0
  35. provide/foundation/integrations/__init__.py +11 -0
  36. provide/foundation/{observability → integrations}/openobserve/__init__.py +10 -7
  37. provide/foundation/{observability → integrations}/openobserve/auth.py +1 -1
  38. provide/foundation/{observability → integrations}/openobserve/client.py +12 -12
  39. provide/foundation/{observability → integrations}/openobserve/commands.py +3 -3
  40. provide/foundation/integrations/openobserve/config.py +37 -0
  41. provide/foundation/{observability → integrations}/openobserve/formatters.py +1 -1
  42. provide/foundation/{observability → integrations}/openobserve/otlp.py +1 -1
  43. provide/foundation/{observability → integrations}/openobserve/search.py +2 -2
  44. provide/foundation/{observability → integrations}/openobserve/streaming.py +4 -4
  45. provide/foundation/logger/config/logging.py +68 -298
  46. provide/foundation/logger/config/telemetry.py +41 -121
  47. provide/foundation/logger/setup/coordinator.py +1 -1
  48. provide/foundation/observability/__init__.py +2 -2
  49. provide/foundation/process/__init__.py +9 -0
  50. provide/foundation/process/exit.py +47 -0
  51. provide/foundation/process/lifecycle.py +33 -33
  52. provide/foundation/resilience/__init__.py +35 -0
  53. provide/foundation/resilience/circuit.py +164 -0
  54. provide/foundation/resilience/decorators.py +220 -0
  55. provide/foundation/resilience/fallback.py +193 -0
  56. provide/foundation/resilience/retry.py +325 -0
  57. provide/foundation/streams/config.py +79 -0
  58. provide/foundation/streams/console.py +7 -8
  59. provide/foundation/streams/core.py +6 -3
  60. provide/foundation/streams/file.py +12 -2
  61. provide/foundation/testing/__init__.py +7 -2
  62. provide/foundation/testing/cli.py +30 -17
  63. provide/foundation/testing/common/__init__.py +0 -2
  64. provide/foundation/testing/common/fixtures.py +0 -27
  65. provide/foundation/testing/file/content_fixtures.py +316 -0
  66. provide/foundation/testing/file/directory_fixtures.py +107 -0
  67. provide/foundation/testing/file/fixtures.py +45 -516
  68. provide/foundation/testing/file/special_fixtures.py +153 -0
  69. provide/foundation/testing/logger.py +76 -0
  70. provide/foundation/testing/process/async_fixtures.py +405 -0
  71. provide/foundation/testing/process/fixtures.py +50 -571
  72. provide/foundation/testing/process/subprocess_fixtures.py +209 -0
  73. provide/foundation/testing/threading/basic_fixtures.py +101 -0
  74. provide/foundation/testing/threading/data_fixtures.py +99 -0
  75. provide/foundation/testing/threading/execution_fixtures.py +263 -0
  76. provide/foundation/testing/threading/fixtures.py +34 -500
  77. provide/foundation/testing/threading/sync_fixtures.py +97 -0
  78. provide/foundation/testing/time/fixtures.py +4 -4
  79. provide/foundation/tools/cache.py +8 -6
  80. provide/foundation/tools/downloader.py +23 -12
  81. provide/foundation/tracer/spans.py +2 -2
  82. provide/foundation/transport/config.py +26 -95
  83. provide/foundation/transport/middleware.py +30 -36
  84. provide/foundation/utils/deps.py +14 -12
  85. provide/foundation/utils/parsing.py +49 -4
  86. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev2.dist-info}/METADATA +1 -1
  87. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev2.dist-info}/RECORD +93 -68
  88. /provide/foundation/{observability → integrations}/openobserve/exceptions.py +0 -0
  89. /provide/foundation/{observability → integrations}/openobserve/models.py +0 -0
  90. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev2.dist-info}/WHEEL +0 -0
  91. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev2.dist-info}/entry_points.txt +0 -0
  92. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev2.dist-info}/licenses/LICENSE +0 -0
  93. {provide_foundation-0.0.0.dev1.dist-info → provide_foundation-0.0.0.dev2.dist-info}/top_level.txt +0 -0
@@ -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 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
@@ -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 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
 
@@ -12,16 +12,16 @@ from requests.adapters import HTTPAdapter
12
12
  from urllib3.util.retry import Retry
13
13
 
14
14
  from provide.foundation.logger import get_logger
15
- from provide.foundation.observability.openobserve.auth import (
15
+ from provide.foundation.integrations.openobserve.auth import (
16
16
  get_auth_headers,
17
17
  validate_credentials,
18
18
  )
19
- from provide.foundation.observability.openobserve.exceptions import (
19
+ from provide.foundation.integrations.openobserve.exceptions import (
20
20
  OpenObserveConfigError,
21
21
  OpenObserveConnectionError,
22
22
  OpenObserveQueryError,
23
23
  )
24
- from provide.foundation.observability.openobserve.models import (
24
+ from provide.foundation.integrations.openobserve.models import (
25
25
  SearchQuery,
26
26
  SearchResponse,
27
27
  StreamInfo,
@@ -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(
@@ -18,7 +18,7 @@ log = get_logger(__name__)
18
18
 
19
19
 
20
20
  if _HAS_CLICK:
21
- from provide.foundation.observability.openobserve import (
21
+ from provide.foundation.integrations.openobserve import (
22
22
  OpenObserveClient,
23
23
  format_output,
24
24
  search_logs,
@@ -198,7 +198,7 @@ if _HAS_CLICK:
198
198
  return 1
199
199
 
200
200
  try:
201
- from provide.foundation.observability.openobserve import search_errors
201
+ from provide.foundation.integrations.openobserve import search_errors
202
202
 
203
203
  response = search_errors(
204
204
  stream=stream,
@@ -240,7 +240,7 @@ if _HAS_CLICK:
240
240
  return 1
241
241
 
242
242
  try:
243
- from provide.foundation.observability.openobserve import search_by_trace_id
243
+ from provide.foundation.integrations.openobserve import search_by_trace_id
244
244
 
245
245
  response = search_by_trace_id(
246
246
  trace_id=trace_id,
@@ -0,0 +1,37 @@
1
+ """OpenObserve integration configuration."""
2
+
3
+ from attrs import define
4
+
5
+ from provide.foundation.config.env import RuntimeConfig
6
+ from provide.foundation.config.base import field
7
+
8
+
9
+ @define(slots=True, repr=False)
10
+ class OpenObserveConfig(RuntimeConfig):
11
+ """Configuration for OpenObserve integration."""
12
+
13
+ url: str | None = field(
14
+ default=None,
15
+ env_var="OPENOBSERVE_URL",
16
+ description="OpenObserve URL endpoint",
17
+ )
18
+ org: str | None = field(
19
+ default=None,
20
+ env_var="OPENOBSERVE_ORG",
21
+ description="OpenObserve organization",
22
+ )
23
+ user: str | None = field(
24
+ default=None,
25
+ env_var="OPENOBSERVE_USER",
26
+ description="OpenObserve username",
27
+ )
28
+ password: str | None = field(
29
+ default=None,
30
+ env_var="OPENOBSERVE_PASSWORD",
31
+ description="OpenObserve password",
32
+ )
33
+ stream: str | None = field(
34
+ default=None,
35
+ env_var="OPENOBSERVE_STREAM",
36
+ description="OpenObserve stream name",
37
+ )
@@ -8,7 +8,7 @@ import io
8
8
  import json
9
9
  from typing import Any
10
10
 
11
- from provide.foundation.observability.openobserve.models import SearchResponse
11
+ from provide.foundation.integrations.openobserve.models import SearchResponse
12
12
 
13
13
 
14
14
  def format_json(response: SearchResponse | dict[str, Any], pretty: bool = True) -> str:
@@ -7,7 +7,7 @@ import json
7
7
  from typing import Any
8
8
 
9
9
  from provide.foundation.logger import get_logger
10
- from provide.foundation.observability.openobserve.client import OpenObserveClient
10
+ from provide.foundation.integrations.openobserve.client import OpenObserveClient
11
11
 
12
12
  log = get_logger(__name__)
13
13
 
@@ -4,8 +4,8 @@ Search operations for OpenObserve.
4
4
 
5
5
 
6
6
  from provide.foundation.logger import get_logger
7
- from provide.foundation.observability.openobserve.client import OpenObserveClient
8
- from provide.foundation.observability.openobserve.models import SearchResponse
7
+ from provide.foundation.integrations.openobserve.client import OpenObserveClient
8
+ from provide.foundation.integrations.openobserve.models import SearchResponse
9
9
 
10
10
  log = get_logger(__name__)
11
11
 
@@ -10,12 +10,12 @@ from typing import Any
10
10
  import requests
11
11
 
12
12
  from provide.foundation.logger import get_logger
13
- from provide.foundation.observability.openobserve.auth import get_auth_headers
14
- from provide.foundation.observability.openobserve.client import OpenObserveClient
15
- from provide.foundation.observability.openobserve.exceptions import (
13
+ from provide.foundation.integrations.openobserve.auth import get_auth_headers
14
+ from provide.foundation.integrations.openobserve.client import OpenObserveClient
15
+ from provide.foundation.integrations.openobserve.exceptions import (
16
16
  OpenObserveStreamingError,
17
17
  )
18
- from provide.foundation.observability.openobserve.models import parse_relative_time
18
+ from provide.foundation.integrations.openobserve.models import parse_relative_time
19
19
 
20
20
  log = get_logger(__name__)
21
21