Hi all,
Some of you might know me from my work Pivot Tracing with my advisor Rodrigo Fonseca at Brown. The purpose of this e-mail is to alert you to our "Tracing Plane" prototype along with 'Baggage Buffers', an IDL for generating context interfaces.
https://github.com/JonathanMace/tracingplaneThis is an ongoing research project, but is at the stage where we can show what we've done and what we're doing.
I've recently been working on the problems of "what should propagated context look like?" and "can different tracing tools use the same context?". The 'Baggage' abstraction that we introduced in Pivot Tracing heads in this direction, but doesn't really provide a complete solution. The benefit of truly general-purpose metadata propagation is that you no longer have to re-instrument your systems if you want to try out new tracing tools or if you want to change existing tracing tools. They can just plug in to the existing instrumented system. This is especially useful if redeploying all of your services is a non-starter.
Side note on terminology: When I use the term 'Baggage', I'm talking about an overarching, general purpose context that is propagated throughout a system (one per request). When I talk about contexts specific to a tracing tool, I mean the metadata that that tool specifically wants to have propagated.
What is the tracing plane?
1. The APIs that you use in your system to pass around baggage
2. The underlying data format of the baggage that is passed around
3. The underlying protocol for accessing and manipulating tool-specific contexts within a baggage
4. An IDL, Baggage Buffers, for easily specifying the layout of tool-specific contexts.
5. The accessor APIs (generated by Baggage Buffers) that you use to get and set values contexts.
The tracing plane has the following features:
1. You only need to instrument your system once. You do this using an instrumentation API that treats baggage as an opaque object (e.g., you think of it as just a blob, versus metadata for a specific tool (e.g., Zipkin headers))
2. You can easily specify new contexts using the Baggage Buffers IDL (similar to protocol buffers). Baggage and Baggage Buffers are general purpose, so there are a wide variety of simple (integers, bytes, strings) and complex (sets, maps, counters, state-based CRDTs) data types.
3. If you want to deploy a new tool and propagate some new context, you don't need to make changes to any of the components in your system. Your components will seamlessly propagate the new context of this new tool in the existing baggage instrumentation.
4. If you want to deploy a new tool and many of your components won't be using the tool at all, those components don't need any changes whatsoever; they will blindly (but correctly) propagate the baggage. For example, suppose you're auditing a database -- you add tags to each request in your front end to specify the user, then at the database you check who is the user. Intermediate layers do not use or modify the tags, and they will continue working with no updates.
5. Baggage can transparently carry multiple contexts from different tracing tools simultaneously. If you have several different tracing tools that all want to propagate their own contexts, it works transparently
6. If you wish to update the specification of a context (e.g., in Baggage Buffers), updates can be incrementally deployed. Old versions of the code will continue to work with the old context specification, and just ignore & propagate any fields they do not recognize.
7. If components in your system have size restrictions, you can trim baggage. Later on, you are able to detect if your context used to be present in baggage, but was lost along the way.
8. Propagating context is very cheap. Inserting or retrieving context values is very cheap. I believe it is cheap enough that even resource-constrained components such as middleboxes can participate.
----------------------
A quick example.
In some of the
discussions about trace context header propagation, they might look as follows in baggage buffers:
bag TraceContext {
fixed32 traceId = 1;
fixed32 spanId = 2;
TraceOptions options = 3;
}
bag TraceOptions {
bool sampled = 1;
int8 traceLevel = 2;
}
Baggage buffers will generate the code for this context as well as accessors. All you need to do is start using it, eg
TraceContext.get()
^^- accesses the baggage, finds tracecontext if it exists.
The main focus of the tracing plane is having a carefully designed underlying serialized representation for contexts and baggage. We separate this into layers called the Atom Layer and the Baggage Layer. The data representation in the Atom Layer enables baggage merging, serialization, and propagation, without needing to know about the baggage contents. The data representation in the Baggage Layer enables contexts from different tools to exist side-by-side, enables nested data structures and sets, and enables accessing contexts and fields.
We will be sharing a preprint paper on the work soon as well. Hopefully I can give a talk at the February workshop.
Looking forward to discussion on this!
Jon