面试题答案
一键面试设计思路
- 日志级别定义:定义不同的日志级别常量,如DEBUG、INFO、WARN、ERROR等。
- 日志配置:设置全局变量来存储当前的日志级别,以便动态调整。
- 格式化输出:设计一个格式化函数,根据日志级别和传入的参数生成格式化后的日志字符串。
- 多模块和多goroutine兼容性:使用
sync.Mutex
来保证在多goroutine环境下日志写入的线程安全,并且采用单例模式来管理日志包实例,确保多模块使用时配置统一。
关键代码实现
package main
import (
"fmt"
"log"
"sync"
)
// 定义日志级别
type LogLevel int
const (
DEBUG LogLevel = iota
INFO
WARN
ERROR
)
var (
currentLevel LogLevel
mu sync.Mutex
instance *Logger
)
// Logger结构体
type Logger struct {
level LogLevel
}
// 获取单例实例
func GetLogger() *Logger {
if instance == nil {
mu.Lock()
defer mu.Unlock()
if instance == nil {
instance = &Logger{
level: DEBUG,
}
}
}
return instance
}
// 设置日志级别
func (l *Logger) SetLevel(level LogLevel) {
l.level = level
}
// 格式化日志输出
func (l *Logger) format(level LogLevel, format string, v ...interface{}) string {
levelStr := ""
switch level {
case DEBUG:
levelStr = "[DEBUG]"
case INFO:
levelStr = "[INFO]"
case WARN:
levelStr = "[WARN]"
case ERROR:
levelStr = "[ERROR]"
}
return fmt.Sprintf("%s %s", levelStr, fmt.Sprintf(format, v...))
}
// 不同级别的日志输出函数
func (l *Logger) Debug(format string, v ...interface{}) {
if l.level <= DEBUG {
mu.Lock()
defer mu.Unlock()
log.Println(l.format(DEBUG, format, v...))
}
}
func (l *Logger) Info(format string, v ...interface{}) {
if l.level <= INFO {
mu.Lock()
defer mu.Unlock()
log.Println(l.format(INFO, format, v...))
}
}
func (l *Logger) Warn(format string, v ...interface{}) {
if l.level <= WARN {
mu.Lock()
defer mu.Unlock()
log.Println(l.format(WARN, format, v...))
}
}
func (l *Logger) Error(format string, v ...interface{}) {
if l.level <= ERROR {
mu.Lock()
defer mu.Unlock()
log.Println(l.format(ERROR, format, v...))
}
}
你可以这样使用这个日志包:
func main() {
logger := GetLogger()
logger.SetLevel(INFO)
logger.Debug("This is a debug log")
logger.Info("This is an info log")
logger.Warn("This is a warn log")
logger.Error("This is an error log")
}