Distributed tracing is used by software engineers to monitor or debug their applications. It is very useful to find which process takes the most time or which function causes errors. One of the systems to do distributed tracing is Jaeger. This article will show you how to run Jaeger in the local environment and trace a Go application.
What is distributed tracing?
According to opentracing.io, distributed tracing is a method to profile and monitor applications, especially applications built using a microservice architecture. Distributed tracing can be very useful when our application gets some performance issue or when we want to improve the performance of our application. It is also useful to do a root cause analysis of a problem. The trace is presented as a chain of function calls. So we can debug our application easier or maybe found some unexpected process flow in our application.
Jaeger is one of the most popular systems to do distributed tracing. It is an open-source, end-to-end distributed tracing system. Jaeger is released by Uber Technology. Jaeger uses OpenTracing compatible data model and instrumentation libraries, so the API and instrumentation of distributed tracing are more standardized.
To run Jaeger in local environment, we can use Jaeger all in one docker image. For other deployment method, you can see in https://www.jaegertracing.io/docs/1.22/deployment/.
docker run -d -p6831:6831/udp -p16686:16686 jaegertracing/all-in-one:latest
This image already contains the Jaeger UI, collector, query, and agent, which is enough to trace our local app. You can go to http://localhost:16686 to open the Jaeger UI.
Now that we have Jaeger running, we can start to trace our application. In this example, we will trace a Go webserver.
Distributed tracing a Go app
To trace our Go application, we need to initialize the tracer first. This code is to initialize Jaeger tracer:
The sampler configuration that we use here is rate-limiting with param
100. It means that Jaeger will collect a maximum of 100 traces per second. You may want to change the type and param which is suitable for your needs.
Then, set global tracer with the Jaeger tracer.
Trace the processes
To trace the functions in our app, we need to start an opentracing span from a context at the start of the function and call its
Finish method before the function return. Note that we need to pass the
context created to the next function call so that Jaeger knows that it is in a chain of function calls. Below is an example of tracing an HTTP handler.
http.Request, and put
span.Finish()in defer. See that we use
ctxcreated on line 2 to call function
isLoggedInon line 5 and
getCityByCountryNameon line 11. Those functions also have to start opentracing span and finish it before the function call.
Next, we try to call the function several times and see the traces in Jaeger UI. Go to Jaeger UI and click
Click one of the traces and we can see its detail.
We can see the traces from the start of our HTTP handler, and which functions it calls. The length of the span indicates how much time did the function take. Try to explore the Jaeger UI and you will find that it is very useful and can help you in many cases.
Distributed tracing is useful to monitor your app. It can show the traces as a chain of function calls and help you debug your application easier. Jaeger is one of the popular systems for distributed tracing. It is easy to run and use, and it implements opentracing. We can see the tracing result in Jaeger UI and find how much time did each function take. It makes it easy to find which function could cause a bottleneck.
You can see the complete sample code of the Go webserver below.
The complete code
The complete code is here (click to expand)