evennia/docs/1.0-dev/_modules/evennia/utils/logger.html
Evennia docbuilder action c18dd858d5 Updated HTML docs
2022-10-23 09:32:39 +00:00

722 lines
No EOL
71 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>evennia.utils.logger &#8212; Evennia 1.0-dev documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut 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 navigation">
<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 1.0-dev</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 class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../../../index.html">
<img class="logo" src="../../../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div 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" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/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>Versions</h3>
<ul>
<li><a href="logger.html">1.0-dev (develop branch)</a></li>
<li><a href="../../../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<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="nn">os</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
<span class="kn">from</span> <span class="nn">traceback</span> <span class="kn">import</span> <span class="n">format_exc</span>
<span class="kn">from</span> <span class="nn">twisted</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="nn">twisted.internet.threads</span> <span class="kn">import</span> <span class="n">deferToThread</span>
<span class="kn">from</span> <span class="nn">twisted.python</span> <span class="kn">import</span> <span class="n">logfile</span>
<span class="kn">from</span> <span class="nn">twisted.python</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="k">def</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">e</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.utils.logger.log_info">[docs]</a><span class="k">def</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="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.utils.logger.log_warn">[docs]</a><span class="k">def</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="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.utils.logger.log_err">[docs]</a><span class="k">def</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="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.utils.logger.log_trace">[docs]</a><span class="k">def</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="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.utils.logger.log_dep">[docs]</a><span class="k">def</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="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.utils.logger.log_sec">[docs]</a><span class="k">def</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="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.utils.logger.log_server">[docs]</a><span class="k">def</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="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.utils.logger.GetLogObserver">[docs]</a><span class="k">class</span> <span class="nc">GetLogObserver</span><span class="p">:</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.utils.logger.GetLogObserver.format_log_event">[docs]</a> <span class="k">def</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="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="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.utils.logger.GetPortalLogObserver">[docs]</a><span class="k">class</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.utils.logger.GetServerLogObserver">[docs]</a><span class="k">class</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.utils.logger.timeformat">[docs]</a><span class="k">def</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="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.utils.logger.WeeklyLogFile">[docs]</a><span class="k">class</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="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.utils.logger.WeeklyLogFile.__init__">[docs]</a> <span class="k">def</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="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="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.utils.logger.WeeklyLogFile.shouldRotate">[docs]</a> <span class="k">def</span> <span class="nf">shouldRotate</span><span class="p">(</span><span class="bp">self</span><span class="p">):</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.utils.logger.WeeklyLogFile.suffix">[docs]</a> <span class="k">def</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="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.utils.logger.WeeklyLogFile.rotate">[docs]</a> <span class="k">def</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.utils.logger.WeeklyLogFile.write">[docs]</a> <span class="k">def</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="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.utils.logger.EvenniaLogFile">[docs]</a><span class="k">class</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="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="nn">django.conf</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.utils.logger.EvenniaLogFile.rotate">[docs]</a> <span class="k">def</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="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.utils.logger.EvenniaLogFile.seek">[docs]</a> <span class="k">def</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="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.utils.logger.EvenniaLogFile.readlines">[docs]</a> <span class="k">def</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="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="nf">_open_log_file</span><span class="p">(</span><span class="n">filename</span><span class="p">):</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="nn">django.conf</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.utils.logger.log_file">[docs]</a><span class="k">def</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="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="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="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="nf">errback</span><span class="p">(</span><span class="n">failure</span><span class="p">):</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.utils.logger.log_file_exists">[docs]</a><span class="k">def</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="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="nn">django.conf</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.utils.logger.rotate_log_file">[docs]</a><span class="k">def</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="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="tail_log_file"><a class="viewcode-back" href="../../../api/evennia.utils.logger.html#evennia.utils.logger.tail_log_file">[docs]</a><span class="k">def</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="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="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="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="nf">errback</span><span class="p">(</span><span class="n">failure</span><span class="p">):</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>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<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 1.0-dev</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 class="develop">develop branch</div>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>