feat(telemetry): add event-with-attributes overload to ScopedSpanGuard

Only SpanGuard carried addEvent(name, attrs), so a call site holding a scoped
guard could not record an event attribute. Forwarding overload, with the no-op
twin in the telemetry-disabled stub, so a span can be converted between scoped
and unscoped without dropping the attributes on its events.
This commit is contained in:
Pratik Mankawde
2026-09-23 13:49:03 +01:00
parent 0b0534af5e
commit 7d21baf558
3 changed files with 48 additions and 0 deletions

View File

@@ -918,6 +918,15 @@ public:
void
addEvent(std::string_view name) noexcept;
/**
* Add a named event with key-value attributes to the span's timeline.
* No-op on a null guard.
* @param name Event name.
* @param attrs Attribute pairs (all string_view for simplicity).
*/
void
addEvent(std::string_view name, std::initializer_list<EventAttribute> attrs) noexcept;
/**
* Record an exception as a span event and mark status as error.
* No-op on a null guard.
@@ -1355,6 +1364,10 @@ public:
{
}
void
addEvent(std::string_view, std::initializer_list<EventAttribute>) noexcept
{
}
void
recordException(std::exception const&) noexcept
{
}

View File

@@ -863,6 +863,14 @@ ScopedSpanGuard::addEvent(std::string_view name) noexcept
impl_->guard.addEvent(name);
}
void
ScopedSpanGuard::addEvent(
std::string_view name,
std::initializer_list<EventAttribute> attrs) noexcept
{
impl_->guard.addEvent(name, attrs);
}
void
ScopedSpanGuard::recordException(std::exception const& e) noexcept
{

View File

@@ -661,6 +661,33 @@ TEST_F(SpanGuardScopeTest, spanGuard_addEvent_without_attributes_records_bare_ev
EXPECT_EQ(events.front().GetAttributes().size(), 0u);
}
// The scoped guard records event attributes too. consensus.accept.apply relies
// on it for one tx.included event per transaction of the accepted set.
TEST_F(SpanGuardScopeTest, scopedGuard_addEvent_records_name_and_attribute_values)
{
namespace cs = consensus::span;
static constexpr std::string_view kEventName{cs::event::txIncluded};
static constexpr std::string_view kTxIdKey{cs::attr::txId};
static constexpr std::string_view kTxId{"6B5F1A2C3D4E5F60718293A4B5C6D7E8"};
{
ScopedSpanGuard guard(TraceCategory::Consensus, seg::consensus, cs::op::acceptApply);
ASSERT_TRUE(static_cast<bool>(guard));
guard.addEvent(kEventName, {{kTxIdKey, kTxId}});
}
auto spans = spanData()->GetSpans();
auto* applySpan = findSpan(spans, cs::acceptApply);
ASSERT_NE(applySpan, nullptr);
auto const& events = applySpan->GetEvents();
ASSERT_EQ(events.size(), 1u);
EXPECT_EQ(events.front().GetName(), std::string(kEventName));
EXPECT_EQ(events.front().GetAttributes().size(), 1u);
EXPECT_EQ(eventAttribute(events.front(), kTxIdKey), std::string(kTxId));
}
// A forced-root span started while a PendingTraceId is active adopts that
// pinned 16-byte trace_id and remains a true root (no parent).
TEST_F(SpanGuardScopeTest, deterministicIdGenerator_forced_root_gets_pending_trace_id)