provide-foundation 0.0.0.dev2__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 (155) hide show
  1. provide/foundation/__init__.py +20 -20
  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 +90 -91
  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 +4 -4
  13. provide/foundation/cli/commands/logs/__init__.py +2 -2
  14. provide/foundation/cli/commands/logs/generate.py +2 -2
  15. provide/foundation/cli/commands/logs/query.py +3 -3
  16. provide/foundation/cli/commands/logs/send.py +2 -2
  17. provide/foundation/cli/commands/logs/tail.py +2 -2
  18. provide/foundation/cli/decorators.py +0 -1
  19. provide/foundation/cli/testing.py +0 -5
  20. provide/foundation/cli/utils.py +1 -2
  21. provide/foundation/config/__init__.py +19 -19
  22. provide/foundation/config/base.py +2 -2
  23. provide/foundation/config/converters.py +81 -83
  24. provide/foundation/config/defaults.py +1 -1
  25. provide/foundation/config/env.py +2 -1
  26. provide/foundation/config/loader.py +1 -1
  27. provide/foundation/config/sync.py +8 -6
  28. provide/foundation/config/types.py +5 -5
  29. provide/foundation/config/validators.py +4 -4
  30. provide/foundation/console/output.py +7 -7
  31. provide/foundation/context/core.py +19 -17
  32. provide/foundation/crypto/certificates/__init__.py +9 -5
  33. provide/foundation/crypto/certificates/base.py +2 -2
  34. provide/foundation/crypto/certificates/certificate.py +48 -19
  35. provide/foundation/crypto/certificates/factory.py +26 -18
  36. provide/foundation/crypto/certificates/generator.py +24 -23
  37. provide/foundation/crypto/certificates/loader.py +24 -16
  38. provide/foundation/crypto/certificates/operations.py +17 -10
  39. provide/foundation/crypto/certificates/trust.py +21 -21
  40. provide/foundation/env/__init__.py +28 -0
  41. provide/foundation/env/core.py +218 -0
  42. provide/foundation/errors/__init__.py +3 -2
  43. provide/foundation/errors/decorators.py +0 -3
  44. provide/foundation/errors/types.py +0 -1
  45. provide/foundation/eventsets/display.py +13 -14
  46. provide/foundation/eventsets/registry.py +61 -31
  47. provide/foundation/eventsets/resolver.py +50 -46
  48. provide/foundation/eventsets/sets/das.py +8 -8
  49. provide/foundation/eventsets/sets/database.py +14 -14
  50. provide/foundation/eventsets/sets/http.py +21 -21
  51. provide/foundation/eventsets/sets/llm.py +16 -16
  52. provide/foundation/eventsets/sets/task_queue.py +13 -13
  53. provide/foundation/eventsets/types.py +7 -7
  54. provide/foundation/file/directory.py +1 -1
  55. provide/foundation/file/lock.py +2 -3
  56. provide/foundation/hub/components.py +19 -21
  57. provide/foundation/hub/config.py +25 -19
  58. provide/foundation/hub/discovery.py +5 -4
  59. provide/foundation/hub/handlers.py +13 -5
  60. provide/foundation/hub/lifecycle.py +10 -9
  61. provide/foundation/hub/manager.py +3 -0
  62. provide/foundation/hub/processors.py +8 -3
  63. provide/foundation/integrations/__init__.py +1 -1
  64. provide/foundation/integrations/openobserve/client.py +2 -2
  65. provide/foundation/integrations/openobserve/commands.py +9 -9
  66. provide/foundation/integrations/openobserve/config.py +2 -2
  67. provide/foundation/integrations/openobserve/otlp.py +2 -2
  68. provide/foundation/integrations/openobserve/search.py +1 -2
  69. provide/foundation/integrations/openobserve/streaming.py +1 -1
  70. provide/foundation/logger/__init__.py +0 -1
  71. provide/foundation/logger/config/base.py +1 -1
  72. provide/foundation/logger/config/logging.py +19 -19
  73. provide/foundation/logger/config/telemetry.py +11 -13
  74. provide/foundation/logger/factories.py +2 -2
  75. provide/foundation/logger/processors/main.py +12 -10
  76. provide/foundation/logger/ratelimit/limiters.py +4 -4
  77. provide/foundation/logger/ratelimit/processor.py +1 -1
  78. provide/foundation/logger/setup/coordinator.py +38 -24
  79. provide/foundation/logger/setup/processors.py +3 -3
  80. provide/foundation/logger/setup/testing.py +14 -0
  81. provide/foundation/logger/trace.py +5 -5
  82. provide/foundation/metrics/__init__.py +1 -1
  83. provide/foundation/metrics/otel.py +3 -1
  84. provide/foundation/observability/__init__.py +1 -1
  85. provide/foundation/process/__init__.py +1 -1
  86. provide/foundation/process/exit.py +6 -5
  87. provide/foundation/process/lifecycle.py +41 -18
  88. provide/foundation/resilience/__init__.py +6 -5
  89. provide/foundation/resilience/circuit.py +32 -30
  90. provide/foundation/resilience/decorators.py +58 -42
  91. provide/foundation/resilience/fallback.py +55 -40
  92. provide/foundation/resilience/retry.py +67 -65
  93. provide/foundation/serialization/__init__.py +16 -0
  94. provide/foundation/serialization/core.py +70 -0
  95. provide/foundation/streams/config.py +8 -9
  96. provide/foundation/streams/console.py +3 -3
  97. provide/foundation/streams/core.py +2 -2
  98. provide/foundation/streams/file.py +1 -1
  99. provide/foundation/testing/__init__.py +22 -7
  100. provide/foundation/testing/archive/__init__.py +7 -7
  101. provide/foundation/testing/archive/fixtures.py +58 -54
  102. provide/foundation/testing/cli.py +3 -6
  103. provide/foundation/testing/common/__init__.py +13 -13
  104. provide/foundation/testing/common/fixtures.py +27 -30
  105. provide/foundation/testing/file/__init__.py +15 -15
  106. provide/foundation/testing/file/content_fixtures.py +65 -92
  107. provide/foundation/testing/file/directory_fixtures.py +19 -19
  108. provide/foundation/testing/file/fixtures.py +14 -17
  109. provide/foundation/testing/file/special_fixtures.py +34 -42
  110. provide/foundation/testing/logger.py +28 -23
  111. provide/foundation/testing/mocking/__init__.py +21 -21
  112. provide/foundation/testing/mocking/fixtures.py +80 -67
  113. provide/foundation/testing/process/__init__.py +23 -23
  114. provide/foundation/testing/process/async_fixtures.py +89 -80
  115. provide/foundation/testing/process/fixtures.py +11 -13
  116. provide/foundation/testing/process/subprocess_fixtures.py +41 -40
  117. provide/foundation/testing/threading/__init__.py +17 -17
  118. provide/foundation/testing/threading/basic_fixtures.py +21 -17
  119. provide/foundation/testing/threading/data_fixtures.py +18 -16
  120. provide/foundation/testing/threading/execution_fixtures.py +67 -52
  121. provide/foundation/testing/threading/fixtures.py +10 -14
  122. provide/foundation/testing/threading/sync_fixtures.py +21 -18
  123. provide/foundation/testing/time/__init__.py +11 -11
  124. provide/foundation/testing/time/fixtures.py +91 -79
  125. provide/foundation/testing/transport/__init__.py +9 -9
  126. provide/foundation/testing/transport/fixtures.py +54 -54
  127. provide/foundation/time/__init__.py +18 -0
  128. provide/foundation/time/core.py +63 -0
  129. provide/foundation/tools/__init__.py +2 -2
  130. provide/foundation/tools/base.py +68 -67
  131. provide/foundation/tools/cache.py +62 -69
  132. provide/foundation/tools/downloader.py +51 -56
  133. provide/foundation/tools/installer.py +51 -57
  134. provide/foundation/tools/registry.py +38 -45
  135. provide/foundation/tools/resolver.py +70 -68
  136. provide/foundation/tools/verifier.py +39 -50
  137. provide/foundation/tracer/spans.py +1 -13
  138. provide/foundation/transport/__init__.py +26 -33
  139. provide/foundation/transport/base.py +32 -30
  140. provide/foundation/transport/client.py +44 -49
  141. provide/foundation/transport/config.py +11 -13
  142. provide/foundation/transport/errors.py +13 -27
  143. provide/foundation/transport/http.py +69 -55
  144. provide/foundation/transport/middleware.py +86 -81
  145. provide/foundation/transport/registry.py +29 -27
  146. provide/foundation/transport/types.py +6 -6
  147. provide/foundation/utils/deps.py +3 -2
  148. provide/foundation/utils/parsing.py +7 -7
  149. {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/METADATA +2 -2
  150. provide_foundation-0.0.0.dev3.dist-info/RECORD +233 -0
  151. provide_foundation-0.0.0.dev2.dist-info/RECORD +0 -225
  152. {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/WHEEL +0 -0
  153. {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/entry_points.txt +0 -0
  154. {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/licenses/LICENSE +0 -0
  155. {provide_foundation-0.0.0.dev2.dist-info → provide_foundation-0.0.0.dev3.dist-info}/top_level.txt +0 -0
@@ -15,14 +15,19 @@ log = get_logger(__name__)
15
15
 
16
16
  def _get_registry_and_lock():
17
17
  """Get registry and lock from components module."""
18
- from provide.foundation.hub.components import get_component_registry, _registry_lock, ComponentCategory
18
+ from provide.foundation.hub.components import (
19
+ ComponentCategory,
20
+ _registry_lock,
21
+ get_component_registry,
22
+ )
23
+
19
24
  return get_component_registry(), _registry_lock, ComponentCategory
20
25
 
21
26
 
22
27
  def get_handlers_for_exception(exception: Exception) -> list[RegistryEntry]:
23
28
  """Get error handlers that can handle the given exception type."""
24
29
  registry, registry_lock, ComponentCategory = _get_registry_and_lock()
25
-
30
+
26
31
  with registry_lock:
27
32
  # Get all error handlers
28
33
  all_entries = list(registry)
@@ -53,7 +58,10 @@ def get_handlers_for_exception(exception: Exception) -> list[RegistryEntry]:
53
58
 
54
59
  @with_error_handling(
55
60
  fallback=None,
56
- context_provider=lambda: {"function": "execute_error_handlers", "module": "hub.handlers"}
61
+ context_provider=lambda: {
62
+ "function": "execute_error_handlers",
63
+ "module": "hub.handlers",
64
+ },
57
65
  )
58
66
  def execute_error_handlers(
59
67
  exception: Exception, context: dict[str, Any]
@@ -76,6 +84,6 @@ def execute_error_handlers(
76
84
 
77
85
 
78
86
  __all__ = [
79
- "get_handlers_for_exception",
80
87
  "execute_error_handlers",
81
- ]
88
+ "get_handlers_for_exception",
89
+ ]
@@ -17,17 +17,18 @@ log = get_logger(__name__)
17
17
  def _get_registry_and_globals():
18
18
  """Get registry, lock, and initialized components from components module."""
19
19
  from provide.foundation.hub.components import (
20
- get_component_registry,
21
- _registry_lock,
22
- _initialized_components
20
+ _initialized_components,
21
+ _registry_lock,
22
+ get_component_registry,
23
23
  )
24
+
24
25
  return get_component_registry(), _registry_lock, _initialized_components
25
26
 
26
27
 
27
28
  def get_or_initialize_component(name: str, dimension: str) -> Any:
28
29
  """Get component, initializing lazily if needed."""
29
30
  registry, registry_lock, initialized_components = _get_registry_and_globals()
30
-
31
+
31
32
  with registry_lock:
32
33
  key = (name, dimension)
33
34
 
@@ -75,7 +76,7 @@ def get_or_initialize_component(name: str, dimension: str) -> Any:
75
76
  async def initialize_async_component(name: str, dimension: str) -> Any:
76
77
  """Initialize component asynchronously."""
77
78
  registry, registry_lock, initialized_components = _get_registry_and_globals()
78
-
79
+
79
80
  with registry_lock:
80
81
  key = (name, dimension)
81
82
 
@@ -122,7 +123,7 @@ async def initialize_async_component(name: str, dimension: str) -> Any:
122
123
  def cleanup_all_components(dimension: str | None = None) -> None:
123
124
  """Clean up all components in dimension."""
124
125
  registry, registry_lock, _ = _get_registry_and_globals()
125
-
126
+
126
127
  with registry_lock:
127
128
  if dimension:
128
129
  entries = [entry for entry in registry if entry.dimension == dimension]
@@ -187,8 +188,8 @@ async def initialize_all_async_components() -> None:
187
188
 
188
189
 
189
190
  __all__ = [
190
- "get_or_initialize_component",
191
- "initialize_async_component",
192
191
  "cleanup_all_components",
192
+ "get_or_initialize_component",
193
193
  "initialize_all_async_components",
194
- ]
194
+ "initialize_async_component",
195
+ ]
@@ -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
 
@@ -10,14 +10,19 @@ from provide.foundation.hub.registry import RegistryEntry
10
10
 
11
11
  def _get_registry_and_lock():
12
12
  """Get registry and lock from components module."""
13
- from provide.foundation.hub.components import get_component_registry, _registry_lock, ComponentCategory
13
+ from provide.foundation.hub.components import (
14
+ ComponentCategory,
15
+ _registry_lock,
16
+ get_component_registry,
17
+ )
18
+
14
19
  return get_component_registry(), _registry_lock, ComponentCategory
15
20
 
16
21
 
17
22
  def get_processor_pipeline() -> list[RegistryEntry]:
18
23
  """Get log processors ordered by priority."""
19
24
  registry, registry_lock, ComponentCategory = _get_registry_and_lock()
20
-
25
+
21
26
  with registry_lock:
22
27
  # Get all processors
23
28
  all_entries = list(registry)
@@ -41,4 +46,4 @@ def get_processors_for_stage(stage: str) -> list[RegistryEntry]:
41
46
  __all__ = [
42
47
  "get_processor_pipeline",
43
48
  "get_processors_for_stage",
44
- ]
49
+ ]
@@ -8,4 +8,4 @@ that are not part of the core foundation library.
8
8
  __all__ = [
9
9
  # Available integrations (import on demand)
10
10
  # "openobserve",
11
- ]
11
+ ]
@@ -11,7 +11,6 @@ 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
14
  from provide.foundation.integrations.openobserve.auth import (
16
15
  get_auth_headers,
17
16
  validate_credentials,
@@ -27,6 +26,7 @@ from provide.foundation.integrations.openobserve.models import (
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:
@@ -27,7 +27,7 @@ if _HAS_CLICK:
27
27
 
28
28
  @click.group("openobserve", help="Query and manage OpenObserve logs")
29
29
  @click.pass_context
30
- def openobserve_group(ctx):
30
+ def openobserve_group(ctx: click.Context) -> None:
31
31
  """OpenObserve log querying and streaming commands."""
32
32
  # Initialize client and store in context
33
33
  try:
@@ -75,7 +75,7 @@ if _HAS_CLICK:
75
75
  help="Pretty print JSON output",
76
76
  )
77
77
  @click.pass_obj
78
- def query_command(client, sql, start, end, size, format, pretty):
78
+ def query_command(client: "OpenObserveClient | None", sql: str, start: str, end: str, size: int, format: str, pretty: bool) -> int | None:
79
79
  """Execute SQL query against OpenObserve logs."""
80
80
  if client is None:
81
81
  click.echo(
@@ -134,7 +134,7 @@ if _HAS_CLICK:
134
134
  help="Output format",
135
135
  )
136
136
  @click.pass_obj
137
- def tail_command(client, stream, filter_sql, lines, follow, format):
137
+ def tail_command(client: "OpenObserveClient | None", stream: str, filter_sql: str | None, lines: int, follow: bool, format: str) -> int | None:
138
138
  """Tail logs from OpenObserve (like 'tail -f')."""
139
139
  if client is None:
140
140
  click.echo(
@@ -191,7 +191,7 @@ if _HAS_CLICK:
191
191
  help="Output format",
192
192
  )
193
193
  @click.pass_obj
194
- def errors_command(client, stream, start, size, format):
194
+ def errors_command(client: "OpenObserveClient | None", stream: str, start: str, size: int, format: str) -> int | None:
195
195
  """Search for error logs."""
196
196
  if client is None:
197
197
  click.echo("OpenObserve not configured.", err=True)
@@ -233,7 +233,7 @@ if _HAS_CLICK:
233
233
  help="Output format",
234
234
  )
235
235
  @click.pass_obj
236
- def trace_command(client, trace_id, stream, format):
236
+ def trace_command(client: "OpenObserveClient | None", trace_id: str, stream: str, format: str) -> int | None:
237
237
  """Search for logs by trace ID."""
238
238
  if client is None:
239
239
  click.echo("OpenObserve not configured.", err=True)
@@ -260,7 +260,7 @@ if _HAS_CLICK:
260
260
 
261
261
  @openobserve_group.command("streams")
262
262
  @click.pass_obj
263
- def streams_command(client):
263
+ def streams_command(client: "OpenObserveClient | None") -> int | None:
264
264
  """List available streams."""
265
265
  if client is None:
266
266
  click.echo("OpenObserve not configured.", err=True)
@@ -297,7 +297,7 @@ if _HAS_CLICK:
297
297
  help="Filter by stream name",
298
298
  )
299
299
  @click.pass_obj
300
- def history_command(client, size, stream):
300
+ def history_command(client: "OpenObserveClient | None", size: int, stream: str | None) -> int | None:
301
301
  """View search history."""
302
302
  if client is None:
303
303
  click.echo("OpenObserve not configured.", err=True)
@@ -326,7 +326,7 @@ if _HAS_CLICK:
326
326
 
327
327
  @openobserve_group.command("test")
328
328
  @click.pass_obj
329
- def test_command(client):
329
+ def test_command(client: "OpenObserveClient | None") -> int | None:
330
330
  """Test connection to OpenObserve."""
331
331
  if client is None:
332
332
  click.echo("OpenObserve not configured.", err=True)
@@ -347,7 +347,7 @@ if _HAS_CLICK:
347
347
 
348
348
  else:
349
349
  # Stub when click is not available
350
- def openobserve_group(*args, **kwargs):
350
+ def openobserve_group(*args: object, **kwargs: object) -> None:
351
351
  """OpenObserve command stub when click is not available."""
352
352
  raise ImportError(
353
353
  "CLI commands require optional dependencies. "
@@ -2,8 +2,8 @@
2
2
 
3
3
  from attrs import define
4
4
 
5
- from provide.foundation.config.env import RuntimeConfig
6
5
  from provide.foundation.config.base import field
6
+ from provide.foundation.config.env import RuntimeConfig
7
7
 
8
8
 
9
9
  @define(slots=True, repr=False)
@@ -34,4 +34,4 @@ class OpenObserveConfig(RuntimeConfig):
34
34
  default=None,
35
35
  env_var="OPENOBSERVE_STREAM",
36
36
  description="OpenObserve stream name",
37
- )
37
+ )
@@ -6,8 +6,8 @@ from datetime import datetime
6
6
  import json
7
7
  from typing import Any
8
8
 
9
- from provide.foundation.logger import get_logger
10
9
  from provide.foundation.integrations.openobserve.client import OpenObserveClient
10
+ from provide.foundation.logger import get_logger
11
11
 
12
12
  log = get_logger(__name__)
13
13
 
@@ -15,7 +15,7 @@ log = get_logger(__name__)
15
15
  try:
16
16
  from opentelemetry import trace
17
17
  from opentelemetry.exporter.otlp.proto.http._log_exporter import OTLPLogExporter
18
- from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
18
+ from opentelemetry.sdk._logs import LoggerProvider
19
19
  from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
20
20
  from opentelemetry.sdk.resources import Resource
21
21
  from opentelemetry.semconv.resource import ResourceAttributes
@@ -2,10 +2,9 @@
2
2
  Search operations for OpenObserve.
3
3
  """
4
4
 
5
-
6
- from provide.foundation.logger import get_logger
7
5
  from provide.foundation.integrations.openobserve.client import OpenObserveClient
8
6
  from provide.foundation.integrations.openobserve.models import SearchResponse
7
+ from provide.foundation.logger import get_logger
9
8
 
10
9
  log = get_logger(__name__)
11
10
 
@@ -9,13 +9,13 @@ from typing import Any
9
9
 
10
10
  import requests
11
11
 
12
- from provide.foundation.logger import get_logger
13
12
  from provide.foundation.integrations.openobserve.auth import get_auth_headers
14
13
  from provide.foundation.integrations.openobserve.client import OpenObserveClient
15
14
  from provide.foundation.integrations.openobserve.exceptions import (
16
15
  OpenObserveStreamingError,
17
16
  )
18
17
  from provide.foundation.integrations.openobserve.models import parse_relative_time
18
+ from provide.foundation.logger import get_logger
19
19
 
20
20
  log = get_logger(__name__)
21
21
 
@@ -8,7 +8,6 @@ Re-exports key components related to logging functionality.
8
8
 
9
9
  # Import trace module early to ensure PrintLogger gets patched
10
10
  from provide.foundation.logger import trace # noqa: F401
11
-
12
11
  from provide.foundation.logger.base import (
13
12
  FoundationLogger, # Class definition
14
13
  get_logger, # Factory function
@@ -9,7 +9,7 @@ import os
9
9
  import sys
10
10
 
11
11
 
12
- def get_config_logger():
12
+ def get_config_logger() -> object:
13
13
  """Get logger for config warnings that respects FOUNDATION_LOG_OUTPUT."""
14
14
  import structlog
15
15
 
@@ -9,22 +9,7 @@ from pathlib import Path
9
9
 
10
10
  from attrs import define
11
11
 
12
- from provide.foundation.config.env import RuntimeConfig
13
12
  from provide.foundation.config.base import field
14
- from provide.foundation.config.defaults import (
15
- DEFAULT_LOG_LEVEL,
16
- DEFAULT_CONSOLE_FORMATTER,
17
- DEFAULT_LOGGER_NAME_EMOJI_ENABLED,
18
- DEFAULT_DAS_EMOJI_ENABLED,
19
- DEFAULT_OMIT_TIMESTAMP,
20
- DEFAULT_FOUNDATION_SETUP_LOG_LEVEL,
21
- DEFAULT_FOUNDATION_LOG_OUTPUT,
22
- DEFAULT_RATE_LIMIT_ENABLED,
23
- DEFAULT_RATE_LIMIT_EMIT_WARNINGS,
24
- DEFAULT_RATE_LIMIT_GLOBAL,
25
- DEFAULT_RATE_LIMIT_GLOBAL_CAPACITY,
26
- DEFAULT_RATE_LIMIT_OVERFLOW_POLICY,
27
- )
28
13
  from provide.foundation.config.converters import (
29
14
  parse_bool_extended,
30
15
  parse_console_formatter,
@@ -34,10 +19,24 @@ from provide.foundation.config.converters import (
34
19
  parse_module_levels,
35
20
  parse_rate_limits,
36
21
  validate_log_level,
37
- validate_non_negative,
38
22
  validate_overflow_policy,
39
23
  validate_positive,
40
24
  )
25
+ from provide.foundation.config.defaults import (
26
+ DEFAULT_CONSOLE_FORMATTER,
27
+ DEFAULT_DAS_EMOJI_ENABLED,
28
+ DEFAULT_FOUNDATION_LOG_OUTPUT,
29
+ DEFAULT_FOUNDATION_SETUP_LOG_LEVEL,
30
+ DEFAULT_LOG_LEVEL,
31
+ DEFAULT_LOGGER_NAME_EMOJI_ENABLED,
32
+ DEFAULT_OMIT_TIMESTAMP,
33
+ DEFAULT_RATE_LIMIT_EMIT_WARNINGS,
34
+ DEFAULT_RATE_LIMIT_ENABLED,
35
+ DEFAULT_RATE_LIMIT_GLOBAL,
36
+ DEFAULT_RATE_LIMIT_GLOBAL_CAPACITY,
37
+ DEFAULT_RATE_LIMIT_OVERFLOW_POLICY,
38
+ )
39
+ from provide.foundation.config.env import RuntimeConfig
41
40
  from provide.foundation.types import (
42
41
  ConsoleFormatterStr,
43
42
  LogLevelStr,
@@ -90,7 +89,7 @@ class LoggingConfig(RuntimeConfig):
90
89
  default=None,
91
90
  env_var="PROVIDE_LOG_FILE",
92
91
  converter=lambda x: Path(x) if x else None,
93
- description="Path to log file"
92
+ description="Path to log file",
94
93
  )
95
94
  foundation_setup_log_level: LogLevelStr = field(
96
95
  default=DEFAULT_FOUNDATION_SETUP_LOG_LEVEL,
@@ -138,7 +137,9 @@ class LoggingConfig(RuntimeConfig):
138
137
  rate_limit_summary_interval: float = field(
139
138
  default=DEFAULT_RATE_LIMIT_GLOBAL,
140
139
  env_var="PROVIDE_LOG_RATE_LIMIT_SUMMARY_INTERVAL",
141
- converter=lambda x: parse_float_with_validation(x, min_val=0.0) if x else DEFAULT_RATE_LIMIT_GLOBAL,
140
+ converter=lambda x: parse_float_with_validation(x, min_val=0.0)
141
+ if x
142
+ else DEFAULT_RATE_LIMIT_GLOBAL,
142
143
  validator=validate_positive,
143
144
  description="Seconds between rate limit summary reports",
144
145
  )
@@ -161,4 +162,3 @@ class LoggingConfig(RuntimeConfig):
161
162
  validator=validate_overflow_policy,
162
163
  description="Policy when queue is full: drop_oldest, drop_newest, or block",
163
164
  )
164
-
@@ -5,24 +5,25 @@
5
5
  TelemetryConfig class for Foundation telemetry configuration.
6
6
  """
7
7
 
8
+ import os
9
+
8
10
  from attrs import define
9
11
 
10
- from provide.foundation.config.env import RuntimeConfig
11
12
  from provide.foundation.config.base import field
12
- from provide.foundation.config.defaults import (
13
- DEFAULT_TELEMETRY_GLOBALLY_DISABLED,
14
- DEFAULT_TRACING_ENABLED,
15
- DEFAULT_METRICS_ENABLED,
16
- DEFAULT_OTLP_PROTOCOL,
17
- DEFAULT_TRACE_SAMPLE_RATE,
18
- )
19
- import os
20
13
  from provide.foundation.config.converters import (
21
14
  parse_bool_extended,
22
15
  parse_headers,
23
16
  parse_sample_rate,
24
17
  validate_sample_rate,
25
18
  )
19
+ from provide.foundation.config.defaults import (
20
+ DEFAULT_METRICS_ENABLED,
21
+ DEFAULT_OTLP_PROTOCOL,
22
+ DEFAULT_TELEMETRY_GLOBALLY_DISABLED,
23
+ DEFAULT_TRACE_SAMPLE_RATE,
24
+ DEFAULT_TRACING_ENABLED,
25
+ )
26
+ from provide.foundation.config.env import RuntimeConfig
26
27
  from provide.foundation.logger.config.logging import LoggingConfig
27
28
 
28
29
 
@@ -45,8 +46,7 @@ class TelemetryConfig(RuntimeConfig):
45
46
  description="Service version for telemetry",
46
47
  )
47
48
  logging: LoggingConfig = field(
48
- factory=lambda: LoggingConfig.from_env(),
49
- description="Logging configuration"
49
+ factory=lambda: LoggingConfig.from_env(), description="Logging configuration"
50
50
  )
51
51
  globally_disabled: bool = field(
52
52
  default=DEFAULT_TELEMETRY_GLOBALLY_DISABLED,
@@ -97,8 +97,6 @@ class TelemetryConfig(RuntimeConfig):
97
97
  description="Sampling rate for traces (0.0 to 1.0)",
98
98
  )
99
99
 
100
-
101
-
102
100
  def get_otlp_headers_dict(self) -> dict[str, str]:
103
101
  """Get OTLP headers dictionary.
104
102
 
@@ -13,7 +13,7 @@ from provide.foundation.logger.core import logger
13
13
  def get_logger(
14
14
  name: str | None = None,
15
15
  emoji: str | None = None,
16
- emoji_hierarchy: dict[str, str] | None = None
16
+ emoji_hierarchy: dict[str, str] | None = None,
17
17
  ) -> Any:
18
18
  """
19
19
  Get a logger instance with the given name and optional emoji customization.
@@ -30,7 +30,7 @@ def get_logger(
30
30
  """
31
31
  # Emoji hierarchy removed - using event sets now
32
32
  # emoji and emoji_hierarchy parameters are deprecated
33
-
33
+
34
34
  return logger.get_logger(name)
35
35
 
36
36
 
@@ -7,7 +7,7 @@ Structlog processors for Foundation Telemetry.
7
7
 
8
8
  import json
9
9
  import logging as stdlib_logging
10
- from typing import TYPE_CHECKING, Any, TextIO, cast
10
+ from typing import Any, TextIO, cast
11
11
 
12
12
  import structlog
13
13
 
@@ -26,7 +26,6 @@ from provide.foundation.types import (
26
26
  LogLevelStr,
27
27
  )
28
28
 
29
-
30
29
  _LEVEL_TO_NUMERIC: dict[LogLevelStr, int] = {
31
30
  "CRITICAL": stdlib_logging.CRITICAL,
32
31
  "ERROR": stdlib_logging.ERROR,
@@ -70,24 +69,29 @@ def _config_create_timestamp_processors(
70
69
 
71
70
 
72
71
  def _config_create_event_enrichment_processors(
73
- logging_config: LoggingConfig
72
+ logging_config: LoggingConfig,
74
73
  ) -> list[StructlogProcessor]:
75
74
  processors: list[StructlogProcessor] = []
76
75
  if logging_config.logger_name_emoji_prefix_enabled:
77
76
  processors.append(cast(StructlogProcessor, add_logger_name_emoji_prefix))
78
77
  if logging_config.das_emoji_prefix_enabled:
78
+
79
79
  def add_event_enrichment_processor(
80
80
  _logger: Any, _method_name: str, event_dict: structlog.types.EventDict
81
81
  ) -> structlog.types.EventDict:
82
82
  # Lazy import to avoid circular dependency
83
- from provide.foundation.eventsets.resolver import get_resolver
84
83
  from provide.foundation.eventsets.registry import discover_event_sets
85
-
84
+ from provide.foundation.eventsets.resolver import get_resolver
85
+
86
86
  # Initialize on first use
87
- if not hasattr(add_event_enrichment_processor, '_initialized'):
87
+ if not hasattr(add_event_enrichment_processor, "_initialized"):
88
+ from provide.foundation.logger.setup.coordinator import create_foundation_internal_logger
89
+ setup_logger = create_foundation_internal_logger()
90
+ setup_logger.trace("Initializing event enrichment processor")
88
91
  discover_event_sets()
89
92
  add_event_enrichment_processor._initialized = True
90
-
93
+ setup_logger.trace("Event enrichment processor initialized")
94
+
91
95
  resolver = get_resolver()
92
96
  return resolver.enrich_event(event_dict)
93
97
 
@@ -95,9 +99,7 @@ def _config_create_event_enrichment_processors(
95
99
  return processors
96
100
 
97
101
 
98
- def _build_core_processors_list(
99
- config: TelemetryConfig
100
- ) -> list[StructlogProcessor]:
102
+ def _build_core_processors_list(config: TelemetryConfig) -> list[StructlogProcessor]:
101
103
  log_cfg = config.logging
102
104
  processors: list[StructlogProcessor] = [
103
105
  structlog.contextvars.merge_contextvars,
@@ -17,7 +17,7 @@ class SyncRateLimiter:
17
17
  Thread-safe implementation suitable for synchronous logging operations.
18
18
  """
19
19
 
20
- def __init__(self, capacity: float, refill_rate: float):
20
+ def __init__(self, capacity: float, refill_rate: float) -> None:
21
21
  """
22
22
  Initialize the rate limiter.
23
23
 
@@ -87,7 +87,7 @@ class AsyncRateLimiter:
87
87
  Uses asyncio.Lock for thread safety in async contexts.
88
88
  """
89
89
 
90
- def __init__(self, capacity: float, refill_rate: float):
90
+ def __init__(self, capacity: float, refill_rate: float) -> None:
91
91
  """
92
92
  Initialize the async rate limiter.
93
93
 
@@ -160,7 +160,7 @@ class GlobalRateLimiter:
160
160
  _instance = None
161
161
  _lock = threading.Lock()
162
162
 
163
- def __new__(cls):
163
+ def __new__(cls) -> "GlobalRateLimiter":
164
164
  if cls._instance is None:
165
165
  with cls._lock:
166
166
  if cls._instance is None:
@@ -168,7 +168,7 @@ class GlobalRateLimiter:
168
168
  cls._instance._initialized = False
169
169
  return cls._instance
170
170
 
171
- def __init__(self):
171
+ def __init__(self) -> None:
172
172
  if self._initialized:
173
173
  return
174
174
 
@@ -107,7 +107,7 @@ class RateLimiterProcessor:
107
107
  stats = self.rate_limiter.get_stats()
108
108
 
109
109
  # Check if there's been any rate limiting activity
110
- global_stats = stats.get("global", {})
110
+ global_stats = stats.get("global") or {}
111
111
  total_denied = global_stats.get("total_denied", 0)
112
112
 
113
113
  if not self.suppressed_counts and total_denied == 0: