Skip to content
Closed
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
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
Loading