- log 2017-03-19T16:58:15+01:00 https://fadeit.dk/blog/tag/log.html Python logging handler for Mailgun 2015-10-12T13:25:30+02:00 https://fadeit.dk/blog /2015/10/12/mailgun-python-log-handler <p>Yet another reason to love python is the wonderful logging API provided by a standard library. Having a decent logger provided by the language saves developers time from integrating with some third-party library, but most importantly it contributes to a clean system where all modules use the same logger. Out of the box, there is a <a href="https://docs.python.org/3/library/logging.handlers.html">handler</a> for almost any typical use-case, but the best feature is the option to create your own with relative ease. So-far we’ve been using <a href="https://docs.python.org/3/library/logging.handlers.html#smtphandler">SMTPHandler</a>, but since moving to <a href="https://www.mailgun.com/">Mailgun</a>, I decided to experiment with a custom handler to submit logs via their API instead. I’d like to mention that creating a custom logging handler is not a requirement, it is still possible to use their SMTP server with SMTP handler. To get started, we need to extend Handler baseclass and override emit method to make a POST request.</p> <div class="language-python highlighter-rouge"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">logging</span> <span class="kn">import</span> <span class="nn">requests</span> <span class="k">class</span> <span class="nc">MailgunHandler</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">Handler</span><span class="p">):</span> <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">api_url</span><span class="p">,</span> <span class="n">api_key</span><span class="p">,</span> <span class="n">sender</span><span class="p">,</span> <span class="n">recipients</span><span class="p">,</span> <span class="n">subject</span><span class="p">):</span> <span class="c"># run the regular Handler __init__</span> <span class="n">logging</span><span class="o">.</span><span class="n">Handler</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="bp">self</span><span class="o">.</span><span class="n">api_url</span> <span class="o">=</span> <span class="n">api_url</span> <span class="bp">self</span><span class="o">.</span><span class="n">api_key</span> <span class="o">=</span> <span class="n">api_key</span> <span class="bp">self</span><span class="o">.</span><span class="n">sender</span> <span class="o">=</span> <span class="n">sender</span> <span class="bp">self</span><span class="o">.</span><span class="n">recipients</span> <span class="o">=</span> <span class="n">recipients</span> <span class="bp">self</span><span class="o">.</span><span class="n">subject</span> <span class="o">=</span> <span class="n">subject</span> <span class="k">def</span> <span class="nf">emit</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">record</span><span class="p">):</span> <span class="c"># record.message is the log message</span> <span class="k">for</span> <span class="n">recipient</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">recipients</span><span class="p">:</span> <span class="n">data</span> <span class="o">=</span> <span class="p">{</span> <span class="s">"from"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">sender</span><span class="p">,</span> <span class="s">"to"</span><span class="p">:</span> <span class="n">recipient</span><span class="p">,</span> <span class="s">"subject"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">subject</span><span class="p">,</span> <span class="s">"text"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">record</span><span class="p">)</span> <span class="p">}</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">api_url</span><span class="p">,</span> <span class="n">auth</span><span class="o">=</span><span class="p">(</span><span class="s">"api"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">api_key</span><span class="p">),</span> <span class="n">data</span><span class="o">=</span><span class="n">data</span><span class="p">)</span> </code></pre> </div> <p>I have created a simple flask application that registers the handler and also implemented a route that triggers an error to test it out.</p> <div class="language-python highlighter-rouge"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">logging</span> <span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span> <span class="kn">from</span> <span class="nn">mailgun_handler</span> <span class="kn">import</span> <span class="n">MailgunHandler</span> <span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> <span class="c"># Setup logging handler</span> <span class="n">mail_handler</span> <span class="o">=</span> <span class="n">MailgunHandler</span><span class="p">(</span> <span class="n">api_url</span><span class="o">=</span><span class="s">'https://api.mailgun.net/v3/fadeit.dk/messages'</span><span class="p">,</span> <span class="n">api_key</span><span class="o">=</span><span class="s">'secret'</span><span class="p">,</span> <span class="n">sender</span><span class="o">=</span><span class="s">'noreply@fadeit.dk'</span><span class="p">,</span> <span class="n">recipients</span><span class="o">=</span><span class="p">[</span><span class="s">'ss@fadeit.dk'</span><span class="p">,</span> <span class="s">'ja@fadeit.dk'</span><span class="p">],</span> <span class="n">subject</span><span class="o">=</span><span class="s">'Application error!'</span> <span class="p">)</span> <span class="n">mail_handler</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">ERROR</span><span class="p">)</span> <span class="n">mail_handler</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">logging</span><span class="o">.</span><span class="n">Formatter</span><span class="p">(</span><span class="s">''' Message type: </span><span class="si">%(levelname)</span><span class="s">s Location: </span><span class="si">%(pathname)</span><span class="s">s:</span><span class="si">%(lineno)</span><span class="s">d Module: </span><span class="si">%(module)</span><span class="s">s Function: </span><span class="si">%(funcName)</span><span class="s">s Time: </span><span class="si">%(asctime)</span><span class="s">s Message: </span><span class="si">%(message)</span><span class="s">s '''</span><span class="p">))</span> <span class="n">app</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">mail_handler</span><span class="p">)</span> <span class="nd">@app.route</span><span class="p">(</span><span class="s">'/error'</span><span class="p">)</span> <span class="k">def</span> <span class="nf">error</span><span class="p">():</span> <span class="k">raise</span> <span class="nb">Exception</span><span class="p">(</span><span class="s">"Beds are burning!"</span><span class="p">)</span> <span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span> <span class="c">#app.run(debug=True) #Handler isn't executed if app is run in debug mode</span> <span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">()</span> </code></pre> </div>