Go 中的应用程序日志模式是什么?如果我有,比如说,5个需要记录的常规程序,我应该..。.
log.Logger
对于简单的情况,在日志包 log.Logger中定义了一个全局日志记录器。这个全局日志记录器可以通过 log.SetFlags配置。
log.SetFlags
然后可以调用日志包的顶级函数,如 log.Printf和 log.Fatalf,它们使用全局实例。
log.Printf
log.Fatalf
创建一个日志。记录器并传递它吗?
这是可能的。 伐木工可以从多个 goroutines 并发使用。
传递一个指向该日志的指针。记录器?
木头。New 返回一个 *Logger,这通常表示您应该将对象作为指针传递。将其作为值传递将创建 struct 的一个副本(即 Logger 的一个副本) ,然后多个 goroutine 可能并发地写入同一个 我是作家。这可能是一个严重的问题,具体取决于编写器的实现。
*Logger
每个 goroutine 或函数都应该创建一个日志记录器吗?
我不会为每个函数或 goroutine 创建单独的日志记录器。Goroutines (和函数)用于非常轻量级的任务,这些任务不需要维护单独的日志记录器。为项目的每个较大组件创建一个日志记录器可能是一个好主意。例如,如果您的项目使用 SMTP 服务发送邮件,那么为邮件服务创建一个单独的日志记录器听起来是个不错的主意,这样您就可以分别过滤和关闭输出。
我是否应该将日志记录器创建为一个全局变量?
这取决于你的包裹。在前面的邮件服务示例中,为每个服务实例设置一个日志记录器可能是一个好主意,这样用户在使用 gmail 服务时可以记录失败,而不同于在使用本地 MTA (例如 sendmail)时发生的失败。
我知道这个问题有点老,但如果,像我一样,你的项目是由多个较小的文件,我投票给你的第四个选项-我已经创建了一个 logger.go,这是包的一部分主。这个 go 文件创建日志记录器,将其分配给一个文件,并将其提供给 main 的其余部分。注意,我还没有想出一个优雅的方式来结束 errorlog..。
logger.go
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) }
我发现默认的日志包(https://golang.org/pkg/log/)有一定的局限性,例如,不支持信息日志和调试日志。 经过一番调查,最终决定使用 https://github.com/golang/glog。这似乎是 https://github.com/google/glog的一个端口,在日志记录方面提供了相当大的灵活性。例如,在本地运行应用程序时,您可能需要 DEBUG 级别的日志,但可能希望在生产中仅以 INFO/ERROR 级别运行。完整的特性/指南列表在这里是 https://google-glog.googlecode.com/svn/trunk/doc/glog.html(它用于 c + + 模块,但大部分转换为 golang 端口)
这是一个较老的问题,但我想建议使用 http://github.com/romana/rlog(我们开发的)。它通过环境变量进行配置,在导入 rlog 时创建并初始化 logger 对象。因此,不需要传递日志记录器。
Rlog 有很多特性:
它非常小,没有外部依赖,除了标准的 Golang 图书馆,并且正在积极开发中。回购协议中提供了实例。
这是一个简单的记录器
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") }
可以考虑的日志记录模块之一是 Klog。它支持“ V”日志记录,可以灵活地在一定级别上进行日志记录
Klog 是 glog 的一个分支,它克服了以下缺点
实施范例
package main import ( "flag" "k8s.io/klog" ) type myError struct { str string } func (e myError) Error() string { return e.str } func main() { klog.InitFlags(nil) flag.Set("v", "1") flag.Parse() klog.Info("hello", "val1", 1, "val2", map[string]int{"k": 1}) klog.V(3).Info("nice to meet you") klog.Error(nil, "uh oh", "trouble", true, "reasons", []float64{0.1, 0.11, 3.14}) klog.Error(myError{"an error occurred"}, "goodbye", "code", -1) klog.Flush() }