dapr_logger.go的源码学习
daprLogger 是实际的日志实现
Dapr logger package中的dapr_logger.go文件的源码分析,daprLogger 是实际的日志实现。
daprLogger 结构体定义
daprLogger 结构体,底层实现是 logrus :
// daprLogger is the implemention for logrus
type daprLogger struct {
// name is the name of logger that is published to log as a scope
name string
// loger is the instance of logrus logger
logger *logrus.Entry
}
创建Dapr logger
创建Dapr logger的逻辑:
func newDaprLogger(name string) *daprLogger {
// 底层是 logrus
newLogger := logrus.New()
// 输出到 stdout
newLogger.SetOutput(os.Stdout)
dl := &daprLogger{
name: name,
logger: newLogger.WithFields(logrus.Fields{
logFieldScope: name,
// 默认是普通log类型
logFieldType: LogTypeLog,
}),
}
// 设置是否启用json输出,defaultJSONOutput默认是false
dl.EnableJSONOutput(defaultJSONOutput)
return dl
}
启用json输出
函数名有点小问题,实际是初始化logger,是否enables JSON只是部分逻辑:
// EnableJSONOutput enables JSON formatted output log
func (l *daprLogger) EnableJSONOutput(enabled bool) {
var formatter logrus.Formatter
fieldMap := logrus.FieldMap{
// If time field name is conflicted, logrus adds "fields." prefix.
// So rename to unused field @time to avoid the confliction.
logrus.FieldKeyTime: logFieldTimeStamp,
logrus.FieldKeyLevel: logFieldLevel,
logrus.FieldKeyMsg: logFieldMessage,
}
hostname, _ := os.Hostname()
l.logger.Data = logrus.Fields{
logFieldScope: l.logger.Data[logFieldScope],
logFieldType: LogTypeLog,
logFieldInstance: hostname,
logFieldDaprVer: DaprVersion,
}
if enabled {
formatter = &logrus.JSONFormatter{
TimestampFormat: time.RFC3339Nano,
FieldMap: fieldMap,
}
} else {
formatter = &logrus.TextFormatter{
TimestampFormat: time.RFC3339Nano,
FieldMap: fieldMap,
}
}
l.logger.Logger.SetFormatter(formatter)
}
logger的设置
设置DaprVersion
var DaprVersion string = "unknown"
func (l *daprLogger) EnableJSONOutput(enabled bool) {
l.logger.Data = logrus.Fields{
......
logFieldDaprVer: DaprVersion,
}
}
DaprVersion的值来自于 makefile (dapr/Makefile
):
LOGGER_PACKAGE_NAME := github.com/dapr/kit/logger
DEFAULT_LDFLAGS:=-X $(BASE_PACKAGE_NAME)/pkg/version.gitcommit=$(GIT_COMMIT) \
-X $(BASE_PACKAGE_NAME)/pkg/version.gitversion=$(GIT_VERSION) \
-X $(BASE_PACKAGE_NAME)/pkg/version.version=$(DAPR_VERSION) \
-X $(LOGGER_PACKAGE_NAME).DaprVersion=$(DAPR_VERSION)
设置appid
设置日志的 app_id 字段,默认为空。
// SetAppID sets app_id field in log. Default value is empty string
func (l *daprLogger) SetAppID(id string) {
l.logger = l.logger.WithField(logFieldAppID, id)
}
这个方法在logger被初始化时调用进行设置,见 options.go 方法:
func ApplyOptionsToLoggers(options *Options) error {
......
if options.appID != undefinedAppID {
v.SetAppID(options.appID)
}
}
设置日志级别
// SetOutputLevel sets log output level
func (l *daprLogger) SetOutputLevel(outputLevel LogLevel) {
l.logger.Logger.SetLevel(toLogrusLevel(outputLevel))
}
func toLogrusLevel(lvl LogLevel) logrus.Level {
// ignore error because it will never happens
l, _ := logrus.ParseLevel(string(lvl))
return l
}
这个是在原有的 daprLogger 实例上进行设置,没啥特殊。
设置日志类型
默认是普通 log 类型,如果要设置log类型:
// WithLogType specify the log_type field in log. Default value is LogTypeLog
func (l *daprLogger) WithLogType(logType string) Logger {
// 这里重新构造了一个新的 daprLogger 结构体,然后返回
return &daprLogger{
name: l.name,
logger: l.logger.WithField(logFieldType, logType),
}
}
疑问和TODO:
- 为什么不是直接设置 l.logger,而是构造一个新的结构体,然后返回还是 Logger ?
- 会不会有隐患?前面logger创建之后是存放在global logger map中的,key是简单的 name 而不是 name + logtype,这岂不是无法保存一个 name 两个类型的两个 logger 对象?
logger的实现
所有的写log的方法都简单代理给了 l.logger (*logrus.Entry):
// Info logs a message at level Info.
func (l *daprLogger) Info(args ...interface{}) {
l.logger.Log(logrus.InfoLevel, args...)
}
// Infof logs a message at level Info.
func (l *daprLogger) Infof(format string, args ...interface{}) {
l.logger.Logf(logrus.InfoLevel, format, args...)
}
// Debug logs a message at level Debug.
func (l *daprLogger) Debug(args ...interface{}) {
l.logger.Log(logrus.DebugLevel, args...)
}
// Debugf logs a message at level Debug.
func (l *daprLogger) Debugf(format string, args ...interface{}) {
l.logger.Logf(logrus.DebugLevel, format, args...)
}
// Warn logs a message at level Warn.
func (l *daprLogger) Warn(args ...interface{}) {
l.logger.Log(logrus.WarnLevel, args...)
}
// Warnf logs a message at level Warn.
func (l *daprLogger) Warnf(format string, args ...interface{}) {
l.logger.Logf(logrus.WarnLevel, format, args...)
}
// Error logs a message at level Error.
func (l *daprLogger) Error(args ...interface{}) {
l.logger.Log(logrus.ErrorLevel, args...)
}
// Errorf logs a message at level Error.
func (l *daprLogger) Errorf(format string, args ...interface{}) {
l.logger.Logf(logrus.ErrorLevel, format, args...)
}
// Fatal logs a message at level Fatal then the process will exit with status set to 1.
func (l *daprLogger) Fatal(args ...interface{}) {
l.logger.Fatal(args...)
}
// Fatalf logs a message at level Fatal then the process will exit with status set to 1.
func (l *daprLogger) Fatalf(format string, args ...interface{}) {
l.logger.Fatalf(format, args...)
}
注意 logrus 的 Fatalf() 方法的实现,在输出日志之后会调用ExitFunc(如果没设置则默认是 os.Exit
)
func (entry *Entry) Fatalf(format string, args ...interface{}) {
entry.Logf(FatalLevel, format, args...)
entry.Logger.Exit(1)
}
func (logger *Logger) Exit(code int) {
runHandlers()
if logger.ExitFunc == nil {
logger.ExitFunc = os.Exit
}
logger.ExitFunc(code)
}
这会导致进程退出。因此要慎用。