Logging to a file or buffer in Go instead of `os.Stdout`

xuanbao · · 68 次点击    
<p>Most logging packages allow you to specify a stream, buffer, or file to write to.</p> <p>Here&#39;s an example of Google&#39;s go-logging package that lets you set a backend (set to <code>os.Stdout</code> below)</p> <pre><code>import ( &#34;fmt&#34; &#34;os&#34; &#34;time&#34; &#34;github.com/op/go-logging&#34; ) var format = logging.MustStringFormatter( fmt.Sprintf( &#34;%v %v&#34;, &#34;%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s}&#34;, &#34;%{id:03x}%{color:reset} %{message}&#34;, ), ) var backend = logging.NewBackendFormatter( logging.NewLogBackend(os.Stdout, &#34;&#34;, 0), format) logging.SetBackend(backend) </code></pre> <p>My problem is that when running <code>go test</code>, it executes my actual Go code which logs a whole bunch of stuff to <code>stdout</code> in various places.</p> <p>Just for the purposes of my tests, I&#39;d love to swap out Stdout for something else, like a file or text buffer. I&#39;d also love to be able to read from that buffer so I can validate output for certain functions. </p> <p>Problem is, I&#39;m new to Go and I have no idea how to do that!</p> <p>Is there a standard (i.e. commonly accepted) way to mock an output stream or a buffer?</p> <p>Thanks!</p> <hr/>**评论:**<br/><br/>jerf: <pre><p>Others have covered the proximal issue, so I&#39;m going to step up one <a href="https://en.wikipedia.org/wiki/5_Whys" rel="nofollow">level of &#34;why?&#34;</a> and suggest that it sounds like you&#39;re setting a global variable as your logger, which left you unsure how to deal with that in your tests. Your code snippet suggests that too, though I can&#39;t be 100% sure because often people simplify bits for posting.</p> <p>That is actually your core problem. You really should be passing that around, possibly bound together into other objects or composed in. You should find that once you start doing this, especially with composition, that it&#39;s easier than you think. But you do need to bite the bullet and start doing it before you can see that. :)</p></pre>WikiTextBot: <pre><p><strong>5 Whys</strong></p> <p>5 Whys is an iterative interrogative technique used to explore the cause-and-effect relationships underlying a particular problem. The primary goal of the technique is to determine the root cause of a defect or problem by repeating the question &#34;Why?&#34; Each answer forms the basis of the next question. The &#34;5&#34; in the name derives from an anecdotal observation on the number of iterations needed to resolve the problem.</p> <p>The technique was formally developed by Sakichi Toyoda and was used within the Toyota Motor Corporation during the evolution of its manufacturing methodologies.</p> <hr/> <p><sup>[</sup> <a href="https://www.reddit.com/message/compose?to=kittens_from_space" rel="nofollow"><sup>PM</sup></a> <sup>|</sup> <a href="https://reddit.com/message/compose?to=WikiTextBot&amp;message=Excludeme&amp;subject=Excludeme" rel="nofollow"><sup>Exclude</sup> <sup>me</sup></a> <sup>|</sup> <a href="https://np.reddit.com/r/golang/about/banned" rel="nofollow"><sup>Exclude</sup> <sup>from</sup> <sup>subreddit</sup></a> <sup>|</sup> <a href="https://np.reddit.com/r/WikiTextBot/wiki/index" rel="nofollow"><sup>FAQ</sup> <sup>/</sup> <sup>Information</sup></a> <sup>|</sup> <a href="https://github.com/kittenswolf/WikiTextBot" rel="nofollow"><sup>Source</sup></a> <sup>]</sup> <sup>Downvote</sup> <sup>to</sup> <sup>remove</sup> <sup>|</sup> <sup>v0.24</sup></p></pre>deusmetallum: <pre><p>use os.OpenFile to get a file handler, and then use that in place of os.Stdout. That&#39;s all you need.</p></pre>quiI: <pre><p>I personally would inject into your &#34;thing&#34; a <code>logDestination io.Writer</code>and then when logging use it with <code>fmt.Fprintf(logDestination, &#34;hello world&#34;)</code> That way you can more or less send your logs anywhere and it&#39;s just a matter of configuration.</p></pre>stone_henge: <pre><blockquote> <p>I&#39;d love to swap out Stdout for something else, like a file or text buffer. I&#39;d also love to be able to read from that buffer so I can validate output for certain functions.</p> <p>Problem is, I&#39;m new to Go and I have no idea how to do that!</p> </blockquote> <p>The correct way to do this in Go is to implement the interface that <code>NewBackendFormatter</code> expects, in this case <code>io.Writer</code>:</p> <pre><code>type Writer interface { Write(p []byte) (n int, err error) } </code></pre> <p>That is, anything with a method matching the Write signature.</p> <p>Use (or create) a type that matches this interface and you can use it as well as <code>os.Stdout</code> as your backend. What you are looking for specifically is probably <code>bytes.Buffer</code>, or occasionally something that just discards the data:</p> <pre><code>b := &amp;bytes.Buffer{} logging.NewLogBackend(b) // do something with b.String() </code></pre> <p>or</p> <pre><code>type discardwriter struct{} func (w discardwriter) Write(p []byte) (n int, err error) { return } // ... backend := logging.NewLogBackend(discardwriter{}) </code></pre></pre>metamatic: <pre><p>Personally, I use a lightweight leveled logging, with Info messages passed to stdout and Debug and Error passed to stderr. Then I have a DEBUG environment variable or command line argument to enable the Debug messages. Originally I set it up like that because of my cloud environment&#39;s log handling, but it works well for local purposes too. It allows me to run tests concisely, then add a -debug flag if I want to see all the details.</p></pre>
68 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传