evennia/docs/latest/_modules/evennia/utils/logger.html
Evennia docbuilder action 4544902e08 Updated HTML docs.
2026-02-15 17:42:43 +00:00

915 lines
No EOL
84 KiB
HTML

<!DOCTYPE html>
<html lang="en" data-content_root="../../../">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>evennia.utils.logger &#8212; Evennia latest documentation</title>
<link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=d75fae25" />
<link rel="stylesheet" type="text/css" href="../../../_static/nature.css?v=279e0f84" />
<link rel="stylesheet" type="text/css" href="../../../_static/custom.css?v=e4a91a55" />
<script src="../../../_static/documentation_options.js?v=c6e86fd7"></script>
<script src="../../../_static/doctools.js?v=9bcbadda"></script>
<script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
<link rel="icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head><body>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../evennia.html" accesskey="U">evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.utils.logger</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<h1>Source code for evennia.utils.logger</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Logging facilities</span>
<span class="sd">These are thin wrappers on top of Twisted&#39;s logging facilities; logs</span>
<span class="sd">are all directed either to stdout (if Evennia is running in</span>
<span class="sd">interactive mode) or to $GAME_DIR/server/logs.</span>
<span class="sd">The log_file() function uses its own threading system to log to</span>
<span class="sd">arbitrary files in $GAME_DIR/server/logs.</span>
<span class="sd">Note: All logging functions have two aliases, log_type() and</span>
<span class="sd">log_typemsg(). This is for historical, back-compatible reasons.</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">re</span>
<span class="kn">import</span><span class="w"> </span><span class="nn">time</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">traceback</span><span class="w"> </span><span class="kn">import</span> <span class="n">format_exc</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">django.conf</span><span class="w"> </span><span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">twisted</span><span class="w"> </span><span class="kn">import</span> <span class="n">logger</span> <span class="k">as</span> <span class="n">twisted_logger</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">twisted.internet.threads</span><span class="w"> </span><span class="kn">import</span> <span class="n">deferToThread</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">twisted.python</span><span class="w"> </span><span class="kn">import</span> <span class="n">logfile</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">twisted.python</span><span class="w"> </span><span class="kn">import</span> <span class="n">util</span> <span class="k">as</span> <span class="n">twisted_util</span>
<span class="n">log</span> <span class="o">=</span> <span class="n">twisted_logger</span><span class="o">.</span><span class="n">Logger</span><span class="p">()</span>
<span class="n">_LOGDIR</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_LOG_ROTATE_SIZE</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_TIMEZONE</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_CHANNEL_LOG_NUM_TAIL_LINES</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_TIME_FORMAT</span> <span class="o">=</span> <span class="s2">&quot;%Y-%m-</span><span class="si">%d</span><span class="s2"> %H:%M:%S&quot;</span>
<span class="n">_SENSITIVE_INPUT_PATTERNS</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">_SENSITIVE_INPUT_PATTERNS_SIGNATURE</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">def</span><span class="w"> </span><span class="nf">_compile_sensitive_input_patterns</span><span class="p">():</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Compile masking regexes from settings.AUDIT_MASKS.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">patterns</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">masks</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s2">&quot;AUDIT_MASKS&quot;</span><span class="p">,</span> <span class="p">[])</span>
<span class="n">signature</span> <span class="o">=</span> <span class="nb">repr</span><span class="p">(</span><span class="n">masks</span><span class="p">)</span>
<span class="k">for</span> <span class="n">mask</span> <span class="ow">in</span> <span class="n">masks</span><span class="p">:</span>
<span class="c1"># auditing format is list[dict[label -&gt; regex]], but we also</span>
<span class="c1"># support plain regex strings as a convenience.</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">mask</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
<span class="n">regexes</span> <span class="o">=</span> <span class="n">mask</span><span class="o">.</span><span class="n">values</span><span class="p">()</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">regexes</span> <span class="o">=</span> <span class="p">[</span><span class="n">mask</span><span class="p">]</span>
<span class="k">for</span> <span class="n">regex</span> <span class="ow">in</span> <span class="n">regexes</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">patterns</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">regex</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">IGNORECASE</span><span class="p">))</span>
<span class="k">except</span> <span class="n">re</span><span class="o">.</span><span class="n">error</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="n">log_err</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Invalid AUDIT_MASKS regex &#39;</span><span class="si">{</span><span class="n">regex</span><span class="si">}</span><span class="s2">&#39;: </span><span class="si">{</span><span class="n">err</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">patterns</span><span class="p">,</span> <span class="n">signature</span>
<div class="viewcode-block" id="mask_sensitive_input">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.mask_sensitive_input">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">mask_sensitive_input</span><span class="p">(</span><span class="n">msg</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Mask sensitive command arguments in a raw command string.</span>
<span class="sd"> Args:</span>
<span class="sd"> msg (str): Raw command line.</span>
<span class="sd"> Returns:</span>
<span class="sd"> str: Same string, with sensitive segments replaced by ``*``.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">global</span> <span class="n">_SENSITIVE_INPUT_PATTERNS</span><span class="p">,</span> <span class="n">_SENSITIVE_INPUT_PATTERNS_SIGNATURE</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">msg</span><span class="p">:</span>
<span class="k">return</span> <span class="n">msg</span>
<span class="k">if</span> <span class="n">_SENSITIVE_INPUT_PATTERNS</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">_SENSITIVE_INPUT_PATTERNS</span><span class="p">,</span> <span class="n">_SENSITIVE_INPUT_PATTERNS_SIGNATURE</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">_compile_sensitive_input_patterns</span><span class="p">()</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">current_signature</span> <span class="o">=</span> <span class="nb">repr</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s2">&quot;AUDIT_MASKS&quot;</span><span class="p">,</span> <span class="p">[]))</span>
<span class="k">if</span> <span class="n">current_signature</span> <span class="o">!=</span> <span class="n">_SENSITIVE_INPUT_PATTERNS_SIGNATURE</span><span class="p">:</span>
<span class="n">_SENSITIVE_INPUT_PATTERNS</span><span class="p">,</span> <span class="n">_SENSITIVE_INPUT_PATTERNS_SIGNATURE</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">_compile_sensitive_input_patterns</span><span class="p">()</span>
<span class="p">)</span>
<span class="k">for</span> <span class="n">pattern</span> <span class="ow">in</span> <span class="n">_SENSITIVE_INPUT_PATTERNS</span><span class="p">:</span>
<span class="n">match</span> <span class="o">=</span> <span class="n">pattern</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
<span class="k">if</span> <span class="n">match</span><span class="p">:</span>
<span class="k">if</span> <span class="s2">&quot;secret&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">pattern</span><span class="o">.</span><span class="n">groupindex</span><span class="p">:</span>
<span class="k">continue</span>
<span class="n">start</span><span class="p">,</span> <span class="n">end</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">span</span><span class="p">(</span><span class="s2">&quot;secret&quot;</span><span class="p">)</span>
<span class="c1"># Keep rough size information while still obscuring short secrets.</span>
<span class="n">masked</span> <span class="o">=</span> <span class="s2">&quot;*&quot;</span> <span class="o">*</span> <span class="nb">max</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="n">end</span> <span class="o">-</span> <span class="n">start</span><span class="p">)</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">msg</span><span class="p">[:</span><span class="n">start</span><span class="p">]</span><span class="si">}{</span><span class="n">masked</span><span class="si">}{</span><span class="n">msg</span><span class="p">[</span><span class="n">end</span><span class="p">:]</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">return</span> <span class="n">msg</span></div>
<span class="k">def</span><span class="w"> </span><span class="nf">_log</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">logfunc</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">msg</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="n">msg</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>
<span class="k">if</span> <span class="n">kwargs</span><span class="p">:</span>
<span class="n">logfunc</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">msg</span><span class="o">.</span><span class="n">splitlines</span><span class="p">():</span>
<span class="n">logfunc</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">{line}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="n">prefix</span><span class="p">,</span> <span class="n">line</span><span class="o">=</span><span class="n">line</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="n">log</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">&quot;Log failure: </span><span class="si">{err}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">err</span><span class="o">=</span><span class="n">err</span><span class="p">)</span>
<span class="c1"># log call functions (each has legacy aliases)</span>
<div class="viewcode-block" id="log_info">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.log_info">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">log_info</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Logs any generic debugging/informative info that should appear in the log.</span>
<span class="sd"> Args:</span>
<span class="sd"> msg: (string) The message to be logged.</span>
<span class="sd"> **kwargs: If given, The `msg` is parsed as a format string with `{..}`</span>
<span class="sd"> formatting markers that should match the keywords.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_log</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></div>
<span class="n">info</span> <span class="o">=</span> <span class="n">log_info</span>
<span class="n">log_infomsg</span> <span class="o">=</span> <span class="n">log_info</span>
<span class="n">log_msg</span> <span class="o">=</span> <span class="n">log_info</span>
<div class="viewcode-block" id="log_warn">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.log_warn">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">log_warn</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Logs warnings that aren&#39;t critical but should be noted.</span>
<span class="sd"> Args:</span>
<span class="sd"> msg (str): The message to be logged.</span>
<span class="sd"> **kwargs: If given, The `msg` is parsed as a format string with `{..}`</span>
<span class="sd"> formatting markers that should match the keywords.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_log</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">log</span><span class="o">.</span><span class="n">warn</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></div>
<span class="n">warn</span> <span class="o">=</span> <span class="n">log_warn</span>
<span class="n">warning</span> <span class="o">=</span> <span class="n">log_warn</span>
<span class="n">log_warnmsg</span> <span class="o">=</span> <span class="n">log_warn</span>
<div class="viewcode-block" id="log_err">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.log_err">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">log_err</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Logs an error message to the server log.</span>
<span class="sd"> Args:</span>
<span class="sd"> msg (str): The message to be logged.</span>
<span class="sd"> **kwargs: If given, The `msg` is parsed as a format string with `{..}`</span>
<span class="sd"> formatting markers that should match the keywords.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_log</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">log</span><span class="o">.</span><span class="n">error</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></div>
<span class="n">error</span> <span class="o">=</span> <span class="n">log_err</span>
<span class="n">err</span> <span class="o">=</span> <span class="n">log_err</span>
<span class="n">log_errmsg</span> <span class="o">=</span> <span class="n">log_err</span>
<div class="viewcode-block" id="log_trace">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.log_trace">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">log_trace</span><span class="p">(</span><span class="n">msg</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Log a traceback to the log. This should be called from within an</span>
<span class="sd"> exception.</span>
<span class="sd"> Args:</span>
<span class="sd"> msg (str, optional): Adds an extra line with added info</span>
<span class="sd"> at the end of the traceback in the log.</span>
<span class="sd"> **kwargs: If given, The `msg` is parsed as a format string with `{..}`</span>
<span class="sd"> formatting markers that should match the keywords.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">tracestring</span> <span class="o">=</span> <span class="n">format_exc</span><span class="p">()</span>
<span class="k">if</span> <span class="n">tracestring</span><span class="p">:</span>
<span class="n">_log</span><span class="p">(</span><span class="n">tracestring</span><span class="p">,</span> <span class="n">log</span><span class="o">.</span><span class="n">error</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;!!&quot;</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="k">if</span> <span class="n">msg</span><span class="p">:</span>
<span class="n">_log</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">log</span><span class="o">.</span><span class="n">error</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;!!&quot;</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></div>
<span class="n">log_tracemsg</span> <span class="o">=</span> <span class="n">log_trace</span>
<span class="n">exception</span> <span class="o">=</span> <span class="n">log_trace</span>
<span class="n">critical</span> <span class="o">=</span> <span class="n">log_trace</span>
<span class="n">trace</span> <span class="o">=</span> <span class="n">log_trace</span>
<div class="viewcode-block" id="log_dep">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.log_dep">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">log_dep</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Prints a deprecation message.</span>
<span class="sd"> Args:</span>
<span class="sd"> msg (str): The deprecation message to log.</span>
<span class="sd"> **kwargs: If given, The `msg` is parsed as a format string with `{..}`</span>
<span class="sd"> formatting markers that should match the keywords.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_log</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">log</span><span class="o">.</span><span class="n">warn</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;DP&quot;</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></div>
<span class="n">dep</span> <span class="o">=</span> <span class="n">log_dep</span>
<span class="n">deprecated</span> <span class="o">=</span> <span class="n">log_dep</span>
<span class="n">log_depmsg</span> <span class="o">=</span> <span class="n">log_dep</span>
<div class="viewcode-block" id="log_sec">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.log_sec">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">log_sec</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Prints a security-related message.</span>
<span class="sd"> Args:</span>
<span class="sd"> msg (str): The security message to log.</span>
<span class="sd"> **kwargs: If given, The `msg` is parsed as a format string with `{..}`</span>
<span class="sd"> formatting markers that should match the keywords.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_log</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;SS&quot;</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></div>
<span class="n">sec</span> <span class="o">=</span> <span class="n">log_sec</span>
<span class="n">security</span> <span class="o">=</span> <span class="n">log_sec</span>
<span class="n">log_secmsg</span> <span class="o">=</span> <span class="n">log_sec</span>
<div class="viewcode-block" id="log_server">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.log_server">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">log_server</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This is for the Portal to log captured Server stdout messages (it&#39;s</span>
<span class="sd"> usually only used during startup, before Server log is open)</span>
<span class="sd"> Args:</span>
<span class="sd"> msg (str): The message to be logged.</span>
<span class="sd"> **kwargs: If given, The `msg` is parsed as a format string with `{..}`</span>
<span class="sd"> formatting markers that should match the keywords.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">_log</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="s2">&quot;Server&quot;</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></div>
<div class="viewcode-block" id="GetLogObserver">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.GetLogObserver">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">GetLogObserver</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Sets up how the system logs are formatted.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">component_prefix</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="n">event_levels</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">twisted_logger</span><span class="o">.</span><span class="n">LogLevel</span><span class="o">.</span><span class="n">debug</span><span class="p">:</span> <span class="s2">&quot;??&quot;</span><span class="p">,</span>
<span class="n">twisted_logger</span><span class="o">.</span><span class="n">LogLevel</span><span class="o">.</span><span class="n">info</span><span class="p">:</span> <span class="s2">&quot;..&quot;</span><span class="p">,</span>
<span class="n">twisted_logger</span><span class="o">.</span><span class="n">LogLevel</span><span class="o">.</span><span class="n">warn</span><span class="p">:</span> <span class="s2">&quot;WW&quot;</span><span class="p">,</span>
<span class="n">twisted_logger</span><span class="o">.</span><span class="n">LogLevel</span><span class="o">.</span><span class="n">error</span><span class="p">:</span> <span class="s2">&quot;EE&quot;</span><span class="p">,</span>
<span class="n">twisted_logger</span><span class="o">.</span><span class="n">LogLevel</span><span class="o">.</span><span class="n">critical</span><span class="p">:</span> <span class="s2">&quot;!!&quot;</span><span class="p">,</span>
<span class="p">}</span>
<div class="viewcode-block" id="GetLogObserver.format_log_event">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.GetLogObserver.format_log_event">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">format_log_event</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">event</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> By assigning log_system here, we skip the spammy display of namespace/level</span>
<span class="sd"> in the default log output.</span>
<span class="sd"> [component_prefix] [date] [system/lvl] [msg]</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># setting log_system fills the [..] block after the time stamp</span>
<span class="n">prefix</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;prefix&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">prefix</span><span class="p">:</span>
<span class="n">event</span><span class="p">[</span><span class="s2">&quot;log_system&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">prefix</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">lvl</span> <span class="o">=</span> <span class="n">event</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;log_level&quot;</span><span class="p">,</span> <span class="n">twisted_logger</span><span class="o">.</span><span class="n">LogLevel</span><span class="o">.</span><span class="n">info</span><span class="p">)</span>
<span class="n">event</span><span class="p">[</span><span class="s2">&quot;log_system&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">event_levels</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">lvl</span><span class="p">,</span> <span class="s2">&quot;-&quot;</span><span class="p">)</span>
<span class="n">event</span><span class="p">[</span><span class="s2">&quot;log_format&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">event</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;log_format&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">))</span>
<span class="n">component_prefix</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">component_prefix</span> <span class="ow">or</span> <span class="s2">&quot;&quot;</span>
<span class="n">log_msg</span> <span class="o">=</span> <span class="n">twisted_logger</span><span class="o">.</span><span class="n">formatEventAsClassicLogText</span><span class="p">(</span>
<span class="n">event</span><span class="p">,</span> <span class="n">formatTime</span><span class="o">=</span><span class="k">lambda</span> <span class="n">e</span><span class="p">:</span> <span class="n">twisted_logger</span><span class="o">.</span><span class="n">formatTime</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">_TIME_FORMAT</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">component_prefix</span><span class="si">}{</span><span class="n">log_msg</span><span class="si">}</span><span class="s2">&quot;</span></div>
<span class="k">def</span><span class="w"> </span><span class="fm">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">outfile</span><span class="p">):</span>
<span class="k">return</span> <span class="n">twisted_logger</span><span class="o">.</span><span class="n">FileLogObserver</span><span class="p">(</span><span class="n">outfile</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">format_log_event</span><span class="p">)</span></div>
<span class="c1"># Called by server/portal on startup</span>
<div class="viewcode-block" id="GetPortalLogObserver">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.GetPortalLogObserver">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">GetPortalLogObserver</span><span class="p">(</span><span class="n">GetLogObserver</span><span class="p">):</span>
<span class="n">component_prefix</span> <span class="o">=</span> <span class="s2">&quot;|Portal| &quot;</span></div>
<div class="viewcode-block" id="GetServerLogObserver">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.GetServerLogObserver">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">GetServerLogObserver</span><span class="p">(</span><span class="n">GetLogObserver</span><span class="p">):</span>
<span class="n">component_prefix</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span></div>
<span class="c1"># logging overrides</span>
<div class="viewcode-block" id="timeformat">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.timeformat">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">timeformat</span><span class="p">(</span><span class="n">when</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This helper function will format the current time in the same</span>
<span class="sd"> way as the twisted logger does, including time zone info. Only</span>
<span class="sd"> difference from official logger is that we only use two digits</span>
<span class="sd"> for the year and don&#39;t show timezone for GMT times.</span>
<span class="sd"> Args:</span>
<span class="sd"> when (int, optional): This is a time in POSIX seconds on the form</span>
<span class="sd"> given by time.time(). If not given, this function will</span>
<span class="sd"> use the current time.</span>
<span class="sd"> Returns:</span>
<span class="sd"> timestring (str): A formatted string of the given time.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">when</span> <span class="o">=</span> <span class="n">when</span> <span class="k">if</span> <span class="n">when</span> <span class="k">else</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span>
<span class="c1"># time zone offset: UTC - the actual offset</span>
<span class="n">tz_offset</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">utcfromtimestamp</span><span class="p">(</span><span class="n">when</span><span class="p">)</span> <span class="o">-</span> <span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">when</span><span class="p">)</span>
<span class="n">tz_offset</span> <span class="o">=</span> <span class="n">tz_offset</span><span class="o">.</span><span class="n">days</span> <span class="o">*</span> <span class="mi">86400</span> <span class="o">+</span> <span class="n">tz_offset</span><span class="o">.</span><span class="n">seconds</span>
<span class="c1"># correct given time to utc</span>
<span class="n">when</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">utcfromtimestamp</span><span class="p">(</span><span class="n">when</span> <span class="o">-</span> <span class="n">tz_offset</span><span class="p">)</span>
<span class="k">if</span> <span class="n">tz_offset</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">tz</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">tz_hour</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">tz_offset</span> <span class="o">//</span> <span class="mi">3600</span><span class="p">))</span>
<span class="n">tz_mins</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">tz_offset</span> <span class="o">//</span> <span class="mi">60</span> <span class="o">%</span> <span class="mi">60</span><span class="p">))</span>
<span class="n">tz_sign</span> <span class="o">=</span> <span class="s2">&quot;-&quot;</span> <span class="k">if</span> <span class="n">tz_offset</span> <span class="o">&gt;=</span> <span class="mi">0</span> <span class="k">else</span> <span class="s2">&quot;+&quot;</span>
<span class="n">tz</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%s%02d%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">tz_sign</span><span class="p">,</span> <span class="n">tz_hour</span><span class="p">,</span> <span class="p">(</span><span class="s2">&quot;:</span><span class="si">%02d</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">tz_mins</span> <span class="k">if</span> <span class="n">tz_mins</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span><span class="p">))</span>
<span class="k">return</span> <span class="s2">&quot;</span><span class="si">%d</span><span class="s2">-</span><span class="si">%02d</span><span class="s2">-</span><span class="si">%02d</span><span class="s2"> </span><span class="si">%02d</span><span class="s2">:</span><span class="si">%02d</span><span class="s2">:</span><span class="si">%02d%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span>
<span class="n">when</span><span class="o">.</span><span class="n">year</span> <span class="o">-</span> <span class="mi">2000</span><span class="p">,</span>
<span class="n">when</span><span class="o">.</span><span class="n">month</span><span class="p">,</span>
<span class="n">when</span><span class="o">.</span><span class="n">day</span><span class="p">,</span>
<span class="n">when</span><span class="o">.</span><span class="n">hour</span><span class="p">,</span>
<span class="n">when</span><span class="o">.</span><span class="n">minute</span><span class="p">,</span>
<span class="n">when</span><span class="o">.</span><span class="n">second</span><span class="p">,</span>
<span class="n">tz</span><span class="p">,</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="WeeklyLogFile">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.WeeklyLogFile">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">WeeklyLogFile</span><span class="p">(</span><span class="n">logfile</span><span class="o">.</span><span class="n">DailyLogFile</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Log file that rotates once per week by default. Overrides key methods to change format.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="WeeklyLogFile.__init__">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.WeeklyLogFile.__init__">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">directory</span><span class="p">,</span> <span class="n">defaultMode</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">day_rotation</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">max_size</span><span class="o">=</span><span class="mi">1000000</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Args:</span>
<span class="sd"> name (str): Name of log file.</span>
<span class="sd"> directory (str): Directory holding the file.</span>
<span class="sd"> defaultMode (str): Permissions used to create file. Defaults to</span>
<span class="sd"> current permissions of this file if it exists.</span>
<span class="sd"> day_rotation (int): How often to rotate the file.</span>
<span class="sd"> max_size (int): Max size of log file before rotation (regardless of</span>
<span class="sd"> time). Defaults to 1M.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">day_rotation</span> <span class="o">=</span> <span class="n">day_rotation</span>
<span class="bp">self</span><span class="o">.</span><span class="n">max_size</span> <span class="o">=</span> <span class="n">max_size</span>
<span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">logfile</span><span class="o">.</span><span class="n">DailyLogFile</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">directory</span><span class="p">,</span> <span class="n">defaultMode</span><span class="o">=</span><span class="n">defaultMode</span><span class="p">)</span></div>
<span class="k">def</span><span class="w"> </span><span class="nf">_openFile</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">logfile</span><span class="o">.</span><span class="n">DailyLogFile</span><span class="o">.</span><span class="n">_openFile</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">size</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_file</span><span class="o">.</span><span class="n">tell</span><span class="p">()</span>
<div class="viewcode-block" id="WeeklyLogFile.shouldRotate">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.WeeklyLogFile.shouldRotate">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">shouldRotate</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Rotate when the date has changed since last write&quot;&quot;&quot;</span>
<span class="c1"># all dates here are tuples (year, month, day)</span>
<span class="n">now</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">toDate</span><span class="p">()</span>
<span class="n">then</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">lastDate</span>
<span class="k">return</span> <span class="p">(</span>
<span class="n">now</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">then</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="ow">or</span> <span class="n">now</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">then</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="ow">or</span> <span class="n">now</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">&gt;</span> <span class="p">(</span><span class="n">then</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">day_rotation</span><span class="p">)</span>
<span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">&gt;=</span> <span class="bp">self</span><span class="o">.</span><span class="n">max_size</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="WeeklyLogFile.suffix">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.WeeklyLogFile.suffix">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">suffix</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">tupledate</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return the suffix given a (year, month, day) tuple or unixtime.</span>
<span class="sd"> Format changed to have 03 for march instead of 3 etc (retaining unix</span>
<span class="sd"> file order)</span>
<span class="sd"> If we get duplicate suffixes in location (due to hitting size limit),</span>
<span class="sd"> we append __1, __2 etc.</span>
<span class="sd"> Examples:</span>
<span class="sd"> server.log.2020_01_29</span>
<span class="sd"> server.log.2020_01_29__1</span>
<span class="sd"> server.log.2020_01_29__2</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">suffix</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
<span class="n">copy_suffix</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">suffix</span> <span class="o">=</span> <span class="s2">&quot;_&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s2">&quot;</span><span class="si">{:02d}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">part</span><span class="p">)</span> <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="n">tupledate</span><span class="p">])</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="c1"># try taking a float unixtime</span>
<span class="n">suffix</span> <span class="o">=</span> <span class="s2">&quot;_&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s2">&quot;</span><span class="si">{:02d}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">part</span><span class="p">)</span> <span class="k">for</span> <span class="n">part</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">toDate</span><span class="p">(</span><span class="n">tupledate</span><span class="p">)])</span>
<span class="n">suffix</span> <span class="o">+=</span> <span class="sa">f</span><span class="s2">&quot;__</span><span class="si">{</span><span class="n">copy_suffix</span><span class="si">}</span><span class="s2">&quot;</span> <span class="k">if</span> <span class="n">copy_suffix</span> <span class="k">else</span> <span class="s2">&quot;&quot;</span>
<span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">path</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">suffix</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">):</span>
<span class="c1"># Append a higher copy_suffix to try to break the tie (starting from 2)</span>
<span class="n">copy_suffix</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">break</span>
<span class="k">return</span> <span class="n">suffix</span></div>
<div class="viewcode-block" id="WeeklyLogFile.rotate">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.WeeklyLogFile.rotate">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">rotate</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">rotate</span><span class="p">()</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="n">log_trace</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Could not rotate the log file </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">.&quot;</span><span class="p">)</span></div>
<div class="viewcode-block" id="WeeklyLogFile.write">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.WeeklyLogFile.write">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">write</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Write data to log file</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">logfile</span><span class="o">.</span><span class="n">BaseLogFile</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">lastDate</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">lastDate</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">toDate</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">+=</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span></div>
</div>
<span class="c1"># Arbitrary file logger</span>
<div class="viewcode-block" id="EvenniaLogFile">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.EvenniaLogFile">[docs]</a>
<span class="k">class</span><span class="w"> </span><span class="nc">EvenniaLogFile</span><span class="p">(</span><span class="n">logfile</span><span class="o">.</span><span class="n">LogFile</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A rotating logfile based off Twisted&#39;s LogFile. It overrides</span>
<span class="sd"> the LogFile&#39;s rotate method in order to append some of the last</span>
<span class="sd"> lines of the previous log to the start of the new log, in order</span>
<span class="sd"> to preserve a continuous chat history for channel log files.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># we delay import of settings to keep logger module as free</span>
<span class="c1"># from django as possible.</span>
<span class="k">global</span> <span class="n">_CHANNEL_LOG_NUM_TAIL_LINES</span>
<span class="k">if</span> <span class="n">_CHANNEL_LOG_NUM_TAIL_LINES</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">django.conf</span><span class="w"> </span><span class="kn">import</span> <span class="n">settings</span>
<span class="n">_CHANNEL_LOG_NUM_TAIL_LINES</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">CHANNEL_LOG_NUM_TAIL_LINES</span>
<span class="n">num_lines_to_append</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">_CHANNEL_LOG_NUM_TAIL_LINES</span><span class="p">)</span>
<div class="viewcode-block" id="EvenniaLogFile.rotate">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.EvenniaLogFile.rotate">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">rotate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">num_lines_to_append</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Rotates our log file and appends some number of lines from</span>
<span class="sd"> the previous log to the start of the new one.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">append_tail</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">num_lines_to_append</span> <span class="k">if</span> <span class="n">num_lines_to_append</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="bp">self</span><span class="o">.</span><span class="n">num_lines_to_append</span>
<span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">append_tail</span><span class="p">:</span>
<span class="n">logfile</span><span class="o">.</span><span class="n">LogFile</span><span class="o">.</span><span class="n">rotate</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">lines</span> <span class="o">=</span> <span class="n">tail_log_file</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">path</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">num_lines_to_append</span><span class="p">)</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">rotate</span><span class="p">()</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">line</span><span class="p">)</span></div>
<div class="viewcode-block" id="EvenniaLogFile.seek">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.EvenniaLogFile.seek">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">seek</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Convenience method for accessing our _file attribute&#39;s seek method,</span>
<span class="sd"> which is used in tail_log_function.</span>
<span class="sd"> Args:</span>
<span class="sd"> *args: Same args as file.seek</span>
<span class="sd"> **kwargs: Same kwargs as file.seek</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_file</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span></div>
<div class="viewcode-block" id="EvenniaLogFile.readlines">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.EvenniaLogFile.readlines">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">readlines</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Convenience method for accessing our _file attribute&#39;s readlines method,</span>
<span class="sd"> which is used in tail_log_function.</span>
<span class="sd"> Args:</span>
<span class="sd"> *args: same args as file.readlines</span>
<span class="sd"> **kwargs: same kwargs as file.readlines</span>
<span class="sd"> Returns:</span>
<span class="sd"> lines (list): lines from our _file attribute.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">lines</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_file</span><span class="o">.</span><span class="n">readlines</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">line</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">))</span>
<span class="k">except</span> <span class="ne">UnicodeDecodeError</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">line</span><span class="p">))</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="n">lines</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="n">lines</span></div>
</div>
<span class="n">_LOG_FILE_HANDLES</span> <span class="o">=</span> <span class="p">{}</span> <span class="c1"># holds open log handles</span>
<span class="n">_LOG_FILE_HANDLE_COUNTS</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">_LOG_FILE_HANDLE_RESET</span> <span class="o">=</span> <span class="mi">500</span>
<span class="k">def</span><span class="w"> </span><span class="nf">_open_log_file</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Helper to open the log file (always in the log dir) and cache its</span>
<span class="sd"> handle. Will create a new file in the log dir if one didn&#39;t</span>
<span class="sd"> exist.</span>
<span class="sd"> To avoid keeping the filehandle open indefinitely we reset it every</span>
<span class="sd"> _LOG_FILE_HANDLE_RESET accesses. This may help resolve issues for very</span>
<span class="sd"> long uptimes and heavy log use.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># we delay import of settings to keep logger module as free</span>
<span class="c1"># from django as possible.</span>
<span class="k">global</span> <span class="n">_LOG_FILE_HANDLES</span><span class="p">,</span> <span class="n">_LOG_FILE_HANDLE_COUNTS</span><span class="p">,</span> <span class="n">_LOGDIR</span><span class="p">,</span> <span class="n">_LOG_ROTATE_SIZE</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">_LOGDIR</span><span class="p">:</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">django.conf</span><span class="w"> </span><span class="kn">import</span> <span class="n">settings</span>
<span class="n">_LOGDIR</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">LOG_DIR</span>
<span class="n">_LOG_ROTATE_SIZE</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="mi">1000</span><span class="p">,</span> <span class="n">settings</span><span class="o">.</span><span class="n">CHANNEL_LOG_ROTATE_SIZE</span><span class="p">)</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">_LOGDIR</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
<span class="k">if</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">_LOG_FILE_HANDLES</span><span class="p">:</span>
<span class="n">_LOG_FILE_HANDLE_COUNTS</span><span class="p">[</span><span class="n">filename</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">if</span> <span class="n">_LOG_FILE_HANDLE_COUNTS</span><span class="p">[</span><span class="n">filename</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">_LOG_FILE_HANDLE_RESET</span><span class="p">:</span>
<span class="c1"># close/refresh handle</span>
<span class="n">_LOG_FILE_HANDLES</span><span class="p">[</span><span class="n">filename</span><span class="p">]</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="k">del</span> <span class="n">_LOG_FILE_HANDLES</span><span class="p">[</span><span class="n">filename</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># return cached handle</span>
<span class="k">return</span> <span class="n">_LOG_FILE_HANDLES</span><span class="p">[</span><span class="n">filename</span><span class="p">]</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">filehandle</span> <span class="o">=</span> <span class="n">EvenniaLogFile</span><span class="o">.</span><span class="n">fromFullPath</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">rotateLength</span><span class="o">=</span><span class="n">_LOG_ROTATE_SIZE</span><span class="p">)</span>
<span class="c1"># filehandle = open(filename, &quot;a+&quot;) # append mode + reading</span>
<span class="n">_LOG_FILE_HANDLES</span><span class="p">[</span><span class="n">filename</span><span class="p">]</span> <span class="o">=</span> <span class="n">filehandle</span>
<span class="n">_LOG_FILE_HANDLE_COUNTS</span><span class="p">[</span><span class="n">filename</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">return</span> <span class="n">filehandle</span>
<span class="k">except</span> <span class="ne">IOError</span><span class="p">:</span>
<span class="n">log_trace</span><span class="p">()</span>
<span class="k">return</span> <span class="kc">None</span>
<div class="viewcode-block" id="log_file">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.log_file">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">log_file</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="s2">&quot;game.log&quot;</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Arbitrary file logger using threads.</span>
<span class="sd"> Args:</span>
<span class="sd"> msg (str): String to append to logfile.</span>
<span class="sd"> filename (str, optional): Defaults to &#39;game.log&#39;. All logs</span>
<span class="sd"> will appear in the logs directory and log entries will start</span>
<span class="sd"> on new lines following datetime info.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">callback</span><span class="p">(</span><span class="n">filehandle</span><span class="p">,</span> <span class="n">msg</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Writing to file and flushing result&quot;&quot;&quot;</span>
<span class="n">msg</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="si">%s</span><span class="s2"> [-] </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">timeformat</span><span class="p">(),</span> <span class="n">msg</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>
<span class="n">filehandle</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
<span class="c1"># since we don&#39;t close the handle, we need to flush</span>
<span class="c1"># manually or log file won&#39;t be written to until the</span>
<span class="c1"># write buffer is full.</span>
<span class="n">filehandle</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
<span class="k">def</span><span class="w"> </span><span class="nf">errback</span><span class="p">(</span><span class="n">failure</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Catching errors to normal log&quot;&quot;&quot;</span>
<span class="n">log_trace</span><span class="p">()</span>
<span class="c1"># save to server/logs/ directory</span>
<span class="n">filehandle</span> <span class="o">=</span> <span class="n">_open_log_file</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<span class="k">if</span> <span class="n">filehandle</span><span class="p">:</span>
<span class="n">deferToThread</span><span class="p">(</span><span class="n">callback</span><span class="p">,</span> <span class="n">filehandle</span><span class="p">,</span> <span class="n">msg</span><span class="p">)</span><span class="o">.</span><span class="n">addErrback</span><span class="p">(</span><span class="n">errback</span><span class="p">)</span></div>
<div class="viewcode-block" id="log_file_exists">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.log_file_exists">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">log_file_exists</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s2">&quot;game.log&quot;</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Determine if a log-file already exists.</span>
<span class="sd"> Args:</span>
<span class="sd"> filename (str): The filename (within the log-dir).</span>
<span class="sd"> Returns:</span>
<span class="sd"> bool: If the log file exists or not.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">global</span> <span class="n">_LOGDIR</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">_LOGDIR</span><span class="p">:</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">django.conf</span><span class="w"> </span><span class="kn">import</span> <span class="n">settings</span>
<span class="n">_LOGDIR</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">LOG_DIR</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">_LOGDIR</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
<span class="k">return</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span></div>
<div class="viewcode-block" id="rotate_log_file">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.rotate_log_file">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">rotate_log_file</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s2">&quot;game.log&quot;</span><span class="p">,</span> <span class="n">num_lines_to_append</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Force-rotate a log-file, without</span>
<span class="sd"> Args:</span>
<span class="sd"> filename (str): The log file, located in settings.LOG_DIR.</span>
<span class="sd"> num_lines_to_append (int, optional): Include N number of</span>
<span class="sd"> lines from previous file in new one. If `None`, use default.</span>
<span class="sd"> Set to 0 to include no lines.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">log_file_exists</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
<span class="n">file_handle</span> <span class="o">=</span> <span class="n">_open_log_file</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<span class="k">if</span> <span class="n">file_handle</span><span class="p">:</span>
<span class="n">file_handle</span><span class="o">.</span><span class="n">rotate</span><span class="p">(</span><span class="n">num_lines_to_append</span><span class="o">=</span><span class="n">num_lines_to_append</span><span class="p">)</span></div>
<div class="viewcode-block" id="delete_log_file">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.delete_log_file">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">delete_log_file</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Delete a log file</span>
<span class="sd"> Args:</span>
<span class="sd"> filename(str): The name of the log file, located in settings.LOG_DIR</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">log_file_exists</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
<span class="k">global</span> <span class="n">_LOGDIR</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">_LOGDIR</span><span class="p">:</span>
<span class="kn">from</span><span class="w"> </span><span class="nn">django.conf</span><span class="w"> </span><span class="kn">import</span> <span class="n">settings</span>
<span class="n">_LOGDIR</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">LOG_DIR</span>
<span class="n">filename</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">_LOGDIR</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
<span class="n">os</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span></div>
<div class="viewcode-block" id="tail_log_file">
<a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.commands.default.comms.tail_log_file">[docs]</a>
<span class="k">def</span><span class="w"> </span><span class="nf">tail_log_file</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">offset</span><span class="p">,</span> <span class="n">nlines</span><span class="p">,</span> <span class="n">callback</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Return the tail of the log file.</span>
<span class="sd"> Args:</span>
<span class="sd"> filename (str): The name of the log file, presumed to be in</span>
<span class="sd"> the Evennia log dir.</span>
<span class="sd"> offset (int): The line offset *from the end of the file* to start</span>
<span class="sd"> reading from. 0 means to start at the latest entry.</span>
<span class="sd"> nlines (int): How many lines to return, counting backwards</span>
<span class="sd"> from the offset. If file is shorter, will get all lines.</span>
<span class="sd"> callback (callable, optional): A function to manage the result of the</span>
<span class="sd"> asynchronous file access. This will get a list of lines. If unset,</span>
<span class="sd"> the tail will happen synchronously.</span>
<span class="sd"> Returns:</span>
<span class="sd"> lines (deferred or list): This will be a deferred if `callable` is given,</span>
<span class="sd"> otherwise it will be a list with The nline entries from the end of the file, or</span>
<span class="sd"> all if the file is shorter than nlines.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span><span class="w"> </span><span class="nf">seek_file</span><span class="p">(</span><span class="n">filehandle</span><span class="p">,</span> <span class="n">offset</span><span class="p">,</span> <span class="n">nlines</span><span class="p">,</span> <span class="n">callback</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;step backwards in chunks and stop only when we have enough lines&quot;&quot;&quot;</span>
<span class="n">lines_found</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">buffer_size</span> <span class="o">=</span> <span class="mi">4098</span>
<span class="n">block_count</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
<span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">lines_found</span><span class="p">)</span> <span class="o">&lt;</span> <span class="p">(</span><span class="n">offset</span> <span class="o">+</span> <span class="n">nlines</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># scan backwards in file, starting from the end</span>
<span class="n">filehandle</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="n">block_count</span> <span class="o">*</span> <span class="n">buffer_size</span><span class="p">,</span> <span class="n">os</span><span class="o">.</span><span class="n">SEEK_END</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">IOError</span><span class="p">:</span>
<span class="c1"># file too small for this seek, take what we&#39;ve got</span>
<span class="n">filehandle</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">lines_found</span> <span class="o">=</span> <span class="n">filehandle</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="k">break</span>
<span class="n">lines_found</span> <span class="o">=</span> <span class="n">filehandle</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="n">block_count</span> <span class="o">-=</span> <span class="mi">1</span>
<span class="c1"># return the right number of lines</span>
<span class="n">lines_found</span> <span class="o">=</span> <span class="n">lines_found</span><span class="p">[</span><span class="o">-</span><span class="n">nlines</span> <span class="o">-</span> <span class="n">offset</span> <span class="p">:</span> <span class="o">-</span><span class="n">offset</span> <span class="k">if</span> <span class="n">offset</span> <span class="k">else</span> <span class="kc">None</span><span class="p">]</span>
<span class="k">if</span> <span class="n">callback</span><span class="p">:</span>
<span class="n">callback</span><span class="p">(</span><span class="n">lines_found</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">lines_found</span>
<span class="k">def</span><span class="w"> </span><span class="nf">errback</span><span class="p">(</span><span class="n">failure</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Catching errors to normal log&quot;&quot;&quot;</span>
<span class="n">log_trace</span><span class="p">()</span>
<span class="n">filehandle</span> <span class="o">=</span> <span class="n">_open_log_file</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<span class="k">if</span> <span class="n">filehandle</span><span class="p">:</span>
<span class="k">if</span> <span class="n">callback</span><span class="p">:</span>
<span class="k">return</span> <span class="n">deferToThread</span><span class="p">(</span><span class="n">seek_file</span><span class="p">,</span> <span class="n">filehandle</span><span class="p">,</span> <span class="n">offset</span><span class="p">,</span> <span class="n">nlines</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span><span class="o">.</span><span class="n">addErrback</span><span class="p">(</span>
<span class="n">errback</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">seek_file</span><span class="p">(</span><span class="n">filehandle</span><span class="p">,</span> <span class="n">offset</span><span class="p">,</span> <span class="n">nlines</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span></div>
</pre></div>
<div class="clearer"></div>
</div>
</div>
</div>
<div class="sphinxsidebar" role="navigation" aria-label="Main">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../index.html">
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo of Evennia"/>
</a></p>
<search id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../../../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
<input type="submit" value="Go" />
</form>
</div>
</search>
<script>document.getElementById('searchbox').style.display = "block"</script><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/evennia/evennia">Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Doc Versions</h3>
<ul>
<li>
<a href="https://www.evennia.com/docs/latest/index.html">latest (main branch)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/5.x/index.html">v5.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/4.x/index.html">v4.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/3.x/index.html">v3.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/2.x/index.html">v2.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/1.x/index.html">v1.0.0 branch (outdated)</a>
</li>
<li>
<a href="https://www.evennia.com/docs/0.x/index.html">v0.9.5 branch (outdated)</a>
</li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="related" role="navigation" aria-label="Related">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../evennia.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.utils.logger</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2024, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.2.3.
</div>
</body>
</html>