remitrace v0.0.1
remitrace
Utilises the tracing metadata available in remit >=2.2.0 to push captured messages to a queue (or to custom loggers) for storage and correlation.
yarn add remitraceconst { remitrace } = require('remitrace')
const remit = require('remit')()
remitrace(remit)See remitrace-mongo for a practical example of its use.
It's a nice, simple function:
remitrace(remit, options)
remitA runningremitinstance of version >=2.2.0optionsAn optional object containing a few options for remitrace:queueNameThe RabbitMQ topic thatremitracewill emit to. Defaults to'remitrace'.customLoggersAny custom actions to be done with traces can be specified as functions in an array here which are passed theeventof the action to be traced. Defaults to[].[console.log]is a nice way to see the traces being logged.ignoredPathsEvent names to ignore when tracing messages. Must be an array of regexes. Defaults to[/^queueName$/]wherequeueNameis the option above.
Tracing with remitrace
remitrace on its own only allows the easy capture of the data needed to trace your calls. There is, however, a usable MongoDB-backed example over at remitrace-mongo. For clarity, I'll explain how it works here too.
remit >=2.2.0 provides some new metadata intended for tracing inside each event in a new metadata object.
originIdThe ID of the initial request or emission that started the entire chain of calls. Every call in a chain will have the same ID here.bubbleIdThe "bubble" (see more below) that the action happened in.fromBubbleIdThe "bubble" (see more below) that the action was triggered from.instanceIdA unique ID for each and every action.flowTypeEither'entry'to show it's an entrypoint to a bubble,'exit'to show it's an exit from a bubble or blank to show it is neither.
These five properties can be used to create a picture of not only how particular calls are triggered, but the effect that a single call can have on an entire system, accessible from any point.
What's a bubble?
A bubble, in this context, is represented as all remit-related actions performed within a handler for an endpoint or listener.
A bubble is created whenever a request or emission is received by an endpoint or listener. This is an 'entry' (as dictated by the flowType metadata). 'exit's are the requests or emissions themselves.
How does the information correlate?
We'll assume for this section that all traces are stored as-is within a simple document store such as MongoDB.
First off, you can easily find all messages created from a single originId by just querying for exactly that:
{
"originId": "01C31N0NMCMS5KX8E4GJ6BV0G2"
}With that, you could list every single action that happened because of that origin message.
You can also, however, get a little better.
A more common practice would be to seek out the cause of a particular event. A listener is receiving an emission, let's say, but you don't know why or where from. Following it through a complex production system would be horrendous, but with remitrace it's easily possible.
As above, an instanceId is a unique ID given to every action. Using this along with flowType's entries and exits, we can easily find the direct route from cause to effect.
Find the trace of the instanceId you wish to track. If it's an entry point, you must find the exit that lead to it. If it's not an entry, find the entry. An example in code:
async function findCause (query, traces = []) {
// handle the initial sending of an instanceId
if (typeof query === 'string') {
query = { 'event.metadata.instanceId': query }
}
// find a trace and return early if it's the end of the line
const nextTrace = await myCol.findOne(query)
if (!nextTrace) return traces
traces.push(nextTrace)
if (!nextTrace.event.metadata.bubbleId) return traces
// sort out what to search for next
const nextQuery = nextTrace.event.metadata.flowType === 'entry' ? {
'event.metadata.flowType': 'exit',
'event.metadata.bubbleId': nextTrace.event.metadata.fromBubbleId,
'event.eventId': nextTrace.event.eventId
} : {
'event.metadata.flowType': 'entry',
'event.metadata.bubbleId': nextTrace.event.metadata.bubbleId
}
// go search for it
return findCause(nextQuery, traces)
}
const traces = await findCause('01C31NWW065X38YPBGJTZXAHVV')The result of this would be a list of traces which lead to the specified action.
8 years ago