Logging is a crucial aspect of microservices. We can write middleware to capture all requests and responses going into and out of a service. Even for a client, we can capture logs while making RPC calls to a service.
Go Micro is a lean framework and doesn't enforce logging by default. We can easily wrap a service handler with our own custom logger. For example, in the encryptService example, we have a file called handlers.go.
In order to activate logging for each request in a custom format, we have to define a wrapper, and then link it to the service. As an example, if we have to log every incoming encryption request, follow these steps:
- Create a new wrapper function. It takes Context, Request, and Response as arguments. Here, we just print the time of the request arrival, like this:
func logWrapper(fn server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req *proto.Request,
rsp *proto.Response) error {
fmt.Printf("encryption request at time: %v", time.Now())
return fn(ctx, req, rsp)
}
}
- In service, we can attach the wrapper, like this:
service := micro.NewService(
micro.Name("encrypter"),
// wrap the client
micro.WrapClient(logWrap),
)
Now, the service logs every request in the format defined in the wrapper function, like so:
encryption request at time: 2019/12/22 23:07:3
The instrumentation of services is out of the scope of this book, but there is an open standard called OpenTracing (https://opentracing.io/). It defines a standard for how to metricize API endpoints, number of requests, and so on. Please feel free to explore it.