clue-python-sdk-core 0.0.1__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.
@@ -0,0 +1,166 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from dataclasses import dataclass
5
+ from typing import Mapping
6
+ from urllib.parse import urlsplit, urlunsplit
7
+
8
+ from .resources import CluePythonResourceConfig, build_resource_attributes, serialize_resource_attributes
9
+
10
+
11
+ @dataclass(frozen=True)
12
+ class CluePythonBootstrapConfig:
13
+ service_name: str
14
+ project_key: str
15
+ environment: str
16
+ deployment_environment: str
17
+ service_type: str
18
+ traces_endpoint: str
19
+ producer_id: str = "python-service"
20
+ api_key: str | None = None
21
+ service_version: str | None = None
22
+ service_namespace: str | None = None
23
+
24
+
25
+ def load_bootstrap_config(
26
+ environ: Mapping[str, str] | None = None,
27
+ ) -> CluePythonBootstrapConfig:
28
+ env = environ or os.environ
29
+ return CluePythonBootstrapConfig(
30
+ service_name=env.get(
31
+ "OTEL_SERVICE_NAME",
32
+ env.get("CLUE_SERVICE_NAME", "python-service"),
33
+ ),
34
+ producer_id=env.get(
35
+ "CLUE_PRODUCER_ID",
36
+ env.get("OTEL_SERVICE_NAME", env.get("CLUE_SERVICE_NAME", "python-service")),
37
+ ),
38
+ project_key=env.get("CLUE_PROJECT_KEY", ""),
39
+ environment=env.get("CLUE_ENVIRONMENT", env.get("ENVIRONMENT", "")),
40
+ deployment_environment=env.get(
41
+ "OTEL_DEPLOYMENT_ENVIRONMENT",
42
+ env.get("DEPLOYMENT_ENVIRONMENT", env.get("ENVIRONMENT", "")),
43
+ ),
44
+ service_type=env.get("CLUE_SERVICE_TYPE", "api"),
45
+ traces_endpoint=env.get(
46
+ "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
47
+ env.get("CLUE_OTLP_TRACES_ENDPOINT", ""),
48
+ ),
49
+ api_key=env.get("CLUE_API_KEY"),
50
+ service_version=env.get("OTEL_SERVICE_VERSION", env.get("CLUE_SERVICE_VERSION")),
51
+ service_namespace=env.get(
52
+ "OTEL_SERVICE_NAMESPACE",
53
+ env.get("CLUE_SERVICE_NAMESPACE"),
54
+ ),
55
+ )
56
+
57
+
58
+ def build_otel_environment(
59
+ config: CluePythonBootstrapConfig,
60
+ ) -> dict[str, str]:
61
+ resource_attributes = build_resource_attributes(
62
+ CluePythonResourceConfig(
63
+ service_name=config.service_name,
64
+ producer_id=config.producer_id,
65
+ project_key=config.project_key,
66
+ environment=config.environment,
67
+ deployment_environment=config.deployment_environment,
68
+ service_type=config.service_type,
69
+ service_version=config.service_version,
70
+ service_namespace=config.service_namespace,
71
+ )
72
+ )
73
+ env = {
74
+ "OTEL_SERVICE_NAME": config.service_name,
75
+ "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT": config.traces_endpoint,
76
+ "OTEL_RESOURCE_ATTRIBUTES": serialize_resource_attributes(resource_attributes),
77
+ }
78
+
79
+ if config.api_key:
80
+ env["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = f"x-clue-api-key={config.api_key}"
81
+
82
+ return env
83
+
84
+
85
+ def default_traces_endpoint_from_ingest_endpoint(ingest_endpoint: str) -> str:
86
+ trimmed = ingest_endpoint.strip()
87
+ if not trimmed:
88
+ return ""
89
+
90
+ parsed = urlsplit(trimmed)
91
+ if not parsed.scheme or not parsed.netloc:
92
+ return ""
93
+
94
+ path = parsed.path.rstrip("/")
95
+ if path.endswith("/ingest/backend"):
96
+ traces_path = path
97
+ elif path.endswith("/api/v1") or path.endswith("/v1"):
98
+ traces_path = f"{path}/ingest/backend"
99
+ else:
100
+ traces_path = f"{path}/api/v1/ingest/backend"
101
+
102
+ return urlunsplit(
103
+ (
104
+ parsed.scheme,
105
+ parsed.netloc,
106
+ traces_path,
107
+ "",
108
+ "",
109
+ )
110
+ )
111
+
112
+
113
+ def configure_opentelemetry_environment(
114
+ config: CluePythonBootstrapConfig,
115
+ target: dict[str, str] | None = None,
116
+ ) -> dict[str, str]:
117
+ env = target if target is not None else os.environ
118
+ for key, value in build_otel_environment(config).items():
119
+ env[key] = value
120
+ return env
121
+
122
+
123
+ def initialize_opentelemetry(config: CluePythonBootstrapConfig) -> bool:
124
+ configure_opentelemetry_environment(config)
125
+ if not config.traces_endpoint.strip():
126
+ return False
127
+
128
+ try:
129
+ from opentelemetry import trace
130
+ from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
131
+ from opentelemetry.sdk.resources import Resource
132
+ from opentelemetry.sdk.trace import TracerProvider
133
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
134
+ except ImportError:
135
+ return False
136
+
137
+ try:
138
+ resource_attributes = build_resource_attributes(
139
+ CluePythonResourceConfig(
140
+ service_name=config.service_name,
141
+ producer_id=config.producer_id,
142
+ project_key=config.project_key,
143
+ environment=config.environment,
144
+ deployment_environment=config.deployment_environment,
145
+ service_type=config.service_type,
146
+ service_version=config.service_version,
147
+ service_namespace=config.service_namespace,
148
+ )
149
+ )
150
+ headers = {"x-clue-api-key": config.api_key} if config.api_key else None
151
+ provider = TracerProvider(
152
+ resource=Resource.create(resource_attributes),
153
+ )
154
+ provider.add_span_processor(
155
+ BatchSpanProcessor(
156
+ OTLPSpanExporter(
157
+ endpoint=config.traces_endpoint,
158
+ headers=headers,
159
+ )
160
+ )
161
+ )
162
+ trace.set_tracer_provider(provider)
163
+ except Exception:
164
+ return False
165
+
166
+ return True