全局记录(跨包)

时间:2015-04-09 12:35:48

标签: logging go

我现在花了很多时间搜索和阅读有关该主题的帖子,但注意到我已经设法完全回答了我的问题 - 或者我只是需要对现有答案进行更多澄清。

我已经阅读了this帖子,该帖子与我的标题相同,但它是关于记录go例程而不是包。

我正在尝试解决的问题是登录主应用程序及其使用的任何软件包。我需要一个可以记录到多个位置的记录器(可以使用io.MultiWriter完成)并且可以执行诸如log.Error()和log.Debug()

之类的操作。

我知道有这样的软件包,我知道如何自己实现这些功能。

我无法理解的是如何在包裹中正确使用它。

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

我理想的解决方案是使用日志包中的内置全局记录器等记录器,但具有上述附加功能。

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

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

4 个答案:

答案 0 :(得分: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.
}

// ...

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

答案 1 :(得分:3)

@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
}

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

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

const (
    DEBUG = 1 << iota
    INFO
    ERROR
)

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

(注意: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
}

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

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
}

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

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

答案 2 :(得分:1)

要添加,如果要对多个Go应用程序进行日志记录,可以使用RPC并创建日志记录服务。这将是一个独立的应用程序,为其他应用程序提供服务。 Golang has its own package for it

答案 3 :(得分:0)

我正在发布适用于我的解决方案!。我只是创建了自己的程序包,并使用了 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"
)

在任何程序包上,只需导入我的程序包,然后执行(信息,警告,错误)功能

package main

import (

    log "logging"
)

func main() {
    log.Error(log.ConfigError, "Testing the error")
}

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