英文:
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 ")
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论