Logger.SetPrefix()在通道/线程之间是否保持不变,就像上下文一样?

huangapple go评论81阅读模式
英文:

Does the Logger.SetPrefix() stick between channels/threads, as a context?

问题

当我在使用其他语言的日志包时,我总是会强制使用一种上下文Guid(UUID),并在每个日志记录调用中记录下来。具体来说,这对于在记录数千个请求时跟踪哪些日志属于哪个Web请求或单个线程非常有帮助。

我正在尝试在Go中使用标准的日志记录器来实现这一点。

type Context struct {
  Log *log.Logger
}

// NewContext构造一个新的上下文。
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) {

    // 创建上下文
    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 Logger(来自"log"包),并使用.SetPrefix("...")

或者,也许可以提供另一个解决方案?

英文:

When I've used log packages for other languages, I always enforced some type of contextual Guid (UUID) that gets logged with each logger call. Specifically, this really helps track down which group of logs belong to what web request, or individual thread, when logging 1000s of requests.

I am attempting to do this with the std logger that comes with 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
}

As you can see, I assign a log.Logger to a value on the struct.

It is used through my defaultHandler(), as well as within other handlers, like this example:

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

Note the c.Log.Printf() call for the logger.

Which outputs something like this:

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

I did this because I was not sure how the following works in the context of channels and sync:

log.SetPrefix("...")

Could someone with more experience with log.SetPrefix() explain how it works in regards to channels and threads, specifically in an http request?

Trying to avoid creating a new logger on each request. Would prefer to use the standard global log Logger from the "log" package, with the .SetPrefix("...").

Or, perhaps outline another solution?

答案1

得分: 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

英文:

You can't use the SetPrefix method. That will set the .prefix attribute in the global logger. All the handlers share the same logger.

The way you are doing it right now is one way to do it. Another way is to add a log Method to your context:

type Context struct {
	UUID string
}

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

Full working example

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

huangapple
  • 本文由 发表于 2014年7月14日 10:50:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/24728925.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定