全局记录(跨包)

Iam*_*NaN 7 logging go

我现在花了很多时间搜索和阅读关于这个主题的帖子但是已经设法完全回答了我的问题 - 或许我只需要对现有答案进行更多澄清.

我读过这篇与我的标题相同的帖子,但它是关于日志而不是包的日志.

我想要解决的是记录主应用程序及其使用的任何包.我需要一个可以记录到多个位置的记录器(可以使用io.MultiWriter完成),并且可以执行log.Error()和log.Debug()之类的操作.

我知道有这样做的包,我知道如何自己实现这些.

我无法理解的是如何正确使用我的包裹.

一种方法当然是在main中创建记录器,然后将其传递给需要记录的所有函数.但它似乎很尴尬.

我理想的解决方案是从日志包中获得一个类似于内置全局记录器的记录器,但具有上述附加功能.

我主要想在包中进行可选的调试日志记录,因此如果需要,我可以在生产版本中启用它.

这样做的正确方法是什么?

Ced*_*ndo 5

正确的方法是你认为理想的方式.只需创建一个包(最好遵循Go的约定https://golang.org/doc/code.html)并使您的Log全局:

package mylog

// Define your custom logger type.
type logger struct { /* Whatever you want */ }

// Optionally make it a interface.
type Logger interface { /* Your functions */ }

// And just go global.
var defaultLogger *Logger

func init(){
   defaultLogger = new(logger)
}

func Debug(params ...string){
   // Have some fun.
}

// ...
Run Code Online (Sandbox Code Playgroud)

另外,我建议在文档中描述您的项目使用该日志记录功能.


Iam*_*NaN 5

@CedmundoMartinez 的回答让我的脑子嗡嗡作响,以至于想出了(非常简单且相当明显,现在我可以使用我的后视镜)答案。

我在这里为对类似解决方案感兴趣的任何人发布我的答案。

我所做的是制作标准日志包(src/log/log.go)的副本并扩展它。获得一个已经完成标准记录器所做的一切以及您想要它做的任何其他事情的全局记录器再简单不过了!在这种情况下,支持分级日志记录。

我必须做的唯一修改:

type Logger struct {
    mu     sync.Mutex // ensures atomic writes; protects the following fields
    prefix string     // prefix to write at beginning of each line
    flag   int        // properties
    out    io.Writer  // destination for output
    buf    []byte     // for accumulating text to write
    level  int        // One of DEBUG, ERROR, INFO
}
Run Code Online (Sandbox Code Playgroud)

只添加了最后一行。log 包设置了一个全局变量std,然后可以使用该变量从包中的任何函数访问结构字段。

接下来我为不同的日志级别添加了常量:

const (
    DEBUG = 1 << iota
    INFO
    ERROR
)
Run Code Online (Sandbox Code Playgroud)

接下来我添加了我的功能:

(注意:ct 是https://github.com/seago/go-colortext包,它允许在 Windows 上为控制台文本着色。所以这里的错误都以红色打印)

func Error(v ...interface{}) {
    if std.level <= ERROR {
        ct.ChangeColor(ct.Red, true, ct.None, false)
        s := fmt.Sprintf("ERROR: %v", v...)
        std.Output(2, s)
        ct.ResetColor()
    }
}

func Info(format string, v ...interface{}) {
    if std.level <= INFO {
        s := fmt.Sprintf("INFO: "+format, v...)
        std.Output(2, s)
    }
}

func Debug(v ...interface{}) {
    if std.level <= DEBUG {
        s := fmt.Sprintf("DEBUG: %v", v...)
        std.Output(2, s)
    }
}

func SetLogLevel(lvl int) {
    std.level = lvl
}
Run Code Online (Sandbox Code Playgroud)

就是这样!有了它,我现在可以通过简单地导入修改后的包而不是标准日志包并注销来使用它:

import (
    "errors"
    "tryme/log" 
)

func main() {
    log.SetLogLevel(log.INFO)
    log.Info("This is a test Info")
    err := errors.New("This is a test error!!!")
    log.Error(err)
    log.Debug("Testing debugging") // won't be printed with log.INFO
}
Run Code Online (Sandbox Code Playgroud)

这当然只是一个演示,可以通过更多日志级别、输出格式等轻松进一步扩展。

您可以使用标准日志包提供的所有功能,如 SetOutput 写入文件或 MultiWriter 写入文件和控制台等。

  • 为什么要复制整个记录器,而不只是将“记录器”嵌入到您自己的新结构中,然后还会实现“错误”、“信息”等?全部复制似乎有点矫枉过正...... (3认同)

小智 5

我正在发布对我有用的解决方案!我刚刚创建了自己的包,并使用了 init函数。

package logging

import (
    "io"
    logging "log"
    "os"

    "github.com/Sirupsen/logrus"
)

var (
    log *logrus.Logger
)

func init() {
    f, err := os.OpenFile("logs/application.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)

    if err != nil {
        logging.Fatalf("error opening file: %v", err)
    }

    log = logrus.New()

    //log.Formatter = &logrus.JSONFormatter{}

    log.SetReportCaller(true)

    mw := io.MultiWriter(os.Stdout, f)
    log.SetOutput(mw)
}

// Info ...
func Info(format string, v ...interface{}) {
    log.Infof(format, v...)
}

// Warn ...
func Warn(format string, v ...interface{}) {
    log.Warnf(format, v...)
}

// Error ...
func Error(format string, v ...interface{}) {
    log.Errorf(format, v...)
}

var (

    // ConfigError ...
    ConfigError = "%v type=config.error"

    // HTTPError ...
    HTTPError = "%v type=http.error"

    // HTTPWarn ...
    HTTPWarn = "%v type=http.warn"

    // HTTPInfo ...
    HTTPInfo = "%v type=http.info"
)
Run Code Online (Sandbox Code Playgroud)

在任何包上,只需导入我的包,然后执行 (Info, Warn, Error) 函数

package main

import (

    log "logging"
)

func main() {
    log.Error(log.ConfigError, "Testing the error")
}
Run Code Online (Sandbox Code Playgroud)

日志条目将保存在屏幕上,并将保存在文件中。