<?xml-stylesheet href="/pretty-feed-v2.xsl" type="text/xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Trys Mudford's Blog</title>
    <link>https://www.trysmudford.com/tags/pino/</link>
    <description>Posts, thoughts, links and photos from Trys</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 30 Apr 2024 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.trysmudford.com/blog/index.xml" rel="self" type="application/rss+xml"/>
    
    <item>
      <title>Next.js edge logging with Pino/Datadog</title>
      <link>https://www.trysmudford.com/blog/nextjs-edge-logging/</link>
      <pubDate>Tue, 30 Apr 2024 00:00:00 +0000</pubDate>
      
      <guid>https://www.trysmudford.com/blog/nextjs-edge-logging/</guid>
      <description><![CDATA[
<p>I encountered an issue with the potent combo of: Next.js App Router, Edge runtime, Server Actions, Pino and Datadog. After much googling, I couldn&rsquo;t find a solution to this problem, hence this keyword-stuffed blog post for future me/others.</p>
<p>First up: logs were appearing in Datadog over multiple lines, which broke the <code>stdout</code> formatting rendering the logs unusable. Note, this only happened with the Edge runtime, not the standard Node variation. To solve this, I added a new section to the standard pino config:</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kr">const</span> <span class="nx">isServer</span> <span class="o">=</span> <span class="k">typeof</span> <span class="nb">window</span> <span class="o">===</span> <span class="s1">&#39;undefined&#39;</span><span class="p">;</span>
<span class="kr">const</span> <span class="nx">isNextEdgeRuntime</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NEXT_RUNTIME</span> <span class="o">===</span> <span class="s1">&#39;edge&#39;</span><span class="p">;</span>

<span class="kr">export</span> <span class="kr">const</span> <span class="nx">config</span> <span class="o">=</span> <span class="p">{</span>	
    <span class="c1">// ...standard pino config
</span><span class="c1"></span>    <span class="p">...(</span><span class="nx">isServer</span> <span class="o">&amp;&amp;</span> <span class="nx">isNextEdgeRuntime</span> <span class="o">&amp;&amp;</span> <span class="p">{</span>
        <span class="nx">browser</span><span class="o">:</span> <span class="p">{</span>
            <span class="nx">write</span><span class="o">:</span> <span class="p">{</span>
                <span class="nx">critical</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">o</span><span class="p">)),</span>
                <span class="nx">debug</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">o</span><span class="p">)),</span>
                <span class="nx">error</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">o</span><span class="p">)),</span>
                <span class="nx">fatal</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">o</span><span class="p">)),</span>
                <span class="nx">info</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">o</span><span class="p">)),</span>
                <span class="nx">trace</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">o</span><span class="p">)),</span>
                <span class="nx">warn</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">o</span><span class="p">)),</span>
            <span class="p">},</span>
        <span class="p">},</span>
    <span class="p">}),</span>
<span class="p">};</span>

<span class="kr">const</span> <span class="nx">loggerInstance</span> <span class="o">=</span> <span class="nx">pino</span><span class="p">(</span><span class="nx">config</span><span class="p">);</span>
</code></pre></div><p>However, this created a second problem. Despite using <code>console.error</code>, errors were still being reported to Datadog as <code>info</code>, which then failed to trigger alerts and monitors. Not great. The solution was to pass a <code>level</code> parameter into the object; pre-stringification, on the <code>warn</code> and <code>error</code> methods.</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kr">const</span> <span class="nx">isServer</span> <span class="o">=</span> <span class="k">typeof</span> <span class="nb">window</span> <span class="o">===</span> <span class="s1">&#39;undefined&#39;</span><span class="p">;</span>
<span class="kr">const</span> <span class="nx">isNextEdgeRuntime</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NEXT_RUNTIME</span> <span class="o">===</span> <span class="s1">&#39;edge&#39;</span><span class="p">;</span>

<span class="kr">export</span> <span class="kr">const</span> <span class="nx">config</span> <span class="o">=</span> <span class="p">{</span>	
    <span class="c1">// ...standard pino config
</span><span class="c1"></span>    <span class="p">...(</span><span class="nx">isServer</span> <span class="o">&amp;&amp;</span> <span class="nx">isNextEdgeRuntime</span> <span class="o">&amp;&amp;</span> <span class="p">{</span>
        <span class="nx">browser</span><span class="o">:</span> <span class="p">{</span>
            <span class="nx">write</span><span class="o">:</span> <span class="p">{</span>
                <span class="nx">critical</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">o</span><span class="p">)),</span>
                <span class="nx">debug</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">o</span><span class="p">)),</span>
                <span class="nx">error</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span> <span class="p">...</span><span class="nx">o</span><span class="p">,</span> <span class="nx">level</span><span class="o">:</span> <span class="s1">&#39;error&#39;</span> <span class="p">})),</span>
                <span class="nx">fatal</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">o</span><span class="p">)),</span>
                <span class="nx">info</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">o</span><span class="p">)),</span>
                <span class="nx">trace</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">o</span><span class="p">)),</span>
                <span class="nx">warn</span><span class="o">:</span> <span class="p">(</span><span class="nx">o</span><span class="o">:</span> <span class="nb">Object</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="nx">console</span><span class="p">.</span><span class="nx">warn</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span> <span class="p">...</span><span class="nx">o</span><span class="p">,</span> <span class="nx">level</span><span class="o">:</span> <span class="s1">&#39;warn&#39;</span> <span class="p">})),</span>
            <span class="p">},</span>
        <span class="p">},</span>
    <span class="p">}),</span>
<span class="p">};</span>

<span class="kr">const</span> <span class="nx">loggerInstance</span> <span class="o">=</span> <span class="nx">pino</span><span class="p">(</span><span class="nx">config</span><span class="p">);</span>
</code></pre></div><p>This tells Datadog to treat the offending logs as errors/warnings, which can then be used to trigger alerts etc.</p>
]]>
      </description>
    </item>
    
  </channel>
</rss>