Skip to content

Commit

Permalink
enable node span events system tests (#2539)
Browse files Browse the repository at this point in the history
* enable node span events system tests
  • Loading branch information
khanayan123 committed Jun 12, 2024
1 parent 2084568 commit 61074b3
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 13 deletions.
61 changes: 48 additions & 13 deletions tests/parametric/test_otel_span_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ def test_otel_span_extended_reserved_attributes_overrides_analytics_event(
@missing_feature(context.library == "php", reason="Not implemented")
@missing_feature(context.library == "java", reason="Not implemented")
@missing_feature(context.library == "ruby", reason="Not implemented")
@missing_feature(context.library == "nodejs", reason="Not implemented")
@missing_feature(context.library < "nodejs@5.17.0", reason="Implemented in v5.17.0 & v4.41.0")
@missing_feature(context.library == "dotnet", reason="Not implemented")
@missing_feature(context.library < "[email protected]", reason="Not implemented")
def test_otel_add_event_meta_serialization(self, test_agent, test_library):
Expand Down Expand Up @@ -874,7 +874,7 @@ def test_otel_add_event_meta_serialization(self, test_agent, test_library):

event2 = events[1]
assert event2.get("name") == "second_event"
assert event2.get("time_unix_nano") == event2_timestamp_ns
assert event2.get("time_unix_nano") // 10000 == event2_timestamp_ns // 10000 # reduce the precision tested
assert event2["attributes"].get("string_val") == "value"

event3 = events[2]
Expand All @@ -891,7 +891,7 @@ def test_otel_add_event_meta_serialization(self, test_agent, test_library):
@missing_feature(context.library == "php", reason="Not implemented")
@missing_feature(context.library == "java", reason="Not implemented")
@missing_feature(context.library == "ruby", reason="Not implemented")
@missing_feature(context.library == "nodejs", reason="Not implemented")
@missing_feature(context.library < "nodejs@5.17.0", reason="Implemented in v5.17.0 & v4.41.0")
@missing_feature(context.library < "[email protected]", reason="Not implemented")
def test_otel_record_exception_does_not_set_error(self, test_agent, test_library):
"""
Expand All @@ -910,7 +910,7 @@ def test_otel_record_exception_does_not_set_error(self, test_agent, test_library
@missing_feature(context.library == "php", reason="Not implemented")
@missing_feature(context.library == "java", reason="Not implemented")
@missing_feature(context.library == "ruby", reason="Not implemented")
@missing_feature(context.library == "nodejs", reason="Not implemented")
@missing_feature(context.library < "nodejs@5.17.0", reason="Implemented in v5.17.0 & v4.41.0")
@missing_feature(context.library == "dotnet", reason="Not implemented")
@missing_feature(context.library < "[email protected]", reason="Not implemented")
def test_otel_record_exception_meta_serialization(self, test_agent, test_library):
Expand All @@ -933,29 +933,64 @@ def test_otel_record_exception_meta_serialization(self, test_agent, test_library

events = json.loads(root_span.get("meta", {}).get("events"))
assert len(events) == 3
event1 = events[0]
assert (
event1.get("name").lower() == "exception" or "error"
) # node uses error objects instead of exception objects
assert event1.get("time_unix_nano") > 0

event2 = events[1]
assert event2.get("name") == "non_exception_event"
assert event2.get("time_unix_nano") > event1.get("time_unix_nano")

event3 = events[2]
assert event3.get("name") == "exception" or "error"
assert event3.get("time_unix_nano") > event2.get("time_unix_nano")

assert root_span["error"] == 1
assert "error.type" in root_span["meta"]
assert "error.stack" in root_span["meta"]

@missing_feature(context.library == "golang", reason="Not implemented")
@missing_feature(context.library == "php", reason="Not implemented")
@missing_feature(context.library == "java", reason="Not implemented")
@missing_feature(context.library == "ruby", reason="Not implemented")
@missing_feature(context.library == "nodejs", reason="Otel Node.js API does not support attributes")
@missing_feature(context.library == "dotnet", reason="Not implemented")
@missing_feature(context.library < "[email protected]", reason="Not implemented")
def test_otel_record_exception_attributes_serialization(self, test_agent, test_library):
"""
Tests the Span.RecordException API (requires Span.AddEvent API support)
and its serialization into the Datadog error tags and the 'events' tag
"""
with test_library:
with test_library.otel_start_span("operation") as span:
span.set_status(OTEL_ERROR_CODE, "error_desc")
span.record_exception(
message="woof1", attributes={"string_val": "value", "exception.stacktrace": "stacktrace1"}
)
span.add_event(name="non_exception_event", attributes={"exception.stacktrace": "non-error"})
span.record_exception(message="woof3", attributes={"exception.message": "message override"})
span.end_span()

root_span = get_span(test_agent)
assert "events" in root_span["meta"]

events = json.loads(root_span.get("meta", {}).get("events"))
assert len(events) == 3
event1 = events[0]
assert event1.get("name") == "exception"
assert event1["attributes"].get("string_val") == "value"
assert event1["attributes"].get("exception.message") == "woof1"
assert event1["attributes"].get("exception.stacktrace") == "stacktrace1"
assert event1.get("time_unix_nano") > 0

event2 = events[1]
assert event2.get("name") == "non_exception_event"
assert event2["attributes"].get("exception.stacktrace") == "non-error"
assert event2.get("time_unix_nano") > event1.get("time_unix_nano")

event3 = events[2]
assert event3.get("name") == "exception"
assert event3["attributes"].get("exception.message") == "message override"
assert event3.get("time_unix_nano") > event2.get("time_unix_nano")

assert root_span["error"] == 1
error_message = root_span["meta"].get("error.message") or root_span["meta"].get("error.msg")
assert error_message == "message override"
assert "error.type" in root_span["meta"]
assert "error.stack" in root_span["meta"]


def run_operation_name_test(expected_operation_name: str, span_kind: int, attributes: dict, test_library, test_agent):
Expand Down
16 changes: 16 additions & 0 deletions utils/build/docker/nodejs/parametric/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const SpanContext = require('dd-trace/packages/dd-trace/src/opentracing/span_con
const OtelSpanContext = require('dd-trace/packages/dd-trace/src/opentelemetry/span_context')

const { trace, ROOT_CONTEXT } = require('@opentelemetry/api')
const { millisToHrTime } = require('@opentelemetry/core')

const { TracerProvider } = tracer
const tracerProvider = new TracerProvider()
Expand Down Expand Up @@ -306,6 +307,21 @@ app.get('/trace/config', (req, res) => {
});
});

app.post("/trace/otel/add_event", (req, res) => {
const { span_id, name, timestamp, attributes } = req.body;
const span = otelSpans[span_id]
// convert to TimeInput object using millisToHrTime
span.addEvent(name, attributes, millisToHrTime(timestamp / 1000))
res.json({})
})

app.post("/trace/otel/record_exception", (req, res) => {
const { span_id, message, attributes } = req.body;
const span = otelSpans[span_id]
span.recordException(new Error(message))
res.json({})
})

// TODO: implement this endpoint correctly, current blockers:
// 1. Fails on invalid url
// 2. does not generate span, because http instrumentation turned off
Expand Down

0 comments on commit 61074b3

Please sign in to comment.