277 lines
15 KiB
Plaintext
Generated

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Go by Example: Logging</title>
<link rel=stylesheet href="site.css">
</head>
<script>
onkeydown = (e) => {
if (e.key == "ArrowLeft") {
window.location.href = 'environment-variables';
}
if (e.key == "ArrowRight") {
window.location.href = 'http-client';
}
}
</script>
<body>
<div class="example" id="logging">
<h2><a href="./">Go by Example</a>: Logging</h2>
<table>
<tr>
<td class="docs">
<p>The Go standard library provides straightforward
tools for outputting logs from Go programs, with
the <a href="https://pkg.go.dev/log">log</a> package for
free-form output and the
<a href="https://pkg.go.dev/log/slog">log/slog</a> package for
structured output.</p>
</td>
<td class="code leading">
<a href="https://go.dev/play/p/Qd0uCqBlYUn"><img title="Run code" src="play.png" class="run" /></a><img title="Copy code" src="clipboard.png" class="copy" />
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">&#34;bytes&#34;</span>
</span></span><span class="line"><span class="cl"> <span class="s">&#34;fmt&#34;</span>
</span></span><span class="line"><span class="cl"> <span class="s">&#34;log&#34;</span>
</span></span><span class="line"><span class="cl"> <span class="s">&#34;os&#34;</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="s">&#34;log/slog&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
<p>Simply invoking functions like <code>Println</code> from the
<code>log</code> package uses the <em>standard</em> logger, which
is already pre-configured for reasonable logging
output to <code>os.Stderr</code>. Additional methods like
<code>Fatal*</code> or <code>Panic*</code> will exit the program after
logging.</p>
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;standard logger&#34;</span><span class="p">)</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
<p>Loggers can be configured with <em>flags</em> to set
their output format. By default, the standard
logger has the <code>log.Ldate</code> and <code>log.Ltime</code> flags
set, and these are collected in <code>log.LstdFlags</code>.
We can change its flags to emit time with
microsecond accuracy, for example.</p>
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">SetFlags</span><span class="p">(</span><span class="nx">log</span><span class="p">.</span><span class="nx">LstdFlags</span> <span class="p">|</span> <span class="nx">log</span><span class="p">.</span><span class="nx">Lmicroseconds</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;with micro&#34;</span><span class="p">)</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
<p>It also supports emitting the file name and
line from which the <code>log</code> function is called.</p>
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">SetFlags</span><span class="p">(</span><span class="nx">log</span><span class="p">.</span><span class="nx">LstdFlags</span> <span class="p">|</span> <span class="nx">log</span><span class="p">.</span><span class="nx">Lshortfile</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">log</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;with file/line&#34;</span><span class="p">)</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
<p>It may be useful to create a custom logger and
pass it around. When creating a new logger, we
can set a <em>prefix</em> to distinguish its output
from other loggers.</p>
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">mylog</span> <span class="o">:=</span> <span class="nx">log</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stdout</span><span class="p">,</span> <span class="s">&#34;my:&#34;</span><span class="p">,</span> <span class="nx">log</span><span class="p">.</span><span class="nx">LstdFlags</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">mylog</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;from mylog&#34;</span><span class="p">)</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
<p>We can set the prefix
on existing loggers (including the standard one)
with the <code>SetPrefix</code> method.</p>
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">mylog</span><span class="p">.</span><span class="nf">SetPrefix</span><span class="p">(</span><span class="s">&#34;ohmy:&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">mylog</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;from mylog&#34;</span><span class="p">)</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
<p>Loggers can have custom output targets;
any <code>io.Writer</code> works.</p>
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="kd">var</span> <span class="nx">buf</span> <span class="nx">bytes</span><span class="p">.</span><span class="nx">Buffer</span>
</span></span><span class="line"><span class="cl"> <span class="nx">buflog</span> <span class="o">:=</span> <span class="nx">log</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">buf</span><span class="p">,</span> <span class="s">&#34;buf:&#34;</span><span class="p">,</span> <span class="nx">log</span><span class="p">.</span><span class="nx">LstdFlags</span><span class="p">)</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
<p>This call writes the log output into <code>buf</code>.</p>
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">buflog</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;hello&#34;</span><span class="p">)</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
<p>This will actually show it on standard output.</p>
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Print</span><span class="p">(</span><span class="s">&#34;from buflog:&#34;</span><span class="p">,</span> <span class="nx">buf</span><span class="p">.</span><span class="nf">String</span><span class="p">())</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
<p>The <code>slog</code> package provides
<em>structured</em> log output. For example, logging
in JSON format is straightforward.</p>
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">jsonHandler</span> <span class="o">:=</span> <span class="nx">slog</span><span class="p">.</span><span class="nf">NewJSONHandler</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stderr</span><span class="p">,</span> <span class="kc">nil</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">myslog</span> <span class="o">:=</span> <span class="nx">slog</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="nx">jsonHandler</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">myslog</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">&#34;hi there&#34;</span><span class="p">)</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
<p>In addition to the message, <code>slog</code> output can
contain an arbitrary number of key=value
pairs.</p>
</td>
<td class="code">
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="nx">myslog</span><span class="p">.</span><span class="nf">Info</span><span class="p">(</span><span class="s">&#34;hello again&#34;</span><span class="p">,</span> <span class="s">&#34;key&#34;</span><span class="p">,</span> <span class="s">&#34;val&#34;</span><span class="p">,</span> <span class="s">&#34;age&#34;</span><span class="p">,</span> <span class="mi">25</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre>
</td>
</tr>
</table>
<table>
<tr>
<td class="docs">
<p>Sample output; the date and time
emitted will depend on when the example ran.</p>
</td>
<td class="code leading">
<pre class="chroma"><code><span class="line"><span class="cl"><span class="gp">$</span> go run logging.go
</span></span><span class="line"><span class="cl"><span class="go">2023/08/22 10:45:16 standard logger
</span></span></span><span class="line"><span class="cl"><span class="go">2023/08/22 10:45:16.904141 with micro
</span></span></span><span class="line"><span class="cl"><span class="go">2023/08/22 10:45:16 logging.go:40: with file/line
</span></span></span><span class="line"><span class="cl"><span class="go">my:2023/08/22 10:45:16 from mylog
</span></span></span><span class="line"><span class="cl"><span class="go">ohmy:2023/08/22 10:45:16 from mylog
</span></span></span><span class="line"><span class="cl"><span class="go">from buflog:buf:2023/08/22 10:45:16 hello</span></span></span></code></pre>
</td>
</tr>
<tr>
<td class="docs">
<p>These are wrapped for clarity of presentation
on the website; in reality they are emitted
on a single line.</p>
</td>
<td class="code">
<pre class="chroma"><code><span class="line"><span class="cl"><span class="go">{&#34;time&#34;:&#34;2023-08-22T10:45:16.904166391-07:00&#34;,
</span></span></span><span class="line"><span class="cl"><span class="go"> &#34;level&#34;:&#34;INFO&#34;,&#34;msg&#34;:&#34;hi there&#34;}
</span></span></span><span class="line"><span class="cl"><span class="go">{&#34;time&#34;:&#34;2023-08-22T10:45:16.904178985-07:00&#34;,
</span></span></span><span class="line"><span class="cl"><span class="go"> &#34;level&#34;:&#34;INFO&#34;,&#34;msg&#34;:&#34;hello again&#34;,
</span></span></span><span class="line"><span class="cl"><span class="go"> &#34;key&#34;:&#34;val&#34;,&#34;age&#34;:25}</span></span></span></code></pre>
</td>
</tr>
</table>
<p class="next">
Next example: <a href="http-client">HTTP Client</a>.
</p>
<p class="footer">
by <a href="https://markmcgranaghan.com">Mark McGranaghan</a> and <a href="https://eli.thegreenplace.net">Eli Bendersky</a> | <a href="https://github.com/mmcgrana/gobyexample">source</a> | <a href="https://github.com/mmcgrana/gobyexample#license">license</a>
</p>
</div>
<script>
var codeLines = [];
codeLines.push('package main\u000A');codeLines.push('import (\u000A \"bytes\"\u000A \"fmt\"\u000A \"log\"\u000A \"os\"\u000A');codeLines.push(' \"log/slog\"\u000A)\u000A');codeLines.push('func main() {\u000A');codeLines.push(' log.Println(\"standard logger\")\u000A');codeLines.push(' log.SetFlags(log.LstdFlags | log.Lmicroseconds)\u000A log.Println(\"with micro\")\u000A');codeLines.push(' log.SetFlags(log.LstdFlags | log.Lshortfile)\u000A log.Println(\"with file/line\")\u000A');codeLines.push(' mylog :\u003D log.New(os.Stdout, \"my:\", log.LstdFlags)\u000A mylog.Println(\"from mylog\")\u000A');codeLines.push(' mylog.SetPrefix(\"ohmy:\")\u000A mylog.Println(\"from mylog\")\u000A');codeLines.push(' var buf bytes.Buffer\u000A buflog :\u003D log.New(\u0026buf, \"buf:\", log.LstdFlags)\u000A');codeLines.push(' buflog.Println(\"hello\")\u000A');codeLines.push(' fmt.Print(\"from buflog:\", buf.String())\u000A');codeLines.push(' jsonHandler :\u003D slog.NewJSONHandler(os.Stderr, nil)\u000A myslog :\u003D slog.New(jsonHandler)\u000A myslog.Info(\"hi there\")\u000A');codeLines.push(' myslog.Info(\"hello again\", \"key\", \"val\", \"age\", 25)\u000A}\u000A');codeLines.push('');codeLines.push('');
</script>
<script src="site.js" async></script>
</body>
</html>