Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test the setup_default_tracing() #718

Merged
merged 1 commit into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 25 additions & 18 deletions jobrunner/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@

logger = logging.getLogger(__name__)

# https://github.com/open-telemetry/semantic-conventions/tree/main/docs/resource#service
resource = Resource.create(
attributes={
"service.name": "jobrunner",
"service.namespace": os.environ.get("BACKEND", "unknown"),
"service.version": config.VERSION,
}
)
provider = TracerProvider(resource=resource)
trace.set_tracer_provider(provider)


def add_exporter(exporter, processor=BatchSpanProcessor):

def get_provider():
# https://github.com/open-telemetry/semantic-conventions/tree/main/docs/resource#service
resource = Resource.create(
attributes={
"service.name": os.environ.get("OTEL_SERVICE_NAME", "jobrunner"),
"service.namespace": os.environ.get("BACKEND", "unknown"),
"service.version": config.VERSION,
}
)
return TracerProvider(resource=resource)


def add_exporter(provider, exporter, processor=BatchSpanProcessor):
"""Utility method to add an exporter.

We use the BatchSpanProcessor by default, which is the default for
Expand All @@ -43,18 +44,24 @@ def add_exporter(exporter, processor=BatchSpanProcessor):
provider.add_span_processor(processor(exporter))


def setup_default_tracing():
def setup_default_tracing(set_global=True):
"""Inspect environment variables and set up exporters accordingly."""

provider = get_provider()

if "OTEL_EXPORTER_OTLP_HEADERS" in os.environ:
if "OTEL_SERVICE_NAME" not in os.environ:
os.environ["OTEL_SERVICE_NAME"] == "jobrunner"
if "OTEL_EXPORTER_OTLP_ENDPOINT" not in os.environ:
os.environ["OTEL_EXPORTER_OTLP_ENDPOINT"] = "https://api.honeycomb.io"

add_exporter(OTLPSpanExporter())
add_exporter(provider, OTLPSpanExporter())

if "OTEL_EXPORTER_CONSOLE" in os.environ:
add_exporter(ConsoleSpanExporter())
add_exporter(provider, ConsoleSpanExporter())

if set_global:
trace.set_tracer_provider(provider)

return provider


@warn_assertions
Expand Down
6 changes: 4 additions & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@
from jobrunner.lib.subprocess_utils import subprocess_run


# set up tracing
# set up test tracing
provider = tracing.get_provider()
tracing.trace.set_tracer_provider(provider)
test_exporter = InMemorySpanExporter()
tracing.add_exporter(test_exporter, processor=SimpleSpanProcessor)
tracing.add_exporter(provider, test_exporter, processor=SimpleSpanProcessor)


def pytest_configure(config):
Expand Down
55 changes: 55 additions & 0 deletions tests/test_tracing.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,68 @@
import os
import time

import opentelemetry.exporter.otlp.proto.http.trace_exporter
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import ConsoleSpanExporter

from jobrunner import config, models, tracing
from tests.conftest import get_trace
from tests.factories import job_factory, job_request_factory, job_results_factory


def test_setup_default_tracing_empty_env(monkeypatch):
env = {}
monkeypatch.setattr(os, "environ", env)
provider = tracing.setup_default_tracing(set_global=False)
assert provider._active_span_processor._span_processors == ()


def test_setup_default_tracing_console(monkeypatch):
env = {"OTEL_EXPORTER_CONSOLE": "1"}
monkeypatch.setattr(os, "environ", env)
provider = tracing.setup_default_tracing(set_global=False)

processor = provider._active_span_processor._span_processors[0]
assert isinstance(processor.span_exporter, ConsoleSpanExporter)


def test_setup_default_tracing_otlp_defaults(monkeypatch):
env = {"OTEL_EXPORTER_OTLP_HEADERS": "foo=bar"}
monkeypatch.setattr(os, "environ", env)
monkeypatch.setattr(
opentelemetry.exporter.otlp.proto.http.trace_exporter, "environ", env
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just curious - why doesn't monkeypatching os also change it here? Is it just because opentelemetry.exporter.otlp.proto.http.trace_exporter does from os import environ rather than just import os, or is there something else going on?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is exactly what is going on, sadly.

provider = tracing.setup_default_tracing(set_global=False)
assert provider.resource.attributes["service.name"] == "jobrunner"

exporter = provider._active_span_processor._span_processors[0].span_exporter
assert isinstance(exporter, OTLPSpanExporter)
assert exporter._endpoint == "https://api.honeycomb.io/v1/traces"
assert exporter._headers == {"foo": "bar"}
assert env["OTEL_EXPORTER_OTLP_ENDPOINT"] == "https://api.honeycomb.io"


def test_setup_default_tracing_otlp_with_env(monkeypatch):
env = {
"OTEL_EXPORTER_OTLP_HEADERS": "foo=bar",
"OTEL_SERVICE_NAME": "service",
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://endpoint",
}
monkeypatch.setattr(os, "environ", env)
monkeypatch.setattr(
opentelemetry.exporter.otlp.proto.http.trace_exporter, "environ", env
)
provider = tracing.setup_default_tracing(set_global=False)
assert provider.resource.attributes["service.name"] == "service"

exporter = provider._active_span_processor._span_processors[0].span_exporter

assert isinstance(exporter, OTLPSpanExporter)
assert exporter._endpoint == "https://endpoint/v1/traces"
assert exporter._headers == {"foo": "bar"}


def test_trace_attributes(db):
jr = job_request_factory(
original=dict(
Expand Down
Loading