aboutsummaryrefslogtreecommitdiff
path: root/src/zentelemetry
diff options
context:
space:
mode:
authorLiam Mitchell <[email protected]>2026-03-09 18:25:30 -0700
committerLiam Mitchell <[email protected]>2026-03-09 18:25:30 -0700
commit57c1683b2935c834250b73eb506319ed67946160 (patch)
tree1fc8f237010b26e65659b731fe6f6eae30422f5c /src/zentelemetry
parentAllow external OidcToken executable to be specified unless disabled via comma... (diff)
parentreduce lock time for project store gc precache and gc validate (#750) (diff)
downloadzen-57c1683b2935c834250b73eb506319ed67946160.tar.xz
zen-57c1683b2935c834250b73eb506319ed67946160.zip
Merge branch 'main' into lm/oidctoken-exe-path
Diffstat (limited to 'src/zentelemetry')
-rw-r--r--src/zentelemetry/include/zentelemetry/otlptrace.h130
-rw-r--r--src/zentelemetry/otlptrace.cpp13
2 files changed, 127 insertions, 16 deletions
diff --git a/src/zentelemetry/include/zentelemetry/otlptrace.h b/src/zentelemetry/include/zentelemetry/otlptrace.h
index f191241ed..49dd90358 100644
--- a/src/zentelemetry/include/zentelemetry/otlptrace.h
+++ b/src/zentelemetry/include/zentelemetry/otlptrace.h
@@ -4,6 +4,7 @@
#include <zenbase/refcount.h>
#include <zencore/memcmp.h>
+#include <zencore/string.h>
#include <zencore/uid.h>
#include <span>
@@ -27,12 +28,26 @@ class MemoryArena;
namespace zen::otel {
-using AttributeList = std::span<std::pair<std::string, std::string>>;
+using AttributeList = std::span<std::pair<std::string_view, std::string_view>>;
class Tracer;
-// OLTP Span ID
+/** Check if OTLP tracing is enabled
+ *
+ * This can be used to avoid unnecessary work when tracing is disabled.
+ *
+ * In many cases it is preferable and more convenient to use the ScopedSpan
+ * constructor which takes a naming function to avoid string formatting work
+ * when tracing is disabled.
+ */
+bool IsOtlpTraceEnabled();
+/** OTLP Span ID
+ *
+ * A SpanId is an 8-byte identifier for a span within a trace. It's not something
+ * that should be interpreted or manipulated directly, but it can be used
+ * for correlating spans during analysis.
+ */
struct SpanId
{
constexpr static size_t kSize = 8;
@@ -60,7 +75,12 @@ private:
uint8_t Id[kSize];
};
-// OLTP Trace ID
+/** OTLP Trace ID
+ *
+ * A TraceId is a 16-byte identifier for a trace. It's not something
+ * that should be interpreted or manipulated directly, but it can be used
+ * for correlating traces during analysis.
+ */
struct TraceId
{
@@ -68,23 +88,35 @@ struct TraceId
std::span<const uint8_t> GetBytes() const { return std::span<const uint8_t>(Id, kSize); }
- inline TraceId() noexcept : Id{0} {}
+ inline TraceId() noexcept { memset(Id, 0, kSize); }
explicit TraceId(const std::span<const uint8_t, kSize> Bytes) noexcept { std::copy(Bytes.begin(), Bytes.end(), Id); }
std::strong_ordering operator<=>(const TraceId& Rhs) const noexcept
{
- int cmp = MemCmpFixed<kSize>(Id, Rhs.Id);
- if (cmp < 0)
+ if (int Diff = MemCmpFixed<kSize>(Id, Rhs.Id); Diff < 0)
+ {
return std::strong_ordering::less;
- if (cmp > 0)
+ }
+ else if (Diff > 0)
+ {
return std::strong_ordering::greater;
- return std::strong_ordering::equal;
+ }
+ else
+ {
+ return std::strong_ordering::equal;
+ }
}
+
inline operator bool() const
{
return !(reinterpret_cast<const uint64_t*>(Id)[0] == 0 && reinterpret_cast<const uint64_t*>(Id)[1] == 0);
}
+ // Generates a new TraceId. The current scheme uses the session ID
+ // as the first 12 bytes, and a counter for the last 4 bytes. This makes
+ // it more likely that traces from the same session can be correlated, and
+ // should make indexes more efficient since the identifiers will be emitted
+ // in a mostly (lexically) increasing order.
static TraceId NewTraceId();
inline const char* GetData() const { return reinterpret_cast<const char*>(Id); }
@@ -93,6 +125,17 @@ private:
uint8_t Id[kSize];
};
+/** OTEL attribute key-value pair
+ *
+ * An AttributePair is a key-value pair that provides additional information
+ * about a span or event. This class is intended to support a variety of
+ * value types, but currently only supports string and integer values.
+ *
+ * This is an internal structure used by the Span class, which encodes
+ * the key-value pair efficiently. Each instance is allocated within
+ * a MemoryArena associated with the trace and will be freed without
+ * explicit deallocation when the arena is destroyed.
+ */
struct AttributePair
{
const char* Key = nullptr;
@@ -129,6 +172,12 @@ struct AttributePair
AttributePair* Next = nullptr;
};
+/** OTEL event
+ *
+ * An event represents a time-stamped annotation of the span, consisting
+ * of a name and optional attributes.
+ *
+ */
struct Event
{
Event* NextEvent = nullptr;
@@ -142,6 +191,10 @@ struct Event
* A span represents a single operation within a trace. Spans can be nested
* to form a trace tree.
*
+ * This class is reference counted in order to support spans which may
+ * cross thread boundaries. A single span may be referenced by multiple threads
+ * and will be finalized when the last reference is released.
+ *
*/
struct Span final : public TRefCounted<Span>
@@ -225,7 +278,21 @@ private:
class ScopedSpan final
{
public:
+ /** Create a new scoped span
+ *
+ * @param Name Name of the span
+ */
ScopedSpan(std::string_view Name);
+
+ /** Create a new scoped span with an initializer function
+ *
+ * This allows initializing the span (e.g. adding attributes etc) in a safe way
+ * that avoids unnecessary work when OTLP tracing is disabled.
+ *
+ * @param Name Name of the span
+ * @param InitializerFunction Function which is called with the newly created span
+ * so that it can be initialized (e.g. adding attributes etc)
+ */
ScopedSpan(std::string_view Name, std::invocable<Span&> auto&& InitializerFunction) : ScopedSpan(Name)
{
if (m_Span)
@@ -233,6 +300,43 @@ public:
InitializerFunction(*m_Span);
}
}
+
+ /** Construct a new span with a naming function
+ *
+ * The naming function will only be called if OTLP tracing is enabled. This can be
+ * used to avoid unnecessary string formatting when tracing is disabled.
+ *
+ * @param NamingFunction Function which is called with a string builder to create the span name
+ */
+ ScopedSpan(std::invocable<StringBuilderBase&> auto&& NamingFunction)
+ {
+ if (!IsOtlpTraceEnabled())
+ {
+ return;
+ }
+
+ ExtendableStringBuilder<128> NameBuilder;
+ NamingFunction(NameBuilder);
+ }
+
+ /** Construct a new span with a naming function AND initializer function
+ *
+ * Both functions will only be called if OTLP tracing is enabled. This can be
+ * used to avoid unnecessary string formatting and span initialization related work
+ * when tracing.
+ *
+ * @param NamingFunction Function which is called with a string builder to create the span name
+ * @param InitializerFunction Function which is called with the newly created span
+ * so that it can be initialized (e.g. adding attributes etc)
+ */
+ ScopedSpan(std::invocable<StringBuilderBase&> auto&& NamingFunction, std::invocable<Span&> auto&& InitializerFunction)
+ : ScopedSpan(NamingFunction)
+ {
+ if (m_Span)
+ {
+ InitializerFunction(*m_Span);
+ }
+ }
ScopedSpan() = delete;
~ScopedSpan();
@@ -241,11 +345,15 @@ public:
ScopedSpan(ScopedSpan&& Rhs) = default;
ScopedSpan(const ScopedSpan& Rhs) = default;
- operator bool() const { return !!m_Span; }
- void WithSpan(auto Func) const { Func(*m_Span); }
+ // Check if the span is valid (i.e OTLP tracing is enabled)
+ inline explicit operator bool() const { return !!m_Span; }
+
+ // Execute a function with the span pointer if valid. This can
+ // be used to add attributes or events to the span after creation
+ inline void WithSpan(auto Func) const { Func(*m_Span); }
private:
- ScopedSpan(Span* InSpan, Tracer* InTracer);
+ void Initialize(std::string_view Name);
Ref<Tracer> m_Tracer; // This needs to precede the span ref to ensure proper destruction order
Ref<Span> m_Span;
diff --git a/src/zentelemetry/otlptrace.cpp b/src/zentelemetry/otlptrace.cpp
index f987afcfe..6a095cfeb 100644
--- a/src/zentelemetry/otlptrace.cpp
+++ b/src/zentelemetry/otlptrace.cpp
@@ -273,7 +273,7 @@ IsRecording()
std::atomic<bool> g_OtlpTraceEnabled{false};
-inline bool
+bool
IsOtlpTraceEnabled()
{
return g_OtlpTraceEnabled.load();
@@ -346,6 +346,12 @@ ScopedSpan::ScopedSpan(std::string_view Name)
return;
}
+ Initialize(Name);
+}
+
+void
+ScopedSpan::Initialize(std::string_view Name)
+{
Tracer* TracerPtr = Tracer::GetTracer();
Tracer::Impl* const ImplPtr = TracerPtr->m_Impl;
@@ -359,12 +365,9 @@ ScopedSpan::ScopedSpan(std::string_view Name)
m_Span = NewSpan;
}
-ScopedSpan::ScopedSpan(Span* InSpan, Tracer* InTracer) : m_Tracer(InTracer), m_Span(InSpan)
-{
-}
-
ScopedSpan::~ScopedSpan()
{
+ // this is not inline to avoid code bloat on every use site
}
} // namespace zen::otel