From 794cabca6f850389a17db95630d6ce9137c802ed Mon Sep 17 00:00:00 2001 From: Tim Klemm Date: Wed, 17 Apr 2024 14:59:04 -0400 Subject: [PATCH] HPCC-31381 Forward trace summary values to Open Telemetry spans Signed-off-by: Tim Klemm --- esp/platform/esp.hpp | 9 + esp/platform/espcontext.cpp | 42 ++- esp/platform/txsummary.cpp | 90 +++++++ esp/platform/txsummary.hpp | 244 +++++++++++++++++- esp/services/esdl_svc_engine/esdl_binding.cpp | 1 + 5 files changed, 378 insertions(+), 8 deletions(-) diff --git a/esp/platform/esp.hpp b/esp/platform/esp.hpp index 65c3008f412..38b754013a8 100644 --- a/esp/platform/esp.hpp +++ b/esp/platform/esp.hpp @@ -93,6 +93,7 @@ typedef enum LogRequest_ #define TXSUMMARY_OUT_TEXT 0x00000001 #define TXSUMMARY_OUT_JSON 0x00000002 +#define TXSUMMARY_FWD_OTEL 0x80000000 #define ESPCTX_NO_NAMESPACES 0x00000001 #define ESPCTX_WSDL 0x00000010 @@ -104,6 +105,7 @@ class CTxSummary; interface IEspSecureContext; interface IEspSecureContextEx; class CumulativeTimer; +enum class TxUnits; interface IEspContext : extends IInterface { @@ -197,9 +199,15 @@ interface IEspContext : extends IInterface virtual CTxSummary* queryTxSummary()=0; virtual void addTraceSummaryValue(unsigned logLevel, const char *name, const char *value, const unsigned int group = TXSUMMARY_GRP_CORE)=0; + virtual void addTraceSummaryValue(unsigned logLevel, const char *name, const char *value, const char* otName, unsigned group = TXSUMMARY_GRP_CORE)=0; virtual void addTraceSummaryValue(unsigned logLevel, const char *name, __int64 value, const unsigned int group = TXSUMMARY_GRP_CORE)=0; + virtual void addTraceSummaryValue(unsigned logLevel, const char *name, __int64 value, const char* otName, unsigned group = TXSUMMARY_GRP_CORE)=0; + virtual void addTraceSummaryValue(unsigned logLevel, const char *name, __int64 value, TxUnits units, unsigned group = TXSUMMARY_GRP_CORE)=0; + virtual void addTraceSummaryValue(unsigned logLevel, const char *name, __int64 value, const char* otName, TxUnits units, unsigned group = TXSUMMARY_GRP_CORE)=0; virtual void addTraceSummaryDoubleValue(unsigned logLevel, const char *name, double value, const unsigned int group = TXSUMMARY_GRP_CORE)=0; + virtual void addTraceSummaryDoubleValue(unsigned logLevel, const char *name, double value, const char* otName, unsigned group = TXSUMMARY_GRP_CORE)=0; virtual void addTraceSummaryTimeStamp(unsigned logLevel, const char *name, const unsigned int group = TXSUMMARY_GRP_CORE)=0; + virtual void addTraceSummaryTimeStamp(unsigned logLevel, const char *name, const char* otName, unsigned group = TXSUMMARY_GRP_CORE)=0; virtual void addTraceSummaryCumulativeTime(unsigned logLevel, const char* name, unsigned __int64 time, const unsigned int group = TXSUMMARY_GRP_CORE)=0; virtual CumulativeTimer* queryTraceSummaryCumulativeTimer(unsigned logLevel, const char *name, const unsigned int group = TXSUMMARY_GRP_CORE)=0; virtual void cancelTxSummary()=0; @@ -236,6 +244,7 @@ interface IEspContext : extends IInterface virtual IHttpMessage* queryRequest() = 0; virtual void setRequestSpan(ISpan * span)=0; // Call this function to set the server span for the query. The spans's lifetime will match the lifetime of the context object. + inline void setActiveSpan(ISpan * span) { setRequestSpan(span); } virtual ISpan * queryActiveSpan() const = 0; virtual IProperties * getClientSpanHeaders() const = 0; virtual const char* getGlobalId() const = 0; diff --git a/esp/platform/espcontext.cpp b/esp/platform/espcontext.cpp index ea2c90f2d23..fc00666b253 100755 --- a/esp/platform/espcontext.cpp +++ b/esp/platform/espcontext.cpp @@ -111,6 +111,7 @@ class CEspContext : public CInterface, implements IEspContext , respSerializationFormat(ESPSerializationANY) { m_txSummary.setown(new CTxSummary(m_creationTime)); + m_txSummary->setConnector(new CTxOpenTelemetryConnector(*this)); updateTraceSummaryHeader(); m_secureContext.setown(secureContext); m_SecurityHandler.setSecureContext(secureContext); @@ -123,7 +124,7 @@ class CEspContext : public CInterface, implements IEspContext if (m_txSummary) { m_txSummary->tailor(this); - m_txSummary->log(getTxSummaryLevel(), getTxSummaryGroup(), getTxSummaryStyle()); + m_txSummary->log(getTxSummaryLevel(), getTxSummaryGroup(), getTxSummaryStyle() | TXSUMMARY_FWD_OTEL); } } virtual void addOptions(unsigned opts){options|=opts;} @@ -512,28 +513,59 @@ class CEspContext : public CInterface, implements IEspContext } virtual void addTraceSummaryValue(LogLevel logLevel, const char *name, const char *value, const unsigned int group = TXSUMMARY_GRP_CORE) + { + addTraceSummaryValue(logLevel, name, value, nullptr, group); + } + + virtual void addTraceSummaryValue(LogLevel logLevel, const char *name, const char *value, const char* otName, const unsigned int group = TXSUMMARY_GRP_CORE) { if (m_txSummary && !isEmptyString(name)) - m_txSummary->append(name, value, logLevel, group); + m_txSummary->append(name, value, otName, TxUnits::NA, logLevel, group); } virtual void addTraceSummaryValue(LogLevel logLevel, const char *name, __int64 value, const unsigned int group = TXSUMMARY_GRP_CORE) + { + addTraceSummaryValue(logLevel, name, value, nullptr, TxUnits::NA, group); + } + + virtual void addTraceSummaryValue(LogLevel logLevel, const char *name, __int64 value, const char* otName, unsigned group = TXSUMMARY_GRP_CORE) override + { + addTraceSummaryValue(logLevel, name, value, otName, TxUnits::NA, group); + } + + virtual void addTraceSummaryValue(LogLevel logLevel, const char *name, __int64 value, TxUnits units, unsigned group = TXSUMMARY_GRP_CORE) override + { + addTraceSummaryValue(logLevel, name, value, nullptr, units, group); + } + + virtual void addTraceSummaryValue(LogLevel logLevel, const char *name, __int64 value, const char* otName, TxUnits units, unsigned group = TXSUMMARY_GRP_CORE) override { if (m_txSummary && !isEmptyString(name)) - m_txSummary->append(name, value, logLevel, group); + m_txSummary->append(name, value, otName, units, logLevel, group); } virtual void addTraceSummaryDoubleValue(LogLevel logLevel, const char *name, double value, const unsigned int group = TXSUMMARY_GRP_CORE) + { + addTraceSummaryDoubleValue(logLevel, name, value, nullptr, group); + } + + virtual void addTraceSummaryDoubleValue(LogLevel logLevel, const char *name, double value, const char* otName, unsigned group = TXSUMMARY_GRP_CORE) { if (m_txSummary && !isEmptyString(name)) - m_txSummary->append(name, value, logLevel, group); + m_txSummary->append(name, value, otName, TxUnits::NA, logLevel, group); } virtual void addTraceSummaryTimeStamp(LogLevel logLevel, const char *name, const unsigned int group = TXSUMMARY_GRP_CORE) + { + addTraceSummaryTimeStamp(logLevel, name, nullptr, group); + } + + virtual void addTraceSummaryTimeStamp(LogLevel logLevel, const char *name, const char* otName, unsigned group = TXSUMMARY_GRP_CORE) override { if (m_txSummary && !isEmptyString(name)) - m_txSummary->append(name, m_txSummary->getElapsedTime(), logLevel, group, "ms"); + m_txSummary->append(name, m_txSummary->getElapsedTime(), otName, TxUnits::millis, logLevel, group, "ms"); } + virtual void flushTraceSummary() { updateTraceSummaryHeader(); diff --git a/esp/platform/txsummary.cpp b/esp/platform/txsummary.cpp index 37c9df7621c..479f80622cc 100755 --- a/esp/platform/txsummary.cpp +++ b/esp/platform/txsummary.cpp @@ -28,6 +28,12 @@ static auto pRequestCount = hpccMetrics::registerCounterMetric("esp.requests.received", "Number of requests received", SMeasureCount); #endif +namespace +{ + // Iteration of summary entries occurs without knowledge of the ssummary or its connector. + static thread_local CTxOpenTelemetryConnector* otelConnector = nullptr; +} + inline bool validate(const char* k) { // Empty or null keys are invalid @@ -126,6 +132,11 @@ StringBuffer& CTxSummary::TxEntryTimer::serialize(StringBuffer& buf, const LogLe buf.append(fullname); buf.appendf("=%" I64F "u;", value->getTotalMillis()); } + else if (requestedStyle & TXSUMMARY_FWD_OTEL) + { + if (otelConnector) + otelConnector->forwardAttribute(name, nullptr, value->getTotalMillis(), TxUnits::millis, queryLogLevel(), queryGroup()); + } return buf; } @@ -517,6 +528,11 @@ void CTxSummary::setProfile(ITxSummaryProfile* profile) m_profile.set(profile); } +void CTxSummary::setConnector(CTxOpenTelemetryConnector* _connector) +{ + connector.setown(_connector); +} + void CTxSummary::serialize(StringBuffer& buffer, const LogLevel logLevel, const unsigned int group, const unsigned int requestedStyle) const { CriticalBlock block(m_sync); @@ -591,6 +607,15 @@ void CTxSummary::log(const LogLevel logLevel, const unsigned int requestedGroup, serialize(summary.clear(), logLevel, requestedGroup, TXSUMMARY_OUT_JSON); DBGLOG("%s", summary.str()); } + + if (requestedStyle & TXSUMMARY_FWD_OTEL) + { + // String values have already been forwarded and should ignore this serialization + // request. Timer values have not been forwarded, and should forward their values. + otelConnector = connector.get(); + serialize(summary.clear(), logLevel, requestedGroup, TXSUMMARY_FWD_OTEL); + otelConnector = nullptr; + } } } @@ -663,3 +688,68 @@ CTxSummary::TxEntryBase* CTxSummary::queryEntry(const char* key) return nullptr; } + +StringBuffer& CTxOpenTelemetryConnector::normalizeKey(const char* txKey, const char* otKey, StringBuffer& normalized) const +{ + getSnakeCase(normalized, isEmptyString(otKey) ? txKey : otKey); + // Keys for custom attributes may be annotated to reflect the source here. + return normalized; +} + +bool CTxOpenTelemetryConnector::isExcluded(const char* key, LogLevel logLevel, unsigned groupMask) const +{ + if ((logLevel > maxLogLevel) || ((groupMask & groupSelector) != groupSelector) || isEmptyString(key)) + return true; + // Redundant attributes may be excluded by key here. For example, if spans include values like + // the global ID, it may be preferred to not forward a trace summary-sourced copy. + return false; +} + +#define ENSURE_TARGET_AND_NAME \ + StringBuffer name; \ + if (isExcluded(normalizeKey(txKey, otKey, name), logLevel, groupMask)) \ + return; \ + ISpan* target = context.queryActiveSpan(); \ + if (!target) \ + return + +void CTxOpenTelemetryConnector::forwardUnsigned(const char* txKey, const char* otKey, uint64_t value, TxUnits units, LogLevel logLevel, unsigned groupMask) const +{ + ENSURE_TARGET_AND_NAME; + target->setSpanAttribute(name, scale(value, units)); +} + +void CTxOpenTelemetryConnector::forwardSigned(const char* txKey, const char* otKey, int64_t value, TxUnits units, LogLevel logLevel, unsigned groupMask) const +{ + ENSURE_TARGET_AND_NAME; + target->setSpanAttribute(name, uint64_t(scale(value, units))); +} + +void CTxOpenTelemetryConnector::forwardDouble(const char* txKey, const char* otKey, double value, LogLevel logLevel, unsigned groupMask) const +{ + ENSURE_TARGET_AND_NAME; + StringBuffer tmp; + tmp.append(value); + target->setSpanAttribute(name, tmp); +} + +void CTxOpenTelemetryConnector::forwardBool(const char* txKey, const char* otKey, bool value, LogLevel logLevel, unsigned groupMask) const +{ + ENSURE_TARGET_AND_NAME; + target->setSpanAttribute(name, uint64_t(value)); +} + +void CTxOpenTelemetryConnector::forwardString(const char* txKey, const char* otKey, const char* value, LogLevel logLevel, unsigned groupMask) const +{ + ENSURE_TARGET_AND_NAME; + target->setSpanAttribute(name, value); +} + +#undef ENSURE_TARGET_AND_NAME + +CTxOpenTelemetryConnector::CTxOpenTelemetryConnector(IEspContext& _context) + : context(_context) +{ + maxLogLevel = getTxSummaryLevel(); + groupSelector = getTxSummaryGroup(); +} diff --git a/esp/platform/txsummary.hpp b/esp/platform/txsummary.hpp index 88370fb8a54..af850f92348 100755 --- a/esp/platform/txsummary.hpp +++ b/esp/platform/txsummary.hpp @@ -41,6 +41,25 @@ #endif interface ITxSummaryProfile; +class CTxOpenTelemetryConnector; + +/** + * @brief Indication of what an instrumented value represents. + * + * Open Telemetry attributes reflecting timing values are expected to be reported as a number of + * nanonseconds. The trace summary records these values as a number of milliseconds. Similarly, + * size quantities are expected as a number of bytes. The enumeration covers use cases where a + * value is reported as one unit of measurement and Open Telemetry requires another. + * + * Customer defined ESPs, plugins, and ESDL scripts may instrument values of their choice. Naming + * conventions, or similar strategies, cannot be relied upon for the platform to deduce correct + * behavior. + */ +enum class TxUnits +{ + NA, /// no scaling required + millis, /// milliseconds to be scaled to nanoseconds +}; class txsummary_decl CTxSummary : extends CInterface { @@ -66,8 +85,9 @@ class txsummary_decl CTxSummary : extends CInterface // Appends all summary entries to the given buffer. // - // JSON serialization supports string, integer numeric, true, false, - // null, and object values. Arrays are not supported. + // JSON serialization supports string, integer numeric, and object values. Arrays are not + // supported. Null values are considered equivalent to empty strings. Boolean values are + // represented as integral 1 and 0 values. virtual void serialize(StringBuffer& buffer, const LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const unsigned int requestedStyle = TXSUMMARY_OUT_TEXT) const; // Adds the unique key and value to the end of the summary. @@ -78,14 +98,34 @@ class txsummary_decl CTxSummary : extends CInterface // entry's position in a hierarcy used when the summary is serialized in a // style such as JSON. When output as text, the key is used verbatim as the // entry name. + // + // Four varations are provided to explicitly control Open Telemetry forwarding behavior. An + // alternate key may be specified for use as the attribute name. A units identifier may be + // given to force value scaling. template bool append(const char* key, const TValue& value, const LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); + template + bool append(const char* key, const TValue& value, const char* otKey, LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); + template + bool append(const char* key, const TValue& value, TxUnits units, LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); + template + bool append(const char* key, const TValue& value, const char* otKey, TxUnits units, LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); // Updates the value, logLevel, group and suffix associated with an existing // key, or appends the keyand value to the summary if it is not already // found. Returns false if the key is NULL or empty. Returns true otherwise. + // + // Four varations are provided to explicitly control Open Telemetry forwarding behavior. An + // alternate key may be specified for use as the attribute name. A unitsidentifier may be + // given to force value scaling. template bool set(const char* key, const TValue& value, const LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); + template + bool set(const char* key, const TValue& value, const char* otKey, const LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); + template + bool set(const char* key, const TValue& value, TxUnits units, const LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); + template + bool set(const char* key, const TValue& value, const char* otKey, TxUnits units, const LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); // Similar to the above set functions, but pulls the value from an existing entry // named 'sourceKey' @@ -113,6 +153,9 @@ class txsummary_decl CTxSummary : extends CInterface // the contents of the summary prior to serialization. virtual void setProfile(ITxSummaryProfile* profile); + // Take ownership of an Open Telemetry connector. Must be set to enable value forwarding. + virtual void setConnector(CTxOpenTelemetryConnector* connector); + protected: // Log the summary contents on destruction. ~CTxSummary(); @@ -273,11 +316,149 @@ class txsummary_decl CTxSummary : extends CInterface unsigned m_creationTime; EntriesInOrder m_entries; Linked m_profile; + Owned connector; +}; + +/** + * @brief Forward trace summary values to currently active Open Telemetry span. + * + * Values are filtered by configured log level and requested group. Values that will be excluded + * from trace summary logging are not forwarded to the span. Additional filtering could be added + * to avoid setting redundant attributes. + * + * Supported value types are signed integers, unsigned integers, doubles, bools, and strings. + * Integer values will be scaled, as needed, based on the given units identifier. Doubles are + * reported as strings to avoid data loss. + * + * Where `CTxSummary` serializes all values to text, this acts only on the original, unserialized, + * values. + */ +class txsummary_decl CTxOpenTelemetryConnector : public CInterface +{ +public: + /** + * @brief Forward an integral or floating point value to an Open Teleemetry span. + * + * Values of non-integral or non-floating point types are ignored. Template specializations + * are used to support other types. + * + * @tparam TValue data type of the value to be forwarded + * @param txKey required key used for trace summary output + * @param otKey optional key used only for Open Telemtry output + * @param value the original value + * @param units indicator of what scaling, if any, is required + * @param logLevel minimum requested log level needed to forward the value + * @param groupMask set of goups that include the value + */ + template + void forwardAttribute(const char* txKey, const char* otKey, TValue value, TxUnits units, LogLevel logLevel, unsigned groupMask) const; + + /** + * @brief Type-specific overload for string values. + * + * @tparam + * @param txKey required key used for trace summary output + * @param otKey optional key used only for Open Telemtry output + * @param value the original value + * @param logLevel minimum requested log level needed to forward the value + * @param groupMask set of goups that include the value + */ + void forwardAttribute(const char* txKey, const char* otKey, const char* value, TxUnits, LogLevel logLevel, unsigned groupMask) const; + + /** + * @brief Type-specific overload for Boolean values. + * + * @tparam + * @param txKey required key used for trace summary output + * @param otKey optional key used only for Open Telemtry output + * @param value the original value + * @param logLevel minimum requested log level needed to forward the value + * @param groupMask set of goups that include the value + */ + void forwardAttribute(const char* txKey, const char* otKey, bool value, TxUnits, LogLevel logLevel, unsigned groupMask) const; + +protected: + /** + * @brief Assemble the correct Open Telemtry attribute name from them input. + * + * An `otKey` value takes precedence over `tcKey`. All keys are converted to snake case. Other + * changes may be applied as needed. + * + * @param txKey required key used for trace summary output + * @param otKey optional key used only for Open Telemtry output + * @param normalized effective key for Open Telemetry output + * @return StringBuffer& the effective key + */ + StringBuffer& normalizeKey(const char* txKey, const char* otKey, StringBuffer& normalized) const; + + /** + * @brief Determine if the value should not be forwarded to Open Telemetry. + * + * A value will be excluded when: + * - `key` is empty; or + * - `logLevel` is greater than the configured trace summary requested log level; or + * - `groupMask` does not include the configured trace summary requested group mask. + * + * Other conditions, such as redundant keys, may be checked here. Redundancy could refer to + * a key being forwarded multiple times, but might also refer to keys known to replicate data + * already in the target span. + * + * @param key normalized value key + * @param logLevel minimum requested log level needed to forward the value + * @param groupMask set of goups that include the value + * @return true when the value is not to be forwarded + * @return false when the value is to be forwarded + */ + bool isExcluded(const char* key, LogLevel logLevel, unsigned groupMask) const; + + void forwardUnsigned(const char* txKey, const char* otKey, uint64_t value, TxUnits units, LogLevel logLevel, unsigned groupMask) const; + void forwardSigned(const char* txKey, const char* otKey, int64_t value, TxUnits units, LogLevel logLevel, unsigned groupMask) const; + void forwardDouble(const char* txKey, const char* otKey, double value, LogLevel logLevel, unsigned groupMask) const; + void forwardBool(const char* txKey, const char* otKey, bool value, LogLevel logLevel, unsigned groupMask) const; + void forwardString(const char* txKey, const char* otKey, const char* value, LogLevel logLevel, unsigned groupMask) const; + + /** + * @brief Apply required arithmetic svaling of values before forwarding. + * + * @tparam TValue data tyoe of the value being scaled, assumed to be integral + * @param value the unscaled value + * @param units indicator of what scaling, if any, is required + * @return TValue potentially scaled value + */ + template + TValue scale(TValue& value, TxUnits units) const; + +private: + IEspContext& context; /// source of the currently active Open Telemetry span + LogLevel maxLogLevel = LogMin; /// configured log level filter constraint + unsigned groupSelector = TXSUMMARY_GRP_CORE; /// configured value group constraint +public: + CTxOpenTelemetryConnector(IEspContext& context); }; template inline bool CTxSummary::append(const char* key, const TValue& value, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) { + return append(key, value, nullptr, TxUnits::NA, logLevel, group, suffix, serializer); +} + +template +inline bool CTxSummary::append(const char* key, const TValue& value, const char* otKey, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +{ + return append(key, value, otKey, TxUnits::NA, logLevel, group, suffix, serializer); +} + +template +inline bool CTxSummary::append(const char* key, const TValue& value, TxUnits units, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +{ + return append(key, value, nullptr, units, logLevel, group, suffix, serializer); +} + +template +inline bool CTxSummary::append(const char* key, const TValue& value, const char* otKey, TxUnits units, LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +{ + if (connector) + connector->forwardAttribute(key, otKey, value, units, logLevel, group); StringBuffer buffer, suffixBuf; serializer.serialize(value, buffer); serializer.serialize(suffix, suffixBuf); @@ -290,6 +471,26 @@ inline bool CTxSummary::append(const char* key, const TValue& value, const LogLe template inline bool CTxSummary::set(const char* key, const TValue& value, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) { + return set(key, value, nullptr, TxUnits::NA, logLevel, group, suffix, serializer); +} + +template +inline bool CTxSummary::set(const char* key, const TValue& value, const char* otKey, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +{ + return set(key, value, otKey, TxUnits::NA, logLevel, group, suffix, serializer); +} + +template +inline bool CTxSummary::set(const char* key, const TValue& value, TxUnits units, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +{ + return set(key, value, nullptr, units, logLevel, group, suffix, serializer); +} + +template +inline bool CTxSummary::set(const char* key, const TValue& value, const char* otKey, TxUnits units, LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +{ + if (connector) + connector->forwardAttribute(key, otKey, value, units, logLevel, group); StringBuffer buffer, suffixBuf; serializer.serialize(value, buffer); serializer.serialize(suffix, suffixBuf); @@ -299,6 +500,44 @@ inline bool CTxSummary::set(const char* key, const TValue& value, const LogLevel return setSerialized(key, serializer.str(buffer), logLevel, group, shouldQuote, serializer.str(suffixBuf)); } +template +inline void CTxOpenTelemetryConnector::forwardAttribute(const char* txKey, const char* otKey, TValue value, TxUnits units, LogLevel logLevel, unsigned groupMask) const +{ + if (std::is_unsigned()) + forwardUnsigned(txKey, otKey, value, units, logLevel, groupMask); + else if (std::is_signed()) + forwardSigned(txKey, otKey, value, units, logLevel, groupMask); + else if (std::is_floating_point()) + forwardDouble(txKey, otKey, value, logLevel, groupMask); +} + +inline void CTxOpenTelemetryConnector::forwardAttribute(const char* txKey, const char* otKey, const char* value, TxUnits, LogLevel logLevel, unsigned groupMask) const +{ + forwardString(txKey, otKey, value, logLevel, groupMask); +} + +inline void CTxOpenTelemetryConnector::forwardAttribute(const char* txKey, const char* otKey, bool value, TxUnits, LogLevel logLevel, unsigned groupMask) const +{ + forwardBool(txKey, otKey, value, logLevel, groupMask); +} + +template +inline TValue CTxOpenTelemetryConnector::scale(TValue& value, TxUnits units) const +{ + switch (units) + { + case TxUnits::NA: + break; + case TxUnits::millis: + value *= 1000000; + break; + default: + IERRLOG("unhandled TxUnits %d for value scaling", int(units)); + break; + } + return value; +} + class txsummary_decl TxSummaryMapVal { public: @@ -376,5 +615,4 @@ class txsummary_decl CTxSummaryProfileBase : public CInterface, implements ITxSu NameToMapVal mapping; }; - #endif // TXSUMMARY_HPP diff --git a/esp/services/esdl_svc_engine/esdl_binding.cpp b/esp/services/esdl_svc_engine/esdl_binding.cpp index 54783bfafb4..cf7c461bd4a 100755 --- a/esp/services/esdl_svc_engine/esdl_binding.cpp +++ b/esp/services/esdl_svc_engine/esdl_binding.cpp @@ -1573,6 +1573,7 @@ void EsdlServiceImpl::sendTargetSOAP(IEspContext & context, ISpan * activeSpan = context.queryActiveSpan(); OwnedSpanScope clientSpan(activeSpan->createClientSpan("soapcall")); + ContextSpanScopeImp clientSpanScope(context, clientSpan); Owned headers = ::getClientHeaders(clientSpan); StringBuffer status;