alma-memory 0.5.1__py3-none-any.whl → 0.7.0__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.
- alma/__init__.py +296 -226
- alma/compression/__init__.py +33 -0
- alma/compression/pipeline.py +980 -0
- alma/confidence/__init__.py +47 -47
- alma/confidence/engine.py +540 -540
- alma/confidence/types.py +351 -351
- alma/config/loader.py +157 -157
- alma/consolidation/__init__.py +23 -23
- alma/consolidation/engine.py +678 -678
- alma/consolidation/prompts.py +84 -84
- alma/core.py +1189 -430
- alma/domains/__init__.py +30 -30
- alma/domains/factory.py +359 -359
- alma/domains/schemas.py +448 -448
- alma/domains/types.py +272 -272
- alma/events/__init__.py +75 -75
- alma/events/emitter.py +285 -284
- alma/events/storage_mixin.py +246 -246
- alma/events/types.py +126 -126
- alma/events/webhook.py +425 -425
- alma/exceptions.py +49 -49
- alma/extraction/__init__.py +31 -31
- alma/extraction/auto_learner.py +265 -265
- alma/extraction/extractor.py +420 -420
- alma/graph/__init__.py +106 -106
- alma/graph/backends/__init__.py +32 -32
- alma/graph/backends/kuzu.py +624 -624
- alma/graph/backends/memgraph.py +432 -432
- alma/graph/backends/memory.py +236 -236
- alma/graph/backends/neo4j.py +417 -417
- alma/graph/base.py +159 -159
- alma/graph/extraction.py +198 -198
- alma/graph/store.py +860 -860
- alma/harness/__init__.py +35 -35
- alma/harness/base.py +386 -386
- alma/harness/domains.py +705 -705
- alma/initializer/__init__.py +37 -37
- alma/initializer/initializer.py +418 -418
- alma/initializer/types.py +250 -250
- alma/integration/__init__.py +62 -62
- alma/integration/claude_agents.py +444 -444
- alma/integration/helena.py +423 -423
- alma/integration/victor.py +471 -471
- alma/learning/__init__.py +101 -86
- alma/learning/decay.py +878 -0
- alma/learning/forgetting.py +1446 -1446
- alma/learning/heuristic_extractor.py +390 -390
- alma/learning/protocols.py +374 -374
- alma/learning/validation.py +346 -346
- alma/mcp/__init__.py +123 -45
- alma/mcp/__main__.py +156 -156
- alma/mcp/resources.py +122 -122
- alma/mcp/server.py +955 -591
- alma/mcp/tools.py +3254 -509
- alma/observability/__init__.py +91 -84
- alma/observability/config.py +302 -302
- alma/observability/guidelines.py +170 -0
- alma/observability/logging.py +424 -424
- alma/observability/metrics.py +583 -583
- alma/observability/tracing.py +440 -440
- alma/progress/__init__.py +21 -21
- alma/progress/tracker.py +607 -607
- alma/progress/types.py +250 -250
- alma/retrieval/__init__.py +134 -53
- alma/retrieval/budget.py +525 -0
- alma/retrieval/cache.py +1304 -1061
- alma/retrieval/embeddings.py +202 -202
- alma/retrieval/engine.py +850 -427
- alma/retrieval/modes.py +365 -0
- alma/retrieval/progressive.py +560 -0
- alma/retrieval/scoring.py +344 -344
- alma/retrieval/trust_scoring.py +637 -0
- alma/retrieval/verification.py +797 -0
- alma/session/__init__.py +19 -19
- alma/session/manager.py +442 -399
- alma/session/types.py +288 -288
- alma/storage/__init__.py +101 -90
- alma/storage/archive.py +233 -0
- alma/storage/azure_cosmos.py +1259 -1259
- alma/storage/base.py +1083 -583
- alma/storage/chroma.py +1443 -1443
- alma/storage/constants.py +103 -103
- alma/storage/file_based.py +614 -614
- alma/storage/migrations/__init__.py +21 -21
- alma/storage/migrations/base.py +321 -321
- alma/storage/migrations/runner.py +323 -323
- alma/storage/migrations/version_stores.py +337 -337
- alma/storage/migrations/versions/__init__.py +11 -11
- alma/storage/migrations/versions/v1_0_0.py +373 -373
- alma/storage/migrations/versions/v1_1_0_workflow_context.py +551 -0
- alma/storage/pinecone.py +1080 -1080
- alma/storage/postgresql.py +1948 -1559
- alma/storage/qdrant.py +1306 -1306
- alma/storage/sqlite_local.py +3041 -1457
- alma/testing/__init__.py +46 -46
- alma/testing/factories.py +301 -301
- alma/testing/mocks.py +389 -389
- alma/types.py +292 -264
- alma/utils/__init__.py +19 -0
- alma/utils/tokenizer.py +521 -0
- alma/workflow/__init__.py +83 -0
- alma/workflow/artifacts.py +170 -0
- alma/workflow/checkpoint.py +311 -0
- alma/workflow/context.py +228 -0
- alma/workflow/outcomes.py +189 -0
- alma/workflow/reducers.py +393 -0
- {alma_memory-0.5.1.dist-info → alma_memory-0.7.0.dist-info}/METADATA +210 -72
- alma_memory-0.7.0.dist-info/RECORD +112 -0
- alma_memory-0.5.1.dist-info/RECORD +0 -93
- {alma_memory-0.5.1.dist-info → alma_memory-0.7.0.dist-info}/WHEEL +0 -0
- {alma_memory-0.5.1.dist-info → alma_memory-0.7.0.dist-info}/top_level.txt +0 -0
alma/observability/config.py
CHANGED
|
@@ -1,302 +1,302 @@
|
|
|
1
|
-
"""
|
|
2
|
-
ALMA Observability Configuration.
|
|
3
|
-
|
|
4
|
-
Centralized configuration for observability features including
|
|
5
|
-
tracing, metrics, and logging setup.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import logging
|
|
9
|
-
import os
|
|
10
|
-
from dataclasses import dataclass, field
|
|
11
|
-
from typing import Any, Dict, Optional
|
|
12
|
-
|
|
13
|
-
# Global state for observability configuration
|
|
14
|
-
_observability_initialized = False
|
|
15
|
-
_tracer_provider = None
|
|
16
|
-
_meter_provider = None
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@dataclass
|
|
20
|
-
class ObservabilityConfig:
|
|
21
|
-
"""
|
|
22
|
-
Configuration for ALMA observability features.
|
|
23
|
-
|
|
24
|
-
Attributes:
|
|
25
|
-
service_name: Name of the service for tracing/metrics
|
|
26
|
-
service_version: Version of the service
|
|
27
|
-
environment: Deployment environment (dev, staging, prod)
|
|
28
|
-
enable_tracing: Whether to enable distributed tracing
|
|
29
|
-
enable_metrics: Whether to enable metrics collection
|
|
30
|
-
enable_logging: Whether to enable structured logging
|
|
31
|
-
log_level: Logging level (DEBUG, INFO, WARNING, ERROR)
|
|
32
|
-
log_format: Log format ("json" or "text")
|
|
33
|
-
otlp_endpoint: OpenTelemetry collector endpoint
|
|
34
|
-
otlp_headers: Headers for OTLP exporter
|
|
35
|
-
trace_sample_rate: Sampling rate for traces (0.0-1.0)
|
|
36
|
-
metric_export_interval_ms: How often to export metrics
|
|
37
|
-
resource_attributes: Additional resource attributes
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
service_name: str = "alma-memory"
|
|
41
|
-
service_version: str = "0.5.1"
|
|
42
|
-
environment: str = field(
|
|
43
|
-
default_factory=lambda: os.environ.get("ALMA_ENVIRONMENT", "development")
|
|
44
|
-
)
|
|
45
|
-
enable_tracing: bool = True
|
|
46
|
-
enable_metrics: bool = True
|
|
47
|
-
enable_logging: bool = True
|
|
48
|
-
log_level: str = field(
|
|
49
|
-
default_factory=lambda: os.environ.get("ALMA_LOG_LEVEL", "INFO")
|
|
50
|
-
)
|
|
51
|
-
log_format: str = field(
|
|
52
|
-
default_factory=lambda: os.environ.get("ALMA_LOG_FORMAT", "json")
|
|
53
|
-
)
|
|
54
|
-
otlp_endpoint: Optional[str] = field(
|
|
55
|
-
default_factory=lambda: os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT")
|
|
56
|
-
)
|
|
57
|
-
otlp_headers: Dict[str, str] = field(default_factory=dict)
|
|
58
|
-
trace_sample_rate: float = 1.0
|
|
59
|
-
metric_export_interval_ms: int = 60000
|
|
60
|
-
resource_attributes: Dict[str, str] = field(default_factory=dict)
|
|
61
|
-
|
|
62
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
63
|
-
"""Convert config to dictionary."""
|
|
64
|
-
return {
|
|
65
|
-
"service_name": self.service_name,
|
|
66
|
-
"service_version": self.service_version,
|
|
67
|
-
"environment": self.environment,
|
|
68
|
-
"enable_tracing": self.enable_tracing,
|
|
69
|
-
"enable_metrics": self.enable_metrics,
|
|
70
|
-
"enable_logging": self.enable_logging,
|
|
71
|
-
"log_level": self.log_level,
|
|
72
|
-
"log_format": self.log_format,
|
|
73
|
-
"otlp_endpoint": self.otlp_endpoint,
|
|
74
|
-
"trace_sample_rate": self.trace_sample_rate,
|
|
75
|
-
"metric_export_interval_ms": self.metric_export_interval_ms,
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def configure_observability(
|
|
80
|
-
service_name: str = "alma-memory",
|
|
81
|
-
service_version: str = "0.5.1",
|
|
82
|
-
environment: Optional[str] = None,
|
|
83
|
-
enable_tracing: bool = True,
|
|
84
|
-
enable_metrics: bool = True,
|
|
85
|
-
enable_logging: bool = True,
|
|
86
|
-
log_level: str = "INFO",
|
|
87
|
-
log_format: str = "json",
|
|
88
|
-
otlp_endpoint: Optional[str] = None,
|
|
89
|
-
trace_sample_rate: float = 1.0,
|
|
90
|
-
resource_attributes: Optional[Dict[str, str]] = None,
|
|
91
|
-
) -> ObservabilityConfig:
|
|
92
|
-
"""
|
|
93
|
-
Configure ALMA observability features.
|
|
94
|
-
|
|
95
|
-
This function should be called once at application startup to initialize
|
|
96
|
-
tracing, metrics, and logging.
|
|
97
|
-
|
|
98
|
-
Args:
|
|
99
|
-
service_name: Name of the service
|
|
100
|
-
service_version: Version of the service
|
|
101
|
-
environment: Deployment environment
|
|
102
|
-
enable_tracing: Enable distributed tracing
|
|
103
|
-
enable_metrics: Enable metrics collection
|
|
104
|
-
enable_logging: Enable structured logging
|
|
105
|
-
log_level: Logging level
|
|
106
|
-
log_format: Log format ("json" or "text")
|
|
107
|
-
otlp_endpoint: OpenTelemetry collector endpoint
|
|
108
|
-
trace_sample_rate: Sampling rate for traces
|
|
109
|
-
resource_attributes: Additional resource attributes
|
|
110
|
-
|
|
111
|
-
Returns:
|
|
112
|
-
ObservabilityConfig with applied settings
|
|
113
|
-
"""
|
|
114
|
-
global _observability_initialized, _tracer_provider, _meter_provider
|
|
115
|
-
|
|
116
|
-
config = ObservabilityConfig(
|
|
117
|
-
service_name=service_name,
|
|
118
|
-
service_version=service_version,
|
|
119
|
-
environment=environment or os.environ.get("ALMA_ENVIRONMENT", "development"),
|
|
120
|
-
enable_tracing=enable_tracing,
|
|
121
|
-
enable_metrics=enable_metrics,
|
|
122
|
-
enable_logging=enable_logging,
|
|
123
|
-
log_level=log_level,
|
|
124
|
-
log_format=log_format,
|
|
125
|
-
otlp_endpoint=otlp_endpoint,
|
|
126
|
-
trace_sample_rate=trace_sample_rate,
|
|
127
|
-
resource_attributes=resource_attributes or {},
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
# Setup logging first
|
|
131
|
-
if config.enable_logging:
|
|
132
|
-
from alma.observability.logging import setup_logging
|
|
133
|
-
|
|
134
|
-
setup_logging(
|
|
135
|
-
level=config.log_level,
|
|
136
|
-
format_type=config.log_format,
|
|
137
|
-
service_name=config.service_name,
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
# Setup tracing
|
|
141
|
-
if config.enable_tracing:
|
|
142
|
-
_tracer_provider = _setup_tracing(config)
|
|
143
|
-
|
|
144
|
-
# Setup metrics
|
|
145
|
-
if config.enable_metrics:
|
|
146
|
-
_meter_provider = _setup_metrics(config)
|
|
147
|
-
|
|
148
|
-
_observability_initialized = True
|
|
149
|
-
|
|
150
|
-
logger = logging.getLogger(__name__)
|
|
151
|
-
logger.info(
|
|
152
|
-
"ALMA observability configured",
|
|
153
|
-
extra={
|
|
154
|
-
"service_name": config.service_name,
|
|
155
|
-
"environment": config.environment,
|
|
156
|
-
"tracing_enabled": config.enable_tracing,
|
|
157
|
-
"metrics_enabled": config.enable_metrics,
|
|
158
|
-
},
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
return config
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
def _setup_tracing(config: ObservabilityConfig):
|
|
165
|
-
"""Setup OpenTelemetry tracing."""
|
|
166
|
-
try:
|
|
167
|
-
from opentelemetry import trace
|
|
168
|
-
from opentelemetry.sdk.resources import Resource
|
|
169
|
-
from opentelemetry.sdk.trace import TracerProvider
|
|
170
|
-
from opentelemetry.sdk.trace.sampling import TraceIdRatioBased
|
|
171
|
-
|
|
172
|
-
# Build resource attributes
|
|
173
|
-
resource_attrs = {
|
|
174
|
-
"service.name": config.service_name,
|
|
175
|
-
"service.version": config.service_version,
|
|
176
|
-
"deployment.environment": config.environment,
|
|
177
|
-
}
|
|
178
|
-
resource_attrs.update(config.resource_attributes)
|
|
179
|
-
|
|
180
|
-
resource = Resource.create(resource_attrs)
|
|
181
|
-
|
|
182
|
-
# Create sampler
|
|
183
|
-
sampler = TraceIdRatioBased(config.trace_sample_rate)
|
|
184
|
-
|
|
185
|
-
# Create and set tracer provider
|
|
186
|
-
provider = TracerProvider(resource=resource, sampler=sampler)
|
|
187
|
-
|
|
188
|
-
# Add OTLP exporter if endpoint is configured
|
|
189
|
-
if config.otlp_endpoint:
|
|
190
|
-
try:
|
|
191
|
-
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
|
192
|
-
OTLPSpanExporter,
|
|
193
|
-
)
|
|
194
|
-
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
195
|
-
|
|
196
|
-
otlp_exporter = OTLPSpanExporter(
|
|
197
|
-
endpoint=config.otlp_endpoint,
|
|
198
|
-
headers=config.otlp_headers or {},
|
|
199
|
-
)
|
|
200
|
-
provider.add_span_processor(BatchSpanProcessor(otlp_exporter))
|
|
201
|
-
except ImportError:
|
|
202
|
-
logging.getLogger(__name__).warning(
|
|
203
|
-
"OTLP exporter not available. Install with: "
|
|
204
|
-
"pip install opentelemetry-exporter-otlp-proto-grpc"
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
trace.set_tracer_provider(provider)
|
|
208
|
-
return provider
|
|
209
|
-
|
|
210
|
-
except ImportError:
|
|
211
|
-
logging.getLogger(__name__).warning(
|
|
212
|
-
"OpenTelemetry SDK not available. Tracing disabled. "
|
|
213
|
-
"Install with: pip install opentelemetry-sdk"
|
|
214
|
-
)
|
|
215
|
-
return None
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
def _setup_metrics(config: ObservabilityConfig):
|
|
219
|
-
"""Setup OpenTelemetry metrics."""
|
|
220
|
-
try:
|
|
221
|
-
from opentelemetry import metrics
|
|
222
|
-
from opentelemetry.sdk.metrics import MeterProvider
|
|
223
|
-
from opentelemetry.sdk.resources import Resource
|
|
224
|
-
|
|
225
|
-
# Build resource attributes
|
|
226
|
-
resource_attrs = {
|
|
227
|
-
"service.name": config.service_name,
|
|
228
|
-
"service.version": config.service_version,
|
|
229
|
-
"deployment.environment": config.environment,
|
|
230
|
-
}
|
|
231
|
-
resource_attrs.update(config.resource_attributes)
|
|
232
|
-
|
|
233
|
-
resource = Resource.create(resource_attrs)
|
|
234
|
-
|
|
235
|
-
# Create meter provider
|
|
236
|
-
provider = MeterProvider(resource=resource)
|
|
237
|
-
|
|
238
|
-
# Add OTLP exporter if endpoint is configured
|
|
239
|
-
if config.otlp_endpoint:
|
|
240
|
-
try:
|
|
241
|
-
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (
|
|
242
|
-
OTLPMetricExporter,
|
|
243
|
-
)
|
|
244
|
-
from opentelemetry.sdk.metrics.export import (
|
|
245
|
-
PeriodicExportingMetricReader,
|
|
246
|
-
)
|
|
247
|
-
|
|
248
|
-
otlp_exporter = OTLPMetricExporter(
|
|
249
|
-
endpoint=config.otlp_endpoint,
|
|
250
|
-
headers=config.otlp_headers or {},
|
|
251
|
-
)
|
|
252
|
-
reader = PeriodicExportingMetricReader(
|
|
253
|
-
otlp_exporter,
|
|
254
|
-
export_interval_millis=config.metric_export_interval_ms,
|
|
255
|
-
)
|
|
256
|
-
provider = MeterProvider(resource=resource, metric_readers=[reader])
|
|
257
|
-
except ImportError:
|
|
258
|
-
logging.getLogger(__name__).warning(
|
|
259
|
-
"OTLP metric exporter not available. Install with: "
|
|
260
|
-
"pip install opentelemetry-exporter-otlp-proto-grpc"
|
|
261
|
-
)
|
|
262
|
-
|
|
263
|
-
metrics.set_meter_provider(provider)
|
|
264
|
-
return provider
|
|
265
|
-
|
|
266
|
-
except ImportError:
|
|
267
|
-
logging.getLogger(__name__).warning(
|
|
268
|
-
"OpenTelemetry SDK not available. Metrics disabled. "
|
|
269
|
-
"Install with: pip install opentelemetry-sdk"
|
|
270
|
-
)
|
|
271
|
-
return None
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
def shutdown_observability():
|
|
275
|
-
"""
|
|
276
|
-
Shutdown observability providers.
|
|
277
|
-
|
|
278
|
-
Should be called at application shutdown to ensure all telemetry
|
|
279
|
-
data is exported.
|
|
280
|
-
"""
|
|
281
|
-
global _observability_initialized, _tracer_provider, _meter_provider
|
|
282
|
-
|
|
283
|
-
if _tracer_provider is not None:
|
|
284
|
-
try:
|
|
285
|
-
_tracer_provider.shutdown()
|
|
286
|
-
except Exception as e:
|
|
287
|
-
logging.getLogger(__name__).error(f"Error shutting down tracer: {e}")
|
|
288
|
-
|
|
289
|
-
if _meter_provider is not None:
|
|
290
|
-
try:
|
|
291
|
-
_meter_provider.shutdown()
|
|
292
|
-
except Exception as e:
|
|
293
|
-
logging.getLogger(__name__).error(f"Error shutting down meter: {e}")
|
|
294
|
-
|
|
295
|
-
_observability_initialized = False
|
|
296
|
-
_tracer_provider = None
|
|
297
|
-
_meter_provider = None
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
def is_observability_initialized() -> bool:
|
|
301
|
-
"""Check if observability has been initialized."""
|
|
302
|
-
return _observability_initialized
|
|
1
|
+
"""
|
|
2
|
+
ALMA Observability Configuration.
|
|
3
|
+
|
|
4
|
+
Centralized configuration for observability features including
|
|
5
|
+
tracing, metrics, and logging setup.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
import os
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Any, Dict, Optional
|
|
12
|
+
|
|
13
|
+
# Global state for observability configuration
|
|
14
|
+
_observability_initialized = False
|
|
15
|
+
_tracer_provider = None
|
|
16
|
+
_meter_provider = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class ObservabilityConfig:
|
|
21
|
+
"""
|
|
22
|
+
Configuration for ALMA observability features.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
service_name: Name of the service for tracing/metrics
|
|
26
|
+
service_version: Version of the service
|
|
27
|
+
environment: Deployment environment (dev, staging, prod)
|
|
28
|
+
enable_tracing: Whether to enable distributed tracing
|
|
29
|
+
enable_metrics: Whether to enable metrics collection
|
|
30
|
+
enable_logging: Whether to enable structured logging
|
|
31
|
+
log_level: Logging level (DEBUG, INFO, WARNING, ERROR)
|
|
32
|
+
log_format: Log format ("json" or "text")
|
|
33
|
+
otlp_endpoint: OpenTelemetry collector endpoint
|
|
34
|
+
otlp_headers: Headers for OTLP exporter
|
|
35
|
+
trace_sample_rate: Sampling rate for traces (0.0-1.0)
|
|
36
|
+
metric_export_interval_ms: How often to export metrics
|
|
37
|
+
resource_attributes: Additional resource attributes
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
service_name: str = "alma-memory"
|
|
41
|
+
service_version: str = "0.5.1"
|
|
42
|
+
environment: str = field(
|
|
43
|
+
default_factory=lambda: os.environ.get("ALMA_ENVIRONMENT", "development")
|
|
44
|
+
)
|
|
45
|
+
enable_tracing: bool = True
|
|
46
|
+
enable_metrics: bool = True
|
|
47
|
+
enable_logging: bool = True
|
|
48
|
+
log_level: str = field(
|
|
49
|
+
default_factory=lambda: os.environ.get("ALMA_LOG_LEVEL", "INFO")
|
|
50
|
+
)
|
|
51
|
+
log_format: str = field(
|
|
52
|
+
default_factory=lambda: os.environ.get("ALMA_LOG_FORMAT", "json")
|
|
53
|
+
)
|
|
54
|
+
otlp_endpoint: Optional[str] = field(
|
|
55
|
+
default_factory=lambda: os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT")
|
|
56
|
+
)
|
|
57
|
+
otlp_headers: Dict[str, str] = field(default_factory=dict)
|
|
58
|
+
trace_sample_rate: float = 1.0
|
|
59
|
+
metric_export_interval_ms: int = 60000
|
|
60
|
+
resource_attributes: Dict[str, str] = field(default_factory=dict)
|
|
61
|
+
|
|
62
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
63
|
+
"""Convert config to dictionary."""
|
|
64
|
+
return {
|
|
65
|
+
"service_name": self.service_name,
|
|
66
|
+
"service_version": self.service_version,
|
|
67
|
+
"environment": self.environment,
|
|
68
|
+
"enable_tracing": self.enable_tracing,
|
|
69
|
+
"enable_metrics": self.enable_metrics,
|
|
70
|
+
"enable_logging": self.enable_logging,
|
|
71
|
+
"log_level": self.log_level,
|
|
72
|
+
"log_format": self.log_format,
|
|
73
|
+
"otlp_endpoint": self.otlp_endpoint,
|
|
74
|
+
"trace_sample_rate": self.trace_sample_rate,
|
|
75
|
+
"metric_export_interval_ms": self.metric_export_interval_ms,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def configure_observability(
|
|
80
|
+
service_name: str = "alma-memory",
|
|
81
|
+
service_version: str = "0.5.1",
|
|
82
|
+
environment: Optional[str] = None,
|
|
83
|
+
enable_tracing: bool = True,
|
|
84
|
+
enable_metrics: bool = True,
|
|
85
|
+
enable_logging: bool = True,
|
|
86
|
+
log_level: str = "INFO",
|
|
87
|
+
log_format: str = "json",
|
|
88
|
+
otlp_endpoint: Optional[str] = None,
|
|
89
|
+
trace_sample_rate: float = 1.0,
|
|
90
|
+
resource_attributes: Optional[Dict[str, str]] = None,
|
|
91
|
+
) -> ObservabilityConfig:
|
|
92
|
+
"""
|
|
93
|
+
Configure ALMA observability features.
|
|
94
|
+
|
|
95
|
+
This function should be called once at application startup to initialize
|
|
96
|
+
tracing, metrics, and logging.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
service_name: Name of the service
|
|
100
|
+
service_version: Version of the service
|
|
101
|
+
environment: Deployment environment
|
|
102
|
+
enable_tracing: Enable distributed tracing
|
|
103
|
+
enable_metrics: Enable metrics collection
|
|
104
|
+
enable_logging: Enable structured logging
|
|
105
|
+
log_level: Logging level
|
|
106
|
+
log_format: Log format ("json" or "text")
|
|
107
|
+
otlp_endpoint: OpenTelemetry collector endpoint
|
|
108
|
+
trace_sample_rate: Sampling rate for traces
|
|
109
|
+
resource_attributes: Additional resource attributes
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
ObservabilityConfig with applied settings
|
|
113
|
+
"""
|
|
114
|
+
global _observability_initialized, _tracer_provider, _meter_provider
|
|
115
|
+
|
|
116
|
+
config = ObservabilityConfig(
|
|
117
|
+
service_name=service_name,
|
|
118
|
+
service_version=service_version,
|
|
119
|
+
environment=environment or os.environ.get("ALMA_ENVIRONMENT", "development"),
|
|
120
|
+
enable_tracing=enable_tracing,
|
|
121
|
+
enable_metrics=enable_metrics,
|
|
122
|
+
enable_logging=enable_logging,
|
|
123
|
+
log_level=log_level,
|
|
124
|
+
log_format=log_format,
|
|
125
|
+
otlp_endpoint=otlp_endpoint,
|
|
126
|
+
trace_sample_rate=trace_sample_rate,
|
|
127
|
+
resource_attributes=resource_attributes or {},
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Setup logging first
|
|
131
|
+
if config.enable_logging:
|
|
132
|
+
from alma.observability.logging import setup_logging
|
|
133
|
+
|
|
134
|
+
setup_logging(
|
|
135
|
+
level=config.log_level,
|
|
136
|
+
format_type=config.log_format,
|
|
137
|
+
service_name=config.service_name,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Setup tracing
|
|
141
|
+
if config.enable_tracing:
|
|
142
|
+
_tracer_provider = _setup_tracing(config)
|
|
143
|
+
|
|
144
|
+
# Setup metrics
|
|
145
|
+
if config.enable_metrics:
|
|
146
|
+
_meter_provider = _setup_metrics(config)
|
|
147
|
+
|
|
148
|
+
_observability_initialized = True
|
|
149
|
+
|
|
150
|
+
logger = logging.getLogger(__name__)
|
|
151
|
+
logger.info(
|
|
152
|
+
"ALMA observability configured",
|
|
153
|
+
extra={
|
|
154
|
+
"service_name": config.service_name,
|
|
155
|
+
"environment": config.environment,
|
|
156
|
+
"tracing_enabled": config.enable_tracing,
|
|
157
|
+
"metrics_enabled": config.enable_metrics,
|
|
158
|
+
},
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
return config
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _setup_tracing(config: ObservabilityConfig):
|
|
165
|
+
"""Setup OpenTelemetry tracing."""
|
|
166
|
+
try:
|
|
167
|
+
from opentelemetry import trace
|
|
168
|
+
from opentelemetry.sdk.resources import Resource
|
|
169
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
170
|
+
from opentelemetry.sdk.trace.sampling import TraceIdRatioBased
|
|
171
|
+
|
|
172
|
+
# Build resource attributes
|
|
173
|
+
resource_attrs = {
|
|
174
|
+
"service.name": config.service_name,
|
|
175
|
+
"service.version": config.service_version,
|
|
176
|
+
"deployment.environment": config.environment,
|
|
177
|
+
}
|
|
178
|
+
resource_attrs.update(config.resource_attributes)
|
|
179
|
+
|
|
180
|
+
resource = Resource.create(resource_attrs)
|
|
181
|
+
|
|
182
|
+
# Create sampler
|
|
183
|
+
sampler = TraceIdRatioBased(config.trace_sample_rate)
|
|
184
|
+
|
|
185
|
+
# Create and set tracer provider
|
|
186
|
+
provider = TracerProvider(resource=resource, sampler=sampler)
|
|
187
|
+
|
|
188
|
+
# Add OTLP exporter if endpoint is configured
|
|
189
|
+
if config.otlp_endpoint:
|
|
190
|
+
try:
|
|
191
|
+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
|
192
|
+
OTLPSpanExporter,
|
|
193
|
+
)
|
|
194
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
195
|
+
|
|
196
|
+
otlp_exporter = OTLPSpanExporter(
|
|
197
|
+
endpoint=config.otlp_endpoint,
|
|
198
|
+
headers=config.otlp_headers or {},
|
|
199
|
+
)
|
|
200
|
+
provider.add_span_processor(BatchSpanProcessor(otlp_exporter))
|
|
201
|
+
except ImportError:
|
|
202
|
+
logging.getLogger(__name__).warning(
|
|
203
|
+
"OTLP exporter not available. Install with: "
|
|
204
|
+
"pip install opentelemetry-exporter-otlp-proto-grpc"
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
trace.set_tracer_provider(provider)
|
|
208
|
+
return provider
|
|
209
|
+
|
|
210
|
+
except ImportError:
|
|
211
|
+
logging.getLogger(__name__).warning(
|
|
212
|
+
"OpenTelemetry SDK not available. Tracing disabled. "
|
|
213
|
+
"Install with: pip install opentelemetry-sdk"
|
|
214
|
+
)
|
|
215
|
+
return None
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _setup_metrics(config: ObservabilityConfig):
|
|
219
|
+
"""Setup OpenTelemetry metrics."""
|
|
220
|
+
try:
|
|
221
|
+
from opentelemetry import metrics
|
|
222
|
+
from opentelemetry.sdk.metrics import MeterProvider
|
|
223
|
+
from opentelemetry.sdk.resources import Resource
|
|
224
|
+
|
|
225
|
+
# Build resource attributes
|
|
226
|
+
resource_attrs = {
|
|
227
|
+
"service.name": config.service_name,
|
|
228
|
+
"service.version": config.service_version,
|
|
229
|
+
"deployment.environment": config.environment,
|
|
230
|
+
}
|
|
231
|
+
resource_attrs.update(config.resource_attributes)
|
|
232
|
+
|
|
233
|
+
resource = Resource.create(resource_attrs)
|
|
234
|
+
|
|
235
|
+
# Create meter provider
|
|
236
|
+
provider = MeterProvider(resource=resource)
|
|
237
|
+
|
|
238
|
+
# Add OTLP exporter if endpoint is configured
|
|
239
|
+
if config.otlp_endpoint:
|
|
240
|
+
try:
|
|
241
|
+
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (
|
|
242
|
+
OTLPMetricExporter,
|
|
243
|
+
)
|
|
244
|
+
from opentelemetry.sdk.metrics.export import (
|
|
245
|
+
PeriodicExportingMetricReader,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
otlp_exporter = OTLPMetricExporter(
|
|
249
|
+
endpoint=config.otlp_endpoint,
|
|
250
|
+
headers=config.otlp_headers or {},
|
|
251
|
+
)
|
|
252
|
+
reader = PeriodicExportingMetricReader(
|
|
253
|
+
otlp_exporter,
|
|
254
|
+
export_interval_millis=config.metric_export_interval_ms,
|
|
255
|
+
)
|
|
256
|
+
provider = MeterProvider(resource=resource, metric_readers=[reader])
|
|
257
|
+
except ImportError:
|
|
258
|
+
logging.getLogger(__name__).warning(
|
|
259
|
+
"OTLP metric exporter not available. Install with: "
|
|
260
|
+
"pip install opentelemetry-exporter-otlp-proto-grpc"
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
metrics.set_meter_provider(provider)
|
|
264
|
+
return provider
|
|
265
|
+
|
|
266
|
+
except ImportError:
|
|
267
|
+
logging.getLogger(__name__).warning(
|
|
268
|
+
"OpenTelemetry SDK not available. Metrics disabled. "
|
|
269
|
+
"Install with: pip install opentelemetry-sdk"
|
|
270
|
+
)
|
|
271
|
+
return None
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def shutdown_observability():
|
|
275
|
+
"""
|
|
276
|
+
Shutdown observability providers.
|
|
277
|
+
|
|
278
|
+
Should be called at application shutdown to ensure all telemetry
|
|
279
|
+
data is exported.
|
|
280
|
+
"""
|
|
281
|
+
global _observability_initialized, _tracer_provider, _meter_provider
|
|
282
|
+
|
|
283
|
+
if _tracer_provider is not None:
|
|
284
|
+
try:
|
|
285
|
+
_tracer_provider.shutdown()
|
|
286
|
+
except Exception as e:
|
|
287
|
+
logging.getLogger(__name__).error(f"Error shutting down tracer: {e}")
|
|
288
|
+
|
|
289
|
+
if _meter_provider is not None:
|
|
290
|
+
try:
|
|
291
|
+
_meter_provider.shutdown()
|
|
292
|
+
except Exception as e:
|
|
293
|
+
logging.getLogger(__name__).error(f"Error shutting down meter: {e}")
|
|
294
|
+
|
|
295
|
+
_observability_initialized = False
|
|
296
|
+
_tracer_provider = None
|
|
297
|
+
_meter_provider = None
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def is_observability_initialized() -> bool:
|
|
301
|
+
"""Check if observability has been initialized."""
|
|
302
|
+
return _observability_initialized
|