diff --git a/README.md b/README.md index df90d449..03ed4b39 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ when the Grafana agent is used to collect spans using HTTP. ```python import ddtrace -from troncos.tracing import configure_tracer +from troncos.tracing import configure_tracer, Exporter, ExporterType # Configure tracer as described in the ddtrace docs. ddtrace.config.django["service_name"] = 'SERVICE_NAME' @@ -87,7 +87,10 @@ TRACE_PORT = "4318" configure_tracer( enabled=False, # Set to True when TRACE_HOST is configured. service_name='SERVICE_NAME', - endpoint=f"http://{TRACE_HOST}:{TRACE_PORT}/v1/traces", + exporter=Exporter( + endpoint=f"http://{TRACE_HOST}:{TRACE_PORT}/v1/traces", + exporter_type=ExporterType.HTTP, + ), resource_attributes={ "app": "app", "component": "component", @@ -140,7 +143,8 @@ troncos = {version="?", extras = ["grpc"]} ``` ```python -from troncos.tracing import configure_tracer, Exporter +from troncos.tracing import configure_tracer, Exporter, ExporterType + TRACE_HOST = "127.0.0.1" # Usually obtained from env variables. TRACE_PORT = "4317" @@ -148,8 +152,10 @@ TRACE_PORT = "4317" configure_tracer( enabled=False, # Set to True when TRACE_HOST is configured. service_name='SERVICE_NAME', - endpoint=f"http://{TRACE_HOST}:{TRACE_PORT}", - exporter=Exporter.GRPC + exporter=Exporter( + endpoint=f"http://{TRACE_HOST}:{TRACE_PORT}", + exporter_type=ExporterType.GRPC, + ), ) ``` @@ -164,8 +170,11 @@ TRACE_PORT = "4317" configure_tracer( enabled=False, # Set to True when TRACE_HOST is configured. service_name='SERVICE_NAME', - endpoint=f"http://{TRACE_HOST}:{TRACE_PORT}", - exporter=Exporter(ExporterType.GRPC, headers={"my", "header"}), + exporter=Exporter( + endpoint=f"http://{TRACE_HOST}:{TRACE_PORT}", + exporter_type=ExporterType.GRPC, + headers={"my", "header"}, + ), ) ``` diff --git a/tests/tracing/test_writer.py b/tests/tracing/test_writer.py index 395c685a..b73e604d 100644 --- a/tests/tracing/test_writer.py +++ b/tests/tracing/test_writer.py @@ -4,7 +4,7 @@ from ddtrace import Tracer from pytest_httpserver import HTTPServer -from troncos.tracing._enums import Exporter, ExporterType +from troncos.tracing._exporter import Exporter, ExporterType from troncos.tracing._writer import OTELWriter @@ -20,9 +20,11 @@ def tracer_test( tracer.configure( writer=OTELWriter( service_name=service_name, + exporter=Exporter( + endpoint=httpserver.url_for("/v1/trace"), + exporter_type=ExporterType.HTTP, + ), resource_attributes=resource_attributes, - endpoint=httpserver.url_for("/v1/trace"), - exporter=Exporter.HTTP, ) ) @@ -82,11 +84,12 @@ def test_headers(httpserver: HTTPServer) -> None: tracer.configure( writer=OTELWriter( service_name="test_headers", - resource_attributes={}, - endpoint=httpserver.url_for("/v1/trace"), exporter=Exporter( - exporter_type=ExporterType.HTTP, headers={"test-header": "works"} + exporter_type=ExporterType.HTTP, + endpoint=httpserver.url_for("/v1/trace"), + headers={"test-header": "works"}, ), + resource_attributes={}, ) ) diff --git a/troncos/tracing/__init__.py b/troncos/tracing/__init__.py index 45712626..9e2b2372 100644 --- a/troncos/tracing/__init__.py +++ b/troncos/tracing/__init__.py @@ -1,29 +1,33 @@ +import os from typing import Any import ddtrace -from ._enums import Exporter, ExporterType +from ._exporter import Exporter, ExporterType from ._writer import OTELWriter __all__ = ["Exporter", "ExporterType"] +_env_host = os.environ.get("OTEL_TRACE_HOST", "localhost") +_env_port = os.environ.get("OTEL_TRACE_PORT", "4318") + def configure_tracer( *, enabled: bool, - endpoint: str, service_name: str, + exporter: Exporter = Exporter( + endpoint=f"http://{_env_host}:{_env_port}", exporter_type=ExporterType.HTTP + ), resource_attributes: dict[str, Any] | None = None, - exporter: Exporter = Exporter.HTTP, ) -> None: """Configure ddtrace to write traces to the otel tracing backend.""" # Initialize our custom writer used to handle ddtrace spans. writer = OTELWriter( service_name=service_name, - resource_attributes=resource_attributes, - endpoint=endpoint, exporter=exporter, + resource_attributes=resource_attributes, ) ddtrace.tracer.configure(writer=writer, enabled=enabled) diff --git a/troncos/tracing/_enums.py b/troncos/tracing/_enums.py deleted file mode 100644 index 468ac567..00000000 --- a/troncos/tracing/_enums.py +++ /dev/null @@ -1,21 +0,0 @@ -from enum import Enum - - -class ExporterType(Enum): - HTTP = "http" - GRPC = "grpc" - - -class Exporter: - HTTP: "Exporter" = None # type: ignore[assignment] - GRPC: "Exporter" = None # type: ignore[assignment] - - def __init__( - self, exporter_type: ExporterType, headers: dict[str, str] | None = None - ) -> None: - self.exporter_type = exporter_type - self.headers = headers - - -Exporter.HTTP = Exporter(ExporterType.HTTP) -Exporter.GRPC = Exporter(ExporterType.GRPC) diff --git a/troncos/tracing/_exporter.py b/troncos/tracing/_exporter.py new file mode 100644 index 00000000..4366b7b5 --- /dev/null +++ b/troncos/tracing/_exporter.py @@ -0,0 +1,19 @@ +from enum import Enum + + +class ExporterType(Enum): + HTTP = "http" + GRPC = "grpc" + + +class Exporter: + def __init__( + self, + *, + endpoint: str, + exporter_type: ExporterType, + headers: dict[str, str] | None = None, + ) -> None: + self.endpoint = endpoint + self.exporter_type = exporter_type + self.headers = headers diff --git a/troncos/tracing/_otel.py b/troncos/tracing/_otel.py index 843b554b..48e1d789 100644 --- a/troncos/tracing/_otel.py +++ b/troncos/tracing/_otel.py @@ -13,7 +13,7 @@ ) from structlog import get_logger -from ._enums import Exporter, ExporterType +from ._exporter import Exporter, ExporterType try: from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import ( @@ -30,9 +30,7 @@ def _bool_from_string(s: str) -> bool: return s.lower() in ["1", "true", "yes"] -def get_otel_span_processors( - *, endpoint: str, exporter: Exporter -) -> list[SpanProcessor]: +def get_otel_span_processors(*, exporter: Exporter) -> list[SpanProcessor]: """ Build a list of span processors to use to process otel spans. """ @@ -42,7 +40,9 @@ def get_otel_span_processors( # Exporter if exporter.exporter_type == ExporterType.HTTP: - span_exporter = HTTPSpanExporter(endpoint=endpoint, headers=exporter.headers) + span_exporter = HTTPSpanExporter( + endpoint=exporter.endpoint, headers=exporter.headers + ) elif exporter.exporter_type == ExporterType.GRPC: if GRPCSpanExporter is None: raise RuntimeError( @@ -50,7 +50,9 @@ def get_otel_span_processors( "to use the GRPC exporter." ) - span_exporter = GRPCSpanExporter(endpoint=endpoint, headers=exporter.headers) + span_exporter = GRPCSpanExporter( + endpoint=exporter.endpoint, headers=exporter.headers + ) else: raise RuntimeError("Unsupported span exporter.") diff --git a/troncos/tracing/_writer.py b/troncos/tracing/_writer.py index 079d3458..c553a1be 100644 --- a/troncos/tracing/_writer.py +++ b/troncos/tracing/_writer.py @@ -4,7 +4,7 @@ from ddtrace.span import Span from opentelemetry.sdk.resources import Resource -from ._enums import Exporter +from ._exporter import Exporter from ._otel import get_otel_span_processors from ._span import default_ignore_attrs, translate_span @@ -13,18 +13,14 @@ class OTELWriter(TraceWriter): def __init__( self, service_name: str, - resource_attributes: dict[str, Any] | None, - endpoint: str, exporter: Exporter, + resource_attributes: dict[str, Any] | None, ) -> None: self.service_name = service_name self.resource_attributes = resource_attributes - self.endpoint = endpoint self.exporter = exporter - self.otel_span_processors = get_otel_span_processors( - endpoint=endpoint, exporter=exporter - ) + self.otel_span_processors = get_otel_span_processors(exporter=exporter) self.otel_default_resource = Resource.create( {"service.name": service_name, **(resource_attributes or {})} ) @@ -35,9 +31,8 @@ def __init__( def recreate(self) -> "OTELWriter": return self.__class__( self.service_name, + self.exporter, self.resource_attributes, - self.endpoint, - exporter=self.exporter, ) def write(self, spans: list[Span] | None = None) -> None: