日志格式规范
- 使用结构化日志:Go 语言中可以使用第三方库如
logrus
或 zap
来生成结构化日志。结构化日志相比传统文本日志,更易于解析和查询。例如使用 logrus
:
package main
import (
"github.com/sirupsen/logrus"
)
func main() {
log := logrus.New()
log.WithFields(logrus.Fields{
"service": "my - go - service",
"status": "running",
}).Info("Service started")
}
- 统一时间格式:日志中的时间字段应采用标准且统一的格式,如 ISO8601 格式。
logrus
和 zap
都支持设置时间格式。对于 logrus
:
log.SetFormatter(&logrus.JSONFormatter{
TimestampFormat: "2006 - 01 - 02T15:04:05Z07:00",
})
- 日志级别规范:遵循常见的日志级别,如
DEBUG
、INFO
、WARN
、ERROR
、FATAL
等。在不同的运行状态和错误情况下使用合适的日志级别。例如在开发和调试阶段使用 DEBUG
级别记录详细信息,在生产环境主要使用 INFO
及以上级别。
元数据添加
- 服务相关元数据:添加服务名称、版本号等信息。以
logrus
为例:
log := logrus.New()
log.SetFormatter(&logrus.JSONFormatter{})
log.WithFields(logrus.Fields{
"service_name": "my - go - service",
"service_version": "1.0.0",
}).Info("Service started")
- 分布式追踪元数据:如果使用分布式追踪系统(如 Jaeger),可以在日志中添加追踪 ID 和跨度 ID 等信息,方便关联不同服务间的请求链路。例如:
import (
"context"
"github.com/opentracing/opentracing - go"
"github.com/sirupsen/logrus"
)
func main() {
ctx := context.Background()
tracer, _ := opentracing.GlobalTracer()
span := tracer.StartSpan("my - operation")
defer span.Finish()
ctx = opentracing.ContextWithSpan(ctx, span)
log := logrus.New()
spanContext := span.Context()
log.WithFields(logrus.Fields{
"trace_id": spanContext.TraceID().String(),
"span_id": spanContext.SpanID().String(),
}).Info("Operation in progress")
}
与日志收集系统适配
- ELK 适配:
- 日志发送:可以使用
logstash - forwarder
(已更名为 Filebeat
)来收集 Go 服务产生的日志文件。在 Go 服务中配置日志输出到文件,如:
file, err := os.OpenFile("app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err!= nil {
log.Fatal(err)
}
log.SetOutput(file)
- **格式处理**:在 `Filebeat` 的配置文件中指定日志格式为 JSON(如果使用结构化日志),并将收集到的日志发送到 `Logstash` 进行进一步处理,如添加或修改元数据、过滤等操作。`Logstash` 配置示例:
input {
beats {
port => 5000
}
}
filter {
if [service_name] == "my - go - service" {
mutate {
add_tag => ["my - go - service - tag"]
}
}
}
output {
elasticsearch {
hosts => ["localhost:9200"]
}
}
- Fluentd 适配:
- 日志发送:在 Go 服务中,可以将日志发送到 Fluentd 的 TCP 或 UDP 端口。例如使用
logrus
结合 fluent - go - sender
库:
import (
"github.com/fluent/fluent - go - sender"
"github.com/sirupsen/logrus"
)
func main() {
sender, err := fluent.NewSender("my - tag", fluent.WithHost("localhost"), fluent.WithPort(24224))
if err!= nil {
logrus.Fatal(err)
}
defer sender.Close()
log := logrus.New()
log.SetOutput(sender)
log.Info("This is a log message for Fluentd")
}
- **格式处理**:在 Fluentd 的配置文件中,配置输入插件接收日志,然后通过过滤器插件对日志格式和元数据进行处理,最后通过输出插件将日志发送到 Elasticsearch 等存储或分析系统。Fluentd 配置示例:
<source>
@type forward
port 24224
</source>
<filter my - tag.**>
@type record_transformer
enable_ruby true
<record>
new_service_name ${record["service_name"] || "default - service"}
</record>
</filter>
<match my - tag.**>
@type elasticsearch
host localhost
port 9200
</match>