We do tracing with Jaeger. You need to run a local image of it on your machine to be able to trace your work and make sure it's the behavior that would be helpful in debugging.

Tracing has two things:

The way this work is you find a root cause for a certain event e.g. endpoint, then create a context and pass it down all the functions being called by this endpoint (ignore trivial functions like validation and focus more on asynchronous operations).

Using a context

await ctx.execute(async ({ span, logger }) => {
  // you can use logger returned from this
  logger.info("some logging information", { hello: "you can pass data here" });

  // you can also set tags here that show in Jaeger and allow for searching
  span.setTag("retires", 2);

  // you always need to have this in the end of every function
  // that uses contexts
  logger.success("a message is optional", { 
    some_data: "this is optional too" 
  });
});

Creating Context for an Endpoint

Call this function to create a context, pass it a name (what the endpoint does) and the req object.

create_endpoint_context("verify phone start", req);

<aside> ⛔ For endpoints that receive sensitive information e.g. passwords and login, you can pass a third argument data that has the data you want to get from req.body

</aside>

Creating Child Context

All the functions that do asynchronous operations must have a _ctx as the first parameter

function send_email(_ctx, { ... }) {
  // do some work
}

To chain spans together so we can track each function and what it does, we need to create a context based on pass context _ctx

const ctx = create_context({
  name: "<name of function or what it does>",
  tags: {
    email, // you can set searchable tags here
  },
  // pass it the context you got passed down
  // if its' null then a new one will be created
  root_context: _ctx,
});