From 8a8f7ec313811d6520185f04214a45a377e29de1 Mon Sep 17 00:00:00 2001 From: Rodrigo Pastrana Date: Fri, 8 Dec 2023 15:25:13 -0500 Subject: [PATCH] HPCC-30474 Provide JTrace option to declare span start time - Exposes helper method to obtain timestamp in nanos - Exposes createServerSpan function w/ optional starttime param - Adds simple cppunit tests excersizing both newly exposed functions Signed-off-by: Rodrigo Pastrana --- system/jlib/jtrace.cpp | 20 ++++++++++++++++++++ system/jlib/jtrace.hpp | 3 +++ testing/unittests/jlibtests.cpp | 13 +++++++++++++ 3 files changed, 36 insertions(+) diff --git a/system/jlib/jtrace.cpp b/system/jlib/jtrace.cpp index 807612337b0..618139aacb8 100644 --- a/system/jlib/jtrace.cpp +++ b/system/jlib/jtrace.cpp @@ -171,6 +171,7 @@ class CTraceManager : implements ITraceManager, public CInterface CTraceManager(); IMPLEMENT_IINTERFACE + virtual ISpan * createServerSpan(const char * name, const IProperties * httpHeaders, SpanFlags flags, std::chrono::nanoseconds spanStartTime) const override; virtual ISpan * createServerSpan(const char * name, StringArray & httpHeaders, SpanFlags flags) const override; virtual ISpan * createServerSpan(const char * name, const IProperties * httpHeaders, SpanFlags flags) const override; @@ -737,6 +738,16 @@ class CServerSpan : public CSpan } public: + CServerSpan(const char * spanName, const IProperties * httpHeaders, SpanFlags flags, std::chrono::nanoseconds spanStartTime) + : CSpan(spanName) + { + opts.start_system_time = opentelemetry::common::SystemTimestamp(std::chrono::duration_cast(spanStartTime)); + opts.kind = opentelemetry::trace::SpanKind::kServer; + setSpanContext(httpHeaders, flags); + init(flags); + setContextAttributes(); + } + CServerSpan(const char * spanName, const IProperties * httpHeaders, SpanFlags flags) : CSpan(spanName) { @@ -808,6 +819,11 @@ class CServerSpan : public CSpan //--------------------------------------------------------------------------------------------------------------------- +std::chrono::nanoseconds nowTimesStampInNanos() +{ + return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()); +} + IProperties * getClientHeaders(const ISpan * span) { Owned headers = createProperties(true); @@ -1062,6 +1078,10 @@ ISpan * CTraceManager::createServerSpan(const char * name, const IProperties * h return new CServerSpan(name, httpHeaders, flags); } +ISpan * CTraceManager::createServerSpan(const char * name, const IProperties * httpHeaders, SpanFlags flags, std::chrono::nanoseconds spanStartTime) const +{ + return new CServerSpan(name, httpHeaders, flags, spanStartTime); +} //--------------------------------------------------------------------------------------------------------------------- diff --git a/system/jlib/jtrace.hpp b/system/jlib/jtrace.hpp index 7998ffd5c3c..f2f23378bc1 100644 --- a/system/jlib/jtrace.hpp +++ b/system/jlib/jtrace.hpp @@ -17,6 +17,7 @@ #ifndef JTRACE_HPP #define JTRACE_HPP +#include /** * @brief This follows open telemetry's span attribute naming conventions @@ -62,6 +63,7 @@ extern jlib_decl IProperties * getSpanContext(const ISpan * span); interface ITraceManager : extends IInterface { + virtual ISpan * createServerSpan(const char * name, const IProperties * httpHeaders, SpanFlags flags, std::chrono::nanoseconds spanStartTime) const = 0; virtual ISpan * createServerSpan(const char * name, StringArray & httpHeaders, SpanFlags flags = SpanFlags::None) const = 0; virtual ISpan * createServerSpan(const char * name, const IProperties * httpHeaders, SpanFlags flags = SpanFlags::None) const = 0; virtual bool isTracingEnabled() const = 0; @@ -70,6 +72,7 @@ interface ITraceManager : extends IInterface extern jlib_decl ISpan * getNullSpan(); extern jlib_decl void initTraceManager(const char * componentName, const IPropertyTree * componentConfig, const IPropertyTree * globalConfig); extern jlib_decl ITraceManager & queryTraceManager(); +extern jlib_decl std::chrono::nanoseconds nowTimesStampInNanos(); //The following class is responsible for ensuring that the active span is restored in a context when the scope is exited //Use a template class so it can be reused for IContextLogger and IEspContext diff --git a/testing/unittests/jlibtests.cpp b/testing/unittests/jlibtests.cpp index 9918b77c5ef..4c7d5707fb9 100644 --- a/testing/unittests/jlibtests.cpp +++ b/testing/unittests/jlibtests.cpp @@ -60,6 +60,7 @@ class JlibTraceTest : public CppUnit::TestFixture CPPUNIT_TEST(testNullSpan); CPPUNIT_TEST(testClientSpanGlobalID); CPPUNIT_TEST(testEnsureTraceID); + CPPUNIT_TEST(testDeclaredSpanStartTime); CPPUNIT_TEST_SUITE_END(); const char * simulatedGlobalYaml = R"!!(global: @@ -104,6 +105,18 @@ class JlibTraceTest : public CppUnit::TestFixture protected: + void testDeclaredSpanStartTime() + { + std::chrono::nanoseconds nownanos = nowTimesStampInNanos(); + Owned emptyMockHTTPHeaders = createProperties(); + + Owned serverSpan = queryTraceManager().createServerSpan("declaredSpanStartSpan", emptyMockHTTPHeaders, SpanFlags::None, nownanos); + + Owned retrievedSpanCtxAttributes = createProperties(); + bool getSpanCtxSuccess = serverSpan->getSpanContext(retrievedSpanCtxAttributes, false); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Unexpected getSpanContext failure detected", true, getSpanCtxSuccess); + } + void testTraceDisableConfig() { Owned testTree = createPTreeFromYAMLString(disableTracingYaml, ipt_none, ptr_ignoreWhiteSpace, nullptr);