如何在golang中实现基于级别的日志记录?

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

How to implement level based logging in golang?

问题

有没有适用于golang的基于级别的日志包装器?
如果没有,我应该如何自己实现一个?

我想要的很简单。我想要一些函数,例如:

log.Error()
log.Info()

等等,它们将将其输出显示到stdout,并将这些输出保存在日志文件中(根据作为命令行参数给定的级别)。
我如何实现这个包装器?

英文:

Is there any good wrapper available for level based logging in golang?
If not, how should I go about implementing one myself?

What I want is pretty simple. I want a few functions e.g.

log.Error()
log.Info()

etc that display their outputs to stdout as well as save these in a log file (based on the level given to the program as commandline argument).
How do I implement this wrapper?

答案1

得分: 73

以下是翻译好的部分:

英文:

Some more suggestions, now that the existing answers are quite old:

答案2

得分: 6

  • Uber-go/Zap: 快速、结构化、分级的Go日志记录
  • Logrus: 可插拔的Go结构化日志记录(支持JSON和文本格式化)

这两个库都有级别钩子的功能,这是一个非常有趣的特性。可以为特定的日志级别注册钩子。例如,当发生任何错误(使用log.Error()记录)时,可以报告给某个监控工具等。

英文:
  • Uber-go/Zap: Fast, structured, leveled logging in Go
  • Logrus: Structured, pluggable logging for Go. (JSON and text formatting)

Both libraries have level hooks also, which is a very interesting feature. Hooks can be registered for particular log levels. So for example any error(logged using log.Error()) occurs you can report to some monitoring tool etc.

答案3

得分: 6

https://github.com/hashicorp/logutils 我发现这个库非常容易使用,而且你甚至不需要改变对标准库的log.Printf方法的调用。

英文:

https://github.com/hashicorp/logutils I found this to be very easy to use and you don't even need to change the method calls to log.Printf of the std library.

答案4

得分: 4

我认为seelog符合你的要求,而且它似乎在日志讨论中经常出现,所以很受欢迎。我从未认真使用过它,所以除此之外我无法发表评论。

英文:

I think seelog fits your requirements, and it seems to be pretty popular as it pops up often in log discussions. I never used it seriously, so I can't comment beyond that.

答案5

得分: 3

请查看http://cgl.tideland.biz,并在那里找到“applog”包。它是以这种方式工作的。

PS:整个CGL目前正在重新制作,并将很快以新功能发布,但使用不同的名称。 如何在golang中实现基于级别的日志记录?

英文:

Take a look at http://cgl.tideland.biz and there at the package "applog". It's working that way.

PS: The whole CGL is currently reworked and will soon be released with new features, but under a different name. 如何在golang中实现基于级别的日志记录?

答案6

得分: 2

stdlog完全符合您的要求:

log := stdlog.GetFromFlags()
log.Info("连接到服务器...")
log.Errorf("连接失败:%q", err)
英文:

stdlog fits exactly your requirements:

log := stdlog.GetFromFlags()
log.Info("Connecting to the server...")
log.Errorf("Connection failed: %q", err)

答案7

得分: 1

我目前正在使用rlog,并且喜欢他们的方法。代码看起来很好,简洁并且有足够的文档说明。

让我信服的原因有:

  • 没有外部依赖

  • 我可以在任何地方使用rlog.Info()而不需要传递引用

  • 很好地使用了环境变量

  • 可以任意设置跟踪级别,例如rlog.Trace(4, "foo")

英文:

I am working with rlog at the moment and like their approach. The code looks good, simplistic and sufficiently documented.

What convinced me:

  • no external dependencies

  • i can use rlog.Info() anywhere without passing around references

  • good usage of environment variables

  • arbitrary number of trace levels e.g. rlog.Trace(4, "foo")

答案8

得分: 1

我已经为内置的Go日志包添加了日志级别支持。你可以在这里找到我的代码:

https://github.com/gologme/log

除了添加对Info、Warn和Debug的支持外,用户还可以定义自己的任意日志级别。日志级别可以单独启用和禁用。这意味着你可以打开Debug日志而不获取其他所有日志。

英文:

I have added logging level support to the built-in Go log package. You can find my code here:

https://github.com/gologme/log

In addition to adding support for Info, Warn, and Debug, users can also define their own arbitrary logging levels. Logging levels are enabled and disabled individually. This means you can turn on Debug logs without also getting everything else.

答案9

得分: 0

你可以使用midlog模块来实现任何其他日志库,https://github.com/lingdor/midlog

英文:

You can use the module midlog to implements any other log library,
https://github.com/lingdor/midlog

答案10

得分: 0

你可以考虑使用klog作为日志模块之一。它支持'V'日志级别,可以灵活地记录日志。

klog是glog的一个分支,克服了以下缺点:

glog存在许多"陷阱",并且在容器化环境中存在挑战,这些都没有很好地记录下来。
glog没有提供一种简单的方法来测试日志,这会影响使用它的软件的稳定性。
glog是基于C++的,而klog是纯粹的golang实现。

示例实现

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()
}
英文:

One of the logging module that you can consider is klog . It support 'V' logging which gives the flexibility to log at certain level

klog is a fork of glog and overcomes following drawbacks

glog presents a lot "gotchas" and introduces challenges in containerized environments, all of which aren't well documented.
glog doesn't provide an easy way to test logs, which detracts from the stability of software using it
glog is C++ based and klog is a pure golang implementation

Sample Implementation

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

答案11

得分: 0

2023年,Go 1.21.0终于推出了一个标准级别的日志记录器:log/slog

现在普通用户不再需要外部库了。

1. 基本用法

package main

import "log/slog"

func main() {
	slog.Info("hello")
	slog.Warn("hello")
	slog.Error("hello")
}
2023/08/09 20:05:49 INFO hello
2023/08/09 20:05:49 WARN hello
2023/08/09 20:05:49 ERROR hello

(默认情况下,Debug日志级别是禁用的。请参阅下面的“4. 创建自己的日志记录器”以启用它。)

2. 添加上下文

它可以选择接收任意数量的键值对:

package main

import "log/slog"

func main() {
	slog.Info("hello", "username", "Mike", "age", 18)
}
2023/08/09 20:07:51 INFO hello username=Mike age=18

3. 自定义格式

可以使用log来自定义log/slog日志记录器的格式。

package main

import "log"
import "log/slog"

func main() {
	slog.Info("hello")
	log.SetFlags(log.Ldate | log.Lmicroseconds)
	slog.Info("hello")
}
2023/08/09 20:15:36 INFO hello
2023/08/09 20:15:36.601583 INFO hello

4. 创建自己的日志记录器

基本用法由顶级函数(例如slog.Info())提供,但您可以创建自己的日志记录器进行详细的自定义。

通过slog.SetDefault()可以将创建的日志记录器设置为默认日志记录器。之后,顶级函数(例如slog.Info())将使用您的日志记录器。

以下是一个示例,其中启用了Debug日志级别并自定义了输出格式:

package main

import (
	"log/slog"
	"os"
)

func main() {
    //文本日志记录器
	{
		handler := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug})
		slog.SetDefault(slog.New(handler))

		slog.Debug("hello", "username", "Mike", "age", 18)
	}

    //JSON日志记录器
	{
		handler := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug})
		slog.SetDefault(slog.New(handler))

		slog.Debug("hello", "username", "Mike", "age", 18)
	}
}
time=2023-08-09T20:31:05.798+09:00 level=DEBUG msg=hello username=Mike age=18
{"time":"2023-08-09T20:31:05.798984192+09:00","level":"DEBUG","msg":"hello","username":"Mike","age":18}

附注

在撰写本答案时,保持默认输出格式的同时启用Debug日志级别似乎是不可能的。

默认日志记录器的格式与slog.NewTexthandler()slog.NewJSONHandler()不同,它是通过log/slog/logger.go中的私有方法创建的:

var defaultLogger atomic.Value

func init() {
	defaultLogger.Store(New(newDefaultHandler(loginternal.DefaultOutput)))
}
英文:

In 2023 today, Go 1.21.0 finally comes with a standard level logger: log/slog package.

No external library is needed anymore for average users.

1. Basic Usage

package main

import "log/slog"

func main() {
	slog.Info("hello")
	slog.Warn("hello")
	slog.Error("hello")
}
2023/08/09 20:05:49 INFO hello
2023/08/09 20:05:49 WARN hello
2023/08/09 20:05:49 ERROR hello

(Debug log level is disabled by default. See "4. Create Your Own Logger" below to enable it.)

2. Add Context

It can optionally receive any number of key-value pairs:

package main

import "log/slog"

func main() {
	slog.Info("hello", "username", "Mike", "age", 18)
}
2023/08/09 20:07:51 INFO hello username=Mike age=18

3. Customize Format

log package can be used to customize the format of log/slog logger.

package main

import "log"
import "log/slog"

func main() {
	slog.Info("hello")
	log.SetFlags(log.Ldate | log.Lmicroseconds)
	slog.Info("hello")
}
2023/08/09 20:15:36 INFO hello
2023/08/09 20:15:36.601583 INFO hello

4. Create Your Own Logger

Basic usage is covered by the top-level functions (e.g. slog.Info()) but you can create your own logger for detailed customization.

A created logger can be set as the default logger via slog.SetDefault(). After that, the top-level functions (e.g. slog.Info()) use your logger.

Here's an example which enables Debug log level and customizes the output format:

package main

import (
	"log/slog"
	"os"
)

func main() {
    //text logger
	{
		handler := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug})
		slog.SetDefault(slog.New(handler))

		slog.Debug("hello", "username", "Mike", "age", 18)
	}

    //JSON logger
	{
		handler := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug})
		slog.SetDefault(slog.New(handler))

		slog.Debug("hello", "username", "Mike", "age", 18)
	}
}
time=2023-08-09T20:31:05.798+09:00 level=DEBUG msg=hello username=Mike age=18
{"time":"2023-08-09T20:31:05.798984192+09:00","level":"DEBUG","msg":"hello","username":"Mike","age":18}

Side Notes

At the time of writing this answer, enabling Debug log level while preserving the default output format seems impossible.

The default logger, whose format is different from slog.NewTexthandler() and slog.NewJSONHandler(), is created via a private method in log/slog/logger.go:

var defaultLogger atomic.Value

func init() {
	defaultLogger.Store(New(newDefaultHandler(loginternal.DefaultOutput)))
}

huangapple
  • 本文由 发表于 2013年6月3日 19:26:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/16895651.html
匿名

发表评论

匿名网友

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

确定