1from __future__ import annotations
2
3import atexit
4
5from opentelemetry import metrics, trace
6from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter
7from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
8from opentelemetry.sdk.metrics import MeterProvider
9from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
10from opentelemetry.sdk.resources import Resource
11from opentelemetry.sdk.trace import TracerProvider, sampling
12from opentelemetry.sdk.trace.export import BatchSpanProcessor
13from opentelemetry.semconv.attributes import service_attributes
14
15from plain.packages import PackageConfig, register_config
16from plain.runtime import settings
17
18
19@register_config
20class Config(PackageConfig):
21 package_label = "plaincloud"
22
23 def ready(self) -> None:
24 if not settings.CLOUD_EXPORT_ENABLED or not settings.CLOUD_EXPORT_TOKEN:
25 return
26
27 resource = Resource.create(
28 {
29 service_attributes.SERVICE_NAME: settings.NAME,
30 service_attributes.SERVICE_VERSION: settings.VERSION,
31 }
32 )
33
34 export_url = str(settings.CLOUD_EXPORT_URL).rstrip("/")
35 headers = {"Authorization": f"Bearer {settings.CLOUD_EXPORT_TOKEN}"}
36
37 # Traces
38 current_provider = trace.get_tracer_provider()
39 if current_provider and not isinstance(
40 current_provider, trace.ProxyTracerProvider
41 ):
42 raise RuntimeError(
43 "A tracer provider already exists."
44 " plain.cloud must be listed before plain.observer in INSTALLED_PACKAGES."
45 )
46
47 span_exporter = OTLPSpanExporter(
48 endpoint=f"{export_url}/v1/traces",
49 headers=headers,
50 )
51 sampler = sampling.TraceIdRatioBased(settings.CLOUD_TRACE_SAMPLE_RATE)
52 tracer_provider = TracerProvider(sampler=sampler, resource=resource)
53 tracer_provider.add_span_processor(BatchSpanProcessor(span_exporter))
54 trace.set_tracer_provider(tracer_provider)
55
56 # Metrics
57 metric_exporter = OTLPMetricExporter(
58 endpoint=f"{export_url}/v1/metrics",
59 headers=headers,
60 )
61 reader = PeriodicExportingMetricReader(metric_exporter)
62 meter_provider = MeterProvider(metric_readers=[reader], resource=resource)
63 metrics.set_meter_provider(meter_provider)
64
65 atexit.register(tracer_provider.shutdown)
66 atexit.register(meter_provider.shutdown)