diff --git a/esp/platform/esp.hpp b/esp/platform/esp.hpp index 65c3008f412..2d626778160 100644 --- a/esp/platform/esp.hpp +++ b/esp/platform/esp.hpp @@ -91,8 +91,12 @@ typedef enum LogRequest_ #define TXSUMMARY_GRP_CORE 0x00000001 #define TXSUMMARY_GRP_ENTERPRISE 0x00000002 +/// Generate original trace summary contnet. #define TXSUMMARY_OUT_TEXT 0x00000001 +/// Generate JSON-formatted trace summary content. #define TXSUMMARY_OUT_JSON 0x00000002 +/// Forward cumulative timer values to a JTrace span using the serialization interface. No serialization. +#define TXSUMMARY_FWD_TIMERS 0x80000000 #define ESPCTX_NO_NAMESPACES 0x00000001 #define ESPCTX_WSDL 0x00000010 @@ -104,6 +108,7 @@ class CTxSummary; interface IEspSecureContext; interface IEspSecureContextEx; class CumulativeTimer; +enum class SummaryValueUnits; interface IEspContext : extends IInterface { @@ -197,9 +202,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* spanAttrName, 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* spanAttrName, unsigned group = TXSUMMARY_GRP_CORE)=0; + virtual void addTraceSummaryValue(unsigned logLevel, const char *name, __int64 value, SummaryValueUnits units, unsigned group = TXSUMMARY_GRP_CORE)=0; + virtual void addTraceSummaryValue(unsigned logLevel, const char *name, __int64 value, const char* spanAttrName, SummaryValueUnits 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* spanAttrName, 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* spanAttrName, 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; diff --git a/esp/platform/espcontext.cpp b/esp/platform/espcontext.cpp index ea2c90f2d23..77311fc46a5 100755 --- a/esp/platform/espcontext.cpp +++ b/esp/platform/espcontext.cpp @@ -123,7 +123,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_TIMERS); } } virtual void addOptions(unsigned opts){options|=opts;} @@ -512,28 +512,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* spanAttrName, const unsigned int group = TXSUMMARY_GRP_CORE) { if (m_txSummary && !isEmptyString(name)) - m_txSummary->append(name, value, logLevel, group); + m_txSummary->append(name, value, spanAttrName, SummaryValueUnits::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, SummaryValueUnits::NA, group); + } + + virtual void addTraceSummaryValue(LogLevel logLevel, const char *name, __int64 value, const char* spanAttrName, unsigned group = TXSUMMARY_GRP_CORE) override + { + addTraceSummaryValue(logLevel, name, value, spanAttrName, SummaryValueUnits::NA, group); + } + + virtual void addTraceSummaryValue(LogLevel logLevel, const char *name, __int64 value, SummaryValueUnits 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* spanAttrName, SummaryValueUnits units, unsigned group = TXSUMMARY_GRP_CORE) override { if (m_txSummary && !isEmptyString(name)) - m_txSummary->append(name, value, logLevel, group); + m_txSummary->append(name, value, spanAttrName, 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* spanAttrName, unsigned group = TXSUMMARY_GRP_CORE) { if (m_txSummary && !isEmptyString(name)) - m_txSummary->append(name, value, logLevel, group); + m_txSummary->append(name, value, spanAttrName, SummaryValueUnits::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* spanAttrName, 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(), spanAttrName, SummaryValueUnits::millis, logLevel, group, "ms"); } + virtual void flushTraceSummary() { updateTraceSummaryHeader(); diff --git a/esp/platform/txsummary.cpp b/esp/platform/txsummary.cpp index 37c9df7621c..30cbc434a77 100755 --- a/esp/platform/txsummary.cpp +++ b/esp/platform/txsummary.cpp @@ -28,6 +28,21 @@ static auto pRequestCount = hpccMetrics::registerCounterMetric("esp.requests.received", "Number of requests received", SMeasureCount); #endif +namespace +{ + // Summary entries iterated for serialization lack awareness of the summary that contains them. + // Forwarding cumulative timers, which piggy-backs on the serialization logic, needs to know + // the summary's span forawarder. The forwarder is set immediately beforo, and cleared after, + // the forwarding iteration. + static thread_local CTxSummarySpanForwarder* spanForwarder = nullptr; + + struct ForwarderScope + { + ForwarderScope(CTxSummarySpanForwarder* forwarder) { spanForwarder = forwarder; } + ~ForwarderScope() { spanForwarder = nullptr; } + }; +} + inline bool validate(const char* k) { // Empty or null keys are invalid @@ -126,6 +141,11 @@ StringBuffer& CTxSummary::TxEntryTimer::serialize(StringBuffer& buf, const LogLe buf.append(fullname); buf.appendf("=%" I64F "u;", value->getTotalMillis()); } + else if (requestedStyle & TXSUMMARY_FWD_TIMERS) + { + if (spanForwarder) + spanForwarder->forwardAttribute(name, nullptr, value->getTotalMillis(), SummaryValueUnits::millis, queryLogLevel(), queryGroup()); + } return buf; } @@ -332,6 +352,7 @@ StringBuffer& CTxSummary::TxEntryObject::serialize(StringBuffer& buf, const LogL CTxSummary::CTxSummary(unsigned creationTime) : m_creationTime(creationTime ? creationTime : msTick()) +, forwarder(new CTxSummarySpanForwarder) { #ifdef _SOLVED_DYNAMIC_METRIC_PROBLEM pRequestCount->inc(1); @@ -591,6 +612,14 @@ 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_TIMERS) + { + // String values have already been forwarded and should ignore this serialization + // request. Timer values have not been forwarded, and should forward their values. + ForwarderScope scope(forwarder); + serialize(summary.clear(), logLevel, requestedGroup, TXSUMMARY_FWD_TIMERS); + } } } @@ -663,3 +692,80 @@ CTxSummary::TxEntryBase* CTxSummary::queryEntry(const char* key) return nullptr; } + +ISpan* CTxSummarySpanForwarder::prepareToForward(const char* summaryKey, const char* spanKey, StringBuffer& actualKey, LogLevel logLevel, unsigned groupMask) const +{ + if (!isExcluded(normalizeKey(summaryKey, spanKey, actualKey), logLevel, groupMask)) + { + ISpan* target = queryThreadedActiveSpan(); + if (target && target->isRecording()) + return target; + } + return nullptr; +} + +StringBuffer& CTxSummarySpanForwarder::normalizeKey(const char* summaryKey, const char* spanKey, StringBuffer& actualKey) const +{ + getSnakeCase(actualKey, isEmptyString(spanKey) ? summaryKey : spanKey); + // Keys for custom attributes may be annotated to reflect the source here. + return actualKey; +} + +bool CTxSummarySpanForwarder::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; +} + +void CTxSummarySpanForwarder::forwardUnsigned(const char* summaryKey, const char* spanKey, uint64_t value, SummaryValueUnits units, LogLevel logLevel, unsigned groupMask) const +{ + StringBuffer attrName; + ISpan* target = prepareToForward(summaryKey, spanKey, attrName, logLevel, groupMask); + if (target) + target->setSpanAttribute(attrName, scale(value, units)); +} + +void CTxSummarySpanForwarder::forwardSigned(const char* summaryKey, const char* spanKey, int64_t value, SummaryValueUnits units, LogLevel logLevel, unsigned groupMask) const +{ + StringBuffer attrName; + ISpan* target = prepareToForward(summaryKey, spanKey, attrName, logLevel, groupMask); + if (target) + target->setSpanAttribute(attrName, uint64_t(scale(value, units))); +} + +void CTxSummarySpanForwarder::forwardDouble(const char* summaryKey, const char* spanKey, double value, LogLevel logLevel, unsigned groupMask) const +{ + StringBuffer attrName; + ISpan* target = prepareToForward(summaryKey, spanKey, attrName, logLevel, groupMask); + if (target) + { + StringBuffer tmp; + tmp.append(value); + target->setSpanAttribute(attrName, tmp); + } +} + +void CTxSummarySpanForwarder::forwardBool(const char* summaryKey, const char* spanKey, bool value, LogLevel logLevel, unsigned groupMask) const +{ + StringBuffer attrName; + ISpan* target = prepareToForward(summaryKey, spanKey, attrName, logLevel, groupMask); + if (target) + target->setSpanAttribute(attrName, uint64_t(value)); +} + +void CTxSummarySpanForwarder::forwardString(const char* summaryKey, const char* spanKey, const char* value, LogLevel logLevel, unsigned groupMask) const +{ + StringBuffer attrName; + ISpan* target = prepareToForward(summaryKey, spanKey, attrName, logLevel, groupMask); + if (target) + target->setSpanAttribute(attrName, value); +} + +CTxSummarySpanForwarder::CTxSummarySpanForwarder() + : maxLogLevel(getTxSummaryLevel()) + , groupSelector(getTxSummaryGroup()) +{ +} diff --git a/esp/platform/txsummary.hpp b/esp/platform/txsummary.hpp index 88370fb8a54..793ded32b1f 100755 --- a/esp/platform/txsummary.hpp +++ b/esp/platform/txsummary.hpp @@ -32,7 +32,7 @@ // Using the existing esp_cfg_decl in this package required including // espcfg.ipp which has additional includes that weren't found by all -// other packagates including txsummary.hpp, triggering changes to +// other packages including txsummary.hpp, triggering changes to // several other CMakeLists.txt files. This seemed cleaner. #ifdef TXSUMMARY_EXPORTS #define txsummary_decl DECL_EXPORT @@ -41,6 +41,25 @@ #endif interface ITxSummaryProfile; +class CTxSummarySpanForwarder; + +/** + * @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 SummaryValueUnits +{ + 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* summaryKey, 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 LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); + bool append(const char* summaryKey, const TValue& value, const char* spanKey, LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); + template + bool append(const char* summaryKey, const TValue& value, SummaryValueUnits units, LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); + template + bool append(const char* summaryKey, const TValue& value, const char* spanKey, SummaryValueUnits 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* summaryKey, 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 LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); + bool set(const char* summaryKey, const TValue& value, const char* spanKey, const LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); + template + bool set(const char* summaryKey, const TValue& value, SummaryValueUnits units, const LogLevel logLevel = LogMin, const unsigned int group = TXSUMMARY_GRP_CORE, const TSuffix& suffix = "", const TSerializer& serializer = TSerializer()); + template + bool set(const char* summaryKey, const TValue& value, const char* spanKey, SummaryValueUnits 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' @@ -273,30 +313,225 @@ class txsummary_decl CTxSummary : extends CInterface unsigned m_creationTime; EntriesInOrder m_entries; Linked m_profile; + Owned forwarder; }; +/** + * @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 CTxSummarySpanForwarder : 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 summaryKey required key used for trace summary output + * @param spanKey optional key used only for Open Telemetry 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* summaryKey, const char* spanKey, TValue value, SummaryValueUnits units, LogLevel logLevel, unsigned groupMask) const; + + /** + * @brief Type-specific overload for string values. + * + * @tparam + * @param summaryKey required key used for trace summary output + * @param spanKey optional key used only for Open Telemetry 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* summaryKey, const char* spanKey, const char* value, SummaryValueUnits, LogLevel logLevel, unsigned groupMask) const; + + /** + * @brief Type-specific overload for Boolean values. + * + * @tparam + * @param summaryKey required key used for trace summary output + * @param spanKey optional key used only for Open Telemetry 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* summaryKey, const char* spanKey, bool value, SummaryValueUnits, LogLevel logLevel, unsigned groupMask) const; + +protected: + ISpan* prepareToForward(const char* summaryKey, const char* spanKey, StringBuffer& actualKey, LogLevel logLevel, unsigned groupMask) const; + + /** + * @brief Assemble the correct Open Telemetry attribute name from them input. + * + * An `spanKey` value takes precedence over `summaryKey`. All keys are converted to snake case. + * Other changes may be applied as needed. + * + * @param summaryKey required key used for trace summary output + * @param spanKey optional key used only for Open Telemetry output + * @param actualKey effective key for Open Telemetry output + * @return StringBuffer& the effective key + */ + StringBuffer& normalizeKey(const char* summaryKey, const char* spanKey, StringBuffer& actualKey) 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* summaryKey, const char* spanKey, uint64_t value, SummaryValueUnits units, LogLevel logLevel, unsigned groupMask) const; + void forwardSigned(const char* summaryKey, const char* spanKey, int64_t value, SummaryValueUnits units, LogLevel logLevel, unsigned groupMask) const; + void forwardDouble(const char* summaryKey, const char* spanKey, double value, LogLevel logLevel, unsigned groupMask) const; + void forwardBool(const char* summaryKey, const char* spanKey, bool value, LogLevel logLevel, unsigned groupMask) const; + void forwardString(const char* summaryKey, const char* spanKey, 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, SummaryValueUnits units) const; + +private: + LogLevel maxLogLevel = LogMin; /// configured log level filter constraint + unsigned groupSelector = TXSUMMARY_GRP_CORE; /// configured value group constraint +public: + CTxSummarySpanForwarder(); +}; + +template +inline bool CTxSummary::append(const char* summaryKey, const TValue& value, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +{ + return append(summaryKey, value, nullptr, SummaryValueUnits::NA, logLevel, group, suffix, serializer); +} + template -inline bool CTxSummary::append(const char* key, const TValue& value, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +inline bool CTxSummary::append(const char* summaryKey, const TValue& value, const char* spanKey, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) { + return append(summaryKey, value, spanKey, SummaryValueUnits::NA, logLevel, group, suffix, serializer); +} + +template +inline bool CTxSummary::append(const char* summaryKey, const TValue& value, SummaryValueUnits units, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +{ + return append(summaryKey, value, nullptr, units, logLevel, group, suffix, serializer); +} + +template +inline bool CTxSummary::append(const char* summaryKey, const TValue& value, const char* spanKey, SummaryValueUnits units, LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +{ + forwarder->forwardAttribute(summaryKey, spanKey, value, units, logLevel, group); StringBuffer buffer, suffixBuf; serializer.serialize(value, buffer); serializer.serialize(suffix, suffixBuf); bool shouldQuote = true; if(std::is_arithmetic()) shouldQuote = false; - return appendSerialized(key, serializer.str(buffer), logLevel, group, shouldQuote, serializer.str(suffixBuf)); + return appendSerialized(summaryKey, serializer.str(buffer), logLevel, group, shouldQuote, serializer.str(suffixBuf)); +} + +template +inline bool CTxSummary::set(const char* summaryKey, const TValue& value, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +{ + return set(summaryKey, value, nullptr, SummaryValueUnits::NA, logLevel, group, suffix, serializer); +} + +template +inline bool CTxSummary::set(const char* summaryKey, const TValue& value, const char* spanKey, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +{ + return set(summaryKey, value, spanKey, SummaryValueUnits::NA, logLevel, group, suffix, serializer); +} + +template +inline bool CTxSummary::set(const char* summaryKey, const TValue& value, SummaryValueUnits units, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +{ + return set(summaryKey, value, nullptr, units, logLevel, group, suffix, serializer); } template -inline bool CTxSummary::set(const char* key, const TValue& value, const LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) +inline bool CTxSummary::set(const char* summaryKey, const TValue& value, const char* spanKey, SummaryValueUnits units, LogLevel logLevel, const unsigned int group, const TSuffix& suffix, const TSerializer& serializer) { + forwarder->forwardAttribute(summaryKey, spanKey, value, units, logLevel, group); StringBuffer buffer, suffixBuf; serializer.serialize(value, buffer); serializer.serialize(suffix, suffixBuf); bool shouldQuote = true; if(std::is_arithmetic()) shouldQuote = false; - return setSerialized(key, serializer.str(buffer), logLevel, group, shouldQuote, serializer.str(suffixBuf)); + return setSerialized(summaryKey, serializer.str(buffer), logLevel, group, shouldQuote, serializer.str(suffixBuf)); +} + +template +inline void CTxSummarySpanForwarder::forwardAttribute(const char* summaryKey, const char* spanKey, TValue value, SummaryValueUnits units, LogLevel logLevel, unsigned groupMask) const +{ + if (std::is_unsigned()) + forwardUnsigned(summaryKey, spanKey, value, units, logLevel, groupMask); + else if (std::is_signed()) + forwardSigned(summaryKey, spanKey, value, units, logLevel, groupMask); + else if (std::is_floating_point()) + forwardDouble(summaryKey, spanKey, value, logLevel, groupMask); +} + +inline void CTxSummarySpanForwarder::forwardAttribute(const char* summaryKey, const char* spanKey, const char* value, SummaryValueUnits, LogLevel logLevel, unsigned groupMask) const +{ + forwardString(summaryKey, spanKey, value, logLevel, groupMask); +} + +inline void CTxSummarySpanForwarder::forwardAttribute(const char* summaryKey, const char* spanKey, bool value, SummaryValueUnits, LogLevel logLevel, unsigned groupMask) const +{ + forwardBool(summaryKey, spanKey, value, logLevel, groupMask); +} + +template +inline TValue CTxSummarySpanForwarder::scale(TValue& value, SummaryValueUnits units) const +{ + switch (units) + { + case SummaryValueUnits::NA: + break; + case SummaryValueUnits::millis: + value *= 1000000; + break; + default: + IERRLOG("unhandled SummaryValueUnits %d for value scaling", int(units)); + break; + } + return value; } class txsummary_decl TxSummaryMapVal @@ -376,5 +611,4 @@ class txsummary_decl CTxSummaryProfileBase : public CInterface, implements ITxSu NameToMapVal mapping; }; - #endif // TXSUMMARY_HPP