Skip to content

Trace Module

ci go report codecov Deps PkgGoDev

Overview

Yokai provides a fxtrace module, allowing your application to produce traces.

It wraps the trace module, based on OpenTelemetry.

Installation

The fxtrace module is automatically loaded by Yokai's core.

When you use a Yokai application template, you have nothing to install, it's ready to use.

Configuration

This module provides the possibility to configure a processor:

  • noop: to async void traces (default and fallback)
  • stdout: to async print traces to stdout
  • otlp-grpc: to async send traces to OTLP/gRPC collectors (ex: Jaeger, Grafana, etc.)
  • test: to sync store traces in memory (for testing assertions)

If an error occurs while creating the processor (for example failing OTLP/gRPC connection), the noop processor will be used as safety fallback (to prevent outages).

This module also provides possibility to configure a sampler:

  • parent-based-always-on: always on depending on parent (default)
  • parent-based-always-off: always off depending on parent
  • parent-based-trace-id-ratio: trace id ratio based depending on parent
  • always-on: always on
  • always-off: always off
  • trace-id-ratio: trace id ratio based

Example with stdout processor (with pretty print) and parent-based-trace-id-ratio sampler (ratio=0.5):

configs/config.yaml
modules:
  trace:
    processor:
      type: stdout
      options:
        pretty: true
    sampler:
      type: parent-based-trace-id-ratio
      options:
        ratio: 0.5

Another example with otlp-grpc processor (sending on jaeger:4317) and always-on sampler:

configs/config.yaml
modules:
  trace:
    processor:
      type: otlp-grpc
      options:
        host: jaeger:4317
    sampler:
      type: always-on

Usage

This module makes available the TracerProvider in Yokai dependency injection system.

It is built on top of OpenTelemetry, see its documentation for more details about available methods.

You can inject the tracer provider where needed, but it's recommended to use the one carried by the context.Context when possible (for automatic traces correlation).

Testing

This module provides the possibility to easily test your trace spans, using the TestTraceExporter with modules.trace.processor.type=test.

configs/config.test.yaml
modules:
  trace:
    processor:
      type: test # to send traces to test buffer

You can use the provided test assertion helpers in your tests:

  • AssertHasTraceSpan: to assert on exact name and exact attributes match
  • AssertHasNotTraceSpan: to assert on exact name and exact attributes non match
  • AssertContainTraceSpan: to assert on exact name and partial attributes match
  • AssertContainNotTraceSpan: to assert on exact name and partial attributes non match

and use Dump() to print the current content of the TestTraceExporter.

For example:

internal/example_test.go
package internal_test

import (
    "context"
    "testing"

    "github.com/ankorstore/yokai/trace/tracetest"
    "github.com/foo/bar/internal"
    "go.opentelemetry.io/otel/attribute"
    "go.opentelemetry.io/otel/trace"
    "go.uber.org/fx"
)

func TestExample(t *testing.T) {
    var traceExporter tracetest.TestTraceExporter

    internal.RunTest(
        t,
        fx.Populate(&traceExporter),
        fx.Invoke(func(tracerProvider trace.TracerProvider) {
            _, span := tracerProvider.Tracer("example tracer").Start(
                context.Background(),
                "example span",
                trace.WithAttributes(attribute.String("example name", "example value")),
            )
            defer span.End()
        }),
    )

    //dump spans
    traceExporter.Dump()

    // trace assertion example
    tracetest.AssertHasTraceSpan(
        t,
        traceExporter,
        "example span",
        attribute.String("example name", "example value"),
    )
}