Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issues/157: add heartbeat to BreachHandler #161

Merged
merged 20 commits into from
Sep 6, 2019
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ most recent version is listed first.
- rename the `naz.hooks.BaseHook` methods: https://github.com/komuw/naz/pull/159
The new names are more correct and indicate what is actually taking place.
- use github actions for CI: https://github.com/komuw/naz/pull/162
- Add heartbeat to BreachHandler: https://github.com/komuw/naz/pull/161


## **version:** v0.6.6
Expand Down
86 changes: 83 additions & 3 deletions docs/_modules/naz/log.html
Original file line number Diff line number Diff line change
Expand Up @@ -368,17 +368,28 @@ <h1>Source code for naz.log</h1><div class="highlight"><pre>
<div class="viewcode-block" id="BreachHandler.__init__"><a class="viewcode-back" href="../../log.html#naz.log.BreachHandler.__init__">[docs]</a> <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">flushLevel</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">WARNING</span><span class="p">,</span>
<span class="n">capacity</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">10_000</span><span class="p">,</span>
<span class="n">capacity</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">1_000</span><span class="p">,</span>
<span class="n">target</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Handler</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">(),</span>
<span class="n">flushOnClose</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
<span class="n">heartbeatInterval</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Union</span><span class="p">[</span><span class="kc">None</span><span class="p">,</span> <span class="nb">float</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Parameters:</span>
<span class="sd"> flushLevel: the log level that will trigger this handler to flush logs to :py:attr:`~target`</span>
<span class="sd"> capacity: the maximum number of log records to store in the ring buffer</span>
<span class="sd"> target: the ultimate `log handler &lt;https://docs.python.org/3.6/library/logging.html#logging.Handler&gt;`_ that will be used.</span>
<span class="sd"> flushOnClose: whether to flush the buffer when the handler is closed even if the flush level hasn&#39;t been exceeded</span>
<span class="sd"> heartbeatInterval: can be a float or None. If it is a float, then a heartbeat log record will be emitted every :py:attr:`~heartbeatInterval` seconds.</span>
<span class="sd"> If it is None(the default), then no heartbeat log record is emitted.</span>
<span class="sd"> If you do decide to set it, a good value is at least 1800(ie 30 minutes).</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_validate_args</span><span class="p">(</span>
<span class="n">flushLevel</span><span class="o">=</span><span class="n">flushLevel</span><span class="p">,</span>
<span class="n">capacity</span><span class="o">=</span><span class="n">capacity</span><span class="p">,</span>
<span class="n">target</span><span class="o">=</span><span class="n">target</span><span class="p">,</span>
<span class="n">flushOnClose</span><span class="o">=</span><span class="n">flushOnClose</span><span class="p">,</span>
<span class="n">heartbeatInterval</span><span class="o">=</span><span class="n">heartbeatInterval</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># call `logging.handlers.MemoryHandler` init</span>
<span class="nb">super</span><span class="p">(</span><span class="n">BreachHandler</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span> <span class="c1"># type: ignore</span>
<span class="n">capacity</span><span class="o">=</span><span class="n">capacity</span><span class="p">,</span>
Expand All @@ -388,16 +399,85 @@ <h1>Source code for naz.log</h1><div class="highlight"><pre>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">buffer</span><span class="p">:</span> <span class="n">collections</span><span class="o">.</span><span class="n">deque</span> <span class="o">=</span> <span class="n">collections</span><span class="o">.</span><span class="n">deque</span><span class="p">(</span>
<span class="n">maxlen</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">capacity</span> <span class="c1"># type: ignore</span>
<span class="p">)</span> <span class="c1"># pytype: disable=attribute-error</span></div>
<span class="p">)</span> <span class="c1"># pytype: disable=attribute-error</span>
<span class="c1"># assuming each log record is 250 bytes, then the maximum</span>
<span class="c1"># memory used by `buffer` will always be == 250*10_000/(1000*1000) == 2.5MB</span>

<span class="bp">self</span><span class="o">.</span><span class="n">heartbeatInterval</span> <span class="o">=</span> <span class="n">heartbeatInterval</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">heartbeatInterval</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">heartbeatInterval</span> <span class="o">=</span> <span class="n">heartbeatInterval</span> <span class="c1"># seconds</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_s_time</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">monotonic</span><span class="p">()</span>

<span class="bp">self</span><span class="o">.</span><span class="n">target</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">DEBUG</span><span class="p">)</span> <span class="c1"># type: ignore</span></div>

<div class="viewcode-block" id="BreachHandler.shouldFlush"><a class="viewcode-back" href="../../log.html#naz.log.BreachHandler.shouldFlush">[docs]</a> <span class="k">def</span> <span class="nf">shouldFlush</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="n">logging</span><span class="o">.</span><span class="n">LogRecord</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Check for record at the flushLevel or higher.</span>
<span class="sd"> Implementation is mostly taken from `logging.handlers.MemoryHandler`</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="n">record</span><span class="o">.</span><span class="n">levelno</span> <span class="o">&gt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">flushLevel</span> <span class="c1"># type: ignore # pytype: disable=attribute-error</span></div></div>
<span class="bp">self</span><span class="o">.</span><span class="n">_heartbeat</span><span class="p">()</span>
<span class="k">return</span> <span class="n">record</span><span class="o">.</span><span class="n">levelno</span> <span class="o">&gt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">flushLevel</span> <span class="c1"># type: ignore # pytype: disable=attribute-error</span></div>

<span class="k">def</span> <span class="nf">_heartbeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">heartbeatInterval</span><span class="p">:</span>
<span class="k">return</span>

<span class="c1"># check if `heartbeatInterval` seconds have passed.</span>
<span class="c1"># if they have, emit a heartbeat log record to the target handler</span>
<span class="n">_now</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">monotonic</span><span class="p">()</span>
<span class="n">_diff</span> <span class="o">=</span> <span class="n">_now</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">_s_time</span>
<span class="k">if</span> <span class="n">_diff</span> <span class="o">&gt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">heartbeatInterval</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_s_time</span> <span class="o">=</span> <span class="n">_now</span>
<span class="c1"># see: https://docs.python.org/3/library/logging.html#logging.LogRecord</span>
<span class="n">record</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">makeLogRecord</span><span class="p">(</span>
<span class="p">{</span>
<span class="s2">&quot;level&quot;</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">INFO</span><span class="p">,</span>
<span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;BreachHandler&quot;</span><span class="p">,</span>
<span class="s2">&quot;pathname&quot;</span><span class="p">:</span> <span class="s2">&quot;.../naz/naz/log.py&quot;</span><span class="p">,</span>
<span class="s2">&quot;func&quot;</span><span class="p">:</span> <span class="s2">&quot;BreachHandler._heartbeat&quot;</span><span class="p">,</span>
<span class="s2">&quot;msg&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">&quot;event&quot;</span><span class="p">:</span> <span class="s2">&quot;naz.BreachHandler.heartbeat&quot;</span><span class="p">,</span>
<span class="s2">&quot;heartbeatInterval&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">heartbeatInterval</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">target</span><span class="o">.</span><span class="n">emit</span><span class="p">(</span><span class="n">record</span><span class="o">=</span><span class="n">record</span><span class="p">)</span> <span class="c1"># pytype: disable=attribute-error</span>

<span class="k">def</span> <span class="nf">_validate_args</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">flushLevel</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
<span class="n">capacity</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span>
<span class="n">target</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="n">flushOnClose</span><span class="p">:</span> <span class="nb">bool</span><span class="p">,</span>
<span class="n">heartbeatInterval</span><span class="p">:</span> <span class="n">typing</span><span class="o">.</span><span class="n">Union</span><span class="p">[</span><span class="kc">None</span><span class="p">,</span> <span class="nb">float</span><span class="p">],</span>
<span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">flushLevel</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
<span class="s2">&quot;`flushLevel` should be of type:: `int` You entered: </span><span class="si">{0}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">flushLevel</span><span class="p">))</span>
<span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">capacity</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
<span class="s2">&quot;`capacity` should be of type:: `int` You entered: </span><span class="si">{0}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">capacity</span><span class="p">))</span>
<span class="p">)</span>

<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">target</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">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
<span class="s2">&quot;`target` should be of type:: `logging.Handler` You entered: </span><span class="si">{0}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="nb">type</span><span class="p">(</span><span class="n">target</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">flushOnClose</span><span class="p">,</span> <span class="nb">bool</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
<span class="s2">&quot;`flushOnClose` should be of type:: `bool` You entered: </span><span class="si">{0}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="nb">type</span><span class="p">(</span><span class="n">flushOnClose</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">heartbeatInterval</span><span class="p">,</span> <span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="kc">None</span><span class="p">),</span> <span class="nb">float</span><span class="p">)):</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
<span class="s2">&quot;`heartbeatInterval` should be of type:: `None` or `float` You entered: </span><span class="si">{0}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
<span class="nb">type</span><span class="p">(</span><span class="n">heartbeatInterval</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">)</span></div>
</pre></div>

</div>
Expand Down
Loading