How to view a Jaeger trace in Chrome Flame Graph

Viewed 123

We have Jaeger instrumentation in our applications. We usually are happy with the Jaeger UI, but with very large traces the web view becomes quite unusable. With Node.js we also use Chrome Flame Graphs with good and very tactile results.

Jaeger can export JSON files that look like this:

{"data":[{"traceID":"16c0500882122d8a16c05008820aeb3a","spans":[{"traceID":"16c0500882122d8a16c05008820aeb3a","spanID":"16c05008820aeb3a","flags":1,"operationName":"TaskProcessor","references":[],"startTime":1639398261835322,"duration":216903298,"tags":[{"key":"host","type":"string","value":""},{"key":"requestUri","type":"bool","value":false},{"key":"queryString","type":"string","value":""},{"key":"internal.span.format","type":"string","value":"proto"}],"logs":[],"processID":"p1","warnings":null},{"traceID":"16c0500882122d8a16c05008820aeb3a","spanID":"16c0500888b52131","flags":1,"operationName":"__construct","references":[{"refType":"CHILD_OF","traceID":"16c0500882122d8a16c05008820aeb3a","spanID":"16c05008820aeb3a"}],"startTime":1639398261946284,"duration":51,"tags":[{"key":"magentoType","type":"string","value":"model"},{"key":"className","type":"string","value":"Peak_Touristcard_Model_TaskProcessor"},{"key":"internal.span.format","type":"string","value":"proto"}],"logs":[],"processID":"p2","warnings":null},{"traceID":"16c0500882122d8a16c05008820aeb3a","spanID":"16c0500888b4c024","flags":1,"operationName":"_initOldFieldsMap","references":[{"refType":"CHILD_OF","traceID":"16c0500882122d8a16c05008820aeb3a","spanID":"16c0500888b52131"}],"startTime":1639398261946305,"duration":6,"tags":[{"key":"magentoType","type":"string","value":"model"},{"key":"className","type":"string","value":"Peak_Touristcard_Model_TaskProcessor"},{"key":"internal.span.format","type":"string","value":"proto"}],"logs":[],"processID":"p2","warnings":null},{"traceID":"16c0500882122d8a16c05008820aeb3a","spanID":"16c0500888b4982a","flags":1,"operationName":"_addFullNames","references":[{"refType":"CHILD_OF","traceID":"16c0500882122d8a16c05008820aeb3a","spanID":"16c0500888b52131"}],"startTime":1639398261946321,"duration":5,"tags":[{"key":"magentoType","type":"string","value":"model"},{"key":"className","type":"string","value":"Peak_Touristcard_Model_TaskProcessor"},{"key":"internal.span.format","type":"string","value":"proto"}],"logs":[],"processID":"p2","warnings":null},{"traceID":"16c0500882122d8a16c05008820aeb3a","spanID":"16c0500888b500f1","flags":1,"operationName":"_construct","references":[{"refType":"CHILD_OF","traceID":"16c0500882122d8a16c05008820aeb3a","spanID":"16c0500888b52131"}],"startTime":1639398261946332,"duration":2,"tags":[{"key":"magentoType","type":"string","value":"model"},{"key":"className","type":"string","value":"Peak_Touristcard_Model_TaskProcessor"},{"key":"internal.span.format","type":"string","value":"proto"}],"logs":[],"processID":"p2","warnings":null},
...

Chrome Flame Graphs can open JSON format like this:

[{"args":{"name":"swapper"},"cat":"__metadata","name":"thread_name","ph":"M","pid":514,"tid":0,"ts":0},
{"args":{"name":"CrBrowserMain"},"cat":"__metadata","name":"thread_name","ph":"M","pid":514,"tid":259,"ts":0},
{"args":{"name":"Compositor"},"cat":"__metadata","name":"thread_name","ph":"M","pid":46733,"tid":42243,"ts":0},
{"args":{"name":"ThreadPoolServiceThread"},"cat":"__metadata","name":"thread_name","ph":"M","pid":514,"tid":25607,"ts":0},
{"args":{"name":"ThreadPoolServiceThread"},"cat":"__metadata","name":"thread_name","ph":"M","pid":46733,"tid":20739,"ts":0},
...

Does anybody have experience with viewing Jaeger traces in anything else than Jaeger UI, possibly even in Google Flame Graph?

1 Answers

To convert traces for simple use cases, consider this nodejs script that takes a Jaeger JSON trace from standard input:

#!/usr/bin/env node

const trace = JSON.parse(require("fs").readFileSync(0).toString());

console.log(JSON.stringify(
  {
    traceEvents: [
      {"pid":1,"tid":1,"ts":0,"ph":"M","cat":"__metadata","name":"process_name","args":{"name":"Service calls"}},
      ...trace.data.flat().map( d=> (
        Object.keys(d.processes).map(key=>
          ({"pid": 1,"tid": Number(key.slice(1)),"ts": 0,"ph": "M","cat": "__metadata","name": "thread_name",
            "args": {"name": d.processes[key].serviceName}}))
      )).flat(),
      ...trace.data[0].spans.map( s=> (
        {
          "name": s.operationName, "ph": "X", "pid": 1, "tid": Number(s.processID.slice(1)), "ts": s.startTime, "dur": s.duration,
          "args":
            Object.fromEntries(
              [...(s.tags||[]).map(t=>(
                  [t.key, t.value]
                )),
                ['  logs',s.logs]]
            )
        }
      ))
    ]
  }
));

This will generate a JSON file matching Google's Trace Event Format and can be opened in chrome://tracing (or https://ui.perfetto.dev) any other Catapult traceviewer for web like Lighthouse/tracehouse, Speedscope, etc.

Aside from the question of visualising traces, consider the difference between these two kinds of tools.

Jaeger has its roots in the server monitoring environment, while Google's Chrome tracer (and Perfetto) are rather more focused on the lower level CPU/threads of a workstation/device. Looking at very large tracers for Jaeger may not be its main use case.

It's possible for this reason that, at the time of writing this, the two may not have much to do with each other. Jaeger is also a backend for transaction traces, and with Open Telemetry eventually graduating from Cloud Native Computing Foundation, your best bet is to look for options down that route. Grafana has integration with Jaeger data sources, as an example.

Related