zipkin Documentation

Zipkin is a distributed tracing system

17,433 stars Java Java 1 file Β· ~12,390 tokens #distributed-tracing#observability#openzipkin#tracing#zipkin
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy zipkin on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name zipkin --restart always openzipkin/zipkin:test
Configured Services & Ports
βš™οΈ zipkin
image: openzipkin/zipkin:test
βš™οΈ sut
image: ghcr.io/openzipkin/alpine:3.23.3
docker-compose.yml
yaml (docker-compose.yml)
#
# Copyright The OpenZipkin Authors
# SPDX-License-Identifier: Apache-2.0
#

services:
  zipkin:
    # Use last build of Zipkin instead of adding a matrix build dependency
    image: openzipkin/zipkin:test
    container_name: zipkin
  # Use fixed service and container name 'sut; so our test script can copy/pasta
  sut:
    container_name: sut
    image: ghcr.io/openzipkin/alpine:3.23.3
    entrypoint: /bin/sh
    # Keep the container running until HEALTHCHECK passes
    command: "-c \"sleep 5m\""
    healthcheck:
      # Return 0 when we can load the UI resources
      test: wget -qO- --spider http://zipkin:9411/zipkin/
    depends_on:
      zipkin:
        condition: service_healthy

1. Project Overview & Quickstart (openzipkin/zipkin)

File: README.md

zipkin



Zipkin is a distributed tracing system. It helps gather
timing data needed to troubleshoot latency problems in service architectures.
Features include both the collection and lookup of this data.

If you have a trace ID in a log file, you can jump directly to it. Otherwise,
you can query based on attributes such as service, operation name, tags and
duration. Some interesting data will be summarized for you, such as the
percentage of time spent in a service, and whether operations failed.

The Zipkin UI also presents a dependency diagram showing how many traced
requests went through each application. This can be helpful for identifying
aggregate behavior including error paths or calls to deprecated services.

Application’s need to be β€œinstrumented” to report trace data to Zipkin. This
usually means configuration of a tracer or instrumentation library. The most
popular ways to report data to Zipkin are via http or Kafka, though many other
options exist, such as Apache ActiveMQ, gRPC, RabbitMQ and Apache Pulsar. The data served to
the UI is stored in-memory, or persistently with a supported backend such as
Apache Cassandra or Elasticsearch.

Quick-start

The quickest way to get started is to fetch the latest released server as a self-contained
executable jar. Note that the Zipkin server requires minimum JRE 17+. For example:

bash
curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar

You can also start Zipkin via Docker.

bash
# Note: this is mirrored as ghcr.io/openzipkin/zipkin
docker run -d -p 9411:9411 openzipkin/zipkin

Once the server is running, you can view traces with the Zipkin UI at http://localhost:9411/zipkin.

If your applications aren't sending traces, yet, configure them with Zipkin instrumentation or try one of our examples.

Check out the zipkin-server documentation for configuration details, or Docker examples for how to use docker-compose.

Zipkin Slim

The slim build of Zipkin is smaller and starts faster. It supports in-memory and Elasticsearch storage, but doesn't support messaging transports like Kafka or RabbitMQ. If these constraints match your needs, you can try slim like below:

Running via Java:

bash
curl -sSL https://zipkin.io/quickstart.sh | bash -s io.zipkin:zipkin-server:LATEST:slim zipkin.jar
java -jar zipkin.jar

Running via Docker:

bash
# Note: this is mirrored as ghcr.io/openzipkin/zipkin-slim
docker run -d -p 9411:9411 openzipkin/zipkin-slim

Running via Homebrew:

bash
brew install zipkin
# to run in foreground
zipkin
# to run in background
brew services start zipkin

Core Library

The core library is used by both Zipkin instrumentation and the Zipkin server.

This includes built-in codec for Zipkin's v1 and v2 json formats. A direct dependency on gson
(json library) is avoided by minifying and repackaging classes used. The result is a 155k jar which
won't conflict with any library you use.

Ex.

java
// All data are recorded against the same endpoint, associated with your service graph
localEndpoint = Endpoint.newBuilder().serviceName("tweetie").ip("192.168.0.1").build()
span = Span.newBuilder()
    .traceId("d3d200866a77cc59")
    .id("d3d200866a77cc59")
    .name("targz")
    .localEndpoint(localEndpoint)
    .timestamp(epochMicros())
    .duration(durationInMicros)
    .putTag("compression.level", "9");

// Now, you can encode it as json
bytes = SpanBytesEncoder.JSON_V2.encode(span);

Note: The above is just an example, most likely you'll want to use an existing tracing library like Brave

Core Library Requires Java 8+

The minimum Java language level of the core library is 8. This helps support those writing agent
instrumentation. Version 2.x was the last to support Java 6.

Note: zipkin-reporter-brave
does not use this library. So, brave still supports Java 6.

Storage Component

Zipkin includes a StorageComponent, used to store and query spans and
dependency links. This is used by the server and those making collectors, or span reporters.
For this reason, storage components have minimal dependencies, though require Java 17+.

Ex.

java
// this won't create network connections
storage = ElasticsearchStorage.newBuilder()
                              .hosts(asList("http://myelastic:9200")).build();

// prepare a call
traceCall = storage.spanStore().getTrace("d3d200866a77cc59");

// execute it synchronously or asynchronously
trace = traceCall.execute();

// clean up any sessions, etc
storage.close();

In-Memory

The InMemoryStorage component is packaged in zipkin's core library. It
is neither persistent, nor viable for realistic work loads. Its purpose
is for testing, for example starting a server on your laptop without any
database needed.

Cassandra

The Cassandra component uses Cassandra
3.11.3+ features, but is tested against the latest patch of Cassandra 4.1.

This is the second generation of our Cassandra schema. It stores spans
using UDTs, such that they appear like Zipkin v2 json in cqlsh. It is
designed for scale, and uses a combination of SASI and manually
implemented indexes to make querying larger data more performant.

Note: This store requires a job to aggregate dependency links.

Elasticsearch

The Elasticsearch component uses
Elasticsearch 5+ features, but is tested against Elasticsearch 7-8.x and
OpenSearch 2.x.

It stores spans as Zipkin v2 json so that integration with other tools is
straightforward. To help with scale, this uses a combination of custom
and manually implemented indexing.

Note: This store requires a spark job to aggregate dependency links.

The following API endpoints provide search features, and are enabled by
default. Search primarily allows the trace list screen of the UI operate.

  • GET /services - Distinct Span.localServiceName
  • GET /remoteServices?serviceName=X - Distinct Span.remoteServiceName by Span.localServiceName
  • GET /spans?serviceName=X - Distinct Span.name by Span.localServiceName
  • GET /autocompleteKeys - Distinct keys of Span.tags subject to configurable whitelist
  • GET /autocompleteValues?key=X - Distinct values of Span.tags by key
  • GET /traces - Traces matching a query possibly including the above criteria

When search is disabled, traces can only be retrieved by ID
(GET /trace/{traceId}). Disabling search is only viable when there is
an alternative way to find trace IDs, such as logs. Disabling search can
reduce storage costs or increase write throughput.

StorageComponent.Builder.searchEnabled(false) is implied when a zipkin
is run with the env variable SEARCH_ENABLED=false.

Legacy (v1) components

The following components are no longer encouraged, but exist to help aid
transition to supported ones. These are indicated as "v1" as they use
data layouts based on Zipkin's V1 Thrift model, as opposed to the
simpler v2 data model currently used.

MySQL

The MySQL v1 component uses MySQL 5.6+
features, but is tested against MariaDB 10.11.

The schema was designed to be easy to understand and get started with;
it was not designed for performance. Ex spans fields are columns, so
you can perform ad-hoc queries using SQL. However, this component has
known performance issues: queries will eventually take seconds to return
if you put a lot of data into it.

This store does not require a job to aggregate dependency links.
However, running the job will improve performance of dependencies
queries.

Running the server from source

The Zipkin server receives spans via HTTP POST and respond to queries
from its UI. It can also run collectors, such as RabbitMQ or Kafka.

To run the server from the currently checked out source, enter the
following. JDK 17+ is required to compile the source.

bash
# Build the server and also make its dependencies
$ ./mvnw -q --batch-mode -DskipTests --also-make -pl zipkin-server clean install
# Run the server
$ java -jar ./zipkin-server/target/zipkin-server-*exec.jar

Artifacts

Server artifacts are under the maven group id io.zipkin
Library artifacts are under the maven group id io.zipkin.zipkin2

Library Releases

Releases are at Maven Central

Library Snapshots

Snapshots are uploaded to Sonatype after
commits to master.

Docker Images

Released versions of zipkin-server are published to Docker Hub as openzipkin/zipkin and GitHub
Container Registry as ghcr.io/openzipkin/zipkin. See docker for details.

Helm Charts

Helm charts are available via helm repo add zipkin https://zipkin.io/zipkin-helm.
See zipkin-helm for details.

Javadocs

https://zipkin.io/zipkin contains versioned folders with JavaDocs published on each (non-PR) build, as well
as releases.


File: benchmarks/README.md

zipkin-benchmarks

This module includes JMH
benchmarks for zipkin. You can use these to measure overhead.

Running the benchmark

From the project directory, run this to build the benchmarks:

bash
$ ./mvnw install -pl benchmarks -am -Dmaven.test.skip.exec=true

and the following to run them:

bash
$ java -jar benchmarks/target/benchmarks.jar

File: build-bin/README.md

Test and Deploy scripts

This is a Maven+Docker project, which uses standard conventions for test and deploy with some
exceptions.

On [../zipkin-lens]:

  • [maybe_install_npm] is used to build on an unsupported node.js architecture.
  • [maven_go_offline] additionally seeds the NPM cache

On test:

  • [test], used by [../.github/workflows/test.yml] runs Maven unit and integration tests.
    • Its "test" job skips docker, as they are run in parallel in "test_docker"
  • [../.github/workflows/readme_test.yml] tests build commands in [../zipkin-server] and [../docker]
    • zipkin, zipkin-lens and zipkin-slim Docker builds use RELEASE_FROM_MAVEN_BUILD=true
      • this avoids invoking Maven builds from within Docker, which are costly and fragile
    • Docker tests run in sequence to avoid queueing delays, which take longer than builds themselves.

On deploy:

  • [deploy], used by [../.github/workflows/deploy.yml] publishes jars and Docker images.
  • [javadoc_to_gh_pages] pushes Javadoc to the gh-pages branch on MAJOR.MINOR.PATCH branch, but not master.
  • Besides production Docker images, this project includes [../docker/test-images].
    • [docker_push] pushes test-images, but only to ghcr.io

Build Overview

build-bin holds portable scripts used in CI to test and deploy the project.

The scripts here are portable. They do not include any CI provider-specific logic or ENV variables.
This helps test.yml (GitHub Actions) and alternatives contain nearly the same contents, even if
certain OpenZipkin projects need slight adjustments here. Portability has proven necessary, as
OpenZipkin has had to transition CI providers many times due to feature and quota constraints.

These scripts serve a second purpose, which is to facilitate manual releases, which has also
happened many times due usually to service outages of CI providers. While tempting to use
CI-provider specific tools, doing so can easily create a dependency where no one knows how to
release anymore. Do not use provider-specific mechanisms to implement release flow. Instead,
automate triggering of the scripts here.

The only scripts that should be modified per project are in the base directory. Those in
subdirectories, such as docker, should not vary project to project except accident of
version drift. Intentional changes in subdirectories should be relevant and tested on multiple
projects to ensure they can be blindly copy/pasted.

Conversely, the files in the base directory are project specific entry-points for test and deploy
actions and are entirely appropriate to vary per project. Here's an overview:

Lint

Lint makes sure that documentation and workflows are in-tact. CI providers should be configured to
run lint on pull requests or pushes to the master branch, notably when the tag is blank. Linters
should only run on documentation-only commits or those who affect workflow files. Linters must not
depend on authenticated resources, as running lint can leak credentials.

We minimally check the following:

  • markdown-link-check on our Markdown content.
  • yamllint on our GitHub Actions Workflow YAML.
    • occasionally need line length exceptions via # yamllint disable-line rule:line-length

Example GitHub Actions setup

A simplest GitHub Actions lint.yml runs linters after configuring them, but only on relevant event
conditions. The name lint.yml and job lint allows easy references to status badges and parity of
the scripts it uses.

The on: section obviates job creation and resource usage for irrelevant events. Notably, GitHub
Actions includes the ability to skip documentation-only jobs.

Here's a partial lint.yml including only the aspects mentioned above.

yaml
---
on:  # yamllint disable-line rule:truthy
  push:  # non-tagged pushes to master
    branches:
      - master
    tags-ignore:
      - '*'
    paths:
      - '**/*.md'
      - '.github/workflows/*.yml'
      - './build-bin/*lint'
      - ./build-bin/mlc_config.json
  pull_request:  # pull requests targeted at the master branch.
    branches:
      - master
    paths:
      - '**/*.md'
      - '.github/workflows/*.yml'
      - './build-bin/*lint'
      - ./build-bin/mlc_config.json

jobs:
  lint:
    name: Lint
    runs-on: ubuntu-24.04  # newest available distribution, aka noble
    # skip commits made by the release plugin
    if: "!contains(github.event.head_commit.message, 'maven-release-plugin')"
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
      - name: Lint
        run: |
          build-bin/configure_lint
          build-bin/lint

Test

Test builds and runs any tests of the project, including integration tests. CI providers should be
configured to run tests on pull requests or pushes to the master branch, notably when the tag is
blank. Tests should not run on documentation-only commits. Tests must not depend on authenticated
resources, as running tests can leak credentials.

  • configure_test - Sets up build environment for tests.
  • test - Builds and runs tests for this project.

Example GitHub Actions setup

A simplest GitHub Actions test.yml runs tests after configuring them, but only on relevant event
conditions. The name test.yml and job test allows easy references to status badges and parity of
the scripts it uses.

The on: section obviates job creation and resource usage for irrelevant events. Notably, GitHub
Actions includes the ability to skip documentation-only jobs.

Here's a partial test.yml including only the aspects mentioned above.

yaml
on:  # yamllint disable-line rule:truthy
  push:  # non-tagged pushes to master
    branches:
      - master
    tags-ignore:
      - '*'
    paths-ignore:
      - '**/*.md'
      - './build-bin/*lint'
      - ./build-bin/mlc_config.json
  pull_request:  # pull requests targeted at the master branch.
    branches:
      - master
    paths-ignore:
      - '**/*.md'
      - './build-bin/*lint'
      - ./build-bin/mlc_config.json

jobs:
  test:
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
      - name: Test
        run: |
          build-bin/configure_test
          build-bin/test

Deploy

Deploy builds and pushes artifacts to a remote repository for master and release commits on it. CI
providers deploy pushes to master on when the tag is blank, but not on documentation-only commits.
Releases should deploy on version tags (ex /^[0-9]+\.[0-9]+\.[0-9]+/), without consideration of if
the commit is documentation only or not.

  • configure_deploy - Sets up environment and logs in.
  • deploy - deploys the project, with arg1 being "master" or a release commit like "1.2.3"

Example GitHub Actions setup

A simplest GitHub Actions deploy.yml deploys after logging in, but only on relevant event
conditions. The name deploy.yml and job deploy allows easy references to status badges and
parity of the scripts it uses.

The on: section obviates job creation and resource usage for irrelevant events. GitHub Actions
cannot implement "master, except documentation only-commits" in the same file. Hence, deployments of
master will happen even on README change.

Here's a partial deploy.yml including only the aspects mentioned above. Notice env variables are
explicitly defined and on.tags is a glob pattern.

yaml
on:  # yamllint disable-line rule:truthy
  push:
    branches:
      - master
    # Don't deploy tags because the same commit for MAJOR.MINOR.PATCH is also
    # on master: Redundant deployment of a release version will fail uploading.
    tags-ignore:
      - '*'

jobs:
  deploy:
    runs-on: ubuntu-24.04  # newest available distribution, aka noble
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 1  # only needed to get the sha label
      - name: Deploy
        env:
          GH_USER: ${{ secrets.GH_USER }}
          GH_TOKEN: ${{ secrets.GH_TOKEN }}
        run: |  # GITHUB_REF = refs/heads/master or refs/tags/MAJOR.MINOR.PATCH
          build-bin/configure_deploy &&
          build-bin/deploy $(echo ${GITHUB_REF} | cut -d/ -f 3)

File: docker/examples/README.md

Zipkin Docker Examples

This project is configured to run docker containers using
docker-compose.

To start the default docker compose configuration, run:

bash
# To use the last released version of zipkin
$ docker compose up
# To use the last built version of zipkin
$ TAG=master docker compose up

View the web UI at $(docker ip):9411. Traces are stored in memory.

To see specific traces in the UI, select "zipkin-server" in the dropdown and
then click the "Find Traces" button.

ActiveMQ

You can collect traces from ActiveMQ in addition to HTTP, using the
docker-compose-activemq.yml file. This configuration starts zipkin and zipkin-activemq in their
own containers.

To add ActiveMQ configuration, run:

bash
$ docker compose -f docker-compose-activemq.yml up

Then configure the ActiveMQ sender
using a brokerUrl value of failover:tcp://localhost:61616 or a non-local hostname if in docker.

Cassandra

You can store traces in Cassandra instead of memory, using the
docker-compose-cassandra.yml file. This configuration starts zipkin, zipkin-cassandra and
zipkin-dependencies (cron job) in their own containers.

To start the Cassandra-backed configuration, run:

bash
$ docker compose -f docker-compose-cassandra.yml up

The zipkin-dependencies container is a scheduled task that runs every hour.
If you want to see the dependency graph before then, you can run it manually
in another terminal like so:

bash
$ docker compose -f docker-compose-cassandra.yml run --rm --no-deps --entrypoint start-zipkin-dependencies dependencies

Elasticsearch

You can store traces in Elasticsearch instead of memory,
using the docker-compose-elasticsearch.yml file. This configuration starts zipkin,
zipkin-elasticsearch and zipkin-dependencies (cron job) in their own containers.

To start the Elasticsearch-backed configuration, run:

bash
$ docker compose -f docker-compose-elasticsearch.yml up

The zipkin-dependencies container is a scheduled task that runs every hour.
If you want to see the dependency graph before then, you can run it manually
in another terminal like so:

bash
$ docker compose -f docker-compose-elasticsearch.yml run --rm --no-deps --entrypoint start-zipkin-dependencies dependencies

Kafka

You can collect traces from Kafka in addition to HTTP, using the
docker-compose-kafka.yml file. This configuration starts zipkin and zipkin-kafka in their
own containers.

To add Kafka configuration, run:

bash
$ docker compose -f docker-compose-kafka.yml up

Then configure the Kafka sender using a bootstrapServers value of host.docker.internal:9092 if your application is inside the same docker network or localhost:19092 if not, but running on the same host.

In other words, if you are running a sample application on your laptop, you would use localhost:19092 bootstrap server to send spans to the Kafka broker running in Docker.

Docker machine and Kafka

If you are using Docker machine, adjust KAFKA_ADVERTISED_HOST_NAME in docker-compose-kafka.yml
and the bootstrapServers configuration of the kafka sender to match your Docker host IP (ex. 192.168.99.100:19092).

MySQL

You can store traces in MySQL instead of memory, using the
docker-compose-mysql.yml file. This configuration starts zipkin, zipkin-mysql and
zipkin-dependencies (cron job) in their own containers.

To start the MySQL-backed configuration, run:

bash
$ docker compose -f docker-compose-mysql.yml up

RabbitMQ

You can collect traces from RabbitMQ in addition to HTTP, using the
docker-compose-rabbitmq.yml file. This configuration starts zipkin and zipkin-rabbitmq in their
own containers.

To add RabbitMQ configuration, run:

bash
$ docker compose -f docker-compose-rabbitmq.yml up

Then configure the RabbitMQ sender
using a host value of localhost or a non-local hostname if in docker.

Pulsar

You can collect traces from Pulsar in addition to HTTP, using the
docker-compose-pulsar.yml file. This configuration starts zipkin and zipkin-pulsar in their
own containers.

To add Pulsar configuration, run:

bash
$ docker compose -f docker-compose-pulsar.yml up

Eureka

You can register Zipkin for service discovery in Eureka
using the docker-compose-eureka.yml file. This configuration starts zipkin and zipkin-eureka
in their own containers.

When zipkin starts, it registers its endpoint into eureka. Then, the two example services
discover zipkin's endpoint from eureka and use it to send spans.

To try this out, run:

bash
$ docker compose -f docker-compose.yml -f docker-compose-eureka.yml up

Example

The docker compose configuration can be extended to host an example application
using the docker-compose-example.yml file. That file employs docker compose overrides
to add a "frontend" and "backend" service.

To add the example configuration, run:

bash
$ docker compose -f docker-compose.yml -f docker-compose-example.yml up

Once the services start, open http://localhost:8081/

Afterward, you can view traces that went through the backend via http://localhost:9411/zipkin?serviceName=backend

UI

The docker compose configuration can be extended to host the UI on port 80
using the docker-compose-ui.yml file. That file employs
docker compose overrides
to add an NGINX container and relevant settings.

To start the NGINX configuration, run:

bash
$ docker compose -f docker-compose.yml -f docker-compose-ui.yml up

This container doubles as a skeleton for creating proxy configuration around
Zipkin like authentication, dealing with CORS with zipkin-js apps, or
terminating SSL.

If you want to run the zipkin-ui standalone against a remote zipkin server, you
need to set ZIPKIN_BASE_URL accordingly:

bash
$ docker run -d -p 80:80 \
  -e ZIPKIN_BASE_URL=http://myfavoritezipkin:9411 \
  openzipkin/zipkin-ui

UI Proxy

The docker compose configuration can be extended to proxy the UI on port 80
using the docker-compose-uiproxy.yml file. That file employs
docker compose overrides to add an NGINX container and relevant settings.

To start the NGINX configuration, run:

bash
$ docker compose -f docker-compose.yml -f docker-compose-uiproxy.yml up

This container helps verify the ZIPKIN_UI_BASEPATH variable by setting it to
"/admin/zipkin". This means when the compose configuration is up, you can
access Zipkin UI at http://localhost/admin/zipkin/

Prometheus

Zipkin comes with a built-in Prometheus metric exporter. The
docker-compose-prometheus.yml file starts Prometheus configured to scrape
Zipkin, exposes it on port 9090. You can open $DOCKER_HOST_IP:9090 and
start exploring metrics (available on the /prometheus endpoint of Zipkin).

docker-compose-prometheus.yml also starts a Grafana with authentication
disabled, exposing it on port 3000. On startup it's configured with the
Prometheus instance started by docker-compose as a data source, and imports
the dashboard published at https://grafana.com/dashboards/1598. This means that,
after running docker-compose ... -f docker-compose-prometheus.yml up, you
can open $DOCKER_IP:3000/dashboard/db/zipkin-prometheus and play around with
the dashboard.


File: docker/test-images/zipkin-uiproxy/README.md

zipkin-uiproxy Docker image

The zipkin-uiproxy testing image proxies the Zipkin UI with NGINX.

Besides norms defined in docker-alpine, this accepts the
following environment variables:

  • ZIPKIN_UI_BASEPATH: The path this proxy serves the UI under. Defaults to /zipkin
  • ZIPKIN_BASE_URL: The proxied zipkin base URL. Defaults to http://zipkin:9411

To build openzipkin/zipkin-ui:test, from the top-level of the repository, run:

bash
$ DOCKER_FILE=docker/test-images/zipkin-uiproxy/Dockerfile build-bin/docker/docker_build openzipkin/zipkin-uiproxy:test

File: docker/test-images/zipkin-ui/README.md

zipkin-ui Docker image

The zipkin-ui testing image contains the static parts of the Zipkin UI served directly with NGINX.

Besides norms defined in docker-alpine, this accepts the
following environment variables:

To build openzipkin/zipkin-ui:test, from the top-level of the repository, run:

bash
$ DOCKER_FILE=docker/test-images/zipkin-ui/Dockerfile build-bin/docker/docker_build openzipkin/zipkin-ui:test

File: docker/test-images/zipkin-rabbitmq/README.md

zipkin-rabbitmq Docker image

The zipkin-rabbitmq testing image runs rabbitmq-server for the
RabbitMQ collector integration.

For convenience, this includes the "guest" user and a default queue named
"zipkin". To add more queues, exec amqp-declare-queue in a running container.

To build openzipkin/zipkin-rabbitmq:test, from the top-level of the repository, run:

bash
$ DOCKER_FILE=docker/test-images/zipkin-rabbitmq/Dockerfile build-bin/docker/docker_build openzipkin/zipkin-rabbitmq:test

File: docker/test-images/zipkin-pulsar/README.md

zipkin-pulsar Docker image

The zipkin-pulsar testing image runs Pulsar for Pulsar collector integration.

To build openzipkin/zipkin-pulsar:test, from the top-level of the repository, run:

bash
$ DOCKER_FILE=docker/test-images/zipkin-pulsar/Dockerfile build-bin/docker/docker_build openzipkin/zipkin-pulsar:test

You can use the env variable PULSAR_LOG_ROOT_LEVEL to change the log level for Pulsar. Defaults to "WARN".


File: docker/test-images/zipkin-opensearch2/README.md

zipkin-opensearch2 Docker image

The zipkin-opensearch2 testing image runs OpenSearch 2.x for Elasticsearch storage
integration.

To build openzipkin/zipkin-opensearch2:test, from the top-level of the repository, run:

bash
$ DOCKER_FILE=docker/test-images/zipkin-opensearch2/Dockerfile build-bin/docker/docker_build openzipkin/zipkin-opensearch2:test

You can use the env variable OPENSEARCH_JAVA_OPTS to change settings such as heap size for OpenSearch.

Host setup

OpenSearch is strict
about virtual memory. You will need to adjust accordingly (especially if you notice OpenSearch crash!)

bash
# If docker is running on your host machine, adjust the kernel setting directly
$ sudo sysctl -w vm.max_map_count=262144

# If using docker-machine/Docker Toolbox/Boot2Docker, remotely adjust the same
$ docker-machine ssh default "sudo sysctl -w vm.max_map_count=262144"

# If using colima, it is similar as well
$ colima ssh "sudo sysctl -w vm.max_map_count=262144"

File: docker/test-images/zipkin-mysql/README.md

zipkin-mysql Docker image

The zipkin-mysql testing image runs MySQL 10.x initialized with Zipkin's schema for
MySQL storage integration.

To build openzipkin/zipkin-mysql:test, from the top-level of the repository, run:

bash
$ DOCKER_FILE=docker/test-images/zipkin-mysql/Dockerfile build-bin/docker/docker_build openzipkin/zipkin-mysql:test

When running with docker-machine, you can connect like so:

bash
$ mysql -h $(docker-machine ip) -u zipkin -pzipkin -D zipkin

2. Official Technical Reference & Guides (openzipkin/openzipkin.github.io)

File: README.md

openzipkin.github.io

This repository contains the source code for the Zipkin documentation site
http://zipkin.io. It's the
organization page
for openzipkin, hosted using
GitHub pages and Jekyll.
This means that everything on the master branch is immediately and
automatically published.

It uses the static site generator Jekyll. Jekyll is
implemented in Ruby and requires Ruby
version >= 2.7.

Contributing

Improvements to the documentation are more than welcome. This section tries to
get you up to speed on how to run the site locally and make changes. Just like
the documentation, this meta-documentation also welcomes all improvements. If
you can, you should use OSX or Linux; Jekyll is not very well supported on
Windows.

If you've done this kind of thing before

You may wish to use rbenv to ensure your Ruby and Bundler versions are
consistent before proceeding.

  1. Fork, branch, clone
  2. bundle
  3. jekyll serve
  4. Make changes, commit, push
  5. Open a pull-request

Preparing your environment

  1. Install Ruby

    The official documentation at
    https://www.ruby-lang.org/en/documentation/installation/ describes the
    procedure for all major operating systems.

  2. System-level dependencies

    Nokogiri, one of the components used by Jekyll,
    requires some system-level libraries to be in place before installation of
    Jekyll can begin. Things should generally work out of the box, but keep in
    mind that if Jekyll installation fails referencing Nokogiri, then the
    Installing Nokogiri
    document most likely has what you need.

  3. Clone the repository

    text
    git clone https://github.com/openzipkin/openzipkin.github.io.git
  4. Install Jekyll and friends

    GitHub quite considerately provides the exact list of packages that are used
    to generate the site on GitHub Pages, which means we can use the exact same
    packages when running the site locally. This minimizes differences between
    what you see locally, and what you'll see in production. Gemfile
    defines the packages to be installed using the list provided by GitHub (and
    Gemfile.lock makes sure we all have the same versions
    locally). To install these packages:

    text
    cd openzipkin.github.io
     bundle
  5. Run the site

    You're now all set! The following command starts Jekyll, and makes the site
    available at http://localhost:4000. It'll also pick
    up any changes you make locally, and regenerate the site, so you can review
    your changes live without having to restart Jekyll.

    text
    bundle exec jekyll serve

Finding your way around the repository

Next up is making some changes to the site. To do that, you'll need to have a
basic understanding of how the repository is structured.

Content for all the pages lives in the pages directory. This makes it
very clear where you need to look when making changes to the website text; it's
clearly separated from all the scaffolding around the actual content. The only
exception is the home page, index.md. It's in the root of the
repository for purely technical reasons (GitHub Pages can only serve the root
document from the root of the repository, and doesn't allow running any Jekyll
plugins).

The rest of the repository contains scaffolding; here's a list to give you a
basic idea of what's what:

  • _data contains lists of things that are rendered into various
    parts of the page. For instance the list of tracers and instrumentation
    is defined here in a structured way.
  • _includes contains HTML snippets that are shared by some or
    all pages.
  • _layouts contains the basic HTML shared by all pages - and
    references snippets in _includes. At the time of writing, all pages use the
    page layout, and I don't foresee new layouts becoming actively used.
  • _sass contains style-sheets implemented in Sass.
  • public contains static content that's directly served to browsers as-is.
  • .editorconfig contains
    EditorConfig configuration that makes sure
    editors supporting EditorConfig format files in this repository in the same
    way (think spaces vs tabs)
  • CNAME tells GitHub pages that this site should be served at
    http://zipkin.io instead of
    http://openzipkin.zipkin.io. For details on
    how, see
    [https://help.github.com/articles/using-a-custom-domain-with-github-pages/](Using
    a custom domain with GitHub Pages)
  • Gemfile and Gemfile.lock describe the Ruby
    packages used for building and serving this site; see the documentation of
    Bundler for more details.
  • _config.yml contains configuration options used by Jekyll
    when generating the site.

Some finer points

There are a few things to keep an eye out for while making changes to the site.

  • For links to work correctly both locally, on forks, and in production, we
    need to include {{ site.github.url }} at the beginning of URLs. For
    example, a link to the Quickstart guide looks like this: {{ site.github.url }}/pages/quickstart. This is expanded by Jekyll to the correct value based
    on where it's running. More documentation is available
    here
  • A link to each page appears in the side-bar. The links are ordered based on a
    custom value weight assigned to each page. By default each page has a
    weight of 100 - the default is defined in _config.yml. This can be
    overridden in each page, see index.md for an example. Pages
    with lower weight come first in the list. Pages with the same weight are
    sorted however Jekyll sees fit - probably alphabetically.
    * This is implemented by custom logic for in
    _includes/sidebar.html. As we add more
    content, we may want to add more structure to the side-bar, and we may
    need to re-think this approach. Worst case, we can manage the side-bar
    contents manually.

Creating a pull-request

Once you've made your changes, you'll want to create a pull-request, so that the
changes can be merged into the master branch of
openzipkin/openzipkin.github.io, and so published for the betterment of all.
This section describes the steps for getting there, assuming you've followed the
instructions so far.

  1. Fork this repository

    Go to
    openzipkin/openzipkin.github.io,
    and click the "Fork" button. Or just
    click here.

  2. Tell git about your fork

    We're going to call your fork origin, and the original openzipkin
    repository upstream. The following commands tell git to make the
    appropriate changes:

    text
    git remote rename origin upstream
     git remote add origin [email protected]:$USER/openzipkin.github.io
     git fetch upstream
  3. Create a branch, commit and push your changes

    text
    git checkout -b my-awesome-changes
     git commit -m 'Short, useful description of my changes'
     git push
  4. Open a pull-request

    Open https://github.com/openzipkin/openzipkin.github.io. You should see a bar
    above the list of files that says you've recently pushed to your branch, with
    a green button on the right to open a pull request. Click it; add text to
    text fields and click buttons as appropriate. See
    https://help.github.com/articles/using-pull-requests/
    for detailed instructions.

Pulling changes

When you come back to the project later, you'll want to make sure you have all
the recent changes downloaded before making any further changes. Note: the
following commands throw away any and all changes you have locally. If that's
not desired, refer to the documentation of your git client.

text
git checkout master
git fetch upstream
git reset --hard upstream/master
git push

You'll also want to make sure you have all the required Ruby packages, at
exactly the required versions:

text
bundle

You are now ready to start a new branch and add more awesome to the
documentation.


File: build-bin/README.md

Test and Deploy scripts

This is a Jekyll project, which only includes the [test] command as files are served as-is with
GitHub Pages.

Unlike code-based projects, we test documentation-only commits: this is literally a website!

Build Overview

build-bin holds portable scripts used in CI to test and deploy the project.

The scripts here are portable. They do not include any CI provider-specific logic or ENV variables.
This helps .travis.yml and test.yml (GitHub Actions) contain nearly the same contents, even if
certain OpenZipkin projects need slight adjustments here. Portability has proven necessary, as
OpenZipkin has had to transition CI providers many times due to feature and quota constraints.

These scripts serve a second purpose, which is to facilitate manual releases, which has also
happened many times due usually to service outages of CI providers. While tempting to use
CI-provider specific tools, doing so can easily create a dependency where no one knows how to
release anymore. Do not use provider-specific mechanisms to implement release flow. Instead,
automate triggering of the scripts here.

The only scripts that should be modified per project are in the base directory. Those in sub
directories, such as [docker], should not vary project to project except accident of version drift.
Intentional changes in sub directories should be relevant and tested on multiple projects to ensure
they can be blindly copy/pasted.

Conversely, the files in the base directory are project specific entry-points for test and deploy
actions and are entirely appropriate to vary per project. Here's an overview:

Test

Test builds and runs any tests of the project, including integration tests. CI providers should be
configured to run tests on pull requests or pushes to the master branch, notably when the tag is
blank. Tests should not run on documentation-only commits. Tests must not depend on authenticated
resources, as running tests can leak credentials. Git checkouts should include the full history so
that license headers or other git analysis can take place.

  • [configure_test] - Sets up build environment for tests.
  • [test] - Builds and runs tests for this project.

Example GitHub Actions setup

A simplest GitHub Actions test.yml runs tests after configuring them, but only on relevant event
conditions. The name test.yml and job test allows easy references to status badges and parity of
the scripts it uses.

The on: section obviates job creation and resource usage for irrelevant events. Notably, GitHub
Actions includes the ability to skip documentation-only jobs.

Combine [configure_test] and [test] into the same run: when configure_test primes file system
cache.

Here's a partial test.yml including only the aspects mentioned above.

yaml
on:
  push:
    tags: ''
    branches: master
    paths-ignore: '**/*.md'
  pull_request:
    branches: master
    paths-ignore: '**/*.md'

jobs:
  test:
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2
        with:
          fetch-depth: 0  # full git history
      - name: Test
        run: build-bin/configure_test && build-bin/test

Example Travis setup

.travis.yml is a monolithic configuration file broken into stages, of which the default is "test".
A simplest Travis test job configures tests in install and runs them as script, but only on
relevant event conditions.

The if: section obviates job creation and resource usage for irrelevant events. Travis does not
support file conditions. A before_install step to skip documentation-only commits will likely
complete in less than a minute (10 credit cost).

Here's a partial .travis.yml including only the aspects mentioned above.

yaml
git:
  depth: false  # full git history for license check, and doc-only skipping

jobs:
  include:
    - stage: test
      if: branch = master AND tag IS blank AND type IN (push, pull_request)
      name: Run unit and integration tests
      before_install: |
        if [ -n "${TRAVIS_COMMIT_RANGE}" ] && ! git diff --name-only "${TRAVIS_COMMIT_RANGE}" -- | grep -qv '\.md$'; then
          echo "Stopping job as changes only affect documentation (ex. README.md)"
          travis_terminate 0
        fi
      install: ./build-bin/configure_test
      script: ./build-bin/test

Deploy

Deploy builds and pushes artifacts to a remote repository for master and release commits on it. CI
providers deploy pushes to master on when the tag is blank, but not on documentation-only commits.
Releases should deploy on version tags (ex /^[0-9]+\.[0-9]+\.[0-9]+/), without consideration of if
the commit is documentation only or not.

  • [configure_deploy] - Sets up environment and logs in, assuming [configure_test] was not called.
  • [deploy] - deploys the project, with arg0 being "master" or a release commit like "1.2.3"

Example GitHub Actions setup

A simplest GitHub Actions deploy.yml deploys after logging in, but only on relevant event
conditions. The name deploy.yml and job deploy allows easy references to status badges and
parity of the scripts it uses.

The on: section obviates job creation and resource usage for irrelevant events. GitHub Actions
cannot implement "master, except documentation only-commits" in the same file. Hence, deployments of
master will happen even on README change.

Combine [configure_deploy] and [deploy] into the same run: when configure_deploy primes file
system cache.

Here's a partial deploy.yml including only the aspects mentioned above. Notice env variables are
explicitly defined and on.tags is a glob pattern.

yaml
on:
  push:
    tags: '[0-9]+.[0-9]+.[0-9]+**'  # Ex. 8.272.10 or 15.0.1_p9
    branches: master

jobs:
  deploy:
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2
        with:
          fetch-depth: 1  # only needed to get the sha label
      - name: Deploy
        env:
          GH_USER: ${{ secrets.GH_USER }}
          GH_TOKEN: ${{ secrets.GH_TOKEN }}
        run: |  # GITHUB_REF will be refs/heads/master or refs/tags/N.M.L
          build-bin/configure_deploy &&
          build-bin/deploy $(echo ${GITHUB_REF} | cut -d/ -f 3)

Example Travis setup

.travis.yml is a monolithic configuration file broken into stages. This means test and deploy
are in the same file. A simplest Travis deploy stage has two jobs: one for master pushes and
another for version tags. These jobs are controlled by event conditions.

The if: section obviates job creation and resource usage for irrelevant events. Travis does not
support file conditions. A before_install step to skip documentation-only commits will likely
complete in less than a minute (10 credit cost).

As billing is by the minute, it is most cost effective to combine test and deploy on master push.

Here's a partial .travis.yml including only the aspects mentioned above. Notice YAML anchors work
in Travis and tag =~ condition is a regular
expression.

yaml
git:
  depth: false  # full git history for license check, and doc-only skipping

_terminate_if_only_docs: &terminate_if_only_docs |
  if [ -n "${TRAVIS_COMMIT_RANGE}" ] && ! git diff --name-only "${TRAVIS_COMMIT_RANGE}" -- | grep -qv '\.md$'; then
    echo "Stopping job as changes only affect documentation (ex. README.md)"
    travis_terminate 0
  fi

jobs:
  include:
    - stage: test
      if: branch = master AND tag IS blank AND type IN (push, pull_request)
      before_install: *terminate_if_only_docs
      install: |
        if [ "${TRAVIS_SECURE_ENV_VARS}" = "true" ] && [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
          export SHOULD_DEPLOY=true
          ./build-bin/configure_deploy
        else
          export SHOULD_DEPLOY=false
          ./build-bin/configure_test
        fi
      script:
        - ./build-bin/test || travis_terminate 1
        - if [ "${SHOULD_DEPLOY}" != "true" ]; then travis_terminate 0; fi
        - travis_wait ./build-bin/deploy master
    - stage: deploy
      # Ex. 8.272.10 or 15.0.1_p9
      if: tag =~ /^[0-9]+\.[0-9]+\.[0-9]+/ AND type = push AND env(GH_TOKEN) IS present
      install: ./build-bin/configure_deploy
      script: ./build-bin/deploy ${TRAVIS_TAG}