Logger.SetPrefix()是否会在通道/线程之间作为上下文?

时间:2014-07-14 02:50:46

标签: logging go

当我将日志包用于其他语言时,我总是强制执行某种类型的上下文Guid(UUID),它会在每次记录器调用时记录。具体来说,这确实有助于在记录1000个请求时跟踪哪组日志属于哪个Web请求或单个线程。

我正在尝试使用Go附带的std记录器执行此操作。

type Context struct {
  Log *log.Logger
}

// NewContext constructs a new context.
func NewContext(r *http.Request) (*Context, error) {

    id, err := newUUID()
    if err != nil {
        log.Printf("ERROR in newUUID() : %s", err)
    }

    c := &Context{
        Log: log.New(os.Stderr, id+" ", log.LstdFlags)
    }

    return c, nil
}

func newUUID() (string, error) {
    uuid := make([]byte, 16)
    n, err := io.ReadFull(rand.Reader, uuid)
    if n != len(uuid) || err != nil {
        return "", err
    }
    // variant bits; see section 4.1.1
    uuid[8] = uuid[8]&^0xc0 | 0x80
    // version 4 (pseudo-random); see section 4.1.3
    uuid[6] = uuid[6]&^0xf0 | 0x40
    return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
}

如您所见,我将log.Logger分配给结构上的值。

它通过我的defaultHandler()以及其他处理程序使用,例如:

func defaultHandler(fn func(http.ResponseWriter, *http.Request, *Context) error) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {

        // create the context
        c, err := NewContext(r)
        if err != nil {
            log.Printf("ERROR in creating context w/NewContext(): %s", http.StatusInternalServerError, err.Error())
        }
        defer c.Unload()

        c.Log.Printf("METRIC, START URL: %s", r.URL.Path)
    }
}

请注意c.Log.Printf()对记录器的调用。

其中输出的内容如下:

8c93fa699f5a46c1a986076b952f5c2c 2014/07/13 22:45:21 METRIC, START URL: /

我之所以这样做,是因为我不确定以下内容如何在频道和同步环境中发挥作用:

log.SetPrefix("...")

对log.SetPrefix()有更多经验的人可以解释它在通道和线程方面的工作原理,特别是在http请求中吗?

尽量避免在每个请求上创建新的记录器。更愿意使用" log"中的标准全局log记录器。包,使用.SetPrefix(" ...")。

或者,或许可以概述另一种解决方案?

1 个答案:

答案 0 :(得分:2)

您无法使用SetPrefix方法。这将在全局记录器中设置.prefix属性。 所有处理程序共享同一个记录器。

你现在这样做是一种方法。另一种方法是在您的上下文中添加日志方法:

type Context struct {
    UUID string
}

func (c *Context) Info(fmt string, args ...interface{}) {
    log.Printf(c.UUID+" "+fmt, args...)
}

完整的工作示例

package main

import (
    "crypto/rand"
    "fmt"
    "io"
    "log"
)

func newUUID() (string, error) {
    uuid := make([]byte, 16)
    n, err := io.ReadFull(rand.Reader, uuid)
    if n != len(uuid) || err != nil {
        return "", err
    }
    // variant bits; see section 4.1.1
    uuid[8] = uuid[8]&^0xc0 | 0x80
    // version 4 (pseudo-random); see section 4.1.3
    uuid[6] = uuid[6]&^0xf0 | 0x40
    return fmt.Sprintf("%x-%x-%x-%x-%x", uuid[0:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]), nil
}

type Context struct {
    UUID string
}

func (c *Context) Info(fmt string, args ...interface{}) {
    log.Printf(c.UUID+" "+fmt, args...)
}

func main() {
    uuid, err := newUUID()
    if err != nil {
        log.Fatal(err)
    }
    c := &Context{UUID: uuid}
    c.Info("Hello ")
}

http://play.golang.org/p/uEIKweC-kp