Hone logo
Hone
Problems

Implementing Basic Distributed Tracing in Go with Jaeger

Distributed tracing is crucial for understanding the flow of requests across multiple services in a microservices architecture. This challenge asks you to implement a basic distributed tracing system in Go, using Jaeger as the tracing backend. You'll instrument a simple HTTP server and client to propagate trace context between them, allowing you to visualize the request flow in Jaeger.

Problem Description

You are tasked with building a simple Go application consisting of two components: an HTTP server and an HTTP client. The server will receive a request, perform a simple operation (e.g., sleeping for a short duration), and then call the client. The client will then respond to the server. The goal is to instrument both the server and client with Jaeger tracing, ensuring that the trace context is propagated between them. This will allow you to see a single, unified trace spanning both the server and client operations within the Jaeger UI.

Key Requirements:

  • Jaeger Integration: Utilize the opentracing-go and jaeger-client-go libraries to interact with a Jaeger collector. Assume a Jaeger collector is running at localhost:14268.
  • Trace Context Propagation: Properly propagate the trace context (trace ID and span ID) when the server makes a request to the client. This is typically done via HTTP headers (e.g., X-B3-TraceId, X-B3-SpanId, X-B3-ParentSpanId).
  • Span Naming: Give meaningful names to your spans (e.g., "HTTP Server Request", "Client Request").
  • Error Handling: Include basic error handling for tracing operations.
  • Minimal Dependencies: Keep the dependencies to a minimum, focusing on the core tracing functionality.

Expected Behavior:

  1. When the server receives an HTTP request, a new trace and span are created.
  2. The server's span is tagged with relevant information (e.g., request path, status code).
  3. When the server calls the client, the trace context is propagated in the HTTP headers.
  4. The client receives the request, creates a new span as a child of the server's span, and tags it appropriately.
  5. Both spans are reported to the Jaeger collector.
  6. In the Jaeger UI, you should see a single trace that spans both the server and client operations, showing the request flow and timings.

Edge Cases to Consider:

  • What happens if the Jaeger collector is unavailable? (Implement basic error handling to log this.)
  • How do you handle errors within the server or client? (Consider tagging spans with error information.)

Examples

Example 1:

Input: Server receives a GET request to "/hello"
Output: A trace is created in Jaeger, with a span named "HTTP Server Request" showing the request path "/hello" and a duration.  A child span is created in the client, named "Client Request", showing a duration.
Explanation: The server creates a trace and span, propagates the context to the client, and the client creates a child span. Both are reported to Jaeger.

Example 2:

Input: Server receives a POST request to "/error" which results in an internal server error.
Output: A trace is created in Jaeger, with a span named "HTTP Server Request" showing the request path "/error" and a duration. The span is tagged with an "error" tag set to "true" and the error message. A child span is not created in the client as the server returns an error.
Explanation: The server creates a trace and span, tags it with error information, and reports it to Jaeger.

Constraints

  • Jaeger Collector: Assume the Jaeger collector is running at localhost:14268.
  • HTTP Server: The server should listen on port 8080.
  • HTTP Client: The client should make requests to localhost:8080.
  • Timeouts: Keep timeouts short (e.g., 1 second) to avoid long delays during testing.
  • Dependencies: Limit the number of external dependencies to the core tracing libraries.
  • Performance: While not a primary focus, avoid unnecessary overhead that would significantly impact performance.

Notes

  • You can use the net/http package for creating the HTTP server and client.
  • Consider using a middleware approach to inject tracing into your HTTP handlers.
  • The opentracing-go library provides utilities for creating and managing spans.
  • The jaeger-client-go library provides the client for sending spans to the Jaeger collector.
  • Focus on demonstrating the core concepts of trace context propagation and span creation. You don't need to implement a full-fledged microservice architecture.
  • Start with a simple "Hello, World!" style server and client and gradually add tracing functionality.
  • Remember to initialize the Jaeger tracer before starting your server and client. Refer to the opentracing-go and jaeger-client-go documentation for initialization details.
Loading editor...
go