logging - Logger.SetPrefix() 是否作为上下文粘在 channel /线程之间?

标签 logging go

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

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

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: /

我这样做是因为我不确定以下内容在 channel 和同步的上下文中是如何工作的:

log.SetPrefix("...")

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

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

或者,或许概述另一个解决方案?

最佳答案

您不能使用 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

关于logging - Logger.SetPrefix() 是否作为上下文粘在 channel /线程之间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24728925/

相关文章:

go - 将 []int64 转换为 []uint64 的最佳方法是什么

Java/Spring : How to find what error opened the Resilence4J circuit breaker?

java - 为什么 ConfigurationBuilder API 不创建记录器?

go - 为什么互斥锁最终会出现线程正在休眠的错误?

go - 如何查找两个 slice 是否引用同一内存?

unit-testing - golang 字符串 channel 发送/接收不一致

sockets - 如何调试以下 Go 代码,它试图与 IP 地址和端口建立 TCP 连接?

java日志记录属性: Log a certain class to a specific log file

hadoop - Log4j RollingFileAppender 没有将映射器和缩减器日志添加到文件

java - 控制台上的 DBCL 消息