Skip to content

Commit dee1179

Browse files
tpellissierclaude
andcommitted
Address Copilot review: 7 telemetry fixes
- Remove unused imports in test_telemetry.py (time, Mock) - Use env vars for org URL/tenant ID in telemetry_demo.py - Normalize None header values to empty string in _odata.py - Include network exceptions (error is not None) in error count metric - Scope _operation_scope per page fetch, not across yield points - Dispatch on_request_error hook for network exceptions - Update SKILL.md docs to match on_request_error behavior Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 320a5bf commit dee1179

6 files changed

Lines changed: 29 additions & 20 deletions

File tree

examples/telemetry_demo.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,16 @@
7777
# Dataverse SDK Setup
7878
# =============================================================================
7979

80+
import os
81+
8082
from PowerPlatform.Dataverse.client import DataverseClient
8183
from PowerPlatform.Dataverse.core.config import DataverseConfig
8284
from PowerPlatform.Dataverse.core.telemetry import TelemetryConfig, TelemetryHook
8385
from azure.identity import InteractiveBrowserCredential
8486

85-
# Org details
86-
ORG_URL = "https://aurorabapenvcc726.crmtest.dynamics.com"
87-
TENANT_ID = "91bee3d9-0c15-4f17-8624-c92bb8b36ead"
87+
# Org details -- set via environment variables
88+
ORG_URL = os.environ.get("DATAVERSE_URL", "https://YOUR_ORG.crm.dynamics.com")
89+
TENANT_ID = os.environ.get("AZURE_TENANT_ID", "")
8890

8991

9092
class DemoTelemetryHook(TelemetryHook):

src/PowerPlatform/Dataverse/claude_skill/dataverse-sdk-use/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ The SDK supports opt-in telemetry via hooks, OpenTelemetry, and Python logging:
324324
from PowerPlatform.Dataverse.core.telemetry import TelemetryConfig, TelemetryHook
325325
from PowerPlatform.Dataverse.core.config import DataverseConfig
326326

327-
# Custom hook -- receives on_request_start, on_request_end, on_request_error
327+
# Custom hook -- receives on_request_start, on_request_end, and on_request_error
328328
class MyHook(TelemetryHook):
329329
def on_request_end(self, request, response):
330330
print(f"{request.operation} -> {response.status_code} in {response.duration_ms:.0f}ms")

src/PowerPlatform/Dataverse/core/telemetry.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ def record_response(
413413
self._request_duration.record(duration_ms, attrs)
414414
self._request_count.add(1, attrs)
415415

416-
if status_code >= 400:
416+
if status_code >= 400 or error is not None:
417417
self._error_count.add(1, attrs)
418418

419419
if retry_count > 0:
@@ -442,6 +442,8 @@ def record_response(
442442
pass
443443

444444
# 4. Hook dispatch (already per-hook exception safe)
445+
if error is not None:
446+
self._dispatch_request_error(ctx, error)
445447
self._dispatch_request_end(ctx, response)
446448

447449
# ------------------------------------------------------------------

src/PowerPlatform/Dataverse/data/_odata.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,8 @@ def _request(self, method: str, url: str, *, expected: tuple[int, ...] = _DEFAUL
245245
operation=operation,
246246
method=method.upper(),
247247
url=url,
248-
client_request_id=request_context.headers.get("x-ms-client-request-id", ""),
249-
correlation_id=request_context.headers.get("x-ms-correlation-id", ""),
248+
client_request_id=request_context.headers.get("x-ms-client-request-id") or "",
249+
correlation_id=request_context.headers.get("x-ms-correlation-id") or "",
250250
table_name=table_name,
251251
) as tracked:
252252
try:

src/PowerPlatform/Dataverse/operations/records.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -434,17 +434,23 @@ def get(
434434

435435
def _paged() -> Iterable[List[Record]]:
436436
with self._client._scoped_odata() as od:
437-
with _operation_scope("records.get_multiple", table):
438-
for page in od._get_multiple(
439-
table,
440-
select=select,
441-
filter=filter,
442-
orderby=orderby,
443-
top=top,
444-
expand=expand,
445-
page_size=page_size,
446-
):
447-
yield [Record.from_api_response(table, row) for row in page]
437+
pages = od._get_multiple(
438+
table,
439+
select=select,
440+
filter=filter,
441+
orderby=orderby,
442+
top=top,
443+
expand=expand,
444+
page_size=page_size,
445+
)
446+
while True:
447+
with _operation_scope("records.get_multiple", table):
448+
try:
449+
page = next(pages)
450+
except StopIteration:
451+
return
452+
records_page = [Record.from_api_response(table, row) for row in page]
453+
yield records_page
448454

449455
return _paged()
450456

tests/unit/core/test_telemetry.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
"""Unit tests for the telemetry infrastructure."""
55

66
import logging
7-
import time
87
import unittest
9-
from unittest.mock import MagicMock, Mock, patch
8+
from unittest.mock import MagicMock, patch
109

1110
from PowerPlatform.Dataverse.core.config import DataverseConfig
1211
from PowerPlatform.Dataverse.core.telemetry import (

0 commit comments

Comments
 (0)