Skip to content

Commit

Permalink
chore(telemetry): improves typing for telemetry metric namespaces (#1…
Browse files Browse the repository at this point in the history
…1564)

Follow up to: #11565 

Prevents telemetry metrics from being queued with an invalid namespace

## Checklist
- [ ] PR author has checked that all the criteria below are met
- The PR description includes an overview of the change
- The PR description articulates the motivation for the change
- The change includes tests OR the PR description describes a testing
strategy
- The PR description notes risks associated with the change, if any
- Newly-added code is easy to change
- The change follows the [library release note
guidelines](https://ddtrace.readthedocs.io/en/stable/releasenotes.html)
- The change includes or references documentation updates if necessary
- Backport labels are set (if
[applicable](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting))

## Reviewer Checklist
- [ ] Reviewer has checked that all the criteria below are met 
- Title is accurate
- All changes are related to the pull request's stated goal
- Avoids breaking
[API](https://ddtrace.readthedocs.io/en/stable/versioning.html#interfaces)
changes
- Testing strategy adequately addresses listed risks
- Newly-added code is easy to change
- Release note makes sense to a user of the library
- If necessary, author has acknowledged and discussed the performance
implications of this PR as reported in the benchmarks PR comment
- Backport labels are set in a manner that is consistent with the
[release branch maintenance
policy](https://ddtrace.readthedocs.io/en/latest/contributing.html#backporting)
  • Loading branch information
mabdinur authored Jan 15, 2025
1 parent cdfc0a6 commit 434d565
Show file tree
Hide file tree
Showing 26 changed files with 216 additions and 156 deletions.
6 changes: 5 additions & 1 deletion ddtrace/_monkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from wrapt.importer import when_imported

from ddtrace.appsec import load_common_appsec_modules
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE

from .appsec._iast._utils import _is_iast_enabled
from .internal import telemetry
Expand Down Expand Up @@ -186,7 +187,10 @@ def on_import(hook):
)
telemetry.telemetry_writer.add_integration(module, False, PATCH_MODULES.get(module) is True, str(e))
telemetry.telemetry_writer.add_count_metric(
"tracers", "integration_errors", 1, (("integration_name", module), ("error_type", type(e).__name__))
TELEMETRY_NAMESPACE.TRACERS,
"integration_errors",
1,
(("integration_name", module), ("error_type", type(e).__name__)),
)
else:
if hasattr(imported_module, "get_versions"):
Expand Down
4 changes: 2 additions & 2 deletions ddtrace/_trace/processor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from ddtrace.internal.sampling import is_single_span_sampled
from ddtrace.internal.service import ServiceStatusError
from ddtrace.internal.telemetry.constants import TELEMETRY_LOG_LEVEL
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE_TAG_TRACER
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE
from ddtrace.internal.writer import TraceWriter


Expand Down Expand Up @@ -392,6 +392,6 @@ def _queue_span_count_metrics(self, metric_name: str, tag_name: str, min_count:
if config._telemetry_enabled and sum(self._span_metrics[metric_name].values()) >= min_count:
for tag_value, count in self._span_metrics[metric_name].items():
telemetry.telemetry_writer.add_count_metric(
TELEMETRY_NAMESPACE_TAG_TRACER, metric_name, count, tags=((tag_name, tag_value),)
TELEMETRY_NAMESPACE.TRACERS, metric_name, count, tags=((tag_name, tag_value),)
)
self._span_metrics[metric_name] = defaultdict(int)
5 changes: 3 additions & 2 deletions ddtrace/_trace/telemetry.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
from typing import Tuple

from ddtrace.internal.telemetry import telemetry_writer
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE


def record_span_pointer_calculation(context: str, span_pointer_count: int) -> None:
telemetry_writer.add_count_metric(
namespace="tracers",
namespace=TELEMETRY_NAMESPACE.TRACERS,
name="span_pointer_calculation",
value=1,
tags=(("context", context), ("count", _span_pointer_count_to_tag(span_pointer_count))),
Expand Down Expand Up @@ -45,7 +46,7 @@ def record_span_pointer_calculation_issue(
tags += additional_tags

telemetry_writer.add_count_metric(
namespace="tracers",
namespace=TELEMETRY_NAMESPACE.TRACERS,
name="span_pointer_calculation.issue",
value=1,
tags=tags,
Expand Down
16 changes: 7 additions & 9 deletions ddtrace/appsec/_iast/_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from ddtrace.internal import telemetry
from ddtrace.internal.logger import get_logger
from ddtrace.internal.telemetry.constants import TELEMETRY_LOG_LEVEL
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE_TAG_IAST
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE
from ddtrace.settings.asm import config as asm_config


Expand Down Expand Up @@ -73,19 +73,19 @@ def _set_metric_iast_instrumented_source(source_type):
from ._taint_tracking import origin_to_str

telemetry.telemetry_writer.add_count_metric(
TELEMETRY_NAMESPACE_TAG_IAST, "instrumented.source", 1, (("source_type", origin_to_str(source_type)),)
TELEMETRY_NAMESPACE.IAST, "instrumented.source", 1, (("source_type", origin_to_str(source_type)),)
)


@metric_verbosity(TELEMETRY_MANDATORY_VERBOSITY)
def _set_metric_iast_instrumented_propagation():
telemetry.telemetry_writer.add_count_metric(TELEMETRY_NAMESPACE_TAG_IAST, "instrumented.propagation", 1)
telemetry.telemetry_writer.add_count_metric(TELEMETRY_NAMESPACE.IAST, "instrumented.propagation", 1)


@metric_verbosity(TELEMETRY_MANDATORY_VERBOSITY)
def _set_metric_iast_instrumented_sink(vulnerability_type, counter=1):
telemetry.telemetry_writer.add_count_metric(
TELEMETRY_NAMESPACE_TAG_IAST, "instrumented.sink", counter, (("vulnerability_type", vulnerability_type),)
TELEMETRY_NAMESPACE.IAST, "instrumented.sink", counter, (("vulnerability_type", vulnerability_type),)
)


Expand All @@ -94,14 +94,14 @@ def _set_metric_iast_executed_source(source_type):
from ._taint_tracking import origin_to_str

telemetry.telemetry_writer.add_count_metric(
TELEMETRY_NAMESPACE_TAG_IAST, "executed.source", 1, (("source_type", origin_to_str(source_type)),)
TELEMETRY_NAMESPACE.IAST, "executed.source", 1, (("source_type", origin_to_str(source_type)),)
)


@metric_verbosity(TELEMETRY_INFORMATION_VERBOSITY)
def _set_metric_iast_executed_sink(vulnerability_type):
telemetry.telemetry_writer.add_count_metric(
TELEMETRY_NAMESPACE_TAG_IAST, "executed.sink", 1, (("vulnerability_type", vulnerability_type),)
TELEMETRY_NAMESPACE.IAST, "executed.sink", 1, (("vulnerability_type", vulnerability_type),)
)


Expand All @@ -115,9 +115,7 @@ def _request_tainted():
def _set_metric_iast_request_tainted():
total_objects_tainted = _request_tainted()
if total_objects_tainted > 0:
telemetry.telemetry_writer.add_count_metric(
TELEMETRY_NAMESPACE_TAG_IAST, "request.tainted", total_objects_tainted
)
telemetry.telemetry_writer.add_count_metric(TELEMETRY_NAMESPACE.IAST, "request.tainted", total_objects_tainted)


def _set_span_tag_iast_request_tainted(span):
Expand Down
10 changes: 5 additions & 5 deletions ddtrace/appsec/_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from ddtrace.internal import telemetry
from ddtrace.internal.logger import get_logger
from ddtrace.internal.telemetry.constants import TELEMETRY_LOG_LEVEL
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE_TAG_APPSEC
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE


log = get_logger(__name__)
Expand Down Expand Up @@ -36,7 +36,7 @@ def _set_waf_updates_metric(info):
tags = (("waf_version", DDWAF_VERSION),)

telemetry.telemetry_writer.add_count_metric(
TELEMETRY_NAMESPACE_TAG_APPSEC,
TELEMETRY_NAMESPACE.APPSEC,
"waf.updates",
1.0,
tags=tags,
Expand All @@ -56,7 +56,7 @@ def _set_waf_init_metric(info):
tags = (("waf_version", DDWAF_VERSION),)

telemetry.telemetry_writer.add_count_metric(
TELEMETRY_NAMESPACE_TAG_APPSEC,
TELEMETRY_NAMESPACE.APPSEC,
"waf.init",
1.0,
tags=tags,
Expand Down Expand Up @@ -90,7 +90,7 @@ def _set_waf_request_metrics(*args):
)

telemetry.telemetry_writer.add_count_metric(
TELEMETRY_NAMESPACE_TAG_APPSEC,
TELEMETRY_NAMESPACE.APPSEC,
"waf.requests",
1.0,
tags=tags_request,
Expand All @@ -101,7 +101,7 @@ def _set_waf_request_metrics(*args):
for rule_type, value in rasp[t].items():
if value:
telemetry.telemetry_writer.add_count_metric(
TELEMETRY_NAMESPACE_TAG_APPSEC,
TELEMETRY_NAMESPACE.APPSEC,
n,
float(value),
tags=_TYPES_AND_TAGS.get(rule_type, ()) + (("waf_version", DDWAF_VERSION),),
Expand Down
12 changes: 7 additions & 5 deletions ddtrace/internal/ci_visibility/telemetry/api_request.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import dataclasses
from typing import Optional

from ddtrace.internal.ci_visibility.telemetry.constants import CIVISIBILITY_TELEMETRY_NAMESPACE as _NAMESPACE
from ddtrace.internal.ci_visibility.telemetry.constants import ERROR_TYPES
from ddtrace.internal.logger import get_logger
from ddtrace.internal.telemetry import telemetry_writer
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE


log = get_logger(__name__)
Expand Down Expand Up @@ -32,18 +32,20 @@ def record_api_request(
error,
)

telemetry_writer.add_count_metric(_NAMESPACE, f"{metric_names.count}", 1)
telemetry_writer.add_distribution_metric(_NAMESPACE, f"{metric_names.duration}", duration)
telemetry_writer.add_count_metric(TELEMETRY_NAMESPACE.CIVISIBILITY, f"{metric_names.count}", 1)
telemetry_writer.add_distribution_metric(TELEMETRY_NAMESPACE.CIVISIBILITY, f"{metric_names.duration}", duration)
if response_bytes is not None:
if metric_names.response_bytes is not None:
# We don't always want to record response bytes (for settings requests), so assume that no metric name
# means we don't want to record it.
telemetry_writer.add_distribution_metric(_NAMESPACE, f"{metric_names.response_bytes}", response_bytes)
telemetry_writer.add_distribution_metric(
TELEMETRY_NAMESPACE.CIVISIBILITY, f"{metric_names.response_bytes}", response_bytes
)

if error is not None:
record_api_request_error(metric_names.error, error)


def record_api_request_error(error_metric_name: str, error: ERROR_TYPES):
log.debug("Recording early flake detection request error telemetry: %s", error)
telemetry_writer.add_count_metric(_NAMESPACE, error_metric_name, 1, (("error_type", error),))
telemetry_writer.add_count_metric(TELEMETRY_NAMESPACE.CIVISIBILITY, error_metric_name, 1, (("error_type", error),))
3 changes: 0 additions & 3 deletions ddtrace/internal/ci_visibility/telemetry/constants.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from enum import Enum


CIVISIBILITY_TELEMETRY_NAMESPACE = "civisibility"


class ERROR_TYPES(str, Enum):
TIMEOUT = "timeout"
NETWORK = "network"
Expand Down
12 changes: 6 additions & 6 deletions ddtrace/internal/ci_visibility/telemetry/coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
from typing import Optional
from typing import Tuple

from ddtrace.internal.ci_visibility.telemetry.constants import CIVISIBILITY_TELEMETRY_NAMESPACE as _NAMESPACE
from ddtrace.internal.ci_visibility.telemetry.constants import TEST_FRAMEWORKS
from ddtrace.internal.logger import get_logger
from ddtrace.internal.telemetry import telemetry_writer
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE


log = get_logger(__name__)
Expand All @@ -30,27 +30,27 @@ def record_code_coverage_started(coverage_library: COVERAGE_LIBRARY, test_framew
_tags: List[Tuple[str, str]] = [("library", coverage_library)]
if test_framework is not None:
_tags.append(("test_framework", test_framework))
telemetry_writer.add_count_metric(_NAMESPACE, COVERAGE_TELEMETRY.STARTED, 1, tuple(_tags))
telemetry_writer.add_count_metric(TELEMETRY_NAMESPACE.CIVISIBILITY, COVERAGE_TELEMETRY.STARTED, 1, tuple(_tags))


def record_code_coverage_finished(coverage_library: COVERAGE_LIBRARY, test_framework: Optional[TEST_FRAMEWORKS] = None):
log.debug("Recording code coverage finished telemetry: %s, %s", test_framework, coverage_library)
_tags: List[Tuple[str, str]] = [("library", coverage_library)]
if test_framework is not None:
_tags.append(("test_framework", test_framework))
telemetry_writer.add_count_metric(_NAMESPACE, COVERAGE_TELEMETRY.FINISHED, 1, tuple(_tags))
telemetry_writer.add_count_metric(TELEMETRY_NAMESPACE.CIVISIBILITY, COVERAGE_TELEMETRY.FINISHED, 1, tuple(_tags))


def record_code_coverage_empty():
log.debug("Recording code coverage empty telemetry")
telemetry_writer.add_count_metric(_NAMESPACE, COVERAGE_TELEMETRY.IS_EMPTY, 1)
telemetry_writer.add_count_metric(TELEMETRY_NAMESPACE.CIVISIBILITY, COVERAGE_TELEMETRY.IS_EMPTY, 1)


def record_code_coverage_files(count_files: int):
log.debug("Recording code coverage files telemetry: %s", count_files)
telemetry_writer.add_distribution_metric(_NAMESPACE, COVERAGE_TELEMETRY.FILES, count_files)
telemetry_writer.add_distribution_metric(TELEMETRY_NAMESPACE.CIVISIBILITY, COVERAGE_TELEMETRY.FILES, count_files)


def record_code_coverage_error():
log.debug("Recording code coverage error telemetry")
telemetry_writer.add_count_metric(_NAMESPACE, COVERAGE_TELEMETRY.ERRORS, 1)
telemetry_writer.add_count_metric(TELEMETRY_NAMESPACE.CIVISIBILITY, COVERAGE_TELEMETRY.ERRORS, 1)
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from enum import Enum

from ddtrace.internal.ci_visibility.telemetry.constants import CIVISIBILITY_TELEMETRY_NAMESPACE as _NAMESPACE
from ddtrace.internal.logger import get_logger
from ddtrace.internal.telemetry import telemetry_writer
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE


log = get_logger(__name__)
Expand All @@ -19,5 +19,7 @@ class EARLY_FLAKE_DETECTION_TELEMETRY(str, Enum):
def record_early_flake_detection_tests_count(early_flake_detection_count: int):
log.debug("Recording early flake detection tests count telemetry: %s", early_flake_detection_count)
telemetry_writer.add_distribution_metric(
_NAMESPACE, EARLY_FLAKE_DETECTION_TELEMETRY.RESPONSE_TESTS.value, early_flake_detection_count
TELEMETRY_NAMESPACE.CIVISIBILITY,
EARLY_FLAKE_DETECTION_TELEMETRY.RESPONSE_TESTS.value,
early_flake_detection_count,
)
20 changes: 14 additions & 6 deletions ddtrace/internal/ci_visibility/telemetry/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
from typing import Optional
from typing import Tuple

from ddtrace.internal.ci_visibility.telemetry.constants import CIVISIBILITY_TELEMETRY_NAMESPACE as _NAMESPACE
from ddtrace.internal.ci_visibility.telemetry.constants import EVENT_TYPES
from ddtrace.internal.ci_visibility.telemetry.constants import TEST_FRAMEWORKS
from ddtrace.internal.logger import get_logger
from ddtrace.internal.telemetry import telemetry_writer
from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE


log = get_logger(__name__)
Expand Down Expand Up @@ -67,7 +67,7 @@ def _record_event(
if early_flake_detection_abort_reason and event == EVENTS_TELEMETRY.FINISHED and event_type == EVENT_TYPES.SESSION:
_tags.append(("early_flake_detection_abort_reason", early_flake_detection_abort_reason))

telemetry_writer.add_count_metric(_NAMESPACE, event.value, 1, tuple(_tags))
telemetry_writer.add_count_metric(TELEMETRY_NAMESPACE.CIVISIBILITY, event.value, 1, tuple(_tags))


def record_event_created(
Expand Down Expand Up @@ -117,11 +117,19 @@ def record_event_finished(
def record_manual_api_event_created(event_type: EVENT_TYPES):
# Note: _created suffix is added in cases we were to change the metric name in the future.
# The current metric applies to event creation even though it does not specify it
telemetry_writer.add_count_metric(_NAMESPACE, EVENTS_TELEMETRY.MANUAL_API_EVENT, 1, (("event_type", event_type),))
telemetry_writer.add_count_metric(
TELEMETRY_NAMESPACE.CIVISIBILITY,
EVENTS_TELEMETRY.MANUAL_API_EVENT,
1,
(("event_type", event_type),)
)


def record_events_enqueued_for_serialization(events_count: int):
telemetry_writer.add_count_metric(_NAMESPACE, EVENTS_TELEMETRY.ENQUEUED_FOR_SERIALIZATION, events_count)
telemetry_writer.add_count_metric(
TELEMETRY_NAMESPACE.CIVISIBILITY,
EVENTS_TELEMETRY.ENQUEUED_FOR_SERIALIZATION,
events_count)


def record_event_created_test(
Expand All @@ -139,7 +147,7 @@ def record_event_created_test(
if is_benchmark:
tags.append(("is_benchmark", "true"))

telemetry_writer.add_count_metric(_NAMESPACE, EVENTS_TELEMETRY.FINISHED, 1, tuple(tags))
telemetry_writer.add_count_metric(TELEMETRY_NAMESPACE.CIVISIBILITY, EVENTS_TELEMETRY.FINISHED, 1, tuple(tags))


def record_event_finished_test(
Expand Down Expand Up @@ -190,4 +198,4 @@ def record_event_finished_test(
if is_quarantined:
tags.append(("is_quarantined", "true"))

telemetry_writer.add_count_metric(_NAMESPACE, EVENTS_TELEMETRY.FINISHED, 1, tuple(tags))
telemetry_writer.add_count_metric(TELEMETRY_NAMESPACE.CIVISIBILITY, EVENTS_TELEMETRY.FINISHED, 1, tuple(tags))
Loading

0 comments on commit 434d565

Please sign in to comment.