Skip to content
File

Blob: src/workerd/io/trace.h

cpp1336 lines
1// Copyright (c) 2017-2022 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4 
5#pragma once
6 
7#include <workerd/io/outcome.capnp.h>
8#include <workerd/io/trace.capnp.h>
9#include <workerd/io/worker-interface.capnp.h>
10#include <workerd/jsg/memory.h>
11#include <workerd/util/own-util.h>
12 
13#include <kj/map.h>
14#include <kj/one-of.h>
15#include <kj/refcount.h>
16#include <kj/string.h>
17#include <kj/time.h>
18#include <kj/vector.h>
19 
20#include <concepts>
21#include <initializer_list>
22 
23namespace kj {
24enum class HttpMethod;
25class EntropySource;
26} // namespace kj
27 
28namespace workerd {
29 
30using kj::byte;
31using kj::uint;
32 
33using LogLevel = rpc::Trace::Log::Level;
34using ExecutionModel = rpc::Trace::ExecutionModel;
35 
36class Trace;
37 
38namespace tracing {
39// A 128-bit globally unique trace identifier. This will be used for both
40// external and internal tracing. Specifically, for internal tracing, this
41// is used to represent tracing IDs for jaeger traces. For external tracing,
42// this is used for both the trace ID and invocation ID for tail workers.
43class TraceId final {
44 public:
45 // A null trace ID. This is only acceptable for use in tests.
46 constexpr TraceId(decltype(nullptr)) {}
47 
48 // A trace ID with the given low and high values.
49 constexpr TraceId(uint64_t low, uint64_t high): low(low), high(high) {}
50 
51 constexpr TraceId(const TraceId& other) = default;
52 constexpr TraceId& operator=(const TraceId& other) = default;
53 
54 constexpr TraceId(TraceId&& other): low(other.low), high(other.high) {
55 other.low = 0;
56 other.high = 0;
57 }
58 
59 constexpr TraceId& operator=(TraceId&& other) {
60 low = other.low;
61 high = other.high;
62 other.low = 0;
63 other.high = 0;
64 return *this;
65 }
66 
67 constexpr TraceId& operator=(decltype(nullptr)) {
68 low = 0;
69 high = 0;
70 return *this;
71 }
72 
73 constexpr bool operator==(const TraceId& other) const {
74 return low == other.low && high == other.high;
75 }
76 constexpr bool operator==(decltype(nullptr)) const {
77 return low == 0 && high == 0;
78 }
79 constexpr operator bool() const {
80 return low || high;
81 }
82 
83 operator kj::String() const {
84 return toGoString();
85 }
86 
87 // Replicates Jaeger go library's string serialization.
88 kj::String toGoString() const;
89 
90 // Replicates Jaeger go library's protobuf serialization.
91 kj::Array<byte> toProtobuf() const;
92 
93 // Replicates W3C Serialization
94 kj::String toW3C() const;
95 
96 // Creates a random Trace Id, optionally using a given entropy source. If an
97 // entropy source is not given, then we fallback to using BoringSSL's RAND_bytes.
98 static TraceId fromEntropy(kj::Maybe<kj::EntropySource&> entropy = kj::none);
99 
100 // Replicates Jaeger go library's string serialization.
101 static kj::Maybe<TraceId> fromGoString(kj::ArrayPtr<const char> s);
102 
103 // Replicates Jaeger go library's protobuf serialization.
104 static kj::Maybe<TraceId> fromProtobuf(kj::ArrayPtr<const kj::byte> buf);
105 
106 // A null trace ID. This is really only acceptable for use in tests.
107 static const TraceId nullId;
108 
109 inline uint64_t getLow() const {
110 return low;
111 }
112 inline uint64_t getHigh() const {
113 return high;
114 }
115 
116 static TraceId fromCapnp(rpc::TraceId::Reader reader);
117 void toCapnp(rpc::TraceId::Builder writer) const;
118 
119 private:
120 uint64_t low = 0;
121 uint64_t high = 0;
122};
123constexpr TraceId TraceId::nullId = nullptr;
124 
125// A 64-bit span identifier.
126class SpanId final {
127 public:
128 // A null span ID. This is only acceptable for use in tests.
129 constexpr SpanId(decltype(nullptr)): id(0) {}
130 
131 constexpr SpanId(uint64_t id): id(id) {}
132 constexpr SpanId(const SpanId& other) = default;
133 constexpr SpanId& operator=(const SpanId& other) = default;
134 constexpr SpanId(SpanId&& other): id(other.id) {
135 other.id = 0;
136 }
137 constexpr SpanId& operator=(SpanId&& other) {
138 id = other.id;
139 other.id = 0;
140 return *this;
141 }
142 constexpr operator bool() const {
143 return id != 0;
144 }
145 constexpr bool operator==(const SpanId& other) const {
146 return id == other.id;
147 }
148 constexpr bool operator==(decltype(nullptr)) const {
149 return id == 0;
150 }
151 
152 inline operator kj::String() const {
153 return toGoString();
154 }
155 
156 inline operator uint64_t() const {
157 return id;
158 }
159 
160 kj::String toGoString() const;
161 
162 static const SpanId nullId;
163 
164 constexpr uint64_t getId() const {
165 return id;
166 }
167 
168 static SpanId fromEntropy(kj::Maybe<kj::EntropySource&> entropy = kj::none);
169 
170 private:
171 uint64_t id;
172};
173constexpr SpanId SpanId::nullId = nullptr;
174// Fixed spanId value to be used for tests
175constexpr uint64_t staticSpanId = 0x2a2a2a2a2a2a2a2aULL;
176 
177// W3C trace flags propagated from an upstream traceparent. Wrapped in kj::Maybe
178// at usage sites: kj::none means no upstream decision was made.
179class TraceFlags final {
180 public:
181 explicit constexpr TraceFlags(uint8_t flags): flags(flags) {}
182 
183 constexpr bool isSampled() const {
184 return flags & SAMPLED;
185 }
186 
187 constexpr operator uint8_t() const {
188 return flags;
189 }
190 
191 constexpr bool operator==(const TraceFlags& other) const {
192 return flags == other.flags;
193 }
194 
195 private:
196 // W3C trace-flags bit: the caller requested this trace be recorded.
197 static constexpr uint8_t SAMPLED = 0x01;
198 
199 uint8_t flags;
200};
201 
202// The InvocationSpanContext is a tuple of a trace id, invocation id, and span id.
203// The trace id represents a top-level request and should be shared across all
204// invocation spans and events within those spans. The invocation id identifies
205// a specific worker invocation. The span id identifies a specific span within an
206// invocation. Every invocation of every worker should have an InvocationSpanContext.
207// That may or may not have a trigger InvocationSpanContext.
208class InvocationSpanContext final {
209 public:
210 // The constructor is public only so kj::rc can see it and create a new instance.
211 // User code should use the static factory methods or the newChild method.
212 InvocationSpanContext(kj::Badge<InvocationSpanContext>,
213 kj::Maybe<kj::EntropySource&> entropySource,
214 TraceId traceId,
215 TraceId invocationId,
216 SpanId spanId,
217 kj::Maybe<const InvocationSpanContext&> parentSpanContext,
218 kj::Maybe<TraceFlags> traceFlags);
219 // Still need a constructor to be available as long as span context is not propagated everywhere
220 // we need it.
221 InvocationSpanContext(
222 TraceId traceId, TraceId invocationId, SpanId spanId, kj::Maybe<TraceFlags> traceFlags)
223 : traceId(traceId),
224 invocationId(invocationId),
225 spanId(spanId),
226 traceFlags(traceFlags) {};
227 
228 KJ_DISALLOW_COPY(InvocationSpanContext);
229 
230 InvocationSpanContext(InvocationSpanContext&& other) = default;
231 InvocationSpanContext& operator=(InvocationSpanContext&& other) = default;
232 
233 inline bool operator==(const InvocationSpanContext& other) const {
234 return traceId == other.traceId && invocationId == other.invocationId && spanId == other.spanId;
235 }
236 
237 inline const TraceId& getTraceId() const {
238 return traceId;
239 }
240 
241 inline const TraceId& getInvocationId() const {
242 return invocationId;
243 }
244 
245 inline const SpanId& getSpanId() const {
246 return spanId;
247 }
248 
249 inline kj::Maybe<const InvocationSpanContext&> getParent() const {
250 KJ_IF_SOME(p, parentSpanContext) {
251 return *p;
252 }
253 return kj::none;
254 }
255 
256 // W3C trace flags propagated from an upstream traceparent. kj::none when
257 // no upstream sampling decision exists.
258 inline kj::Maybe<TraceFlags> getTraceFlags() const {
259 return traceFlags;
260 }
261 
262 // Creates a new child span. If the current context does not have an entropy
263 // source this will assert. If isTrigger() is true then it will not have an
264 // entropy source.
265 InvocationSpanContext newChild() const;
266 
267 // An InvocationSpanContext is a trigger context if it has no entropy source.
268 // This generally means the SpanContext was create from a capnp message and
269 // represents an InvocationSpanContext that was propagated from a parent
270 // or triggering context.
271 bool isTrigger() const {
272 return entropySource == kj::none;
273 }
274 
275 // Creates a new InvocationSpanContext. If the triggerContext is given, then its
276 // traceId is used as the traceId for the newly created context. Otherwise a new
277 // traceId is generated. The invocationId is always generated new and the spanId
278 // will be 0 with no parent span.
279 static InvocationSpanContext newForInvocation(
280 kj::Maybe<const InvocationSpanContext&> triggerContext = kj::none,
281 kj::Maybe<kj::EntropySource&> entropySource = kj::none);
282 
283 // Creates a new InvocationSpanContext from a capnp message. The returned
284 // InvocationSpanContext will not be capable of creating child spans and
285 // is considered only a "trigger" span.
286 static kj::Maybe<InvocationSpanContext> fromCapnp(rpc::InvocationSpanContext::Reader reader);
287 void toCapnp(rpc::InvocationSpanContext::Builder writer) const;
288 InvocationSpanContext clone() const;
289 
290 private:
291 // If there is no entropy source, then child spans cannot be created from
292 // this InvocationSpanContext.
293 kj::Maybe<kj::EntropySource&> entropySource;
294 TraceId traceId;
295 TraceId invocationId;
296 SpanId spanId;
297 
298 // The parentSpanContext can be either a direct parent or a trigger
299 // context. If it is a trigger context, then it should have the same
300 // traceId but a different invocationId (unless predictable mode for
301 // testing is enabled). The isTrigger() should also return true.
302 kj::Maybe<kj::Own<InvocationSpanContext>> parentSpanContext;
303 
304 // W3C trace flags from an upstream traceparent, propagated through the
305 // invocation chain. kj::none when no upstream sampling decision was made.
306 kj::Maybe<TraceFlags> traceFlags;
307};
308 
309// SpanContext as used for streaming tail worker tail events. spanId is always set except for Onset
310// events that don't inherit context from another invocation.
311struct SpanContext {
312 SpanContext(
313 TraceId traceId, kj::Maybe<SpanId> spanId, kj::Maybe<TraceFlags> traceFlags = kj::none)
314 : traceId(traceId),
315 spanId(spanId),
316 traceFlags(traceFlags) {};
317 KJ_DISALLOW_COPY(SpanContext);
318 SpanContext(SpanContext&& other) = default;
319 SpanContext& operator=(SpanContext&& other) = default;
320 
321 inline bool operator==(const SpanContext& other) const {
322 return traceId == other.traceId && spanId == other.spanId;
323 }
324 
325 inline const TraceId& getTraceId() const {
326 return traceId;
327 }
328 
329 inline kj::Maybe<SpanId> getSpanId() const {
330 return spanId;
331 }
332 
333 // W3C trace flags from an upstream traceparent. kj::none when no upstream
334 // sampling decision was made (e.g. subrequest propagation without a
335 // worker_tracing header).
336 inline kj::Maybe<TraceFlags> getTraceFlags() const {
337 return traceFlags;
338 }
339 
340 static SpanContext fromCapnp(rpc::SpanContext::Reader reader);
341 void toCapnp(rpc::SpanContext::Builder writer) const;
342 static SpanContext clone(const SpanContext& ctx) {
343 return SpanContext(ctx.traceId, ctx.spanId, ctx.traceFlags);
344 }
345 
346 // Parse a W3C traceparent string into a SpanContext.
347 // Format: "{version}-{trace-id}-{parent-id}-{flags}"
348 static kj::Maybe<SpanContext> tryFromTraceparent(kj::StringPtr traceparent);
349 
350 private:
351 TraceId traceId;
352 kj::Maybe<SpanId> spanId;
353 kj::Maybe<TraceFlags> traceFlags;
354};
355 
356kj::String KJ_STRINGIFY(const SpanId& id);
357kj::String KJ_STRINGIFY(const TraceId& id);
358kj::String KJ_STRINGIFY(const InvocationSpanContext& context);
359kj::String KJ_STRINGIFY(const SpanContext& context);
360 
361// The various structs defined below are used in both buffered tail workers
362// and streaming tail workers to report tail events.
363 
364// Describes a fetch request
365struct FetchEventInfo final {
366 struct Header;
367 
368 explicit FetchEventInfo(
369 kj::HttpMethod method, kj::String url, kj::String cfJson, kj::Array<Header> headers);
370 FetchEventInfo(rpc::Trace::FetchEventInfo::Reader reader);
371 FetchEventInfo(FetchEventInfo&&) noexcept = default;
372 FetchEventInfo& operator=(FetchEventInfo&&) = default;
373 KJ_DISALLOW_COPY(FetchEventInfo);
374 
375 struct Header final {
376 explicit Header(kj::String name, kj::String value);
377 Header(rpc::Trace::FetchEventInfo::Header::Reader reader);
378 Header(Header&&) noexcept = default;
379 Header& operator=(Header&&) = default;
380 KJ_DISALLOW_COPY(Header);
381 
382 kj::String name;
383 kj::String value;
384 
385 void copyTo(rpc::Trace::FetchEventInfo::Header::Builder builder) const;
386 Header clone() const;
387 kj::String toString() const;
388 
389 JSG_MEMORY_INFO(Header) {
390 tracker.trackField("name", name);
391 tracker.trackField("value", value);
392 }
393 };
394 
395 kj::HttpMethod method;
396 kj::String url;
397 // TODO(perf): It might be more efficient to store some sort of parsed JSON result instead?
398 kj::String cfJson;
399 kj::Array<Header> headers;
400 
401 void copyTo(rpc::Trace::FetchEventInfo::Builder builder) const;
402 FetchEventInfo clone() const;
403 kj::String toString() const;
404};
405 
406// Describes a jsrpc request
407struct JsRpcEventInfo final {
408 explicit JsRpcEventInfo(kj::String methodName);
409 JsRpcEventInfo(rpc::Trace::JsRpcEventInfo::Reader reader);
410 JsRpcEventInfo(JsRpcEventInfo&&) noexcept = default;
411 JsRpcEventInfo& operator=(JsRpcEventInfo&&) = default;
412 KJ_DISALLOW_COPY(JsRpcEventInfo);
413 
414 kj::String methodName;
415 
416 void copyTo(rpc::Trace::JsRpcEventInfo::Builder builder) const;
417 JsRpcEventInfo clone() const;
418 kj::String toString() const;
419};
420 
421class ConnectEventInfo {
422 public:
423 explicit ConnectEventInfo();
424 explicit ConnectEventInfo(rpc::Trace::ConnectEventInfo::Reader reader);
425 
426 void copyTo(rpc::Trace::ConnectEventInfo::Builder builder) const;
427 ConnectEventInfo clone() const;
428};
429 
430// Describes a scheduled request
431struct ScheduledEventInfo final {
432 explicit ScheduledEventInfo(double scheduledTime, kj::String cron);
433 ScheduledEventInfo(rpc::Trace::ScheduledEventInfo::Reader reader);
434 ScheduledEventInfo(ScheduledEventInfo&&) noexcept = default;
435 ScheduledEventInfo& operator=(ScheduledEventInfo&&) = default;
436 KJ_DISALLOW_COPY(ScheduledEventInfo);
437 
438 double scheduledTime;
439 kj::String cron;
440 
441 void copyTo(rpc::Trace::ScheduledEventInfo::Builder builder) const;
442 ScheduledEventInfo clone() const;
443};
444 
445// Describes a Durable Object alarm request
446struct AlarmEventInfo final {
447 explicit AlarmEventInfo(kj::Date scheduledTime);
448 AlarmEventInfo(rpc::Trace::AlarmEventInfo::Reader reader);
449 AlarmEventInfo(AlarmEventInfo&&) noexcept = default;
450 AlarmEventInfo& operator=(AlarmEventInfo&&) = default;
451 KJ_DISALLOW_COPY(AlarmEventInfo);
452 
453 kj::Date scheduledTime;
454 
455 void copyTo(rpc::Trace::AlarmEventInfo::Builder builder) const;
456 AlarmEventInfo clone() const;
457};
458 
459// Describes a queue worker request
460struct QueueEventInfo final {
461 explicit QueueEventInfo(kj::String queueName, uint32_t batchSize);
462 QueueEventInfo(rpc::Trace::QueueEventInfo::Reader reader);
463 QueueEventInfo(QueueEventInfo&&) noexcept = default;
464 QueueEventInfo& operator=(QueueEventInfo&&) = default;
465 KJ_DISALLOW_COPY(QueueEventInfo);
466 
467 kj::String queueName;
468 uint32_t batchSize;
469 
470 void copyTo(rpc::Trace::QueueEventInfo::Builder builder) const;
471 QueueEventInfo clone() const;
472};
473 
474// Describes an email request
475struct EmailEventInfo final {
476 explicit EmailEventInfo(kj::String mailFrom, kj::String rcptTo, uint32_t rawSize);
477 EmailEventInfo(rpc::Trace::EmailEventInfo::Reader reader);
478 EmailEventInfo(EmailEventInfo&&) noexcept = default;
479 EmailEventInfo& operator=(EmailEventInfo&&) = default;
480 KJ_DISALLOW_COPY(EmailEventInfo);
481 
482 kj::String mailFrom;
483 kj::String rcptTo;
484 uint32_t rawSize;
485 
486 void copyTo(rpc::Trace::EmailEventInfo::Builder builder) const;
487 EmailEventInfo clone() const;
488};
489 
490// Describes a buffered tail worker request
491struct TracePreview final {
492 explicit TracePreview(kj::String id, kj::String slug, kj::String name);
493 TracePreview(rpc::Trace::TracePreviewInfo::Reader reader);
494 TracePreview(TracePreview&&) noexcept = default;
495 TracePreview& operator=(TracePreview&&) = default;
496 KJ_DISALLOW_COPY(TracePreview);
497 
498 kj::String id;
499 kj::String slug;
500 kj::String name;
501 
502 void copyTo(rpc::Trace::TracePreviewInfo::Builder builder) const;
503 TracePreview clone() const;
504};
505 
506struct TraceEventInfo final {
507 struct TraceItem;
508 
509 explicit TraceEventInfo(kj::ArrayPtr<const kj::Own<Trace>> traces);
510 TraceEventInfo(kj::Array<TraceItem> traces): traces(kj::mv(traces)) {}
511 TraceEventInfo(rpc::Trace::TraceEventInfo::Reader reader);
512 TraceEventInfo(TraceEventInfo&&) noexcept = default;
513 TraceEventInfo& operator=(TraceEventInfo&&) = default;
514 KJ_DISALLOW_COPY(TraceEventInfo);
515 
516 struct TraceItem final {
517 explicit TraceItem(kj::Maybe<kj::String> scriptName);
518 TraceItem(rpc::Trace::TraceEventInfo::TraceItem::Reader reader);
519 TraceItem(TraceItem&&) noexcept = default;
520 TraceItem& operator=(TraceItem&&) = default;
521 KJ_DISALLOW_COPY(TraceItem);
522 
523 kj::Maybe<kj::String> scriptName;
524 
525 void copyTo(rpc::Trace::TraceEventInfo::TraceItem::Builder builder) const;
526 TraceItem clone() const;
527 };
528 
529 kj::Vector<TraceItem> traces;
530 
531 void copyTo(rpc::Trace::TraceEventInfo::Builder builder) const;
532 TraceEventInfo clone() const;
533};
534 
535// Describes a hibernatable web socket event
536struct HibernatableWebSocketEventInfo final {
537 struct Message final {};
538 struct Close final {
539 uint16_t code;
540 bool wasClean;
541 };
542 struct Error final {};
543 
544 using Type = kj::OneOf<Message, Close, Error>;
545 
546 explicit HibernatableWebSocketEventInfo(Type type);
547 HibernatableWebSocketEventInfo(rpc::Trace::HibernatableWebSocketEventInfo::Reader reader);
548 HibernatableWebSocketEventInfo(HibernatableWebSocketEventInfo&&) noexcept = default;
549 HibernatableWebSocketEventInfo& operator=(HibernatableWebSocketEventInfo&&) = default;
550 KJ_DISALLOW_COPY(HibernatableWebSocketEventInfo);
551 
552 Type type;
553 
554 void copyTo(rpc::Trace::HibernatableWebSocketEventInfo::Builder builder) const;
555 HibernatableWebSocketEventInfo clone() const;
556 static Type readFrom(rpc::Trace::HibernatableWebSocketEventInfo::Reader reader);
557};
558 
559// Describes a custom event
560struct CustomEventInfo final {
561 explicit CustomEventInfo() {};
562 CustomEventInfo(rpc::Trace::CustomEventInfo::Reader reader) {};
563};
564 
565// Describes a fetch response
566struct FetchResponseInfo final {
567 explicit FetchResponseInfo(uint16_t statusCode);
568 FetchResponseInfo(rpc::Trace::FetchResponseInfo::Reader reader);
569 FetchResponseInfo(FetchResponseInfo&&) noexcept = default;
570 FetchResponseInfo& operator=(FetchResponseInfo&&) = default;
571 KJ_DISALLOW_COPY(FetchResponseInfo);
572 
573 uint16_t statusCode;
574 
575 void copyTo(rpc::Trace::FetchResponseInfo::Builder builder) const;
576 FetchResponseInfo clone() const;
577};
578 
579// Describes an event published using the node:diagnostics_channel API
580struct DiagnosticChannelEvent final {
581 explicit DiagnosticChannelEvent(
582 kj::Date timestamp, kj::String channel, kj::Array<kj::byte> message);
583 DiagnosticChannelEvent(rpc::Trace::DiagnosticChannelEvent::Reader reader);
584 DiagnosticChannelEvent(DiagnosticChannelEvent&&) noexcept = default;
585 KJ_DISALLOW_COPY(DiagnosticChannelEvent);
586 
587 kj::Date timestamp;
588 kj::String channel;
589 kj::Array<kj::byte> message;
590 
591 void copyTo(rpc::Trace::DiagnosticChannelEvent::Builder builder) const;
592 DiagnosticChannelEvent clone() const;
593};
594 
595// Describes a stream diagnostics event. Currently only droppedEvents is supported.
596struct StreamDiagnosticsEvent final {
597 explicit StreamDiagnosticsEvent(uint32_t droppedEventsCount);
598 StreamDiagnosticsEvent(rpc::Trace::StreamDiagnosticsEvent::Reader reader);
599 StreamDiagnosticsEvent(StreamDiagnosticsEvent&&) noexcept = default;
600 KJ_DISALLOW_COPY(StreamDiagnosticsEvent);
601 
602 // The count of dropped events for the "droppedEvents" diagnostic. When we support other event
603 // types, this should be replaced with a kj::OneOf<> of all the different types.
604 uint32_t droppedEventsCount;
605 
606 void copyTo(rpc::Trace::StreamDiagnosticsEvent::Builder builder) const;
607 StreamDiagnosticsEvent clone() const;
608};
609 
610// Describes a log event
611struct Log final {
612 explicit Log(kj::Date timestamp, LogLevel logLevel, kj::String message);
613 Log(rpc::Trace::Log::Reader reader);
614 Log(Log&&) noexcept = default;
615 KJ_DISALLOW_COPY(Log);
616 ~Log() noexcept(false) = default;
617 
618 // Only as accurate as Worker's Date.now(), for Spectre mitigation.
619 kj::Date timestamp;
620 
621 LogLevel logLevel;
622 // TODO(soon): Just string for now. Eventually, capture serialized JS objects.
623 kj::String message;
624 
625 void copyTo(rpc::Trace::Log::Builder builder) const;
626 Log clone() const;
627};
628 
629// Describes an exception event
630struct Exception final {
631 explicit Exception(
632 kj::Date timestamp, kj::String name, kj::String message, kj::Maybe<kj::String> stack);
633 Exception(rpc::Trace::Exception::Reader reader);
634 Exception(Exception&&) noexcept = default;
635 KJ_DISALLOW_COPY(Exception);
636 ~Exception() noexcept(false) = default;
637 
638 // Only as accurate as Worker's Date.now(), for Spectre mitigation.
639 kj::Date timestamp;
640 
641 kj::String name;
642 kj::String message;
643 
644 kj::Maybe<kj::String> stack;
645 
646 void copyTo(rpc::Trace::Exception::Builder builder) const;
647 Exception clone() const;
648};
649 
650// EventInfo types are used to describe the onset of an invocation. The FetchEventInfo
651// can also be used to describe the start of a fetch subrequest.
652using EventInfo = kj::OneOf<FetchEventInfo,
653 JsRpcEventInfo,
654 ScheduledEventInfo,
655 AlarmEventInfo,
656 QueueEventInfo,
657 EmailEventInfo,
658 TraceEventInfo,
659 HibernatableWebSocketEventInfo,
660 ConnectEventInfo,
661 CustomEventInfo>;
662 
663EventInfo cloneEventInfo(const EventInfo& info);
664 
665template <typename T>
666concept AttributeValue = kj::isSameType<kj::ConstString, T>() || kj::isSameType<bool, T>() ||
667 kj::isSameType<double, T>() || kj::isSameType<int64_t, T>();
668 
669// An Attribute mark is used to add detail to a span over its lifetime.
670// The Attribute struct can also be used to provide arbitrary additional
671// properties for some other structs.
672// Modeled after https://opentelemetry.io/docs/concepts/signals/traces/#attributes
673struct Attribute final {
674 using Value = kj::OneOf<kj::ConstString, bool, double, int64_t>;
675 using Values = kj::Array<Value>;
676 
677 explicit Attribute(kj::ConstString name, Value&& value);
678 explicit Attribute(kj::ConstString name, Values&& values);
679 
680 template <AttributeValue V>
681 explicit Attribute(kj::ConstString name, kj::Array<V> vals)
682 : Attribute(kj::mv(name), KJ_MAP(v, vals) { return Value(kj::mv(v)); }) {}
683 
684 template <AttributeValue V>
685 explicit Attribute(kj::ConstString name, std::initializer_list<V> list)
686 : Attribute(kj::mv(name), kj::heapArray<V>(list)) {}
687 
688 Attribute(rpc::Trace::Attribute::Reader reader);
689 Attribute(Attribute&&) noexcept = default;
690 Attribute& operator=(Attribute&&) = default;
691 KJ_DISALLOW_COPY(Attribute);
692 
693 kj::ConstString name;
694 Values value;
695 
696 void copyTo(rpc::Trace::Attribute::Builder builder) const;
697 Attribute clone() const;
698 kj::String toString() const;
699};
700using CustomInfo = kj::Array<Attribute>;
701kj::String KJ_STRINGIFY(const CustomInfo& customInfo);
702 
703struct SpanOpenData {
704 // Represents the data needed for a SpanOpen event
705 tracing::SpanId spanId;
706 tracing::SpanId parentSpanId;
707 
708 kj::ConstString operationName;
709 kj::Date startTime;
710 
711 SpanOpenData(rpc::SpanOpenData::Reader reader);
712 void copyTo(rpc::SpanOpenData::Builder builder) const;
713 explicit SpanOpenData(tracing::SpanId spanId,
714 tracing::SpanId parentSpanId,
715 kj::ConstString operationName,
716 kj::Date startTime)
717 : spanId(spanId),
718 parentSpanId(parentSpanId),
719 operationName(kj::mv(operationName)),
720 startTime(startTime) {}
721};
722 
723struct SpanEndData {
724 // Represents the data needed when closing a span, including the Attributes and SpanClose events.
725 tracing::SpanId spanId;
726 
727 kj::Date endTime;
728 // Should be Span::TagMap, but we can't forward-declare that.
729 kj::HashMap<kj::ConstString, tracing::Attribute::Value> tags;
730 
731 SpanEndData(rpc::SpanEndData::Reader reader);
732 void copyTo(rpc::SpanEndData::Builder builder) const;
733 explicit SpanEndData(tracing::SpanId spanId,
734 kj::Date endTime,
735 kj::HashMap<kj::ConstString, tracing::Attribute::Value> tags =
736 kj::HashMap<kj::ConstString, tracing::Attribute::Value>())
737 : spanId(spanId),
738 endTime(endTime),
739 tags(kj::mv(tags)) {}
740};
741 
742// A Return mark is used to mark the point at which a span operation returned
743// a value. For instance, when a fetch subrequest response is received, or when
744// the fetch handler returns a Response. Importantly, it does not signal that the
745// span has closed, which may not happen for some period of time after the return
746// mark is recorded (e.g. due to things like waitUntils or waiting to fully ready
747// the response body payload, etc).
748struct Return final {
749 explicit Return(kj::Maybe<FetchResponseInfo> info = kj::none);
750 Return(rpc::Trace::Return::Reader reader);
751 Return(Return&&) noexcept = default;
752 Return& operator=(Return&&) = default;
753 KJ_DISALLOW_COPY(Return);
754 
755 kj::Maybe<FetchResponseInfo> info = kj::none;
756 
757 void copyTo(rpc::Trace::Return::Builder builder) const;
758 Return clone() const;
759};
760 
761// Mark events no longer have a corresponding type, but the term generally refers to DiagnosticChannelEvent, Exception, Log, Return, and CustomInfo events.
762 
763// Marks the opening of a child span within the streaming tail session.
764struct SpanOpen final {
765 // If the span represents a subrequest, then the info describes the
766 // details of that subrequest.
767 using Info = kj::OneOf<FetchEventInfo, JsRpcEventInfo, CustomInfo>;
768 
769 explicit SpanOpen(SpanId spanId, kj::ConstString operationName, kj::Maybe<Info> info = kj::none);
770 SpanOpen(rpc::Trace::SpanOpen::Reader reader);
771 SpanOpen(SpanOpen&&) noexcept = default;
772 SpanOpen& operator=(SpanOpen&&) = default;
773 KJ_DISALLOW_COPY(SpanOpen);
774 
775 kj::ConstString operationName;
776 kj::Maybe<Info> info = kj::none;
777 SpanId spanId;
778 
779 void copyTo(rpc::Trace::SpanOpen::Builder builder) const;
780 SpanOpen clone() const;
781 kj::String toString() const;
782};
783 
784// Marks the closing of a child span within the streaming tail session.
785// Once emitted, no further mark events should occur within the closed
786// span.
787struct SpanClose final {
788 explicit SpanClose(EventOutcome outcome = EventOutcome::OK);
789 SpanClose(rpc::Trace::SpanClose::Reader reader);
790 SpanClose(SpanClose&&) noexcept = default;
791 SpanClose& operator=(SpanClose&&) = default;
792 KJ_DISALLOW_COPY(SpanClose);
793 
794 EventOutcome outcome = EventOutcome::OK;
795 
796 void copyTo(rpc::Trace::SpanClose::Builder builder) const;
797 SpanClose clone() const;
798 kj::String toString() const;
799};
800 
801// The Onset and Outcome event types are special forms of SpanOpen and
802// SpanClose that explicitly mark the start and end of the root span.
803// A streaming tail session will always begin with an Onset event, and
804// always end with an Outcome event.
805struct Onset final {
806 using Info = EventInfo;
807 
808 // Information about the worker that is being tailed.
809 struct WorkerInfo final {
810 ExecutionModel executionModel = ExecutionModel::STATELESS;
811 kj::Maybe<kj::String> scriptName;
812 kj::Maybe<kj::Own<ScriptVersion::Reader>> scriptVersion;
813 kj::Maybe<TracePreview> preview;
814 kj::Maybe<kj::String> dispatchNamespace;
815 kj::Maybe<kj::String> scriptId;
816 kj::Maybe<kj::Array<kj::String>> scriptTags;
817 kj::Maybe<kj::String> entrypoint;
818 
819 WorkerInfo clone() const;
820 };
821 
822 explicit Onset(
823 tracing::SpanId spanId, Info&& info, WorkerInfo&& workerInfo, CustomInfo attributes);
824 
825 Onset(rpc::Trace::Onset::Reader reader);
826 Onset(Onset&&) noexcept = default;
827 Onset& operator=(Onset&&) = default;
828 KJ_DISALLOW_COPY(Onset);
829 
830 tracing::SpanId spanId;
831 Info info;
832 WorkerInfo workerInfo;
833 CustomInfo attributes;
834 
835 void copyTo(rpc::Trace::Onset::Builder builder) const;
836 Onset clone() const;
837};
838 
839// Helper functions to copy onset info to/from rpc reader
840Onset::Info readOnsetInfo(const rpc::Trace::Onset::Info::Reader& info);
841void writeOnsetInfo(const tracing::Onset::Info& info, rpc::Trace::Onset::Info::Builder& builder);
842 
843struct Outcome final {
844 explicit Outcome(EventOutcome outcome, kj::Duration cpuTime, kj::Duration wallTime);
845 Outcome(rpc::Trace::Outcome::Reader reader);
846 Outcome(Outcome&&) noexcept = default;
847 Outcome& operator=(Outcome&&) = default;
848 KJ_DISALLOW_COPY(Outcome);
849 
850 EventOutcome outcome = EventOutcome::OK;
851 kj::Duration cpuTime;
852 kj::Duration wallTime;
853 
854 void copyTo(rpc::Trace::Outcome::Builder builder) const;
855 Outcome clone() const;
856 kj::String toString() const;
857};
858 
859// A streaming tail worker receives a series of Tail Events. Tail events always
860// occur within an InvocationSpanContext. The first TailEvent delivered to a
861// streaming tail session is always an Onset. The final TailEvent delivered is
862// always an Outcome. Between those can be any number of SpanOpen, SpanClose,
863// and Mark events. Every SpanOpen *must* be associated with a SpanClose unless
864// the stream was abruptly terminated.
865// A future version may add support for Link events again.
866struct TailEvent final {
867 using Event = kj::OneOf<Onset,
868 Outcome,
869 SpanOpen,
870 SpanClose,
871 DiagnosticChannelEvent,
872 Exception,
873 Log,
874 StreamDiagnosticsEvent,
875 Return,
876 CustomInfo>;
877 
878 explicit TailEvent(SpanContext context,
879 TraceId invocationId,
880 kj::Date timestamp,
881 kj::uint sequence,
882 Event&& event);
883 TailEvent(TraceId traceId,
884 TraceId invocationId,
885 kj::Maybe<SpanId> spanId,
886 kj::Date timestamp,
887 kj::uint sequence,
888 Event&& event,
889 kj::Maybe<TraceFlags> traceFlags = kj::none);
890 TailEvent(rpc::Trace::TailEvent::Reader reader);
891 TailEvent(TailEvent&&) = default;
892 TailEvent& operator=(TailEvent&&) = default;
893 KJ_DISALLOW_COPY(TailEvent);
894 
895 // The span context this event is associated with.
896 SpanContext spanContext;
897 TraceId invocationId;
898 
899 kj::Date timestamp; // Unix epoch, Spectre-mitigated resolution
900 kj::uint sequence;
901 
902 Event event;
903 
904 void copyTo(rpc::Trace::TailEvent::Builder builder) const;
905 TailEvent clone() const;
906};
907 
908kj::String KJ_STRINGIFY(const tracing::TailEvent::Event& event);
909 
910} // namespace tracing
911 
912enum class PipelineLogLevel {
913 // WARNING: This must be kept in sync with PipelineDef::LogLevel (which is not in the OSS
914 // release).
915 NONE,
916 FULL
917};
918 
919// TODO(someday): See if we can merge similar code concepts... Trace fills a role similar to
920// MetricsCollector::Reporter::StageEvent, and Tracer fills a role similar to
921// MetricsCollector::Request. Currently, the major differences are:
922//
923// - MetricsCollector::Request uses its destructor to measure a IoContext's wall time, so
924// it needs to live exactly as long as its IoContext. Tracer currently needs to live as
925// long as both the IoContext and those of any subrequests.
926// - Due to the difference in lifetimes, results of each become available in a different order,
927// and intermediate values can be freed at different times.
928// - Request builds a vector of results, while Tracer builds a tree.
929 
930// TODO(cleanup) - worth separating into immutable Trace vs. mutable TraceBuilder?
931 
932// Collects trace information about the handling of a worker/pipeline fetch event.
933class Trace final: public kj::Refcounted {
934 public:
935 explicit Trace(kj::Maybe<kj::String> stableId,
936 kj::Maybe<kj::String> scriptName,
937 kj::Maybe<kj::Own<ScriptVersion::Reader>> scriptVersion,
938 kj::Maybe<kj::String> dispatchNamespace,
939 kj::Maybe<kj::String> scriptId,
940 kj::Array<kj::String> scriptTags,
941 kj::Maybe<kj::String> entrypoint,
942 ExecutionModel executionModel,
943 kj::Maybe<kj::String> durableObjectId = kj::none,
944 kj::Maybe<tracing::TracePreview> preview = kj::none);
945 Trace(rpc::Trace::Reader reader);
946 ~Trace() noexcept(false);
947 KJ_DISALLOW_COPY_AND_MOVE(Trace);
948 
949 // Empty for toplevel worker.
950 kj::Maybe<kj::String> stableId;
951 
952 // We treat the origin value as "unset".
953 kj::Date eventTimestamp = kj::UNIX_EPOCH;
954 
955 kj::Maybe<tracing::EventInfo> eventInfo;
956 
957 // TODO(someday): Work out what sort of information we may want to convey about the parent
958 // trace, if any.
959 
960 kj::Maybe<kj::String> scriptName;
961 kj::Maybe<kj::Own<ScriptVersion::Reader>> scriptVersion;
962 kj::Maybe<kj::String> dispatchNamespace;
963 kj::Maybe<kj::String> scriptId;
964 kj::Array<kj::String> scriptTags;
965 kj::Maybe<kj::Array<tracing::Attribute>> tailAttributes;
966 kj::Maybe<kj::String> entrypoint;
967 kj::Maybe<tracing::TracePreview> preview;
968 kj::Maybe<kj::String> durableObjectId;
969 
970 kj::Vector<tracing::Log> logs;
971 // A request's trace can have multiple exceptions due to separate request/waitUntil tasks.
972 kj::Vector<tracing::Exception> exceptions;
973 
974 kj::Vector<tracing::DiagnosticChannelEvent> diagnosticChannelEvents;
975 
976 ExecutionModel executionModel;
977 EventOutcome outcome = EventOutcome::UNKNOWN;
978 
979 kj::Maybe<tracing::FetchResponseInfo> fetchResponseInfo;
980 
981 kj::Duration cpuTime;
982 kj::Duration wallTime;
983 
984 bool truncated = false;
985 bool exceededLogLimit = false;
986 bool exceededExceptionLimit = false;
987 bool exceededDiagnosticChannelEventLimit = false;
988 // Trace data is recorded outside of the JS heap. To avoid DoS, we keep an estimate of trace
989 // data size, and we stop recording if too much is used.
990 size_t bytesUsed = 0;
991 
992 // Copy content from this trace into `builder`.
993 void copyTo(rpc::Trace::Builder builder) const;
994 
995 // Adds all content from `reader` to this `Trace`. (Typically this trace is empty before the
996 // call.) Also applies filtering to the trace as if it were recorded with the given
997 // pipelineLogLevel.
998 void mergeFrom(rpc::Trace::Reader reader, PipelineLogLevel pipelineLogLevel);
999};
1000 
1001// =======================================================================================
1002 
1003// Helper function used when setting "truncated_script_id" tags. Truncates the scriptId to 10
1004// characters.
1005inline kj::String truncateScriptId(kj::StringPtr id) {
1006 auto truncatedId = id.first(kj::min(id.size(), 10));
1007 return kj::str(truncatedId);
1008}
1009 
1010// =======================================================================================
1011// Span tracing
1012//
1013// TODO(cleanup): (Streaming) tail workers now have access to span tracing as well, but with that
1014// the trace worker and span interfaces are still mostly independent of each other; separate span
1015// tracing into a separate header.
1016 
1017class SpanBuilder;
1018class SpanObserver;
1019 
1020struct Span {
1021 // Represents a trace span. `Span` objects are delivered to `SpanObserver`s for recording. To
1022 // create a `Span`, use a `SpanBuilder`.
1023 
1024 public:
1025 using TagValue = tracing::Attribute::Value;
1026 // TODO(someday): Support binary bytes, too.
1027 using TagMap = kj::HashMap<kj::ConstString, TagValue>;
1028 using Tag = TagMap::Entry;
1029 
1030 struct Log {
1031 kj::Date timestamp;
1032 Tag tag;
1033 };
1034 
1035 kj::ConstString operationName;
1036 kj::Date startTime;
1037 kj::Date endTime;
1038 TagMap tags;
1039 kj::Vector<Log> logs;
1040 
1041 // We set an arbitrary (-ish) cap on log messages for safety. If we drop logs because of this,
1042 // we report how many in a final "dropped_logs" log.
1043 //
1044 // At the risk of being too clever, I chose a limit that is one below a power of two so that
1045 // we'll typically have space for one last element available for the "dropped_logs" log without
1046 // needing to grow the vector.
1047 static constexpr auto MAX_LOGS = 1023;
1048 uint droppedLogs = 0;
1049 
1050 explicit Span(kj::ConstString operationName, kj::Date startTime)
1051 : operationName(kj::mv(operationName)),
1052 startTime(startTime),
1053 endTime(startTime) {}
1054};
1055 
1056// Utility functions for handling span tags.
1057void serializeTagValue(rpc::TagValue::Builder builder, const Span::TagValue& value);
1058Span::TagValue deserializeTagValue(rpc::TagValue::Reader value);
1059 
1060// Clone function for span tags, avoids memory allocation for string literals and non-string values.
1061Span::TagValue spanTagClone(const Span::TagValue& tag);
1062 
1063// An opaque token which can be used to create child spans of some parent. This is typically
1064// passed down from a caller to a callee when the caller wants to allow the callee to create
1065// spans for itself that show up as children of the caller's span, but the caller does not
1066// want to give the callee any other ability to modify the parent span.
1067class SpanParent {
1068 public:
1069 SpanParent(SpanBuilder& builder);
1070 
1071 // Make a SpanParent that causes children not to be reported anywhere.
1072 SpanParent(decltype(nullptr)) {}
1073 
1074 SpanParent(kj::Maybe<kj::Own<SpanObserver>> observer): observer(kj::mv(observer)) {}
1075 
1076 SpanParent(SpanParent&& other) = default;
1077 SpanParent& operator=(SpanParent&& other) = default;
1078 KJ_DISALLOW_COPY(SpanParent);
1079 
1080 SpanParent addRef();
1081 
1082 // Create a new child span.
1083 //
1084 // `operationName` should be a string literal with infinite lifetime.
1085 [[nodiscard]] SpanBuilder newChild(
1086 kj::ConstString operationName, kj::Maybe<kj::Date> startTime = kj::none);
1087 
1088 // Useful to skip unnecessary code when not observed.
1089 bool isObserved() {
1090 return observer != kj::none;
1091 }
1092 
1093 // Get the underlying SpanObserver representing the parent span.
1094 //
1095 // This is needed in particular when making outbound network requests that must be annotated with
1096 // trace IDs in a way that is specific to the trace back-end being used. The caller must downcast
1097 // the `SpanObserver` to the expected observer type in order to extract the trace ID.
1098 kj::Maybe<SpanObserver&> getObserver() {
1099 return observer;
1100 }
1101 
1102 // Return the serializable identity of this span for cross-boundary propagation.
1103 kj::Maybe<tracing::SpanContext> toSpanContext();
1104 
1105 // Returns the observer's spanId, or SpanId::nullId if there is none.
1106 tracing::SpanId getSpanId();
1107 
1108 private:
1109 kj::Maybe<kj::Own<SpanObserver>> observer;
1110};
1111 
1112// Interface for writing a span. Essentially, this is a mutable interface to a `Span` object,
1113// given only to the code which is meant to create the span, whereas code that merely collects
1114// and reports spans gets the `Span` type.
1115//
1116// The reason we use a separate builder type rather than rely on constness is so that the methods
1117// can be no-ops when there is no observer, avoiding unnecessary allocations. To allow for this,
1118// SpanBuilder is designed to be write-only -- you cannot read back the content. Only the
1119// observer (if there is one) receives the content.
1120class SpanBuilder {
1121 public:
1122 // Create a new top-level span that will report to the given observer. If the observer is null,
1123 // no data is collected.
1124 //
1125 // `operationName` should be a string literal with infinite lifetime, or somehow otherwise be
1126 // attached to the observer observing this span.
1127 explicit SpanBuilder(kj::Maybe<kj::Own<SpanObserver>> observer,
1128 kj::ConstString operationName,
1129 kj::Maybe<kj::Date> startTime = kj::none);
1130 
1131 // Make a SpanBuilder that ignores all calls. (Useful if you want to assign it later.)
1132 SpanBuilder(decltype(nullptr)) {}
1133 
1134 SpanBuilder(SpanBuilder&& other) = default;
1135 SpanBuilder& operator=(SpanBuilder&& other); // ends the existing span and starts a new one
1136 KJ_DISALLOW_COPY(SpanBuilder);
1137 
1138 ~SpanBuilder() noexcept(false);
1139 
1140 // Finishes and submits the span. This is done implicitly by the destructor, but sometimes it's
1141 // useful to be able to submit early. The SpanBuilder ignores all further method calls after this
1142 // is invoked.
1143 void end();
1144 
1145 // Useful to skip unnecessary code when not observed.
1146 bool isObserved() {
1147 return observer != kj::none;
1148 }
1149 
1150 // Get the underlying SpanObserver representing the span.
1151 //
1152 // This is needed in particular when making outbound network requests that must be annotated with
1153 // trace IDs in a way that is specific to the trace back-end being used. The caller must downcast
1154 // the `SpanObserver` to the expected observer type in order to extract the trace ID.
1155 kj::Maybe<SpanObserver&> getObserver() {
1156 return observer;
1157 }
1158 
1159 // Create a new child span.
1160 //
1161 // `operationName` should be a string literal with infinite lifetime.
1162 [[nodiscard]] SpanBuilder newChild(
1163 kj::ConstString operationName, kj::Maybe<kj::Date> startTime = kj::none);
1164 
1165 // Change the operation name from what was specified at span creation.
1166 //
1167 // `operationName` should be a string literal with infinite lifetime.
1168 void setOperationName(kj::ConstString operationName);
1169 
1170 using TagValue = Span::TagValue;
1171 // `key` must point to memory that will remain valid all the way until this span's data is
1172 // serialized.
1173 // Allow setting tags with an extended set of types to elide string allocations when we have a
1174 // string literal or are not being observed. We include String/LiteralStringConst here to avoid
1175 // having to manually cast them to ConstString each time.
1176 using TagInitValue = kj::OneOf<kj::StringPtr,
1177 kj::String,
1178 kj::LiteralStringConst,
1179 kj::ConstString,
1180 bool,
1181 double,
1182 int64_t>;
1183 
1184 void setTag(kj::ConstString key, TagInitValue value);
1185 
1186 // `key` must point to memory that will remain valid all the way until this span's data is
1187 // serialized.
1188 //
1189 // The differences between this and `setTag()` is that logs are timestamped and may have
1190 // duplicate keys.
1191 void addLog(kj::Date timestamp, kj::ConstString key, TagValue value);
1192 
1193 private:
1194 kj::Maybe<kj::Own<SpanObserver>> observer;
1195 // The under-construction span, or null if the span has ended.
1196 kj::Maybe<Span> span;
1197 
1198 friend class SpanParent;
1199};
1200 
1201// Abstract interface for observing trace spans reported by the runtime. Different
1202// implementations might support different tracing back-ends, e.g. Trace Workers, Jaeger, or
1203// whatever infrastructure you prefer to use for this.
1204//
1205// A new SpanObserver is created at the start of each Span. The SpanBuilder drives the observer
1206// through its lifecycle: onOpen() is called when the span is created, onClose() when the span
1207// ends, and onUpdateName() if the operation name changes between open and close.
1208class SpanObserver: public kj::Refcounted {
1209 public:
1210 // Allocate a new child span.
1211 //
1212 // Note that children can be created long after a span has completed.
1213 [[nodiscard]] virtual kj::Own<SpanObserver> newChild() = 0;
1214 
1215 // Allocate a child for a span initiated directly by user JavaScript (via
1216 // `ctx.tracing.enterSpan`). Allows implementations to apply different policies than for
1217 // runtime-issued spans (notably, edgeworker bypasses its operation-name allowlist here).
1218 [[nodiscard]] virtual kj::Own<SpanObserver> newChildFromUserCode() {
1219 return newChild();
1220 }
1221 
1222 // Called when the span is opened. Delivers the initial operation name and start time.
1223 // Called exactly once, before any other lifecycle method.
1224 virtual void onOpen(kj::ConstString operationName, kj::Date startTime) = 0;
1225 
1226 // Called when the span is closed. Delivers the end time, tags, and logs.
1227 // Called exactly once per observer, after onOpen(). Tags and logs are moved from the span;
1228 // the observer takes ownership.
1229 virtual void onClose(kj::Date endTime, Span::TagMap&& tags, kj::Vector<Span::Log>&& logs) = 0;
1230 
1231 // Called when the operation name is changed after the span was opened (via
1232 // SpanBuilder::setOperationName()). Observers that eagerly stream the open event should handle
1233 // this; others may simply update their buffered state. Default implementation is a no-op.
1234 virtual void onUpdateName(kj::ConstString operationName) {}
1235 
1236 // The current time to be provided for the span. For user tracing, we will override this to
1237 // provide I/O time. This *requires* that spans are only created when an IOContext is available
1238 // (usually it is difficult to violate this assumption, but care must be taken that the observer
1239 // isn't used directly to create a span before the IoContext has been constructed (previously this
1240 // was a case with a top-level span owned by the WorkerTracer itself).
1241 virtual kj::Date getTime() {
1242 return kj::systemPreciseCalendarClock().now();
1243 }
1244 
1245 // Return the serializable identity of this span for cross-boundary propagation.
1246 // Returns kj::none if this observer doesn't carry identity.
1247 virtual kj::Maybe<tracing::SpanContext> toSpanContext() {
1248 return kj::none;
1249 }
1250 
1251 // Returns this observer's spanId, or SpanId::nullId if it has no identity.
1252 virtual tracing::SpanId getSpanId() {
1253 return tracing::SpanId::nullId;
1254 }
1255};
1256 
1257inline kj::Maybe<tracing::SpanContext> SpanParent::toSpanContext() {
1258 KJ_IF_SOME(obs, observer) {
1259 return obs->toSpanContext();
1260 }
1261 return kj::none;
1262}
1263 
1264inline tracing::SpanId SpanParent::getSpanId() {
1265 KJ_IF_SOME(obs, observer) {
1266 return obs->getSpanId();
1267 }
1268 return tracing::SpanId::nullId;
1269}
1270 
1271inline SpanParent::SpanParent(SpanBuilder& builder): observer(mapAddRef(builder.observer)) {}
1272 
1273inline SpanParent SpanParent::addRef() {
1274 return SpanParent(mapAddRef(observer));
1275}
1276 
1277inline SpanBuilder SpanParent::newChild(
1278 kj::ConstString operationName, kj::Maybe<kj::Date> startTime) {
1279 return SpanBuilder(observer.map([](kj::Own<SpanObserver>& obs) { return obs->newChild(); }),
1280 kj::mv(operationName), startTime);
1281}
1282 
1283inline SpanBuilder SpanBuilder::newChild(
1284 kj::ConstString operationName, kj::Maybe<kj::Date> startTime) {
1285 return SpanBuilder(observer.map([](kj::Own<SpanObserver>& obs) { return obs->newChild(); }),
1286 kj::mv(operationName), startTime);
1287}
1288 
1289// TraceContext to keep track of user tracing/existing tracing better
1290class TraceContext {
1291 public:
1292 TraceContext(): span(nullptr), userSpan(nullptr) {}
1293 TraceContext(SpanBuilder span, SpanBuilder userSpan)
1294 : span(kj::mv(span)),
1295 userSpan(kj::mv(userSpan)) {}
1296 TraceContext(TraceContext&& other) = default;
1297 TraceContext& operator=(TraceContext&& other) = default;
1298 KJ_DISALLOW_COPY(TraceContext);
1299 
1300 // Set a tag on both the internal span and user span.
1301 void setTag(kj::ConstString key, SpanBuilder::TagInitValue value);
1302 bool isObserved() {
1303 return span.isObserved() || userSpan.isObserved();
1304 }
1305 SpanParent getInternalSpanParent() {
1306 return SpanParent(span);
1307 }
1308 
1309 SpanParent getUserSpanParent() {
1310 return SpanParent(userSpan);
1311 }
1312 
1313 private:
1314 SpanBuilder span;
1315 SpanBuilder userSpan;
1316};
1317 
1318// RAII object that measures the time duration over its lifetime. It tags this duration onto a
1319// given request span using a specified tag name. Ideal for automatically tracking and logging
1320// execution times within a scoped block.
1321class ScopedDurationTagger {
1322 public:
1323 explicit ScopedDurationTagger(
1324 SpanBuilder& span, kj::ConstString key, const kj::MonotonicClock& timer);
1325 ~ScopedDurationTagger() noexcept(false);
1326 KJ_DISALLOW_COPY_AND_MOVE(ScopedDurationTagger);
1327 
1328 private:
1329 SpanBuilder& span;
1330 kj::ConstString key;
1331 const kj::MonotonicClock& timer;
1332 const kj::TimePoint startTime;
1333};
1334 
1335} // namespace workerd