在Golang基于gRPC的微服务开发中,常常需要对分布式系统进行日志和链路追踪,以便更好地进行监控和调试。下面是一个简单的设计示例:
- 安装依赖:
$ go get google.golang.org/grpc
$ go get github.com/golang/protobuf/proto
$ go get github.com/golang/protobuf/protoc-gen-go
# 安装logrus和logrus的json格式输出插件。
$ go get github.com/sirupsen/logrus
$ go get github.com/mattn/go-isatty
# 安装opentracing相关库。
$ go get github.com/opentracing/opentracing-go
$ go get github.com/uber/jaeger-client-go/config
- 在main函数中初始化Logrus、Jaeger等组件并设置日志级别、输出格式等参数:
import (
"log"
"os"
"github.com/sirupsen/logrus"
"github.com/mattn/go-isatty"
"github.com/opentracing/opentracing-go"
"github.com/uber/jaeger-client-go/config"
)
func main() {
// 初始化Logrus,并设置日志级别、输出格式等参数。
logrus.SetFormatter(&logrus.JSONFormatter{})
if isatty.IsTerminal(os.Stdout.Fd()) {
logrus.SetLevel(logrus.DebugLevel)
} else {
logrus.SetLevel(logrus.InfoLevel)
}
logrus.SetOutput(os.Stdout)
// 初始化Jaeger Tracer。
cfg, err := config.FromEnv()
if err != nil {
log.Fatalf("Failed to read Jaeger config from env: %v", err)
}
tracer, closer, err := cfg.NewTracer()
if err != nil {
log.Fatalf("Failed to create Jaeger tracer: %v", err)
}
defer closer.Close()
opentracing.SetGlobalTracer(tracer)
// ...
}
- 封装Logrus和Jaeger,以便在Golang基于gRPC的微服务开发中进行使用:
import (
"github.com/sirupsen/logrus"
"github.com/opentracing/opentracing-go"
"github.com/opentracing/opentracing-go/ext"
"github.com/uber/jaeger-client-go"
jaegercfg "github.com/uber/jaeger-client-go/config"
)
var log *logrus.Entry
func init() {
log = logrus.WithFields(logrus.Fields{
"app": "myapp",
"env": "production",
})
}
func doSomething(ctx context.Context) {
// 创建Span。
span, ctx := opentracing.StartSpanFromContext(ctx, "doSomething")
defer span.Finish()
// 记录日志。
log.WithFields(logrus.Fields{
"operation": span.OperationName(),
"trace_id": span.Context().(jaeger.SpanContext).TraceID().String(),
"span_id": span.Context().(jaeger.SpanContext).SpanID().String(),
}).Infof("doing something")
// 发起下游调用,将当前Span传递给下游服务。
req := &pb.Request{...}
resp, err := client.Call(ctx, req)
if err != nil {...}
// 记录返回结果,并设置相关标签。
ext.HTTPStatusCode.Set(span, uint16(resp.StatusCode))
log.WithFields(logrus.Fields{
"operation": span.OperationName(),
"trace_id": span.Context().(jaeger.SpanContext).TraceID().String(),
"span_id": span.Context().(jaeger.SpanContext).SpanID().String(),
"response_code": resp.StatusCode,
}).Infof("got response")
// ...
}
在这个设计中,我们使用了Logrus作为日志组件,并使用Jaeger作为分布式链路追踪组件。在main函数中初始化Logrus和Jaeger,并设置日志级别、输出格式等参数。封装Logrus和Jaeger时,可以在init函数中创建全局log实例和tracer实例,并设置一些默认的字段值,然后在需要打印日志或者记录Span的地方调用对应的方法即可。注意,在记录日志和记录Span时都要将当前上下文ctx传递给相关方法,以便进行跨服务间的信息传递。同时,在发起下游调用时也需要将当前Span传递给下游服务,以便进行链路追踪。
内容由零声教学AI助手提供,问题来源于学员提问