Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 6 additions & 2 deletions loq.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ max_lines = 750
# Source files that still need exceptions above 750
[[rules]]
path = "src/docket/worker.py"
max_lines = 1125
max_lines = 1120

[[rules]]
path = "src/docket/cli.py"
max_lines = 945

[[rules]]
path = "src/docket/execution.py"
max_lines = 903
max_lines = 910

[[rules]]
path = "src/docket/docket.py"
Expand All @@ -27,3 +27,7 @@ max_lines = 866
[[rules]]
path = "src/docket/strikelist.py"
max_lines = 616

[[rules]]
path = "src/docket/_redis.py"
max_lines = 544
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ dependencies = [
"exceptiongroup>=1.2.0; python_version < '3.11'",
"taskgroup>=0.2.2; python_version < '3.11'",
"fakeredis[lua]>=2.32.1",
"opentelemetry-api>=1.33.0",
"prometheus-client>=0.21.1",
"py-key-value-aio[memory,redis]>=0.3.0",
"python-json-logger>=2.0.7",
Expand All @@ -39,7 +38,11 @@ dependencies = [
]

[project.optional-dependencies]
telemetry = [
"opentelemetry-api>=1.33.0",
]
metrics = [
"pydocket[telemetry]",
"opentelemetry-sdk>=1.33.0",
]

Expand Down
140 changes: 140 additions & 0 deletions src/docket/_otel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
"""Unified OpenTelemetry interface with fallback to stubs.

This module provides a single import point for OpenTelemetry functionality.
When OpenTelemetry is installed, it uses the real implementation.
When not installed, it falls back to noop stubs.

Usage:
from docket._otel import trace, metrics, get_tracer, get_meter, OTEL_AVAILABLE
"""

from typing import Any

# Try importing OpenTelemetry, fall back to stubs if not available
try:
from opentelemetry import context as _otel_context
from opentelemetry import metrics as _otel_metrics
from opentelemetry import propagate as _otel_propagate
from opentelemetry import trace as _otel_trace
from opentelemetry.context import _SUPPRESS_INSTRUMENTATION_KEY
from opentelemetry.metrics import set_meter_provider
from opentelemetry.propagators.textmap import Getter, Setter
from opentelemetry.trace import Link, SpanKind, Status, StatusCode

OTEL_AVAILABLE = True

# Re-export trace functions
def get_tracer(
instrumenting_module_name: str,
instrumenting_library_version: str | None = None,
tracer_provider: Any = None,
schema_url: str | None = None,
) -> Any:
"""Get a tracer from OpenTelemetry."""
return _otel_trace.get_tracer(
instrumenting_module_name,
instrumenting_library_version,
tracer_provider,
schema_url,
)

def get_current_span(context: Any = None) -> Any:
"""Get the current span."""
return _otel_trace.get_current_span(context)

# Re-export metrics functions
def get_meter(
name: str,
version: str = "",
meter_provider: Any = None,
) -> Any:
"""Get a meter from OpenTelemetry."""
return _otel_metrics.get_meter(name, version, meter_provider)

# Re-export context functions
def context_get_current() -> Any:
"""Get the current context."""
return _otel_context.get_current()

def context_set_value(key: str, value: Any, context: Any = None) -> Any:
"""Set a value in context."""
return _otel_context.set_value(key, value, context)

def context_attach(context: Any) -> object:
"""Attach a context."""
return _otel_context.attach(context)

def context_detach(token: object) -> None:
"""Detach a context."""
_otel_context.detach(token)

# Re-export propagation functions
def propagate_inject(
carrier: Any,
context: Any = None,
setter: Any = None,
) -> None:
"""Inject trace context into a carrier."""
_otel_propagate.inject(carrier, context, setter)

def propagate_extract(
carrier: Any,
context: Any = None,
getter: Any = None,
) -> Any:
"""Extract trace context from a carrier."""
return _otel_propagate.extract(carrier, context, getter)

# Context type for type hints
Context = _otel_context.Context

except ImportError:
from ._otel_stubs import (
Link,
NoopContext,
NoopGetter as Getter,
NoopSetter as Setter,
SpanKind,
Status,
StatusCode,
_SUPPRESS_INSTRUMENTATION_KEY,
context_attach,
context_detach,
context_get_current,
context_set_value,
get_current_span,
get_meter,
get_tracer,
propagate_extract,
propagate_inject,
set_meter_provider,
)

OTEL_AVAILABLE = False

# Context type for type hints when OTel not available
Context = NoopContext # type: ignore[misc,assignment]


__all__ = [
"OTEL_AVAILABLE",
"Context",
"Getter",
"Link",
"Setter",
"SpanKind",
"Status",
"StatusCode",
"_SUPPRESS_INSTRUMENTATION_KEY",
"context_attach",
"context_detach",
"context_get_current",
"context_set_value",
"get_current_span",
"get_meter",
"get_tracer",
"propagate_extract",
"propagate_inject",
"set_meter_provider",
]

Loading