Skip to content

Commit 297569d

Browse files
authored
Enable OpenTelemetry in debug mode (#91)
* Remove health-checks dependency * Add pyroscope * Add Pyroscope instrumentation configuration and implementation * Adding Pyroscope integration to OpenTelemetry instrument for span processing and configuration adjustments * Add service_debug option to enable console span export in OpentelemetryConfig * Add PyroscopeInstrument and simplify OpentelemetryInstrument checks * Adjust is_ready check and conditionally add OTLPSpanProcessor based on endpoint * Add span formatting function for console exporter in opentelemetry_instrument.py * Optimize Litestar bootstrapper by removing Pyroscope integration * Adjust minimal opentelemetry config and test checks * Adjust minimal_opentelemetry_config for bootstrap readiness test in test_opentelemetry.py * Simplify minimal_opentelemetry_config fixture return statement * Adjusts minimal_opentelemetry_config to include namespace and container name
1 parent f720c32 commit 297569d

File tree

4 files changed

+33
-31
lines changed

4 files changed

+33
-31
lines changed

microbootstrap/instruments/opentelemetry_instrument.py

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
from __future__ import annotations
22
import dataclasses
3+
import os
34
import typing
45

56
import pydantic
67
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
78
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor # type: ignore[attr-defined] # noqa: TC002
89
from opentelemetry.sdk import resources
10+
from opentelemetry.sdk.trace import ReadableSpan
911
from opentelemetry.sdk.trace import TracerProvider as SdkTracerProvider
10-
from opentelemetry.sdk.trace.export import BatchSpanProcessor
12+
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter, SimpleSpanProcessor
1113
from opentelemetry.trace import set_tracer_provider
1214

1315

@@ -29,6 +31,7 @@ class OpenTelemetryInstrumentor:
2931

3032

3133
class OpentelemetryConfig(BaseInstrumentConfig):
34+
service_debug: bool = True
3235
service_name: str = "micro-service"
3336
service_version: str = "1.0.0"
3437
health_checks_path: str = "/health/"
@@ -58,46 +61,46 @@ class FastStreamOpentelemetryConfig(OpentelemetryConfig):
5861
opentelemetry_middleware_cls: type[FastStreamTelemetryMiddlewareProtocol] | None = None
5962

6063

64+
def _format_span(readable_span: ReadableSpan) -> str:
65+
return typing.cast("str", readable_span.to_json(indent=None)) + os.linesep
66+
67+
6168
class BaseOpentelemetryInstrument(Instrument[OpentelemetryConfigT]):
6269
instrument_name = "Opentelemetry"
6370
ready_condition = "Provide all necessary config parameters"
6471

6572
def is_ready(self) -> bool:
66-
return all(
67-
[
68-
self.instrument_config.opentelemetry_endpoint,
69-
self.instrument_config.opentelemetry_namespace,
70-
self.instrument_config.service_name,
71-
self.instrument_config.service_version,
72-
self.instrument_config.opentelemetry_container_name,
73-
],
74-
)
73+
return bool(self.instrument_config.opentelemetry_endpoint) or self.instrument_config.service_debug
7574

7675
def teardown(self) -> None:
7776
for instrumentor_with_params in self.instrument_config.opentelemetry_instrumentors:
7877
instrumentor_with_params.instrumentor.uninstrument(**instrumentor_with_params.additional_params)
7978

8079
def bootstrap(self) -> None:
81-
resource: typing.Final = resources.Resource.create(
82-
attributes={
83-
resources.SERVICE_NAME: self.instrument_config.opentelemetry_service_name
84-
or self.instrument_config.service_name,
85-
resources.TELEMETRY_SDK_LANGUAGE: "python",
86-
resources.SERVICE_NAMESPACE: self.instrument_config.opentelemetry_namespace, # type: ignore[dict-item]
87-
resources.SERVICE_VERSION: self.instrument_config.service_version,
88-
resources.CONTAINER_NAME: self.instrument_config.opentelemetry_container_name, # type: ignore[dict-item]
89-
},
90-
)
80+
attributes = {
81+
resources.SERVICE_NAME: self.instrument_config.opentelemetry_service_name
82+
or self.instrument_config.service_name,
83+
resources.TELEMETRY_SDK_LANGUAGE: "python",
84+
resources.SERVICE_VERSION: self.instrument_config.service_version,
85+
}
86+
if self.instrument_config.opentelemetry_namespace:
87+
attributes[resources.SERVICE_NAMESPACE] = self.instrument_config.opentelemetry_namespace
88+
if self.instrument_config.opentelemetry_container_name:
89+
attributes[resources.CONTAINER_NAME] = self.instrument_config.opentelemetry_container_name
90+
resource: typing.Final = resources.Resource.create(attributes=attributes)
9191

9292
self.tracer_provider = SdkTracerProvider(resource=resource)
93-
self.tracer_provider.add_span_processor(
94-
BatchSpanProcessor(
95-
OTLPSpanExporter(
96-
endpoint=self.instrument_config.opentelemetry_endpoint,
97-
insecure=self.instrument_config.opentelemetry_insecure,
93+
if self.instrument_config.service_debug:
94+
self.tracer_provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter(formatter=_format_span)))
95+
if self.instrument_config.opentelemetry_endpoint:
96+
self.tracer_provider.add_span_processor(
97+
BatchSpanProcessor(
98+
OTLPSpanExporter(
99+
endpoint=self.instrument_config.opentelemetry_endpoint,
100+
insecure=self.instrument_config.opentelemetry_insecure,
101+
),
98102
),
99-
),
100-
)
103+
)
101104
for opentelemetry_instrumentor in self.instrument_config.opentelemetry_instrumentors:
102105
opentelemetry_instrumentor.instrumentor.instrument(
103106
tracer_provider=self.tracer_provider,

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ litestar = [
6060
"prometheus-client>=0.20",
6161
]
6262
granian = ["granian[reload]>=1"]
63-
faststream = ["faststream~=0.5", "health-checks>=1", "prometheus-client>=0.20"]
63+
faststream = ["faststream~=0.5", "prometheus-client>=0.20"]
6464

6565
[dependency-groups]
6666
dev = [

tests/conftest.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,6 @@ def minimal_health_checks_config() -> HealthChecksConfig:
7878
@pytest.fixture
7979
def minimal_opentelemetry_config() -> OpentelemetryConfig:
8080
return OpentelemetryConfig(
81-
service_name="test-micro-service",
82-
service_version="1.0.0",
8381
opentelemetry_endpoint="/my-engdpoint",
8482
opentelemetry_namespace="namespace",
8583
opentelemetry_container_name="container-name",

tests/instruments/test_opentelemetry.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ def test_opentelemetry_is_ready(
2323

2424

2525
def test_opentelemetry_bootstrap_is_not_ready(minimal_opentelemetry_config: OpentelemetryConfig) -> None:
26-
minimal_opentelemetry_config.service_name = ""
26+
minimal_opentelemetry_config.service_debug = False
27+
minimal_opentelemetry_config.opentelemetry_endpoint = None
2728
opentelemetry_instrument: typing.Final = OpentelemetryInstrument(minimal_opentelemetry_config)
2829
assert not opentelemetry_instrument.is_ready()
2930

0 commit comments

Comments
 (0)