# Trace Log with traceId
In web applications, a single request may go through many business processes. To facilitate troubleshooting, we want all logs generated by different business processes to have a unified traceId. Having a traceId allows us to link all logs related to the entire business process, making it easier to trace and analyze where problems occur in the business flow.
In other open-source frameworks, it's generally recommended to pass a context.Context
parameter to all functions, which is also recommended by the official Golang documentation. However, we believe that adding this extra parameter to every function is burdensome. We aim to avoid passing additional parameters to every function just to print a traceId in logs. Therefore, in Gone, we provide a built-in Goner to achieve this functionality.
# Burying Related Goners in the Cemetery
tip: To understand the core concepts and terminology of Gone, please read: Core Concepts of Gone (opens new window)
Here, we use the BasePriest
from the package github.com/gone-io/gone/tree/main/goner
to bury related Goners. In the BasePriest
, Goners related to tracer
, config
, and logrus
are all buried into the Cemetery, as these three packages are commonly used together.
func MasterPriest(cemetery gone.Cemetery) error {
_ = goner.BasePriest(cemetery)
// Bury other Goners
return nil
}
# Simple Usage
When the tracer is buried, when we print logs using the injected logrus.Logger
interface, a traceId will automatically be added to the logs.
//...
type service struct {
gone.Flag
log logrus.Logger `gone:"gone-logger"` // Named injection into nested log attributes
}
func (svc *service) Business(input string) (string, error) {
// Print log
svc.log.Infof("input content is %s", input)
return input, nil
}
//...
For example, the 061ad00f-8c0d-479c-bc4c-393e0cf2cca2
is the traceId:
2024-05-11 09:09:57.784|INFO|**/Users/jim/go/pkg/mod/github.com/gone-io/gone@v0.1.4/goner/gin/server.go:46**|061ad00f-8c0d-479c-bc4c-393e0cf2cca2|Server Listen At :8080
# Passing TraceId Across Goroutines
In the previous example, it's normal if no new goroutines are used. If a new goroutine is started using the go
keyword, it will be noticed that the logs printed by the goroutine do not have a traceId. To solve this, inject the tracer.Tracer
interface and use the Go
method instead of the go
keyword to start a new goroutine.
//...
type service struct {
gone.Flag
log logrus.Logger `gone:"gone-logger"` // Named injection into nested log attributes
tracer.Tracer `gone:"gone-tracer"` // Inject tracer
}
func (svc *service) Business(input string) (string, error) {
svc.Go(func() {
// Print log in a new goroutine
svc.log.Infof("log in new goroutine")
})
return input, nil
}
//...
# Passing TraceId Across Processes/Services
In microservices, a web request typically spans multiple microservices. Cross-service communication is generally done through:
- Message middleware To facilitate the passing of traceId in the message middleware and to facilitate the use of the message middleware to pass business events, we have open-sourced the https://github.com/gone-io/emitter (opens new window) repository. In this repository, we have implemented an adapter for Rocket MQ, and plan to adapt to other mainstream message middleware such as Kafka and RabbitMQ in the future.
- RPC calls/internal http calls Use the built-in Goner urllib (opens new window) to send http requests to Gone Web programs, and the traceId will be automatically passed between services. Additionally, using the built-in grpc (opens new window) to implement gRPC calls will also automatically pass the traceId. More RPC call support will be provided in the future.
# Multi-language Support
To pass the traceId in an HTTP request, a special header X-Trace-ID
is added to carry the traceId. Therefore, if multiple programming languages are used, as long as the different services follow the rule of "attaching X-Trace-ID
when making requests on the client side and parsing X-Trace-ID
when processing requests on the server side," traceId can be seamlessly passed across services developed in different languages.
We plan to develop packages in other languages to seamlessly integrate with other languages in the future.