clm-kernel 0.0.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.
- clm/__init__.py +230 -0
- clm/__main__.py +25 -0
- clm/cross_cutting/__init__.py +50 -0
- clm/cross_cutting/_test_runner.py +36 -0
- clm/cross_cutting/async_utils.py +25 -0
- clm/cross_cutting/cel_builder.py +123 -0
- clm/cross_cutting/cel_converter.py +697 -0
- clm/cross_cutting/cel_engine.py +252 -0
- clm/cross_cutting/cel_ops.py +72 -0
- clm/cross_cutting/cel_ops_db.py +157 -0
- clm/cross_cutting/cel_ops_files.py +99 -0
- clm/cross_cutting/cel_ops_state.py +71 -0
- clm/cross_cutting/cel_ops_strings.py +64 -0
- clm/cross_cutting/cel_resolver.py +63 -0
- clm/cross_cutting/cel_slices.py +56 -0
- clm/cross_cutting/cel_store.py +330 -0
- clm/cross_cutting/clm_logger.py +140 -0
- clm/cross_cutting/config/__init__.py +155 -0
- clm/cross_cutting/config/config_constants.py +392 -0
- clm/cross_cutting/config/env_parameters.py +90 -0
- clm/cross_cutting/config/logging.py +378 -0
- clm/cross_cutting/config/settings.py +504 -0
- clm/cross_cutting/context.py +5 -0
- clm/cross_cutting/domain_models.py +55 -0
- clm/cross_cutting/domain_types.py +61 -0
- clm/cross_cutting/effects.py +67 -0
- clm/cross_cutting/errors.py +153 -0
- clm/cross_cutting/governance.py +331 -0
- clm/cross_cutting/guards.py +41 -0
- clm/cross_cutting/mcard.py +321 -0
- clm/cross_cutting/native.py +185 -0
- clm/cross_cutting/observability.py +289 -0
- clm/cross_cutting/pcard.py +434 -0
- clm/cross_cutting/registry.py +71 -0
- clm/cross_cutting/resources.py +84 -0
- clm/cross_cutting/secrets.py +44 -0
- clm/cross_cutting/subprocess_utils.py +118 -0
- clm/cross_cutting/telemetry.py +164 -0
- clm/cross_cutting/testing/__init__.py +8 -0
- clm/cross_cutting/testing/comparator.py +187 -0
- clm/cross_cutting/testing/datasets.py +87 -0
- clm/cross_cutting/timeutil.py +20 -0
- clm/cross_cutting/types/new_type_check.py +0 -0
- clm/cross_cutting/utils/__init__.py +1 -0
- clm/cross_cutting/utils/url_safety.py +50 -0
- clm/cross_cutting/vcard.py +560 -0
- clm/cross_cutting/writer.py +118 -0
- clm/layer0/README.md +50 -0
- clm/layer0/__init__.py +223 -0
- clm/layer0/algebra.py +60 -0
- clm/layer0/algebra_baldwin.py +133 -0
- clm/layer0/algebra_baldwin_generators.py +36 -0
- clm/layer0/algebra_equivalence.py +262 -0
- clm/layer0/algebra_ingest.py +306 -0
- clm/layer0/algebra_manifest_io.py +156 -0
- clm/layer0/assembler.py +481 -0
- clm/layer0/cel/__init__.py +23 -0
- clm/layer0/cel_eval.py +491 -0
- clm/layer0/codec.py +106 -0
- clm/layer0/context.py +122 -0
- clm/layer0/db.py +160 -0
- clm/layer0/exceptions.py +73 -0
- clm/layer0/fibration.py +106 -0
- clm/layer0/gates.py +50 -0
- clm/layer0/hash.py +80 -0
- clm/layer0/loader.py +826 -0
- clm/layer0/math_utils.py +163 -0
- clm/layer0/mcard.py +96 -0
- clm/layer0/model/__init__.py +0 -0
- clm/layer0/model/action.py +223 -0
- clm/layer0/model/card.py +280 -0
- clm/layer0/model/card_triad.py +427 -0
- clm/layer0/model/compatibility.py +60 -0
- clm/layer0/model/dictionary.py +46 -0
- clm/layer0/model/dots.py +331 -0
- clm/layer0/model/event_producer.py +88 -0
- clm/layer0/model/g_time.py +89 -0
- clm/layer0/model/handle.py +163 -0
- clm/layer0/model/hash/__init__.py +6 -0
- clm/layer0/model/hash/algorithms/__init__.py +3 -0
- clm/layer0/model/hash/algorithms/custom_hash.py +7 -0
- clm/layer0/model/hash/algorithms/local_sha256.py +178 -0
- clm/layer0/model/hash/constants.py +53 -0
- clm/layer0/model/hash/enums.py +60 -0
- clm/layer0/model/hash/validator.py +307 -0
- clm/layer0/model/interpreter.py +275 -0
- clm/layer0/model/pagination.py +45 -0
- clm/layer0/model/pcard.py +716 -0
- clm/layer0/model/schema.py +44 -0
- clm/layer0/model/utils/__init__.py +1 -0
- clm/layer0/model/utils/content_analyzer.py +152 -0
- clm/layer0/model/validators/__init__.py +1 -0
- clm/layer0/model/validators/base_validator.py +44 -0
- clm/layer0/model/validators/binary_validator.py +66 -0
- clm/layer0/model/validators/text_validator.py +82 -0
- clm/layer0/model/validators/validation_registry.py +49 -0
- clm/layer0/model/vcard.py +823 -0
- clm/layer0/model/vcard_ext/__init__.py +39 -0
- clm/layer0/model/vcard_ext/core.py +60 -0
- clm/layer0/model/vcard_ext/network.py +23 -0
- clm/layer0/model/vcard_ext/observability.py +63 -0
- clm/layer0/model/vcard_ext/storage.py +60 -0
- clm/layer0/model/vcard_ext/vendors.py +211 -0
- clm/layer0/model/vcard_sandwich.py +119 -0
- clm/layer0/model/vcard_vocabulary.py +463 -0
- clm/layer0/model/workflow.py +274 -0
- clm/layer0/narrative.py +431 -0
- clm/layer0/ontology/collection.py +125 -0
- clm/layer0/parser.py +429 -0
- clm/layer0/relations.py +73 -0
- clm/layer0/rule_evaluator.py +251 -0
- clm/layer0/schema/__init__.py +38 -0
- clm/layer0/schema/ddl.py +97 -0
- clm/layer0/templates/abstract.yaml +99 -0
- clm/layer0/templates/balanced.yaml +253 -0
- clm/layer0/templates/concrete.yaml +172 -0
- clm/layer0/type_registry.py +223 -0
- clm/layer0/types.py +204 -0
- clm/layer0/utils.py +886 -0
- clm/layer0/verifier_core.py +262 -0
- clm/layer1/__init__.py +31 -0
- clm/layer1/action_dispatcher.py +275 -0
- clm/layer1/adapter_registry.py +233 -0
- clm/layer1/algebra_baldwin_generators.py +192 -0
- clm/layer1/arrow_compiler.py +525 -0
- clm/layer1/batch_processor.py +152 -0
- clm/layer1/cel/__init__.py +27 -0
- clm/layer1/cel/builder.py +173 -0
- clm/layer1/engine.py +759 -0
- clm/layer1/engine_async.py +89 -0
- clm/layer1/eval_callback.py +49 -0
- clm/layer1/gate_composer.py +229 -0
- clm/layer1/hoare_sandwich.py +298 -0
- clm/layer1/identity_guard.py +348 -0
- clm/layer1/matrix.py +138 -0
- clm/layer1/neural_runtime.py +221 -0
- clm/layer1/operations/__init__.py +123 -0
- clm/layer1/operations/augment.py +156 -0
- clm/layer1/operations/base.py +109 -0
- clm/layer1/operations/builtins.py +338 -0
- clm/layer1/operations/dispatch.py +144 -0
- clm/layer1/operations/exclude.py +107 -0
- clm/layer1/operations/handle.py +197 -0
- clm/layer1/operations/identity.py +139 -0
- clm/layer1/operations/invert.py +66 -0
- clm/layer1/operations/loader.py +116 -0
- clm/layer1/operations/manipulators/__init__.py +23 -0
- clm/layer1/operations/manipulators/document.py +211 -0
- clm/layer1/operations/manipulators/media.py +134 -0
- clm/layer1/operations/manipulators/structured.py +159 -0
- clm/layer1/operations/manipulators/tabular.py +334 -0
- clm/layer1/operations/port.py +65 -0
- clm/layer1/operations/services.py +529 -0
- clm/layer1/operations/split.py +117 -0
- clm/layer1/operations/substitute.py +75 -0
- clm/layer1/petri.py +1052 -0
- clm/layer1/pocketflow_orchestrator.py +408 -0
- clm/layer1/pocketflow_scheduler.py +519 -0
- clm/layer1/protocols.py +197 -0
- clm/layer1/runtime_adapter.py +718 -0
- clm/layer1/runtimes/__init__.py +71 -0
- clm/layer1/runtimes/_generated_assertions.py +125 -0
- clm/layer1/runtimes/_generated_types.py +42 -0
- clm/layer1/runtimes/base.py +265 -0
- clm/layer1/runtimes/binary.py +101 -0
- clm/layer1/runtimes/factory.py +203 -0
- clm/layer1/runtimes/javascript.py +321 -0
- clm/layer1/runtimes/javascript_runtime.js +33 -0
- clm/layer1/runtimes/js_scripts/isomorphism.mjs +22 -0
- clm/layer1/runtimes/js_scripts/loader.mjs +52 -0
- clm/layer1/runtimes/lambda_calc.py +126 -0
- clm/layer1/runtimes/python.py +288 -0
- clm/layer1/runtimes/python_runtime.py +41 -0
- clm/layer1/runtimes/script.py +114 -0
- clm/layer1/sandbox.py +334 -0
- clm/layer1/savepoint_guard.py +136 -0
- clm/layer1/sparse_net.py +122 -0
- clm/layer1/spec_tester.py +165 -0
- clm/layer1/store.py +295 -0
- clm/layer1/test_runner.py +498 -0
- clm/layer1/type_inspector.py +166 -0
- clm/layer1/verifier.py +772 -0
- clm/layer1/vm.py +91 -0
- clm/layer2/__init__.py +78 -0
- clm/layer2/card_collection.py +678 -0
- clm/layer2/classifier.py +479 -0
- clm/layer2/engine/__init__.py +1 -0
- clm/layer2/engine/abstract_sql_engine.py +320 -0
- clm/layer2/engine/base.py +193 -0
- clm/layer2/engine/duckdb_engine.py +576 -0
- clm/layer2/engine/sqlite_engine.py +518 -0
- clm/layer2/fiber/__init__.py +31 -0
- clm/layer2/fiber/context.py +89 -0
- clm/layer2/fiber/disposable.py +163 -0
- clm/layer2/fiber/fiber.py +125 -0
- clm/layer2/fiber/hoare.py +191 -0
- clm/layer2/file_io.py +376 -0
- clm/layer2/file_registrar.py +77 -0
- clm/layer2/ingest.py +202 -0
- clm/layer2/lineage.py +322 -0
- clm/layer2/mcard_fs.py +262 -0
- clm/layer2/merkle.py +11 -0
- clm/layer2/mime.py +244 -0
- clm/layer2/mime_detector.py +245 -0
- clm/layer2/private_collection.py +118 -0
- clm/layer2/shared_store.py +11 -0
- clm/layer2/storage/__init__.py +190 -0
- clm/layer2/storage/db_bitemporal.py +141 -0
- clm/layer2/storage/db_driver.py +331 -0
- clm/layer2/storage/db_hyperlinks.py +214 -0
- clm/layer2/storage/db_pool.py +139 -0
- clm/layer2/storage/db_repository.py +229 -0
- clm/layer2/storage/savepoint.py +78 -0
- clm/layer2/storage/sqlite_wal.py +74 -0
- clm/layer2/tridb.py +245 -0
- clm/layer2/vcard_receipt.py +71 -0
- clm/layer2/vfs.py +17 -0
- clm/layer3/__init__.py +141 -0
- clm/layer3/agency/__init__.py +19 -0
- clm/layer3/agency/config.py +220 -0
- clm/layer3/agency/providers/__init__.py +15 -0
- clm/layer3/agency/providers/base.py +91 -0
- clm/layer3/agency/providers/mlc_llm.py +169 -0
- clm/layer3/agency/providers/ollama.py +203 -0
- clm/layer3/agency/router.py +71 -0
- clm/layer3/agency/runtime.py +524 -0
- clm/layer3/gateway.py +353 -0
- clm/layer3/open_interpreter_adapter.py +159 -0
- clm/layer3/rag/__init__.py +70 -0
- clm/layer3/rag/cli.py +228 -0
- clm/layer3/rag/config.py +153 -0
- clm/layer3/rag/embeddings/__init__.py +16 -0
- clm/layer3/rag/embeddings/base.py +79 -0
- clm/layer3/rag/embeddings/ollama.py +211 -0
- clm/layer3/rag/embeddings/vision.py +290 -0
- clm/layer3/rag/engine.py +276 -0
- clm/layer3/rag/graph/__init__.py +22 -0
- clm/layer3/rag/graph/community.py +198 -0
- clm/layer3/rag/graph/engine.py +433 -0
- clm/layer3/rag/graph/extractor.py +255 -0
- clm/layer3/rag/graph/schema.py +115 -0
- clm/layer3/rag/graph/store.py +641 -0
- clm/layer3/rag/indexer.py +333 -0
- clm/layer3/rag/llm_providers.json +52 -0
- clm/layer3/rag/semantic_versioning.py +313 -0
- clm/layer3/rag/vector/__init__.py +28 -0
- clm/layer3/rag/vector/handle_vector_store.py +749 -0
- clm/layer3/rag/vector/schema.py +151 -0
- clm/layer3/rag/vector/store.py +632 -0
- clm/layer3/reticulum/__init__.py +55 -0
- clm/layer3/reticulum/bridge.py +74 -0
- clm/layer3/reticulum/daemon.py +88 -0
- clm/layer3/reticulum/discovery.py +164 -0
- clm/layer3/reticulum/identity.py +107 -0
- clm/layer3/reticulum/media.py +148 -0
- clm/layer3/reticulum/transport.py +133 -0
- clm/layer3/satori/__init__.py +209 -0
- clm/layer3/satori/alpha_conversion.py +168 -0
- clm/layer3/satori/beta_reduction.py +359 -0
- clm/layer3/satori/continuation.py +38 -0
- clm/layer3/satori/eta_conversion.py +205 -0
- clm/layer3/satori/free_variables.py +163 -0
- clm/layer3/satori/io_effects.py +370 -0
- clm/layer3/satori/lambda_runtime.py +726 -0
- clm/layer3/satori/lambda_term.py +230 -0
- clm/layer3/satori/sheaf_audit.py +261 -0
- clm/layer3/satori/speech_act.py +279 -0
- clm/layer4/README.md +9 -0
- clm/layer4/__init__.py +67 -0
- clm/layer4/_sovereign_executor.py +580 -0
- clm/layer4/action_commands.py +719 -0
- clm/layer4/api.py +236 -0
- clm/layer4/bootstrap/__init__.py +13 -0
- clm/layer4/bootstrap/bootstrapper.py +118 -0
- clm/layer4/bootstrap/cleanup.py +44 -0
- clm/layer4/bootstrap/clm_hooks.py +49 -0
- clm/layer4/bootstrap/genesis.py +77 -0
- clm/layer4/bootstrap/injection.py +125 -0
- clm/layer4/cli.py +549 -0
- clm/layer4/collection_manager.py +553 -0
- clm/layer4/commands/__init__.py +81 -0
- clm/layer4/commands/action_cmd.py +42 -0
- clm/layer4/commands/check_cmd.py +82 -0
- clm/layer4/commands/envelope.py +73 -0
- clm/layer4/commands/evaluate_cmd.py +224 -0
- clm/layer4/commands/mcard_cmd.py +24 -0
- clm/layer4/commands/petri_cmd.py +92 -0
- clm/layer4/commands/tridb_cmd.py +319 -0
- clm/layer4/commands/version_cmd.py +27 -0
- clm/layer4/diff_commands.py +167 -0
- clm/layer4/eoa_sponsor.py +232 -0
- clm/layer4/events.py +69 -0
- clm/layer4/flux_gateway.py +133 -0
- clm/layer4/gateway.py +91 -0
- clm/layer4/loader.py +307 -0
- clm/layer4/mcard_commands.py +166 -0
- clm/layer4/membrane.py +273 -0
- clm/layer4/navigation.py +50 -0
- clm/layer4/protocol/protocol_entry_python.py +108 -0
- clm/layer4/protocol/python_sync.py +126 -0
- clm/layer4/runner.py +150 -0
- clm/layer4/satori.py +262 -0
- clm/layer4/server/python_sync_client.py +150 -0
- clm/layer4/server/python_sync_server.py +139 -0
- clm/layer4/server/service_api.py +315 -0
- clm/layer4/server/start_servers.py +107 -0
- clm/layer4/server/stop_servers.py +24 -0
- clm/layer4/simulated_optimization_fix.py +0 -0
- clm/layer4/storage.py +463 -0
- clm/layer4/tridb_admin.py +268 -0
- clm/layer4/websocket/test_ws_client.py +104 -0
- clm/layer4/websocket/test_ws_server.py +138 -0
- clm/layer4/websocket/ws_server_local.py +160 -0
- clm/layer5/__init__.py +51 -0
- clm/layer5/async_batch_writer.py +133 -0
- clm/layer5/learning.py +276 -0
- clm/layer5/telemetry_hook.py +107 -0
- clm/layer5/type_lattice.py +238 -0
- clm/py.typed +0 -0
- clm/schemas/__init__.py +652 -0
- clm/schemas/abstract_face_schema.yaml +77 -0
- clm/schemas/cel_schema.yaml +416 -0
- clm/schemas/lifecycle/__init__.py +45 -0
- clm/schemas/lifecycle/models.py +123 -0
- clm/schemas/lifecycle/service.py +364 -0
- clm/schemas/mcard_schema.sql +192 -0
- clm/schemas/mcard_vector_schema.sql +283 -0
- clm/schemas/mlp-context-v1.json +91 -0
- clm_kernel-0.0.0.dist-info/METADATA +121 -0
- clm_kernel-0.0.0.dist-info/RECORD +333 -0
- clm_kernel-0.0.0.dist-info/WHEEL +4 -0
- clm_kernel-0.0.0.dist-info/entry_points.txt +3 -0
- clm_kernel-0.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
from functools import wraps
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
# OpenTelemetry imports (with fallback if not installed)
|
|
11
|
+
try:
|
|
12
|
+
from opentelemetry import metrics, trace
|
|
13
|
+
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import (
|
|
14
|
+
OTLPMetricExporter,
|
|
15
|
+
)
|
|
16
|
+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
|
|
17
|
+
from opentelemetry.metrics import Meter
|
|
18
|
+
from opentelemetry.sdk.metrics import MeterProvider
|
|
19
|
+
from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
|
|
20
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
21
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
22
|
+
from opentelemetry.trace import SpanKind, Status, StatusCode, Tracer
|
|
23
|
+
|
|
24
|
+
OTEL_AVAILABLE = True
|
|
25
|
+
except ImportError:
|
|
26
|
+
OTEL_AVAILABLE = False
|
|
27
|
+
Tracer = None
|
|
28
|
+
Span = None
|
|
29
|
+
Meter = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class REPLPhase:
|
|
33
|
+
"""Enum-like class for REPL phases."""
|
|
34
|
+
|
|
35
|
+
PREP = "prep"
|
|
36
|
+
EXEC = "exec"
|
|
37
|
+
POST = "post"
|
|
38
|
+
AWAIT = "await"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class OpenTelemetrySidecar:
|
|
42
|
+
"""
|
|
43
|
+
OpenTelemetry Sidecar for PTR Engine observability.
|
|
44
|
+
|
|
45
|
+
Provides instrumentation hooks for each REPL phase:
|
|
46
|
+
- prep: Artifact loading, V_pre validation
|
|
47
|
+
- exec: CLM execution, sandbox runtime
|
|
48
|
+
- post: Balanced verification, VCard generation
|
|
49
|
+
- await: Handle history recording, state transition
|
|
50
|
+
|
|
51
|
+
Usage:
|
|
52
|
+
sidecar = OpenTelemetrySidecar.get_instance()
|
|
53
|
+
sidecar.initialize({
|
|
54
|
+
"endpoint": "http://localhost:4317",
|
|
55
|
+
"service_name": "ptr-runtime",
|
|
56
|
+
"service_version": "1.0.0"
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
with sidecar.trace_phase(REPLPhase.PREP, pcard_hash="abc123"):
|
|
60
|
+
# do prep work
|
|
61
|
+
pass
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
_instance: OpenTelemetrySidecar | None = None
|
|
65
|
+
|
|
66
|
+
def __init__(self):
|
|
67
|
+
self.logger = logging.getLogger(__name__)
|
|
68
|
+
self._initialized = False
|
|
69
|
+
self._tracer: Tracer | None = None
|
|
70
|
+
self._meter: Meter | None = None
|
|
71
|
+
self._config: dict[str, Any] = {}
|
|
72
|
+
|
|
73
|
+
# Metrics
|
|
74
|
+
self._phase_duration_histogram = None
|
|
75
|
+
self._phase_counter = None
|
|
76
|
+
self._error_counter = None
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def get_instance(cls) -> OpenTelemetrySidecar:
|
|
80
|
+
"""Get singleton instance of OpenTelemetrySidecar."""
|
|
81
|
+
if cls._instance is None:
|
|
82
|
+
cls._instance = OpenTelemetrySidecar()
|
|
83
|
+
return cls._instance
|
|
84
|
+
|
|
85
|
+
def initialize(self, config: dict[str, Any]) -> bool:
|
|
86
|
+
"""
|
|
87
|
+
Initialize OpenTelemetry with provided configuration.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
config: Configuration dictionary with keys:
|
|
91
|
+
- endpoint: OTLP endpoint (e.g., "http://localhost:4317")
|
|
92
|
+
- service_name: Name of the service
|
|
93
|
+
- service_version: Version of the service
|
|
94
|
+
- namespace: Optional namespace prefix
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
True if initialization succeeded, False otherwise
|
|
98
|
+
"""
|
|
99
|
+
if not OTEL_AVAILABLE:
|
|
100
|
+
self.logger.warning(
|
|
101
|
+
"[OpenTelemetrySidecar] OpenTelemetry SDK not installed. "
|
|
102
|
+
"Install with: pip install opentelemetry-sdk opentelemetry-exporter-otlp"
|
|
103
|
+
)
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
if self._initialized:
|
|
107
|
+
self.logger.warning("[OpenTelemetrySidecar] Already initialized")
|
|
108
|
+
return True
|
|
109
|
+
|
|
110
|
+
self._config = config
|
|
111
|
+
endpoint = config.get("endpoint", "http://localhost:4317")
|
|
112
|
+
service_name = config.get("service_name", "ptr-runtime")
|
|
113
|
+
service_version = config.get("service_version", "1.0.0")
|
|
114
|
+
namespace = config.get("namespace", "ptr")
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
# Set up tracer provider
|
|
118
|
+
tracer_provider = TracerProvider()
|
|
119
|
+
span_exporter = OTLPSpanExporter(endpoint=endpoint, insecure=True)
|
|
120
|
+
tracer_provider.add_span_processor(BatchSpanProcessor(span_exporter))
|
|
121
|
+
trace.set_tracer_provider(tracer_provider)
|
|
122
|
+
self._tracer = trace.get_tracer(service_name, service_version)
|
|
123
|
+
|
|
124
|
+
# Set up meter provider
|
|
125
|
+
metric_exporter = OTLPMetricExporter(endpoint=endpoint, insecure=True)
|
|
126
|
+
metric_reader = PeriodicExportingMetricReader(metric_exporter)
|
|
127
|
+
meter_provider = MeterProvider(metric_readers=[metric_reader])
|
|
128
|
+
metrics.set_meter_provider(meter_provider)
|
|
129
|
+
self._meter = metrics.get_meter(service_name, service_version)
|
|
130
|
+
|
|
131
|
+
# Create metrics instruments
|
|
132
|
+
self._phase_duration_histogram = self._meter.create_histogram(
|
|
133
|
+
name=f"{namespace}.repl.phase.duration",
|
|
134
|
+
description="Duration of REPL phase execution in milliseconds",
|
|
135
|
+
unit="ms",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
self._phase_counter = self._meter.create_counter(
|
|
139
|
+
name=f"{namespace}.repl.phase.count",
|
|
140
|
+
description="Count of REPL phase executions",
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
self._error_counter = self._meter.create_counter(
|
|
144
|
+
name=f"{namespace}.repl.error.count",
|
|
145
|
+
description="Count of errors during REPL execution",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
self._initialized = True
|
|
149
|
+
self.logger.info(
|
|
150
|
+
f"[OpenTelemetrySidecar] Initialized for {service_name}@{service_version} "
|
|
151
|
+
f"-> {endpoint}"
|
|
152
|
+
)
|
|
153
|
+
return True
|
|
154
|
+
|
|
155
|
+
except (OSError, ValueError, ImportError) as e:
|
|
156
|
+
self.logger.error(
|
|
157
|
+
f"[OpenTelemetrySidecar] Initialization failed: {e}", exc_info=True
|
|
158
|
+
)
|
|
159
|
+
return False
|
|
160
|
+
|
|
161
|
+
@contextmanager
|
|
162
|
+
def trace_phase(
|
|
163
|
+
self,
|
|
164
|
+
phase: str,
|
|
165
|
+
pcard_hash: str | None = None,
|
|
166
|
+
target_hash: str | None = None,
|
|
167
|
+
attributes: dict[str, Any] | None = None,
|
|
168
|
+
):
|
|
169
|
+
"""
|
|
170
|
+
Context manager for tracing a REPL phase.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
phase: One of REPLPhase.PREP, EXEC, POST, AWAIT
|
|
174
|
+
pcard_hash: Optional PCard hash for context
|
|
175
|
+
target_hash: Optional target hash for context
|
|
176
|
+
attributes: Optional additional attributes
|
|
177
|
+
|
|
178
|
+
Yields:
|
|
179
|
+
The active span (or None if not initialized)
|
|
180
|
+
"""
|
|
181
|
+
if not self._initialized or not self._tracer:
|
|
182
|
+
yield None
|
|
183
|
+
return
|
|
184
|
+
|
|
185
|
+
span_name = f"ptr.repl.{phase}"
|
|
186
|
+
span_attributes = {
|
|
187
|
+
"repl.phase": phase,
|
|
188
|
+
"ptr.pcard_hash": pcard_hash or "",
|
|
189
|
+
"ptr.target_hash": target_hash or "",
|
|
190
|
+
}
|
|
191
|
+
if attributes:
|
|
192
|
+
span_attributes.update(attributes)
|
|
193
|
+
|
|
194
|
+
start_time = datetime.now(timezone.utc)
|
|
195
|
+
|
|
196
|
+
with self._tracer.start_as_current_span(
|
|
197
|
+
span_name, kind=SpanKind.INTERNAL, attributes=span_attributes
|
|
198
|
+
) as span:
|
|
199
|
+
try:
|
|
200
|
+
yield span
|
|
201
|
+
span.set_status(Status(StatusCode.OK))
|
|
202
|
+
except (ValueError, TypeError, RuntimeError, OSError) as e:
|
|
203
|
+
span.set_status(Status(StatusCode.ERROR, str(e)))
|
|
204
|
+
span.record_exception(e)
|
|
205
|
+
self._record_error(phase)
|
|
206
|
+
raise
|
|
207
|
+
finally:
|
|
208
|
+
end_time = datetime.now(timezone.utc)
|
|
209
|
+
duration_ms = (end_time - start_time).total_seconds() * 1000
|
|
210
|
+
self._record_phase_duration(phase, duration_ms)
|
|
211
|
+
self._record_phase_count(phase)
|
|
212
|
+
|
|
213
|
+
def log_event(
|
|
214
|
+
self, phase: str, event_name: str, attributes: dict[str, Any] | None = None
|
|
215
|
+
):
|
|
216
|
+
"""
|
|
217
|
+
Log an event within a REPL phase.
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
phase: The current REPL phase
|
|
221
|
+
event_name: Name of the event
|
|
222
|
+
attributes: Optional event attributes
|
|
223
|
+
"""
|
|
224
|
+
if not self._initialized or not self._tracer:
|
|
225
|
+
self.logger.info(f"[{phase}] {event_name}: {attributes}")
|
|
226
|
+
return
|
|
227
|
+
|
|
228
|
+
current_span = trace.get_current_span()
|
|
229
|
+
if current_span:
|
|
230
|
+
current_span.add_event(event_name, attributes=attributes or {})
|
|
231
|
+
|
|
232
|
+
def _record_phase_duration(self, phase: str, duration_ms: float):
|
|
233
|
+
"""Record phase duration metric."""
|
|
234
|
+
if self._phase_duration_histogram:
|
|
235
|
+
self._phase_duration_histogram.record(
|
|
236
|
+
duration_ms, attributes={"repl.phase": phase}
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
def _record_phase_count(self, phase: str):
|
|
240
|
+
"""Record phase execution count."""
|
|
241
|
+
if self._phase_counter:
|
|
242
|
+
self._phase_counter.add(1, attributes={"repl.phase": phase})
|
|
243
|
+
|
|
244
|
+
def _record_error(self, phase: str):
|
|
245
|
+
"""Record error count."""
|
|
246
|
+
if self._error_counter:
|
|
247
|
+
self._error_counter.add(1, attributes={"repl.phase": phase})
|
|
248
|
+
|
|
249
|
+
def is_initialized(self) -> bool:
|
|
250
|
+
"""Check if sidecar is initialized."""
|
|
251
|
+
return self._initialized
|
|
252
|
+
|
|
253
|
+
def get_tracer(self) -> Tracer | None:
|
|
254
|
+
"""Get the underlying tracer instance."""
|
|
255
|
+
return self._tracer
|
|
256
|
+
|
|
257
|
+
def get_meter(self) -> Meter | None:
|
|
258
|
+
"""Get the underlying meter instance."""
|
|
259
|
+
return self._meter
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
# Convenience decorator for phase instrumentation
|
|
263
|
+
def instrument_phase(phase: str):
|
|
264
|
+
"""
|
|
265
|
+
Decorator to instrument a function as a REPL phase.
|
|
266
|
+
|
|
267
|
+
Usage:
|
|
268
|
+
@instrument_phase(REPLPhase.PREP)
|
|
269
|
+
def _prep(self, pcard_hash, target_hash):
|
|
270
|
+
...
|
|
271
|
+
"""
|
|
272
|
+
|
|
273
|
+
def decorator(func: Callable):
|
|
274
|
+
@wraps(func)
|
|
275
|
+
def wrapper(self, *args, **kwargs):
|
|
276
|
+
sidecar = OpenTelemetrySidecar.get_instance()
|
|
277
|
+
|
|
278
|
+
# Extract common attributes
|
|
279
|
+
pcard_hash = kwargs.get("pcard_hash") or (args[0] if args else None)
|
|
280
|
+
target_hash = kwargs.get("target_hash") or (
|
|
281
|
+
args[1] if len(args) > 1 else None
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
with sidecar.trace_phase(phase, pcard_hash, target_hash):
|
|
285
|
+
return func(self, *args, **kwargs)
|
|
286
|
+
|
|
287
|
+
return wrapper
|
|
288
|
+
|
|
289
|
+
return decorator
|