Skip to content

Commit 0e561cd

Browse files
chore(aap): telemetry wrapper for ato sdk v1 (#13727)
Add telemetry support for the legacy ATO SDK. This will also be tested using system tests DataDog/system-tests#4806 APPSEC-58051 ## Checklist - [x] 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 - [x] 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)
1 parent 04cdf7f commit 0e561cd

File tree

2 files changed

+64
-8
lines changed

2 files changed

+64
-8
lines changed
Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,38 @@
11
"""Public API for User events"""
2+
from functools import wraps
23

4+
from ddtrace.appsec import _metrics
35
from ddtrace.appsec._trace_utils import block_request # noqa: F401
46
from ddtrace.appsec._trace_utils import block_request_if_user_blocked # noqa: F401
57
from ddtrace.appsec._trace_utils import should_block_user # noqa: F401
6-
from ddtrace.appsec._trace_utils import track_custom_event # noqa: F401
7-
from ddtrace.appsec._trace_utils import track_user_login_failure_event # noqa: F401
8-
from ddtrace.appsec._trace_utils import track_user_login_success_event # noqa: F401
9-
from ddtrace.appsec._trace_utils import track_user_signup_event # noqa: F401
8+
from ddtrace.appsec._trace_utils import track_custom_event
9+
from ddtrace.appsec._trace_utils import track_user_login_failure_event
10+
from ddtrace.appsec._trace_utils import track_user_login_success_event
11+
from ddtrace.appsec._trace_utils import track_user_signup_event
1012
import ddtrace.internal.core
1113

1214

1315
ddtrace.internal.core.on("set_user_for_asm", block_request_if_user_blocked, "block_user")
16+
17+
18+
def _telemetry_report_factory(event_name: str):
19+
"""
20+
Factory function to create a telemetry report decorator.
21+
This decorator will report the event name when the decorated function is called.
22+
"""
23+
24+
def decorator(func):
25+
@wraps(func)
26+
def wrapper(*args, **kwargs):
27+
_metrics._report_ato_sdk_usage(event_name, False)
28+
return func(*args, **kwargs)
29+
30+
return wrapper
31+
32+
return decorator
33+
34+
35+
track_custom_event = _telemetry_report_factory("custom")(track_custom_event)
36+
track_user_login_success_event = _telemetry_report_factory("login_success")(track_user_login_success_event)
37+
track_user_login_failure_event = _telemetry_report_factory("login_failure")(track_user_login_failure_event)
38+
track_user_signup_event = _telemetry_report_factory("signup")(track_user_signup_event)

tests/appsec/appsec/test_appsec_trace_utils.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import logging
2+
from unittest.mock import MagicMock
3+
from unittest.mock import patch as mock_patch
24

35
import pytest
46

@@ -14,12 +16,17 @@
1416
from ddtrace.appsec.track_user_sdk import track_user
1517
from ddtrace.contrib.internal.trace_utils import set_user
1618
from ddtrace.ext import user
19+
import ddtrace.internal.telemetry
1720
import tests.appsec.rules as rules
1821
from tests.appsec.utils import asm_context
1922
from tests.appsec.utils import is_blocked
2023
from tests.utils import TracerTestCase
2124

2225

26+
def get_telemetry_metrics(mocked):
27+
return [(args[0].value, args[1].value) + args[2:] for args, kwargs in mocked.add_metric.call_args_list]
28+
29+
2330
config_asm = {"_asm_enabled": True}
2431
config_good_rules = {"_asm_static_rule_file": rules.RULES_GOOD_PATH, "_asm_enabled": True}
2532

@@ -137,7 +144,9 @@ def test_track_user_login_event_success_auto_mode_extended(self):
137144
assert root_span.get_tag(APPSEC.AUTO_LOGIN_EVENTS_SUCCESS_MODE) == str(LOGIN_EVENTS_MODE.IDENT)
138145

139146
def test_track_user_login_event_success_with_metadata(self):
140-
with asm_context(tracer=self.tracer, span_name="test_success2", config=config_asm):
147+
with mock_patch.object(
148+
ddtrace.internal.telemetry.telemetry_writer, "_namespace", MagicMock()
149+
) as telemetry_mock, asm_context(tracer=self.tracer, span_name="test_success2", config=config_asm):
141150
track_user_login_success_event(self.tracer, "1234", metadata={"foo": "bar"})
142151
root_span = self.tracer.current_root_span()
143152
assert root_span.get_tag("appsec.events.users.login.success.track") == "true"
@@ -152,6 +161,14 @@ def test_track_user_login_event_success_with_metadata(self):
152161
assert not root_span.get_tag(user.SCOPE)
153162
assert not root_span.get_tag(user.ROLE)
154163
assert not root_span.get_tag(user.SESSION_ID)
164+
metrics = get_telemetry_metrics(telemetry_mock)
165+
assert (
166+
"count",
167+
"appsec",
168+
"sdk.event",
169+
1,
170+
(("event_type", "login_success"), ("sdk_version", "v1")),
171+
) in metrics
155172

156173
def test_track_user_login_event_failure_user_exists(self):
157174
with asm_context(tracer=self.tracer, span_name="test_failure", config=config_asm):
@@ -192,7 +209,9 @@ def test_track_user_login_event_failure_user_exists(self):
192209
assert not root_span.get_tag(user.SESSION_ID)
193210

194211
def test_track_user_login_event_failure_user_doesnt_exists(self):
195-
with self.trace("test_failure"):
212+
with mock_patch.object(
213+
ddtrace.internal.telemetry.telemetry_writer, "_namespace", MagicMock()
214+
) as telemetry_mock, self.trace("test_failure"):
196215
track_user_login_failure_event(
197216
self.tracer,
198217
"john",
@@ -202,22 +221,34 @@ def test_track_user_login_event_failure_user_doesnt_exists(self):
202221
root_span = self.tracer.current_root_span()
203222
failure_prefix = "%s.failure" % APPSEC.USER_LOGIN_EVENT_PREFIX_PUBLIC
204223
assert root_span.get_tag("%s.%s" % (failure_prefix, user.EXISTS)) == "false"
224+
metrics = get_telemetry_metrics(telemetry_mock)
225+
assert metrics == [
226+
("count", "appsec", "sdk.event", 1, (("event_type", "login_failure"), ("sdk_version", "v1")))
227+
]
205228

206229
def test_track_user_signup_event_exists(self):
207-
with self.trace("test_signup_exists"):
230+
with mock_patch.object(
231+
ddtrace.internal.telemetry.telemetry_writer, "_namespace", MagicMock()
232+
) as telemetry_mock, self.trace("test_signup_exists"):
208233
track_user_signup_event(self.tracer, "john", True)
209234
root_span = self.tracer.current_root_span()
210235
assert root_span.get_tag(APPSEC.USER_SIGNUP_EVENT) == "true"
211236
assert root_span.get_tag(user.ID) == "john"
237+
metrics = get_telemetry_metrics(telemetry_mock)
238+
assert metrics == [("count", "appsec", "sdk.event", 1, (("event_type", "signup"), ("sdk_version", "v1")))]
212239

213240
def test_custom_event(self):
214-
with self.trace("test_custom"):
241+
with mock_patch.object(
242+
ddtrace.internal.telemetry.telemetry_writer, "_namespace", MagicMock()
243+
) as telemetry_mock, self.trace("test_custom"):
215244
event = "some_event"
216245
track_custom_event(self.tracer, event, {"foo": "bar"})
217246
root_span = self.tracer.current_root_span()
218247

219248
assert root_span.get_tag("%s.%s.foo" % (APPSEC.CUSTOM_EVENT_PREFIX, event)) == "bar"
220249
assert root_span.get_tag("%s.%s.track" % (APPSEC.CUSTOM_EVENT_PREFIX, event)) == "true"
250+
metrics = get_telemetry_metrics(telemetry_mock)
251+
assert metrics == [("count", "appsec", "sdk.event", 1, (("event_type", "custom"), ("sdk_version", "v1")))]
221252

222253
def test_set_user_blocked(self):
223254
with asm_context(tracer=self.tracer, span_name="fake_span", config=config_good_rules) as span:

0 commit comments

Comments
 (0)