Skip to content

Commit

Permalink
WC-2707 Only submit non-empty traces to trace workers
Browse files Browse the repository at this point in the history
Currently, any invocation for a stage generates a trace, even for
PipelineLogLevel::NONE. The only difference is that NONE does not attach
logs, exceptions, or eventInfo to the trace.

This leads us to see traces with a null event for stages you opted to
not get traces from, which we often see when there's a FPW in a pipeline
that we did not intend to see.

There are quite a few places throughout this and edgeworker that note
that we do this to "keep the request tree contiguous", but from my
investigation and chats with other people, these traces are not used for
anything other than delivery to trace/tail handlers, i.e. this isn't
used to report metrics or billing. So there's no reason to filter these
out before delivering traces.

This is of course not as efficient as it could be, as we are allocating
for empty traces and then discarding them before submitting. A more
comprehensive approach would be to not generate traces at all when the
stage / subpipeline's log level is NONE, but that's probably beyond me
currently (although I would welcome the help).

I do have a tests that are tweaked to reflect these changes in
edgeworker, but there seem to be some quirks / nuances I don't
understand there (for example, the tests pass normally but do not pass
for process sandboxing) so I was recommended to get a PR up to workerd
to begin the discussion here.
  • Loading branch information
matthewdavidrodgers committed Oct 17, 2024
1 parent 01c901b commit 110a18c
Showing 1 changed file with 9 additions and 2 deletions.
11 changes: 9 additions & 2 deletions src/workerd/api/trace.c++
Original file line number Diff line number Diff line change
Expand Up @@ -607,17 +607,24 @@ kj::Promise<void> sendTracesToExportedHandler(kj::Own<IoContext::IncomingRequest
t.setEventInfo(context.now(), Trace::TraceEventInfo(traces));
}

auto nonEmptyTraces = kj::Vector<kj::Own<Trace>>(kj::size(traces));
for (auto& trace : traces) {
if (trace->eventInfo != kj::none) {
nonEmptyTraces.add(kj::mv(trace));
}
}

// Add the actual JS as a wait until because the handler may be an event listener which can't
// wait around for async resolution. We're relying on `drain()` below to persist `incomingRequest`
// and its members until this task completes.
auto entrypointName = entrypointNamePtr.map([](auto s) { return kj::str(s); });
try {
co_await context.run([&context, traces = mapAddRef(traces),
co_await context.run([&context, nonEmptyTraces = kj::mv(nonEmptyTraces),
entrypointName = kj::mv(entrypointName)](Worker::Lock& lock) mutable {
jsg::AsyncContextFrame::StorageScope traceScope = context.makeAsyncTraceScope(lock);

auto handler = lock.getExportedHandler(entrypointName, context.getActor());
return lock.getGlobalScope().sendTraces(traces, lock, handler);
return lock.getGlobalScope().sendTraces(nonEmptyTraces.asPtr(), lock, handler);
});
} catch (kj::Exception e) {
// TODO(someday): We only report sendTraces() as failed for metrics/logging if the initial
Expand Down

0 comments on commit 110a18c

Please sign in to comment.