/jaeger-tutorial

Microservice tracing tutorial with a client and two services. Written in javascript with much haste.

Primary LanguageJavaScript

Step 1: Create a Tracer

A tracer needs a:

Config: * serviceName * sampler * reporter

Options: * logger * metrics

The options are optional, but I recommend providing a logger.


A trace is a directed acyclic graph (DAG) which means that it has a definite start and end nodes with directed edges establishing the relationship between each parent and child.

Each node in the graph is a Span, each edge (relationship) is known as a SpanReference. A SpanReference consists of a ReferenceType and a SpanContext.

For a parent span to finish, all child spans need to finish.

A SpanContext is an immutable thread safe part of a span that can be used to establish a reference or propogated over the wire.

A SpanContext can be Injected and Extracted from a process.


Step 2: Span

  • A tracer can create a span.

  • A span has an operation name.

  • A span ends when finish is called.


Step 3: Annotating a Span

A Span can be annotated with Tags and Logs.

Tags are metadata that can be added to a span. A Tag must not be time sensitive data. It should remain the same for the entire duration of the span.

A log is an event that is associated with a clear timestamp.

OpenTracing API exposes a span.log method, each log must contain an event field.


Step 4: Nested Spans

  • A span can be a child or a parent of another span.

  • To declare a span as a child of another span, use:

tracer.startSpan('<span-name>', { childOf: rootSpan });

Create a tracer

const { initTracer } = require('jaeger-client')

module.exports = createTracer

function createTracer (serviceName) {
  const sampler = { type: 'const', param: 1 }

  // collectorEndpoint: 'http://xxx.xxx.xxx'
  // agentHost: 'xxx.xxx.xxx',
  // agentPort: 6832
  const reporter = { logSpans: true }

  const config = { serviceName, sampler, reporter }

  const logger = { info: msg => console.log('INFO', msg), error: msg => console.error('ERROR', msg) }

  return initTracer(config, { logger })
}

Use a tracer for a function

const tracer = initTracer(serviceName)

const sayHello = helloTo => {
  const span = tracer.startSpan('say-hello')

  span.setTag('hello-to', helloTo)

  const helloStr = `Hello, ${helloTo}!`
  span.log({ event: 'string-format', value: helloStr })

  console.log(helloStr)
  span.log({ event: 'print-string' })

  span.finish()
}

sayHello('Dark')
tracer.close(() => process.exit())

Child Spans

const tracer = initTracer(serviceName)

const printHello = (rootSpan, helloStr) => {
  const span = tracer.startSpan('print-hello', { childOf: rootSpan });
  console.log(helloStr)
  span.log({ event: 'print-string' })
  span.finish();
}

const formatString = (rootSpan, helloTo) => {
  const span = tracer.startSpan('format-string', { childOf: rootSpan });
  const str = `Hello ${helloTo}`
  span.log({ event: 'format-string', value: str })
  span.finish();
  return str
}

const sayHello = helloTo => {
  const span = tracer.startSpan('say-hello')
  span.setTag('hello-to', helloTo)
  const str = formatString(span, helloTo)
  printHello(span, str)
  span.finish();
}

sayHello('Dark')
tracer.close(() => process.exit())