Skip to content

Commit 8ecf217

Browse files
committed
feat: add trace_semantics check
1 parent 2f88046 commit 8ecf217

File tree

4 files changed

+49
-10
lines changed

4 files changed

+49
-10
lines changed

ddapm_test_agent/agent.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
from .trace_checks import CheckTraceCountHeader
5151
from .trace_checks import CheckTraceDDService
5252
from .trace_checks import CheckTracePeerService
53+
from .trace_checks import CheckTraceSemantics
5354
from .trace_checks import CheckTraceStallAsync
5455
from .tracerflare import TracerFlareEvent
5556
from .tracerflare import v1_decode as v1_tracerflare_decode
@@ -646,6 +647,7 @@ async def _handle_traces(self, request: Request, version: Literal["v0.4", "v0.5"
646647
await checks.check(
647648
"trace_peer_service", span=span, dd_config_env=request.get("_dd_trace_env_variables", {})
648649
)
650+
await checks.check("trace_semantics", span=span)
649651

650652
await checks.check(
651653
"trace_dd_service", trace=trace, dd_config_env=request.get("_dd_trace_env_variables", {})
@@ -1051,12 +1053,13 @@ def make_app(
10511053
)
10521054
checks = Checks(
10531055
checks=[
1054-
CheckMetaTracerVersionHeader,
1055-
CheckTraceCountHeader,
1056-
CheckTraceContentLength,
1057-
CheckTraceStallAsync,
1058-
CheckTracePeerService,
1059-
CheckTraceDDService,
1056+
CheckMetaTracerVersionHeader(),
1057+
CheckTraceCountHeader(),
1058+
CheckTraceContentLength(),
1059+
CheckTraceStallAsync(),
1060+
CheckTracePeerService(),
1061+
CheckTraceDDService(),
1062+
CheckTraceSemantics(),
10601063
],
10611064
enabled=enabled_checks,
10621065
)

ddapm_test_agent/checks.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from typing import Generator
99
from typing import List
1010
from typing import Tuple
11-
from typing import Type
1211

1312

1413
CHECK_TRACE: contextvars.ContextVar["CheckTrace"] = contextvars.ContextVar("check_trace")
@@ -181,10 +180,10 @@ def check(self, *args, **kwargs):
181180

182181
@dataclasses.dataclass()
183182
class Checks:
184-
checks: List[Type[Check]] = dataclasses.field(init=True)
183+
checks: List[Check] = dataclasses.field(init=True)
185184
enabled: List[str] = dataclasses.field(init=True)
186185

187-
def _get_check(self, name: str) -> Type[Check]:
186+
def _get_check(self, name: str) -> Check:
188187
for c in self.checks:
189188
if c.name == name:
190189
return c
@@ -199,7 +198,7 @@ def is_enabled(self, name: str) -> bool:
199198

200199
async def check(self, name: str, *args: Any, **kwargs: Any) -> None:
201200
"""Find and run the check with the given ``name`` if it is enabled."""
202-
check = self._get_check(name)()
201+
check = self._get_check(name)
203202

204203
if self.is_enabled(name):
205204
# Register the check with the current trace

ddapm_test_agent/trace_checks.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
from typing import List
66

77
from aiohttp.web import Request
8+
from jsonschema import ValidationError
9+
from jsonschema import validate
810
from multidict import CIMultiDictProxy
11+
import requests
912

1013
from .checks import Check
1114
from .trace import Span
@@ -221,3 +224,36 @@ def check(self, trace: List[Span], dd_config_env: Dict[str, str]) -> None:
221224
else:
222225
log.debug(f"Successfully completed ``service`` name Span Check for Span: {span['name']}")
223226
return
227+
228+
229+
SCHEMA_URL = "https://raw.githubusercontent.com/DataDog/schema/main/semantic-core/v1/schema.json"
230+
231+
232+
class CheckTraceSemantics(Check):
233+
name = "trace_semantics"
234+
description = """
235+
The trace should follow semantic conventions defined by semantic-core.
236+
More info here: https://github.com/datadog/semantic-core.
237+
""".strip()
238+
schema = None
239+
240+
def __init__(self):
241+
log.debug("Initializing CheckTraceSemantics")
242+
243+
resp = requests.get(SCHEMA_URL)
244+
if resp.status_code != 200:
245+
log.fatal(f"Failed to download trace semantics schema: {resp}")
246+
247+
log.debug("Successfully downloaded semantic-core JSON Schema")
248+
249+
self.schema = resp.json()
250+
super().__init__()
251+
252+
def check(self, span: Span) -> None:
253+
log.info("Performing ``Trace Semantics`` Span Check")
254+
255+
try:
256+
validate(instance=span, schema=self.schema)
257+
log.debug(f"Span Check ``trace_semantics`` succeeded for Span {span['name']}")
258+
except ValidationError as err:
259+
self.fail(json.dumps(span, indent=4) + f"\nSpan '{span['name']}' failed semantic validation: {err}.")

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"requests",
3434
"typing_extensions",
3535
"yarl",
36+
"jsonschema",
3637
],
3738
tests_require=testing_deps,
3839
setup_requires=["setuptools_scm"],

0 commit comments

Comments
 (0)