Skip to content

Commit

Permalink
Use a SpanId class to wrap the span id rather than just a uint64_T
Browse files Browse the repository at this point in the history
  • Loading branch information
jasnell committed Dec 6, 2024
1 parent fd43f7d commit 3590bec
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 21 deletions.
16 changes: 8 additions & 8 deletions src/workerd/io/trace-test.c++
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ KJ_TEST("InvocationSpanContext") {
static constexpr auto kCheck = TraceId(0x2a2a2a2a2a2a2a2a, 0x2a2a2a2a2a2a2a2a);
KJ_EXPECT(sc->getTraceId() == kCheck);
KJ_EXPECT(sc->getInvocationId() == kCheck);
KJ_EXPECT(sc->getSpanId() == 0);
KJ_EXPECT(sc->getSpanId() == SpanId(1));

// And serialize that to a capnp struct...
capnp::MallocMessageBuilder builder;
Expand All @@ -104,32 +104,32 @@ KJ_TEST("InvocationSpanContext") {
auto sc2 = KJ_ASSERT_NONNULL(InvocationSpanContext::fromCapnp(root.asReader()));
KJ_EXPECT(sc2->getTraceId() == kCheck);
KJ_EXPECT(sc2->getInvocationId() == kCheck);
KJ_EXPECT(sc2->getSpanId() == 0);
KJ_EXPECT(sc2->getSpanId() == SpanId(1));
KJ_EXPECT(sc2->isTrigger());

// The one that has been deserialized from capnp cannot create children...
try {
sc2->newChild();
KJ_FAIL_ASSERT("should not be able to create child span with SpanContext from capnp");
} catch (kj::Exception& ex) {
// KJ_EXPECT(ex.getDescription() ==
// "expected !isTrigger(); unable to create child spans on this context"_kj);
KJ_EXPECT(ex.getDescription() ==
"expected !isTrigger(); unable to create child spans on this context"_kj);
}

auto sc3 = sc->newChild();
KJ_EXPECT(sc3->getTraceId() == kCheck);
KJ_EXPECT(sc3->getInvocationId() == kCheck);
KJ_EXPECT(sc3->getSpanId() == 1);
KJ_EXPECT(sc3->getSpanId() == SpanId(2));

auto sc4 = InvocationSpanContext::newForInvocation(sc2);
auto sc4 = InvocationSpanContext::newForInvocation(sc2, fakeEntropySource);
KJ_EXPECT(sc4->getTraceId() == kCheck);
KJ_EXPECT(sc4->getInvocationId() == kCheck);
KJ_EXPECT(sc4->getSpanId() == 0);
KJ_EXPECT(sc4->getSpanId() == SpanId(3));

auto& sc5 = KJ_ASSERT_NONNULL(sc4->getParent());
KJ_EXPECT(sc5->getTraceId() == kCheck);
KJ_EXPECT(sc5->getInvocationId() == kCheck);
KJ_EXPECT(sc5->getSpanId() == 0);
KJ_EXPECT(sc5->getSpanId() == SpanId(1));
KJ_EXPECT(sc5->isTrigger());
}

Expand Down
32 changes: 24 additions & 8 deletions src/workerd/io/trace.c++
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,21 @@ TraceId TraceId::fromEntropy(kj::Maybe<kj::EntropySource&> entropySource) {
return TraceId(getRandom64Bit(entropySource), getRandom64Bit(entropySource));
}

kj::String SpanId::toGoString() const {
kj::Vector<char> s(16);
addHex(s, id);
s.add('\0');
return kj::String(s.releaseAsArray());
}

SpanId SpanId::fromEntropy(kj::Maybe<kj::EntropySource&> entropySource) {
return SpanId(getRandom64Bit(entropySource));
}

kj::String KJ_STRINGIFY(const SpanId& id) {
return id;
}

kj::String KJ_STRINGIFY(const TraceId& id) {
return id;
}
Expand All @@ -162,18 +177,18 @@ InvocationSpanContext::InvocationSpanContext(kj::Badge<InvocationSpanContext>,
kj::Maybe<kj::EntropySource&> entropySource,
TraceId traceId,
TraceId invocationId,
uint64_t spanId,
SpanId spanId,
kj::Maybe<kj::Rc<InvocationSpanContext>> parentSpanContext)
: entropySource(entropySource),
traceId(kj::mv(traceId)),
invocationId(kj::mv(invocationId)),
spanId(spanId),
spanId(kj::mv(spanId)),
parentSpanContext(kj::mv(parentSpanContext)) {}

kj::Rc<InvocationSpanContext> InvocationSpanContext::newChild() {
KJ_ASSERT(!isTrigger(), "unable to create child spans on this context");
return kj::rc<InvocationSpanContext>(kj::Badge<InvocationSpanContext>(), entropySource, traceId,
invocationId, getRandom64Bit(entropySource), addRefToThis());
invocationId, SpanId::fromEntropy(entropySource), addRefToThis());
}

kj::Rc<InvocationSpanContext> InvocationSpanContext::newForInvocation(
Expand All @@ -186,7 +201,8 @@ kj::Rc<InvocationSpanContext> InvocationSpanContext::newForInvocation(
return ctx->traceId;
}).orDefault([&] { return TraceId::fromEntropy(entropySource); });
return kj::rc<InvocationSpanContext>(kj::Badge<InvocationSpanContext>(), entropySource,
kj::mv(traceId), TraceId::fromEntropy(entropySource), 0, kj::mv(parent));
kj::mv(traceId), TraceId::fromEntropy(entropySource), SpanId::fromEntropy(entropySource),
kj::mv(parent));
}

TraceId TraceId::fromCapnp(rpc::InvocationSpanContext::TraceId::Reader reader) {
Expand Down Expand Up @@ -1315,10 +1331,10 @@ kj::Maybe<tracing::TailEvent::Context> getParentContextFromSpan(
}
} // namespace

tracing::TailEvent::Context::Context(TraceId traceId, TraceId invocationId, kj::uint spanId)
: traceId(traceId),
invocationId(invocationId),
spanId(spanId) {}
tracing::TailEvent::Context::Context(TraceId traceId, TraceId invocationId, SpanId spanId)
: traceId(kj::mv(traceId)),
invocationId(kj::mv(invocationId)),
spanId(kj::mv(spanId)) {}

tracing::TailEvent::Context::Context(rpc::InvocationSpanContext::Reader reader)
: traceId(TraceId::fromCapnp(reader.getTraceId())),
Expand Down
61 changes: 56 additions & 5 deletions src/workerd/io/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,56 @@ class TraceId final {
};
constexpr TraceId TraceId::nullId = nullptr;

// A 64-bit span identifier.
class SpanId final {
public:
// A null span ID. This is only acceptable for use in tests.
constexpr SpanId(decltype(nullptr)): id(0) {}

constexpr SpanId(uint64_t id): id(id) {}
constexpr SpanId(const SpanId& other) = default;
constexpr SpanId& operator=(const SpanId& other) = default;
constexpr SpanId(SpanId&& other): id(other.id) {
other.id = 0;
}
constexpr SpanId& operator=(SpanId&& other) {
id = other.id;
other.id = 0;
return *this;
}
constexpr operator bool() const {
return id != 0;
}
constexpr bool operator==(const SpanId& other) const {
return id == other.id;
}
constexpr bool operator==(decltype(nullptr)) const {
return id == 0;
}

inline operator kj::String() const {
return toGoString();
}

inline operator uint64_t() const {
return id;
}

kj::String toGoString() const;

static const SpanId nullId;

constexpr uint64_t getId() const {
return id;
}

static SpanId fromEntropy(kj::Maybe<kj::EntropySource&> entropy = kj::none);

private:
uint64_t id;
};
constexpr SpanId SpanId::nullId = nullptr;

// The InvocationSpanContext is a tuple of a trace id, invocation id, and span id.
// The trace id represents a top-level request and should be shared across all
// invocation spans and events within those spans. The invocation id identifies
Expand All @@ -135,7 +185,7 @@ class InvocationSpanContext final: public kj::Refcounted,
kj::Maybe<kj::EntropySource&> entropySource,
TraceId traceId,
TraceId invocationId,
uint64_t spanId = 0ULL,
SpanId spanId,
kj::Maybe<kj::Rc<InvocationSpanContext>> parentSpanContext = kj::none);
KJ_DISALLOW_COPY_AND_MOVE(InvocationSpanContext);

Expand All @@ -147,7 +197,7 @@ class InvocationSpanContext final: public kj::Refcounted,
return invocationId;
}

inline const uint64_t getSpanId() const {
inline const SpanId& getSpanId() const {
return spanId;
}

Expand Down Expand Up @@ -189,7 +239,7 @@ class InvocationSpanContext final: public kj::Refcounted,
kj::Maybe<kj::EntropySource&> entropySource;
const TraceId traceId;
const TraceId invocationId;
const uint64_t spanId;
const SpanId spanId;

// The parentSpanContext can be either a direct parent or a trigger
// context. If it is a trigger context, then it should have the same
Expand All @@ -198,6 +248,7 @@ class InvocationSpanContext final: public kj::Refcounted,
const kj::Maybe<kj::Rc<InvocationSpanContext>> parentSpanContext;
};

kj::String KJ_STRINGIFY(const SpanId& id);
kj::String KJ_STRINGIFY(const TraceId& id);
kj::String KJ_STRINGIFY(const kj::Rc<InvocationSpanContext>& context);

Expand Down Expand Up @@ -606,14 +657,14 @@ struct TailEvent final {
using Event = kj::OneOf<Onset, Outcome, Hibernate, SpanOpen, SpanClose, Mark>;

struct Context final {
explicit Context(TraceId traceId, TraceId invocationId, kj::uint spanId);
explicit Context(TraceId traceId, TraceId invocationId, SpanId spanId);
Context(rpc::InvocationSpanContext::Reader reader);
Context(Context&&) = default;
Context& operator=(Context&&) = default;
KJ_DISALLOW_COPY(Context);
TraceId traceId;
TraceId invocationId;
kj::uint spanId;
SpanId spanId;

void copyTo(rpc::InvocationSpanContext::Builder builder);
Context clone();
Expand Down

0 comments on commit 3590bec

Please sign in to comment.