Skip to content

Commit 22fc114

Browse files
chore(ci_visibility): add telemetry to the new plugin, part 3 (#15570)
## Description Add telemetry for parsing errors in API requests, as well as git packfile upload events. This PR also introduces tests for the API client and the various error conditions. ## Testing Unit tests, manual testing. ## Risks None. ## Additional Notes None.
1 parent ddb3870 commit 22fc114

File tree

6 files changed

+1386
-94
lines changed

6 files changed

+1386
-94
lines changed

ddtrace/testing/internal/api_client.py

Lines changed: 196 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from ddtrace.testing.internal.http import FileAttachment
1313
from ddtrace.testing.internal.settings_data import Settings
1414
from ddtrace.testing.internal.settings_data import TestProperties
15+
from ddtrace.testing.internal.telemetry import ErrorType
1516
from ddtrace.testing.internal.telemetry import TelemetryAPI
1617
from ddtrace.testing.internal.test_data import ITRSkippingLevel
1718
from ddtrace.testing.internal.test_data import ModuleRef
@@ -52,36 +53,50 @@ def get_settings(self) -> Settings:
5253
error="git_requests.settings_errors",
5354
)
5455

55-
request_data = {
56-
"data": {
57-
"id": str(uuid.uuid4()),
58-
"type": "ci_app_test_service_libraries_settings",
59-
"attributes": {
60-
"test_level": self.itr_skipping_level.value,
61-
"service": self.service,
62-
"env": self.env,
63-
"repository_url": self.env_tags[GitTag.REPOSITORY_URL],
64-
"sha": self.env_tags[GitTag.COMMIT_SHA],
65-
"branch": self.env_tags[GitTag.BRANCH],
66-
"configurations": self.configurations,
67-
},
56+
try:
57+
request_data = {
58+
"data": {
59+
"id": str(uuid.uuid4()),
60+
"type": "ci_app_test_service_libraries_settings",
61+
"attributes": {
62+
"test_level": self.itr_skipping_level.value,
63+
"service": self.service,
64+
"env": self.env,
65+
"repository_url": self.env_tags[GitTag.REPOSITORY_URL],
66+
"sha": self.env_tags[GitTag.COMMIT_SHA],
67+
"branch": self.env_tags[GitTag.BRANCH],
68+
"configurations": self.configurations,
69+
},
70+
}
6871
}
69-
}
72+
73+
except KeyError as e:
74+
log.error("Git info not available, cannot fetch settings (missing key: %s)", e)
75+
telemetry.record_error(ErrorType.UNKNOWN)
76+
return Settings()
7077

7178
try:
7279
result = self.connector.post_json(
7380
"/api/v2/libraries/tests/services/setting", request_data, telemetry=telemetry
7481
)
7582
result.on_error_raise_exception()
83+
84+
except Exception as e:
85+
log.error("Error getting settings from API: %s", e)
86+
return Settings()
87+
88+
try:
7689
attributes = result.parsed_response["data"]["attributes"]
7790
settings = Settings.from_attributes(attributes)
78-
self.telemetry_api.record_settings(settings)
79-
return settings
8091

81-
except Exception:
82-
log.exception("Error getting settings from API")
92+
except Exception as e:
93+
log.exception("Error getting settings from API: %s", e)
94+
telemetry.record_error(ErrorType.BAD_JSON)
8395
return Settings()
8496

97+
self.telemetry_api.record_settings(settings)
98+
return settings
99+
85100
def get_known_tests(self) -> t.Set[TestRef]:
86101
telemetry = self.telemetry_api.with_request_metric_names(
87102
count="known_tests.request",
@@ -90,22 +105,34 @@ def get_known_tests(self) -> t.Set[TestRef]:
90105
error="known_tests.request_errors",
91106
)
92107

93-
request_data = {
94-
"data": {
95-
"id": str(uuid.uuid4()),
96-
"type": "ci_app_libraries_tests_request",
97-
"attributes": {
98-
"service": self.service,
99-
"env": self.env,
100-
"repository_url": self.env_tags[GitTag.REPOSITORY_URL],
101-
"configurations": self.configurations,
102-
},
108+
try:
109+
request_data = {
110+
"data": {
111+
"id": str(uuid.uuid4()),
112+
"type": "ci_app_libraries_tests_request",
113+
"attributes": {
114+
"service": self.service,
115+
"env": self.env,
116+
"repository_url": self.env_tags[GitTag.REPOSITORY_URL],
117+
"configurations": self.configurations,
118+
},
119+
}
103120
}
104-
}
121+
122+
except KeyError as e:
123+
log.error("Git info not available, cannot fetch known tests (missing key: %s)", e)
124+
telemetry.record_error(ErrorType.UNKNOWN)
125+
return set()
105126

106127
try:
107128
result = self.connector.post_json("/api/v2/ci/libraries/tests", request_data, telemetry=telemetry)
108129
result.on_error_raise_exception()
130+
131+
except Exception as e:
132+
log.exception("Error getting known tests from API: %s", e)
133+
return set()
134+
135+
try:
109136
tests_data = result.parsed_response["data"]["attributes"]["tests"]
110137
known_test_ids = set()
111138

@@ -116,13 +143,14 @@ def get_known_tests(self) -> t.Set[TestRef]:
116143
for test in tests:
117144
known_test_ids.add(TestRef(suite_ref, test))
118145

119-
self.telemetry_api.record_known_tests_count(len(known_test_ids))
120-
return known_test_ids
121-
122146
except Exception:
123147
log.exception("Error getting known tests from API")
148+
telemetry.record_error(ErrorType.BAD_JSON)
124149
return set()
125150

151+
self.telemetry_api.record_known_tests_count(len(known_test_ids))
152+
return known_test_ids
153+
126154
def get_test_management_properties(self) -> t.Dict[TestRef, TestProperties]:
127155
telemetry = self.telemetry_api.with_request_metric_names(
128156
count="test_management_tests.request",
@@ -131,23 +159,35 @@ def get_test_management_properties(self) -> t.Dict[TestRef, TestProperties]:
131159
error="test_management_tests.request_errors",
132160
)
133161

134-
request_data = {
135-
"data": {
136-
"id": str(uuid.uuid4()),
137-
"type": "ci_app_libraries_tests_request",
138-
"attributes": {
139-
"repository_url": self.env_tags[GitTag.REPOSITORY_URL],
140-
"commit_message": self.env_tags[GitTag.COMMIT_MESSAGE],
141-
"sha": self.env_tags[GitTag.COMMIT_SHA],
142-
},
162+
try:
163+
request_data = {
164+
"data": {
165+
"id": str(uuid.uuid4()),
166+
"type": "ci_app_libraries_tests_request",
167+
"attributes": {
168+
"repository_url": self.env_tags[GitTag.REPOSITORY_URL],
169+
"commit_message": self.env_tags[GitTag.COMMIT_MESSAGE],
170+
"sha": self.env_tags[GitTag.COMMIT_SHA],
171+
},
172+
}
143173
}
144-
}
174+
175+
except KeyError as e:
176+
log.error("Git info not available, cannot fetch Test Management properties (missing key: %s)", e)
177+
telemetry.record_error(ErrorType.UNKNOWN)
178+
return {}
145179

146180
try:
147181
result = self.connector.post_json(
148182
"/api/v2/test/libraries/test-management/tests", request_data, telemetry=telemetry
149183
)
150184
result.on_error_raise_exception()
185+
186+
except Exception as e:
187+
log.error("Error getting Test Management properties from API: %s", e)
188+
return {}
189+
190+
try:
151191
test_properties: t.Dict[TestRef, TestProperties] = {}
152192
modules = result.parsed_response["data"]["attributes"]["modules"]
153193

@@ -166,54 +206,105 @@ def get_test_management_properties(self) -> t.Dict[TestRef, TestProperties]:
166206
attempt_to_fix=properties.get("attempt_to_fix", False),
167207
)
168208

169-
self.telemetry_api.record_test_management_tests_count(len(test_properties))
170-
171-
return test_properties
172-
173209
except Exception:
174-
log.exception("Failed to parse Test Management tests data")
210+
log.exception("Failed to parse Test Management tests data from API")
211+
telemetry.record_error(ErrorType.BAD_JSON)
175212
return {}
176213

214+
self.telemetry_api.record_test_management_tests_count(len(test_properties))
215+
return test_properties
216+
177217
def get_known_commits(self, latest_commits: t.List[str]) -> t.List[str]:
178-
request_data = {
179-
"meta": {
180-
"repository_url": self.env_tags[GitTag.REPOSITORY_URL],
181-
},
182-
"data": [{"id": sha, "type": "commit"} for sha in latest_commits],
183-
}
218+
telemetry = self.telemetry_api.with_request_metric_names(
219+
count="git_requests.search_commits",
220+
duration="git_requests.search_commits_ms",
221+
response_bytes=None,
222+
error="git_requests.search_commits_errors",
223+
)
224+
225+
try:
226+
request_data = {
227+
"meta": {
228+
"repository_url": self.env_tags[GitTag.REPOSITORY_URL],
229+
},
230+
"data": [{"id": sha, "type": "commit"} for sha in latest_commits],
231+
}
232+
233+
except KeyError as e:
234+
log.error("Git info not available, cannot fetch known commits (missing key: %s)", e)
235+
telemetry.record_error(ErrorType.UNKNOWN)
236+
return []
184237

185238
try:
186-
result = self.connector.post_json("/api/v2/git/repository/search_commits", request_data)
239+
result = self.connector.post_json(
240+
"/api/v2/git/repository/search_commits", request_data, telemetry=telemetry
241+
)
187242
result.on_error_raise_exception()
188-
return [item["id"] for item in result.parsed_response["data"] if item["type"] == "commit"]
243+
244+
except Exception as e:
245+
log.error("Error getting known commits from API: %s", e)
246+
return []
247+
248+
try:
249+
known_commits = [item["id"] for item in result.parsed_response["data"] if item["type"] == "commit"]
189250

190251
except Exception:
191252
log.exception("Failed to parse search_commits data")
253+
telemetry.record_error(ErrorType.BAD_JSON)
192254
return []
193255

194-
def send_git_pack_file(self, packfile: Path) -> None:
195-
metadata = {
196-
"data": {"id": self.env_tags[GitTag.COMMIT_SHA], "type": "commit"},
197-
"meta": {"repository_url": self.env_tags[GitTag.REPOSITORY_URL]},
198-
}
199-
content = packfile.read_bytes()
200-
files = [
201-
FileAttachment(
202-
name="pushedSha",
203-
filename=None,
204-
content_type="application/json",
205-
data=json.dumps(metadata).encode("utf-8"),
206-
),
207-
FileAttachment(
208-
name="packfile", filename=packfile.name, content_type="application/octet-stream", data=content
209-
),
210-
]
256+
return known_commits
257+
258+
def send_git_pack_file(self, packfile: Path) -> t.Optional[int]:
259+
telemetry = self.telemetry_api.with_request_metric_names(
260+
count="git_requests.objects_pack",
261+
duration="git_requests.objects_pack_ms",
262+
response_bytes=None,
263+
error="git_requests.objects_pack_errors",
264+
)
265+
266+
try:
267+
metadata = {
268+
"data": {"id": self.env_tags[GitTag.COMMIT_SHA], "type": "commit"},
269+
"meta": {"repository_url": self.env_tags[GitTag.REPOSITORY_URL]},
270+
}
271+
272+
except KeyError as e:
273+
log.error("Git info not available, cannot send git packfile (missing key: %s)", e)
274+
telemetry.record_error(ErrorType.UNKNOWN)
275+
return None
276+
211277
try:
212-
result = self.connector.post_files("/api/v2/git/repository/packfile", files=files, send_gzip=False)
278+
content = packfile.read_bytes()
279+
280+
files = [
281+
FileAttachment(
282+
name="pushedSha",
283+
filename=None,
284+
content_type="application/json",
285+
data=json.dumps(metadata).encode("utf-8"),
286+
),
287+
FileAttachment(
288+
name="packfile", filename=packfile.name, content_type="application/octet-stream", data=content
289+
),
290+
]
291+
292+
except Exception:
293+
log.exception("Error sending Git pack data")
294+
telemetry.record_error(ErrorType.UNKNOWN)
295+
return None
296+
297+
try:
298+
result = self.connector.post_files(
299+
"/api/v2/git/repository/packfile", files=files, send_gzip=False, telemetry=telemetry
300+
)
213301
result.on_error_raise_exception()
214302

215303
except Exception:
216-
log.warning("Failed to upload git pack data")
304+
log.warning("Failed to upload Git pack data")
305+
return None
306+
307+
return len(content)
217308

218309
def get_skippable_tests(self) -> t.Tuple[t.Set[t.Union[SuiteRef, TestRef]], t.Optional[str]]:
219310
telemetry = self.telemetry_api.with_request_metric_names(
@@ -223,24 +314,36 @@ def get_skippable_tests(self) -> t.Tuple[t.Set[t.Union[SuiteRef, TestRef]], t.Op
223314
error="itr_skippable_tests.request_errors",
224315
)
225316

226-
request_data = {
227-
"data": {
228-
"id": str(uuid.uuid4()),
229-
"type": "test_params",
230-
"attributes": {
231-
"service": self.service,
232-
"env": self.env,
233-
"repository_url": self.env_tags[GitTag.REPOSITORY_URL],
234-
"sha": self.env_tags[GitTag.COMMIT_SHA],
235-
"configurations": self.configurations,
236-
"test_level": self.itr_skipping_level.value,
237-
},
317+
try:
318+
request_data = {
319+
"data": {
320+
"id": str(uuid.uuid4()),
321+
"type": "test_params",
322+
"attributes": {
323+
"service": self.service,
324+
"env": self.env,
325+
"repository_url": self.env_tags[GitTag.REPOSITORY_URL],
326+
"sha": self.env_tags[GitTag.COMMIT_SHA],
327+
"configurations": self.configurations,
328+
"test_level": self.itr_skipping_level.value,
329+
},
330+
}
238331
}
239-
}
332+
333+
except KeyError as e:
334+
log.error("Git info not available, cannot get skippable items (missing key: %s)", e)
335+
telemetry.record_error(ErrorType.UNKNOWN)
336+
return set(), None
337+
240338
try:
241339
result = self.connector.post_json("/api/v2/ci/tests/skippable", request_data, telemetry=telemetry)
242340
result.on_error_raise_exception()
243341

342+
except Exception as e:
343+
log.error("Error getting skippable tests from API: %s", e)
344+
return set(), None
345+
346+
try:
244347
skippable_items: t.Set[t.Union[SuiteRef, TestRef]] = set()
245348

246349
for item in result.parsed_response["data"]:
@@ -255,10 +358,11 @@ def get_skippable_tests(self) -> t.Tuple[t.Set[t.Union[SuiteRef, TestRef]], t.Op
255358

256359
correlation_id = result.parsed_response["meta"]["correlation_id"]
257360

258-
self.telemetry_api.record_skippable_count(count=len(skippable_items), level=self.itr_skipping_level)
259-
260-
return skippable_items, correlation_id
261-
262361
except Exception:
263-
log.exception("Error getting skippable tests from API")
362+
log.exception("Failed to parse skippable tests data from API")
363+
telemetry.record_error(ErrorType.BAD_JSON)
264364
return set(), None
365+
366+
self.telemetry_api.record_skippable_count(count=len(skippable_items), level=self.itr_skipping_level)
367+
368+
return skippable_items, correlation_id

0 commit comments

Comments
 (0)