正确处理Golang的全球采伐问题
Go的应用程序日志模式是什么? 如果我有,我需要从5login,我应该…
- 创build一个
log.Logger
并传递给它? - 传递一个指向该
log.Logger
的指针? - 每个goroutine或函数应该创build一个logging器?
- 我应该创build一个全局variables的logging器?
- 创build一个log.Logger并传递给它?
这是可能的。 log.Logger可以从多个goroutines同时使用。
- 传递一个指向该log.Logger的指针?
log.New返回一个*Logger
,这通常表示您应该将指针传递给对象。 将它作为值传递会创build一个结构的副本(即Logger的一个副本),然后多个goroutine可能同时写入同一个io.Writer 。 这可能是一个严重的问题,取决于作者的实施。
- 每个goroutine或函数应该创build一个logging器?
我不会为每个函数或goroutine创build一个单独的logging器。 Goroutines(和函数)用于非常轻量级的任务,这不会certificate维护一个单独的logging器。 为您的项目的每个更大的组件创build一个logging器可能是一个好主意。 例如,如果您的项目使用SMTP服务发送邮件,则为邮件服务创build单独的logging器听起来像是个好主意,这样您就可以单独过滤和closures输出。
- 我应该创build一个全局variables的logging器?
这取决于你的包。 在以前的邮件服务示例中,为每个服务实例分配一个日志logging器可能是一个好主意,这样,用户可以在使用gmail邮件服务时logging失败,而不像使用本地MTA时发生的失败(例如sendmail )。
对于简单的情况,在日志包log.Logger
定义了一个全局logging器。 这个全局logging器可以通过log.SetFlags
进行configuration。
之后,可以调用log.Printf
和log.Fatalf
等使用该全局实例的日志包的顶层函数。
我知道这个问题有点老,但是,如果像我一样,你的项目是由多个小文件组成的,我投票支持你的第四个选项 – 我创build了一个logger.go
,它是package main的一部分。 这个去文件创buildlogging器,分配给一个文件,并提供给其余的主。 注意我还没有想出一个优雅的方式来closures错误日志…
package main import ( "fmt" "log" "os" ) var errorlog *os.File var logger *log.Logger func init() { errorlog, err := os.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) if err != nil { fmt.Printf("error opening file: %v", err) os.Exit(1) } logger = log.New(errorlog, "applog: ", log.Lshortfile|log.LstdFlags) }
这是一个老问题,但我想build议使用http://github.com/romana/rlog (我们开发)。 它是通过环境variablesconfiguration的,logger对象在导入rlog时被创build并初始化。 因此,不需要绕过logging器。
rlog有很多function:
- 完全可configuration的date/时间戳
- 同时输出到stderr或stdout以及文件。
- 标准日志级别(Debug,Info等)以及可自由configuration的多级日志logging。
- 根据需要logging来电者信息(文件,行号,function)。
- 能够为不同的源文件设置不同的日志级别。
除了标准的Golang库以外,它非常小,没有外部依赖,正在积极开发。 回购中提供了一些例子。
我发现默认的日志包( https://golang.org/pkg/log/ )有一些限制。 例如,不支持信息与debugging日志。
经过一番探索后,决定使用https://github.com/golang/glog 。 这似乎是https://github.com/google/glog的一个端口,并在日志logging中提供了不错的灵活性。; 例如,在本地运行应用程序时,您可能需要DEBUG级别的日志,但可能只想在生产中的INFO / ERROR级别运行。 完整的function/指南的列表是,在这里https://google-glog.googlecode.com/svn/trunk/doc/glog.html (其为c + +模块,但大部分转换为golang端口)
这是一个简单的logging器
package customlogger import ( "log" "os" "sync" ) type logger struct { filename string *log.Logger } var logger *logger var once sync.Once // start loggeando func GetInstance() *logger { once.Do(func() { logger = createLogger("mylogger.log") }) return logger } func createLogger(fname string) *logger { file, _ := os.OpenFile(fname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0777) return &logger{ filename: fname, Logger: log.New(file, "My app Name ", log.Lshortfile), } }
你可以这样使用它
package main import ( "customlogger" "fmt" "net/http" ) func main() { logger := customlogger.GetInstance() logger.Println("Starting") http.HandleFunc("/", sroot) http.ListenAndServe(":8080", nil) } func sroot(w http.ResponseWriter, r *http.Request) { logger := customlogger.GetInstance() fmt.Fprintf(w, "welcome") logger.Println("Starting") }