<p>Logrus seems to be the most popular from Github stars but I also like the simplicity of Nate's suggestion by just using the standard lib but haven't seen any projects use it: <a href="https://forum.golangbridge.org/t/whats-so-bad-about-the-stdlibs-log-package/1435" rel="nofollow">https://forum.golangbridge.org/t/whats-so-bad-about-the-stdlibs-log-package/1435</a></p>
<p>There's tons of others and not sure what way to go. What is everyone using?</p>
<hr/>**评论:**<br/><br/>shovelpost: <pre><p>In my opinion, unless someone needs structured logging or something advanced, there's no reason to add a whole dependency just for logging. Use the standard library log.</p>
<p>Do you want logging levels? Then <a href="https://github.com/upspin/upspin/tree/master/log" rel="nofollow">add them</a>. It's not that difficult. The standard log package is very extensible.</p></pre>carsncode: <pre><p>This all day. Coming from log4* land, I saw the log package and balked at the lack of, well... everything. But using it for a while I've noticed that I just don't need it, the only two log levels I really need are log message and crash message, and the stdlib logger does both just fine.</p></pre>divan0: <pre><p>I often use custom log writer whenever I need colors/file_linenumber for [ERROR] levels and just use fmt.Println("[ERROR] foo"): <a href="https://play.golang.org/p/JrNvJGDOzm" rel="nofollow">https://play.golang.org/p/JrNvJGDOzm</a></p></pre>ragefacesmirk: <pre><p>Agreed. Adding a dependency for logging seems like a waste. One project that uses it is <a href="HTTPS://github.com/CloudFoundry/loggregator" rel="nofollow">HTTPS://github.com/CloudFoundry/loggregator</a></p></pre>gentleman_tech: <pre><p>It's a rite of passage for new Go devs.</p>
<p>You look at the stdlib log package and scoff gently at how such a simple package can possibly do all the complex things you need it to.</p>
<p>So you create your own logging package that does all the things you think you need.</p>
<p>Then you get more into the Go mindset, and stop using half the things you thought you'd need.</p>
<p>Then eventually you understand why the log package is so simple.</p>
<p>Then you delete your logging package with a small blush of embarrassment.</p>
<p>I have trod this path. Many others have too :)</p></pre>Sphax: <pre><p>Nowadays I declare a function like this:</p>
<pre><code>type LogFn func(fmt string, args ...interface{})
</code></pre>
<p>and use that everywhere. I never use leveled logging so I have no need for the rest. With this interface consumers of my libraries can give it whatever they want, a std logger, logrus logger or anything else really as long as there's a Printf method.</p>
<p>It has worked really well at my work, usually I define only one std logger in main and pass it around everywhere. </p></pre>robbert229: <pre><p>I do a similar thing as well. Do you do anything fancy with logging? Ie elk, oklog, or other magiks?</p></pre>Sphax: <pre><p>We don't have aynthing fancy, we wrote a log shipper that simply sends every log line in a Kafka record, that way we can do a <code>tail -f</code> on all logs. It's not ideal, but we don't have time to test oklog unfortunately.</p></pre>robbert229: <pre><p>Makes sense.</p></pre>notsoobadusername: <pre><p>I'm still kind of new to Go and I don't quite understand this. How do you use args?</p></pre>Sphax: <pre><p>If you look at <a href="https://golang.org/pkg/log/#Printf" rel="nofollow">log.Printf</a>, args in my example is the same as v here. In both cases it allows you to pass arguments of any type for your format string.
<a href="https://play.golang.org/p/Jj4n4UGBFk" rel="nofollow">Here</a> is a more concrete example of what I meant. I can't test with logrus on the playground but it will work with it too. </p>
<p>Hope that helps</p></pre>emilepels: <pre><p>It's a variadic function, which means you can pass it any number of arguments of that type. In this case, the empty interface is used, which is implicitly satisfied by every type (as it has no methods).</p>
<p>In other words: for args, you can pass any number of values of any type. </p>
<p><a href="https://gobyexample.com/variadic-functions" rel="nofollow">https://gobyexample.com/variadic-functions</a>
<a href="https://tour.golang.org/methods/14" rel="nofollow">https://tour.golang.org/methods/14</a></p></pre>tex0: <pre><p>Go-kit log with the level package and JSON output works great for us.</p></pre>robbert229: <pre><p>I use logrus logging to stdout + logspout + oklog. My only complaint with logrus is that i wish it relied more heavily on interfaces. Other than that its all rainbows and sunshine.</p></pre>notsoobadusername: <pre><p>What advantages does logrus have over Nate's suggestion? It just seems very complex to me.</p></pre>robbert229: <pre><p>It really depends. I don't care as much about the logger itself ( logrus or log ) as much as how its used. </p>
<p>As a project grows in size I have found that the global state ( in nates design ) can cause other packages to have external dependencies and can make the code more brittle, harder to change, and less maintainable in the long run. I prefer to pass my logger in via interfaces. Mind you that this is my opinion.</p>
<p>TLDR I don't care about the logging implementation, just interfaces and no global state.</p></pre>bmurphy1976: <pre><p>I've been trying a different approach in my latest project. Log methods are static wrappers around the standard library functions, but they all take a context. I can manipulate the context to affect what and how I'm logging. The key thing is I can automatically include environmental information such as active user, security context, parent references, etc. without having to always explicitly specify them.</p>
<p>It's a little bit of a pain in the ass to pass the context around, but I have to do it anyways for other reasons. Since there's no thread local storage I don't really see a better way, but I prefer this anyways since it's more explicit what is going on.</p>
<p>I'm not sure if there is an open source library that follows the same pattern, I haven't looked yet since I wasn't sure I was going to stick to this approach. If I don't find one I'll consider open sourcing what I have even though there isn't much to it. It might not be the best approach for every situation but it's working out well for this project.</p></pre>sleepydog: <pre><p>I generally don't log in libraries I write, as that would force my choice on the users. Instead I try to convey the necessary info through return values. When I do need to log, I define an interface:</p>
<pre><code>type Logger interface {
Printf(format string, args ...interface{})
}
</code></pre>
<p>And allow the user to provide an implementation with their logger of their choice. They can use <code>log.New()</code> or something else.</p>
<p>For applications, I use the standard lib's log package. If I needed levelled or structured logging, I would probably use logrus or glog.</p></pre>__david__: <pre><p>If you're writing libraries, <em>don't</em> use logrus. Instead just use the standard logging interface and let the application control which logger they want to use.</p>
<p>I've been using Oxy in an application and it's a pain because they use logrus, and use the default global logrus logger at that, which forces my application to know and care about logrus. Now I have to deal with 2 logging systems—the stdlib default logger (which other libs use) and the logrus default logger. It's really stupid.</p></pre>Sythe2o0: <pre><p>We built our own little level-based multi-logger (to stdout and file) with text filtering support, but I've been meaning to replace it with calls out to a more featured library.</p></pre>sharptoothy: <pre><p>I wrote a <a href="https://github.com/skillian/logging" rel="nofollow">logging library</a> that nobody uses!</p>
<p>The problem I perceived with the <code>log</code> library wasn't just the lack of levels but of the ability to log different levels to multiple targets, like logging everything (including debug) to a file (if desired), logging info through error to a database, and logging everything from warning to error to the console. I started off with wrapping multiple <code>log.Logger</code> structs depending on the level, but then I wanted the ability to fine-tune the output more than what I could figure out how to do with just the logger's flags. Eventually, I thought it made sense to just write my own.</p>
<p>It's based on Python's <code>logging</code> package, so Pythonistas should find it easy to use. It's the first real project I've done in Go, so I don't know if it's all idiomatic Go, but I tried to make it correct in that regard.</p></pre>notsoobadusername: <pre><p>Also, why does Nate discard the Trace logs? Wouldn't Debug be turned off by default but Trace on by default? Sorry if I am missing something obvious</p></pre>TheMerovius: <pre><p>I first declare an interface</p>
<pre><code>type Logger interface {
Logf(format string, v ...interface{})
}
</code></pre>
<p>and then:</p>
<pre><code>type Loggers struct {
Debug Logger
// Other levels, if preferred
Error Logger
}
type nopLogger struct{}
func (nopLogger) Logf(format string, v ...interface{}) {}
func WithLog(ctx context.Context, debug, error Logger) context.Context {
return context.WithValue(ctxLog, Loggers{ debug, error})
}
func Log(ctx context.Context) Loggers {
l, _ := ctx.Value(ctxLog).(Loggers)
if l.Debug == nil { l.debug = nopLogger{} }
if l.Error == nil { l.error = nopLogger{} }
return l
}
func Foo(ctx context.Context) {
log := Log(ctx)
log.Debug.Logf("Some debug logging")
log.Error.Logf("Some error logging")
}
</code></pre>
<p>I also have an implementation, that writes to an <code>io.Writer</code>.</p>
<p>Now, this might seem complicated, but I have this in one, central helper package. The reason I do it like this, is, that it's the only way I've found that</p>
<ol>
<li>Makes logging an actual nop (without even formatting overhead), when logging isn't enabled</li>
<li>Makes it possible to enable different log-levels and -destinations per request (for tracing or if you want to debug why a particular request goes wrong) and with a suitable implementation of <code>Logger</code> also per package</li>
<li>Makes it possible to use a <code>*testing.T</code> as a Logger (and thus can get full debug logs for failing tests without extra effort). You can not use a <code>func(fmt string, args ...interface{})</code>, as suggested elsewhere, because that would screw up the line-numbers (the "Caller" of that func would be the line of code where you do <code>t.Logf</code>). So you <em>need</em> that interface and you need the method to be called <code>Logf</code>.</li>
<li>Doesn't have significant syntactic overhead in the callers of the logging-function. This is why those nil-checks are there; <code>Log</code> is guaranteed to provide a usable <code>Loggers</code>, even if none was given in the context.</li>
</ol>
<p>Unfortunately, any kind of helper or wrapper would automatically screw up line-number reporting (so, you can't, for example, wrap a <code>Logger</code> with something that forks of the log to two different sinks. Which is annoying af). But in general, this pattern still seems to give good bang-for-the-buck.</p></pre>jere_jones: <pre><p>I use C# and nlog a lot. I love nlog's ability to specify different logging levels and targets for different parts of the code on the fly via a config file change.</p>
<p>Unfortunately, I have been unable to find a golang equivalent. So I'm writing my own. That's what I use.</p></pre>SilentWeaponQuietWar: <pre><p>ive bounced around between a few, like log15 and logrus the best. Currently using logrus on most projects for the premade hooks for GELF and a few others.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传