MST

星途 面试题库

面试题:Go语言自定义日志包实现日志级别管理

假设标准库的日志包无法满足项目需求,要求你自定义一个Go语言的日志包,实现完整的日志级别管理功能,包括不同日志级别日志的格式化输出、日志级别动态调整,并且要考虑该日志包在多模块、多goroutine环境下的兼容性和稳定性,描述你的设计思路及关键代码实现。
38.2万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 日志级别定义:定义不同的日志级别常量,如DEBUG、INFO、WARN、ERROR等。
  2. 日志配置:设置全局变量来存储当前的日志级别,以便动态调整。
  3. 格式化输出:设计一个格式化函数,根据日志级别和传入的参数生成格式化后的日志字符串。
  4. 多模块和多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")
}