Microservice architectures have become ubiquitous nowadays and tend to be the preferred way of building server applications. Back when logging was as easy as injecting a logger class into your domain classes, tracing the request was achieved by a unique id generated somewhere in the request pipeline and attached to the logger. You can still follow this method in microservice architectures. Nevertheless, you will end with numerous incoherent log messages distributed over your several services. This article presents a simple HTTP pipeline in Golang, paired with a request-id shared between all services.

To achieve systemwide log coherency we have to share a common identifier between our services. In the case of HTTP APIs, we can transmit this identifier in a header. This way, we don’t have to change the request bodies or query parameters that contain the business-related data — it stays hidden from the domain logic. To put the identifier in the headers, you need to have it accessible in any place of your program that communicates with other services.

Context

In Golang, the context API is the recommended way of transferring context-related data between different methods. Context-related data refers to any data that is not included in the domain logic. For example, an article number is domain-related data, while the caller’s IP address might not (depending on the business case). The context is an immutable struct that can be extended with key-value pairs by cloning the current context and creating a new one. Every http.Request comes with a context attached to it that can be extended with additional data.

The context has to be passed into any method that wants to make API calls. By convention, the context has to be the first parameter named ctx.

func DoCall(ctx context.Context, url string) error {
  ...
}

#golang #golang #microservices #api

Distributed Request Logging in Golang with Context API
20.00 GEEK