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

chore(tracer): make ddtrace.Tracer a singleton #11823

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
18 changes: 18 additions & 0 deletions ddtrace/_trace/tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,24 @@ class Tracer(object):
"""

SHUTDOWN_TIMEOUT = 5
_instance = None

def ___new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(Tracer, cls).__new__(cls)
else:
# ddtrace library does not support context propagation for multiple tracers.
# All instances of ddtrace ContextProviders share the same ContextVars. This means that
# if you create multiple instances of Tracer, spans will be shared between them creating a
# broken experience.
# TODO(mabdinur): Convert this warning to an ValueError in 3.0.0
deprecate(
"Creating multiple Tracer instances is deprecated",
"Use ddtrace.tracer to access the global tracer instance",
category=DDTraceDeprecationWarning,
removal_version="3.0.0",
)
return cls._instance

def __init__(
self,
Expand Down
8 changes: 3 additions & 5 deletions ddtrace/contrib/grpc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,12 @@
``Pin`` API::

import grpc
from ddtrace import Pin, patch, Tracer
from ddtrace import Pin, patch

patch(grpc=True)
custom_tracer = Tracer()

# override the pin on the client
Pin.override(grpc.Channel, service='mygrpc', tracer=custom_tracer)
Pin.override(grpc.Channel, service='mygrpc')
with grpc.insecure_channel('localhost:50051') as channel:
# create stubs and send requests
pass
Expand All @@ -64,10 +63,9 @@
from ddtrace import Pin, patch, Tracer

patch(grpc=True)
custom_tracer = Tracer()

# override the pin on the server
Pin.override(grpc.Server, service='mygrpc', tracer=custom_tracer)
Pin.override(grpc.Server, service='mygrpc')
server = grpc.server(logging_pool.pool(2))
server.add_insecure_port('localhost:50051')
add_MyServicer_to_server(MyServicer(), server)
Expand Down
3 changes: 1 addition & 2 deletions ddtrace/contrib/vertica/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,10 @@

import vertica_python

custom_tracer = Tracer()
conn = vertica_python.connect(**YOUR_VERTICA_CONFIG)

# override the service and tracer to be used
Pin.override(conn, service='myverticaservice', tracer=custom_tracer)
Pin.override(conn, service='myverticaservice')
"""

from ddtrace.internal.utils.importlib import require_modules
Expand Down
14 changes: 11 additions & 3 deletions ddtrace/opentracer/tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from ddtrace.internal.constants import SPAN_API_OPENTRACING
from ddtrace.internal.utils.config import get_application_name
from ddtrace.settings import ConfigException
from ddtrace.vendor.debtcollector import deprecate

from ..internal.logger import get_logger
from .propagation import HTTPPropagator
Expand Down Expand Up @@ -70,8 +71,8 @@ def __init__(
If ``None`` is provided, defaults to
:class:`opentracing.scope_managers.ThreadLocalScopeManager`.
:param dd_tracer: (optional) the Datadog tracer for this tracer to use. This
should only be passed if a custom Datadog tracer is being used. Defaults
to the global ``ddtrace.tracer`` tracer.
parameter is deprecated and will be removed in v3.0.0. The
to the global tracer (``ddtrace.tracer``) should always be used.
"""
# Merge the given config with the default into a new dict
self._config = DEFAULT_CONFIG.copy()
Expand Down Expand Up @@ -99,7 +100,14 @@ def __init__(
self._scope_manager = scope_manager or ThreadLocalScopeManager()
dd_context_provider = get_context_provider_for_scope_manager(self._scope_manager)

self._dd_tracer = dd_tracer or ddtrace.tracer or DatadogTracer()
if dd_tracer is not None:
deprecate(
"The ``dd_tracer`` parameter is deprecated",
message="The global tracer (``ddtrace.tracer``) will be used instead.",
removal_version="3.0.0",
)

self._dd_tracer = dd_tracer or ddtrace.tracer
self._dd_tracer.set_tags(self._config.get(keys.GLOBAL_TAGS)) # type: ignore[arg-type]
self._dd_tracer.configure(
enabled=self._config.get(keys.ENABLED),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
deprecations:
- |
tracing: Deprecates the use of multiple tracer instances in the same process. The global tracer (``ddtrace.tracer``) `should be used instead.
5 changes: 5 additions & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,11 @@ class DummyTracer(Tracer):
DummyTracer is a tracer which uses the DummyWriter by default
"""

def ___new__(cls, *args, **kwargs):
# Override the __new__ method to ensure we can have multiple instances of the DummyTracer
cls._instance = super(object, cls).__new__(cls)
return cls._instance

def __init__(self, *args, **kwargs):
super(DummyTracer, self).__init__()
self._trace_flush_disabled_via_env = not asbool(os.getenv("_DD_TEST_TRACE_FLUSH_ENABLED", True))
Expand Down
Loading