Skip to content

Commit

Permalink
fix telemetry tests
Browse files Browse the repository at this point in the history
  • Loading branch information
brettlangdon committed May 1, 2024
1 parent 9ab07ee commit 222043d
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 20 deletions.
13 changes: 9 additions & 4 deletions ddtrace/internal/runtime/runtime_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@
import attr

import ddtrace
from ddtrace import config
from ddtrace.internal import atexit
from ddtrace.internal import forksafe

from .. import periodic
from .. import telemetry
from ..dogstatsd import get_dogstatsd_client
from ..logger import get_logger
from ..telemetry.constants import TELEMETRY_RUNTIMEMETRICS_ENABLED
from .constants import DEFAULT_RUNTIME_METRICS
from .metric_collectors import GCRuntimeMetricCollector
from .metric_collectors import PSUtilRuntimeMetricCollector
Expand All @@ -24,6 +23,10 @@

log = get_logger(__name__)

if config._telemetry_enabled:
import ddtrace.internal.telemetry as telemetry
from ddtrace.internal.telemetry.constants import TELEMETRY_RUNTIMEMETRICS_ENABLED


class RuntimeCollectorsIterable(object):
def __init__(self, enabled=None):
Expand Down Expand Up @@ -108,7 +111,8 @@ def disable(cls):
cls.enabled = False

# Report status to telemetry
telemetry.telemetry_writer.add_configuration(TELEMETRY_RUNTIMEMETRICS_ENABLED, False, origin="unknown")
if config._telemetry_enabled:
telemetry.telemetry_writer.add_configuration(TELEMETRY_RUNTIMEMETRICS_ENABLED, False, origin="unknown")

@classmethod
def _restart(cls):
Expand All @@ -135,7 +139,8 @@ def enable(cls, flush_interval=None, tracer=None, dogstatsd_url=None):
cls.enabled = True

# Report status to telemetry
telemetry.telemetry_writer.add_configuration(TELEMETRY_RUNTIMEMETRICS_ENABLED, True, origin="unknown")
if config._telemetry_enabled:
telemetry.telemetry_writer.add_configuration(TELEMETRY_RUNTIMEMETRICS_ENABLED, True, origin="unknown")

def flush(self):
# type: () -> None
Expand Down
77 changes: 61 additions & 16 deletions tests/telemetry/test_telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def test_enable(test_agent_session, run_python_code_in_subprocess):


@pytest.mark.snapshot
def test_telemetry_enabled_on_first_tracer_flush(test_agent_session, ddtrace_run_python_code_in_subprocess):
def test_telemetry_enabled_on_first_tracer_flush(test_agent_session, run_python_code_in_subprocess):
"""assert telemetry events are generated after the first trace is flushed to the agent"""

# Submit a trace to the agent in a subprocess
Expand All @@ -65,7 +65,7 @@ def test_telemetry_enabled_on_first_tracer_flush(test_agent_session, ddtrace_run
span = tracer.trace("test-telemetry")
span.finish()
"""
_, stderr, status, _ = ddtrace_run_python_code_in_subprocess(code, env=get_default_telemetry_env())
_, stderr, status, _ = run_python_code_in_subprocess(code, env=get_default_telemetry_env())
assert status == 0, stderr
assert stderr == b""
# Ensure telemetry events were sent to the agent (snapshot ensures one trace was generated)
Expand All @@ -82,7 +82,7 @@ def test_telemetry_enabled_on_first_tracer_flush(test_agent_session, ddtrace_run


@flaky(1735812000)
def test_enable_fork(test_agent_session, run_python_code_in_subprocess):
def test_enable_fork(test_agent_session, ddtrace_run_python_code_in_subprocess):
"""assert app-started/app-closing events are only sent in parent process"""
code = """
import warnings
Expand All @@ -96,11 +96,6 @@ def test_enable_fork(test_agent_session, run_python_code_in_subprocess):
from ddtrace.internal.telemetry import telemetry_writer
from ddtrace.settings import _config
# We have to start before forking since fork hooks are not enabled until after enabling
_config._telemetry_dependency_collection = False
telemetry_writer.enable()
telemetry_writer._app_started_event()
if os.fork() == 0:
# Send multiple started events to confirm none get sent
telemetry_writer._app_started_event()
Expand All @@ -111,7 +106,7 @@ def test_enable_fork(test_agent_session, run_python_code_in_subprocess):
print(get_runtime_id())
"""

stdout, stderr, status, _ = run_python_code_in_subprocess(code, env=get_default_telemetry_env())
stdout, stderr, status, _ = ddtrace_run_python_code_in_subprocess(code, env=get_default_telemetry_env())
assert status == 0, stderr
assert stderr == b"", stderr

Expand Down Expand Up @@ -266,12 +261,14 @@ def process_trace(self, trace):
]["message"]


def test_app_started_error_unhandled_exception(test_agent_session, run_python_code_in_subprocess):
def test_app_started_error_unhandled_exception(test_agent_session, ddtrace_run_python_code_in_subprocess):
env = get_default_telemetry_env(
{"DD_SPAN_SAMPLING_RULES": "invalid_rules", "DD_INSTRUMENTATION_TELEMETRY_ENABLED": "true"}
)

_, stderr, status, _ = run_python_code_in_subprocess("import ddtrace", env=env)
# DEV: This can be an empty command because we are using ddtrace-run python, which loading ddtrace
# causes the unhandled exception
_, stderr, status, _ = ddtrace_run_python_code_in_subprocess("", env=env)
assert status == 1, stderr
assert b"Unable to parse DD_SPAN_SAMPLING_RULES=" in stderr

Expand Down Expand Up @@ -364,22 +361,19 @@ def test_handled_integration_error(test_agent_session, run_python_code_in_subpro
assert integration_error["tags"] == ["integration_name:sqlite3", "error_type:attributeerror"]


def test_unhandled_integration_error(test_agent_session, run_python_code_in_subprocess):
def test_unhandled_integration_error(test_agent_session, ddtrace_run_python_code_in_subprocess):
code = """
import logging
logging.basicConfig()
import ddtrace
ddtrace.patch(flask=True)
import flask
f = flask.Flask("hi")
# Call flask.wsgi_app with an incorrect number of args
f.wsgi_app()
"""

_, stderr, status, _ = run_python_code_in_subprocess(code, env=get_default_telemetry_env())
_, stderr, status, _ = ddtrace_run_python_code_in_subprocess(code, env=get_default_telemetry_env())

assert status == 1, stderr

Expand Down Expand Up @@ -465,3 +459,54 @@ def test_instrumentation_telemetry_disabled(test_agent_session, run_python_code_

assert status == 0, stderr
assert stderr == b""


def test_instrumentation_telemetry_disabled_ddtrace_run(test_agent_session, ddtrace_run_python_code_in_subprocess):
"""Ensure no telemetry events are sent when telemetry is disabled"""
initial_event_count = len(test_agent_session.get_events())

env = get_default_telemetry_env({"DD_INSTRUMENTATION_TELEMETRY_ENABLED": "false"})

code = """
from ddtrace import tracer
# Create a span to start the telemetry writer
tracer.trace("hi").finish()
# Importing ddtrace.internal.telemetry.__init__ creates the telemetry writer. This has a performance cost.
# We want to avoid this cost when telemetry is disabled.
import sys
assert "ddtrace.internal.telemetry" not in sys.modules
"""
_, stderr, status, _ = ddtrace_run_python_code_in_subprocess(code, env=env)

events = test_agent_session.get_events()
assert len(events) == initial_event_count

assert status == 0, stderr
assert stderr == b""


def test_instrumentation_telemetry_disabled_ddtrace_auto(test_agent_session, run_python_code_in_subprocess):
"""Ensure no telemetry events are sent when telemetry is disabled"""
initial_event_count = len(test_agent_session.get_events())

env = get_default_telemetry_env({"DD_INSTRUMENTATION_TELEMETRY_ENABLED": "false"})

code = """
import ddtrace.auto
from ddtrace import tracer
# Create a span to start the telemetry writer
tracer.trace("hi").finish()
# Importing ddtrace.internal.telemetry.__init__ creates the telemetry writer. This has a performance cost.
# We want to avoid this cost when telemetry is disabled.
import sys
assert "ddtrace.internal.telemetry" not in sys.modules
"""
_, stderr, status, _ = run_python_code_in_subprocess(code, env=env)

events = test_agent_session.get_events()
assert len(events) == initial_event_count

assert status == 0, stderr
assert stderr == b""

0 comments on commit 222043d

Please sign in to comment.