Sophie

Sophie

distrib > Mandriva > 2010.1 > x86_64 > media > contrib-backports > by-pkgid > e15f173f36ff245dfb6d502e2debb9a7 > files > 64

python-twiggy-0.4.4-1mdv2010.2.noarch.rpm



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script type="text/javascript">

      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-3052036-8']);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
      })();
    </script>
    <title>Reference Guide &mdash; Twiggy</title>
    <link rel="stylesheet" href="_static/default.css" type="text/css" />
    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    '',
        VERSION:     '0.4.4',
        COLLAPSE_INDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true
      };
    </script>
    <script type="text/javascript" src="_static/jquery.js"></script>
    <script type="text/javascript" src="_static/underscore.js"></script>
    <script type="text/javascript" src="_static/doctools.js"></script>
    <link rel="search" type="application/opensearchdescription+xml"
          title="Search within Twiggy"
          href="_static/opensearch.xml"/>
    <link rel="top" title="Twiggy" href="index.html" />
    <link rel="next" title="API Reference" href="api.html" />
    <link rel="prev" title="Configuring Output" href="configuration.html" /> 
  </head>
  <body>
    <div class="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="api.html" title="API Reference"
             accesskey="N">next</a> |</li>
        <li class="right" >
          <a href="configuration.html" title="Configuring Output"
             accesskey="P">previous</a> |</li>
        <li><a href="index.html">Twiggy v0.4.4 documentation</a> &raquo;</li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body">
            
  <div class="section" id="reference-guide">
<h1>Reference Guide<a class="headerlink" href="#reference-guide" title="Permalink to this headline">¶</a></h1>
<div class="section" id="dynamic-logging">
<span id="dynamic-messages"></span><h2>Dynamic Logging<a class="headerlink" href="#dynamic-logging" title="Permalink to this headline">¶</a></h2>
<p>Any functions in message args/fields are called and the value substitued.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">os</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">twiggy.lib</span> <span class="kn">import</span> <span class="n">thread_name</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">thread_name</span><span class="p">()</span>
<span class="go">&#39;MainThread&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">log</span><span class="o">.</span><span class="n">fields</span><span class="p">(</span><span class="n">pid</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">getpid</span><span class="p">)</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">&quot;I&#39;m in thread {0}&quot;</span><span class="p">,</span> <span class="n">thread_name</span><span class="p">)</span>
<span class="go">INFO:pid=...:I&#39;m in thread MainThread</span>
</pre></div>
</div>
<p>This can be useful with partially-bound loggers, which lets us do some cool stuff. Here&#8217;s a proxy class that logs which thread accesses attributes.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">ThreadTracker</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;a proxy that logs attribute access&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__obj</span> <span class="o">=</span> <span class="n">obj</span>
        <span class="c"># a partially bound logger</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__log</span> <span class="o">=</span> <span class="n">log</span><span class="o">.</span><span class="n">name</span><span class="p">(</span><span class="s">&quot;tracker&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">fields</span><span class="p">(</span><span class="n">obj_id</span><span class="o">=</span><span class="nb">id</span><span class="p">(</span><span class="n">obj</span><span class="p">),</span> <span class="n">thread</span><span class="o">=</span><span class="n">thread_name</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">&quot;started tracking&quot;</span><span class="p">)</span>
    <span class="k">def</span> <span class="nf">__getattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">attr</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">&quot;accessed {0}&quot;</span><span class="p">,</span> <span class="n">attr</span><span class="p">)</span>
        <span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">__obj</span><span class="p">,</span> <span class="n">attr</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">Bunch</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">pass</span>
</pre></div>
</div>
<p>Let&#8217;s see it in action.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">foo</span> <span class="o">=</span> <span class="n">Bunch</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">foo</span><span class="o">.</span><span class="n">bar</span> <span class="o">=</span> <span class="mi">42</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">tracked</span> <span class="o">=</span> <span class="n">ThreadTracker</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span>
<span class="go">DEBUG:tracker:obj_id=...:thread=MainThread:started tracking</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">tracked</span><span class="o">.</span><span class="n">bar</span>
<span class="go">DEBUG:tracker:obj_id=...:thread=MainThread:accessed bar</span>
<span class="go">42</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">threading</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">=</span><span class="n">threading</span><span class="o">.</span><span class="n">Thread</span><span class="p">(</span><span class="n">target</span> <span class="o">=</span> <span class="k">lambda</span><span class="p">:</span> <span class="n">tracked</span><span class="o">.</span><span class="n">bar</span> <span class="o">*</span> <span class="mi">2</span><span class="p">,</span> <span class="n">name</span> <span class="o">=</span> <span class="s">&quot;TheDoubler&quot;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">t</span><span class="o">.</span><span class="n">start</span><span class="p">();</span> <span class="n">t</span><span class="o">.</span><span class="n">join</span><span class="p">()</span>
<span class="go">DEBUG:tracker:obj_id=...:thread=TheDoubler:accessed bar</span>
</pre></div>
</div>
<p>If you really want to log a callable, <tt class="docutils literal"><span class="pre">repr()</span></tt> it or wrap it in lambda.</p>
<div class="admonition-see-also admonition seealso">
<p class="first admonition-title">See also</p>
<p class="last"><a class="reference internal" href="api.html#module-twiggy.features.procinfo" title="twiggy.features.procinfo"><tt class="xref py py-mod docutils literal"><span class="pre">procinfo</span></tt></a> feature</p>
</div>
</div>
<div class="section" id="features">
<h2>Features!<a class="headerlink" href="#features" title="Permalink to this headline">¶</a></h2>
<p><a class="reference internal" href="api.html#module-twiggy.features" title="twiggy.features"><tt class="xref py py-mod docutils literal"><span class="pre">Features</span></tt></a> are optional additons of logging functionality to the <a class="reference internal" href="api.html#twiggy.log" title="twiggy.log"><tt class="xref py py-obj docutils literal"><span class="pre">log</span></tt></a>. They encapsulate common logging patterns. Code can be written using a feature, enhancing what information is logged. The feature can be disabled at <a class="reference internal" href="configuration.html#twiggy-setup"><em>runtime</em></a> if desired.</p>
<div class="admonition warning">
<p class="first admonition-title">Warning</p>
<p class="last">Features are currently deprecated, pending a reimplementation in version 0.5</p>
</div>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">twiggy.features</span> <span class="kn">import</span> <span class="n">socket</span> <span class="k">as</span> <span class="n">socket_feature</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">log</span><span class="o">.</span><span class="n">addFeature</span><span class="p">(</span><span class="n">socket_feature</span><span class="o">.</span><span class="n">socket</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="kn">import</span> <span class="nn">socket</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="o">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span><span class="o">.</span><span class="n">connect</span><span class="p">((</span><span class="s">&#39;www.python.org&#39;</span><span class="p">,</span> <span class="mi">80</span><span class="p">))</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">log</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">&quot;connected&quot;</span><span class="p">)</span>
<span class="go">DEBUG:host=dinsdale.python.org:ip_addr=82.94.164.162:port=80:service=www:connected</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># turn off the feature - the name is still available</span>
<span class="gp">... </span><span class="n">log</span><span class="o">.</span><span class="n">disableFeature</span><span class="p">(</span><span class="s">&#39;socket&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">log</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">&quot;connected&quot;</span><span class="p">)</span>
<span class="go">DEBUG:connected</span>
<span class="gp">&gt;&gt;&gt; </span><span class="c"># use a different implementation</span>
<span class="gp">... </span><span class="n">log</span><span class="o">.</span><span class="n">addFeature</span><span class="p">(</span><span class="n">socket_feature</span><span class="o">.</span><span class="n">socket_minimal</span><span class="p">,</span> <span class="s">&#39;socket&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">log</span><span class="o">.</span><span class="n">socket</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">&quot;connected&quot;</span><span class="p">)</span>
<span class="go">DEBUG:ip_addr=82.94.164.162:port=80:connected</span>
</pre></div>
</div>
</div>
<div class="section" id="stays-out-of-your-way">
<span id="never-raises"></span><h2>Stays Out of Your Way<a class="headerlink" href="#stays-out-of-your-way" title="Permalink to this headline">¶</a></h2>
<p>Twiggy tries to stay out of your way.  Specifically, an error in logging should <strong>never</strong> propogate outside the logging subsystem and cause your main application to crash. Instead, errors are trapped and reported by the  <a class="reference internal" href="api.html#twiggy.internal_log" title="twiggy.internal_log"><tt class="xref py py-data docutils literal"><span class="pre">internal_log</span></tt></a>.</p>
<p>Instances of <a class="reference internal" href="api.html#twiggy.logger.InternalLogger" title="twiggy.logger.InternalLogger"><tt class="xref py py-class docutils literal"><span class="pre">InternalLogger</span></tt></a> only have a single <a class="reference internal" href="api.html#twiggy.outputs.Output" title="twiggy.outputs.Output"><tt class="xref py py-class docutils literal"><span class="pre">Output</span></tt></a> - they do not use emitters. By default, these messages are sent to standard error. You may assign an alternate ouput (such as a file) to <tt class="xref py py-obj docutils literal"><span class="pre">twiggy.internal_log.output</span></tt> if desired, with the following conditions:</p>
<ul class="simple">
<li>the output should be failsafe - any errors that occur during internal logging will be dumped to standard error, and suppressed, causing the original message to be discarded.</li>
<li>accordingly, networked or asynchronous outputs are not recommended.</li>
<li>make sure someone is reading these log messages!</li>
</ul>
</div>
<div class="section" id="concurrency">
<h2>Concurrency<a class="headerlink" href="#concurrency" title="Permalink to this headline">¶</a></h2>
<p>Locking in twiggy is as fine-grained as possible. Each individual output has its own lock (if necessary), and only holds that lock when writing. Using redundant outputs (ie, pointing to the same file) is not supported and will cause logfile corruption.</p>
<p>Asynchronous loggers never lock.</p>
</div>
<div class="section" id="use-by-libraries">
<h2>Use by Libraries<a class="headerlink" href="#use-by-libraries" title="Permalink to this headline">¶</a></h2>
<p>Libraries require special care to be polite and usable by application code.  The library should have a single bound in its top-level package that&#8217;s used by modules. Library logging should generally be silent by default.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># in mylib/__init__.py</span>
<span class="n">log</span> <span class="o">=</span> <span class="n">twiggy</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">name</span><span class="p">(</span><span class="s">&#39;mylib&#39;</span><span class="p">)</span>
<span class="n">log</span><span class="o">.</span><span class="n">min_level</span> <span class="o">=</span> <span class="n">twiggy</span><span class="o">.</span><span class="n">levels</span><span class="o">.</span><span class="n">DISABLED</span>

<span class="c"># in mylib/some_module.py</span>
<span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">log</span>
<span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">&quot;hi there&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This allows application code to enable/disable all of library&#8217;s logging as needed.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># in twiggy_setup</span>
<span class="kn">import</span> <span class="nn">mylib</span>
<span class="n">mylib</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">min_level</span> <span class="o">=</span> <span class="n">twiggy</span><span class="o">.</span><span class="n">levels</span><span class="o">.</span><span class="n">INFO</span>
</pre></div>
</div>
<p>In addition to <a class="reference internal" href="api.html#twiggy.logger.BaseLogger.min_level" title="twiggy.logger.BaseLogger.min_level"><tt class="xref py py-attr docutils literal"><span class="pre">min_level</span></tt></a>, loggers also have a <a class="reference internal" href="api.html#twiggy.logger.Logger.filter" title="twiggy.logger.Logger.filter"><tt class="xref py py-attr docutils literal"><span class="pre">filter</span></tt></a>. This filter operates <em>only on the format string</em>, and is intended to allow users to selectively disable individual messages in a poorly-written library.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># in mylib:</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="mi">1000000</span><span class="p">):</span>
    <span class="n">log</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s">&quot;blah blah {0}&quot;</span><span class="p">,</span> <span class="mi">42</span><span class="p">)</span>

<span class="c"># in twiggy_setup: turn off stupidness</span>
<span class="n">mylib</span><span class="o">.</span><span class="n">log</span><span class="o">.</span><span class="n">filter</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">format_spec</span><span class="p">:</span> <span class="n">format_spec</span> <span class="o">!=</span> <span class="s">&quot;blah blah {0}&quot;</span>
</pre></div>
</div>
<p>Note that using a filter this way is an optimization - in general, application code should use <a class="reference internal" href="api.html#twiggy.emitters" title="twiggy.emitters"><tt class="xref py py-data docutils literal"><span class="pre">emitters</span></tt></a> instead.</p>
</div>
<div class="section" id="tips-and-tricks">
<h2>Tips And Tricks<a class="headerlink" href="#tips-and-tricks" title="Permalink to this headline">¶</a></h2>
<div class="section" id="alternate-styles">
<span id="id1"></span><h3>Alternate Styles<a class="headerlink" href="#alternate-styles" title="Permalink to this headline">¶</a></h3>
<p>In addition to the default new-style (braces) format specs, twiggy also supports old-style (percent, aka printf) and templates (dollar).</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">log</span><span class="o">.</span><span class="n">options</span><span class="p">(</span><span class="n">style</span><span class="o">=</span><span class="s">&#39;percent&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">&#39;I like </span><span class="si">%s</span><span class="s">&#39;</span><span class="p">,</span> <span class="s">&quot;bikes&quot;</span><span class="p">)</span>
<span class="go">INFO:I like bikes</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">log</span><span class="o">.</span><span class="n">options</span><span class="p">(</span><span class="n">style</span><span class="o">=</span><span class="s">&#39;dollar&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">&#39;$what kill&#39;</span><span class="p">,</span> <span class="n">what</span><span class="o">=</span><span class="s">&#39;Cars&#39;</span><span class="p">)</span>
<span class="go">INFO:Cars kill</span>
</pre></div>
</div>
</div>
<div class="section" id="use-fields">
<h3>Use Fields<a class="headerlink" href="#use-fields" title="Permalink to this headline">¶</a></h3>
<p>Use <a class="reference internal" href="api.html#twiggy.logger.BaseLogger.fields" title="twiggy.logger.BaseLogger.fields"><tt class="xref py py-meth docutils literal"><span class="pre">fields()</span></tt></a> to include key-value data in a message instead of embedding it the human-readable string.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c"># do this:</span>
<span class="n">log</span><span class="o">.</span><span class="n">fields</span><span class="p">(</span><span class="n">key1</span><span class="o">=</span><span class="s">&#39;a&#39;</span><span class="p">,</span> <span class="n">key2</span><span class="o">=</span><span class="s">&#39;b&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">&quot;stuff happenend&quot;</span><span class="p">)</span>

<span class="c"># not this:</span>
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">&quot;stuff happened. key1: {0} key2: {1}&quot;</span><span class="p">,</span> <span class="s">&#39;a&#39;</span><span class="p">,</span> <span class="s">&#39;b&#39;</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="section" id="technical-details">
<h2>Technical Details<a class="headerlink" href="#technical-details" title="Permalink to this headline">¶</a></h2>
<div class="section" id="independence-of-logger-instances">
<h3>Independence of logger instances<a class="headerlink" href="#independence-of-logger-instances" title="Permalink to this headline">¶</a></h3>
<p>Each log instance created by partial binding is independent from each other. In particular, a logger&#8217;s <a class="reference internal" href="api.html#twiggy.logger.BaseLogger.name" title="twiggy.logger.BaseLogger.name"><tt class="xref py py-meth docutils literal"><span class="pre">name()</span></tt></a> has no relation to the object; it&#8217;s just for human use.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">log</span><span class="o">.</span><span class="n">name</span><span class="p">(</span><span class="s">&#39;bob&#39;</span><span class="p">)</span> <span class="ow">is</span> <span class="n">log</span><span class="o">.</span><span class="n">name</span><span class="p">(</span><span class="s">&#39;bob&#39;</span><span class="p">)</span>
<span class="go">False</span>
</pre></div>
</div>
</div>
<div class="section" id="optimizations">
<h3>Optimizations<a class="headerlink" href="#optimizations" title="Permalink to this headline">¶</a></h3>
<p>Twiggy has been written to be fast, minimizing the performance impact on the main execution path. In particular, messages that will cause no output are handled as quickly as possible.  Users are therefore encouraged to add lots of logging for development/debugging purposes and then turn them off in production.</p>
<p>The emit methods can be hidden behind an appropriate <tt class="docutils literal"><span class="pre">assert</span></tt>. Python will eliminate the statement entirely when run with bytecode optimization (<tt class="docutils literal"><span class="pre">python</span> <span class="pre">-O</span></tt>).</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">assert</span> <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">&quot;This goes away with python -O&quot;</span><span class="p">)</span> <span class="ow">is</span> <span class="bp">None</span>
<span class="k">assert</span> <span class="ow">not</span> <span class="n">log</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s">&quot;So does this&quot;</span><span class="p">)</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">The author doesn&#8217;t particularly care for code written like this, but likes making his users happy more.</p>
</div>
</div>
</div>
<div class="section" id="extending-twiggy">
<h2>Extending Twiggy<a class="headerlink" href="#extending-twiggy" title="Permalink to this headline">¶</a></h2>
<p>When developing extensions to twiggy, use the <a class="reference internal" href="api.html#twiggy.devel_log" title="twiggy.devel_log"><tt class="xref py py-data docutils literal"><span class="pre">devel_log</span></tt></a>. An <a class="reference internal" href="api.html#twiggy.logger.InternalLogger" title="twiggy.logger.InternalLogger"><tt class="xref py py-class docutils literal"><span class="pre">InternalLogger</span></tt></a>, the devel_log is completely separate from the main <a class="reference internal" href="api.html#twiggy.log" title="twiggy.log"><tt class="xref py py-data docutils literal"><span class="pre">log</span></tt></a>.  By default, messages logged to the devel_log are discarded; assigning an appropriate <a class="reference internal" href="api.html#twiggy.outputs.Output" title="twiggy.outputs.Output"><tt class="xref py py-class docutils literal"><span class="pre">Output</span></tt></a> to its <tt class="xref py py-attr docutils literal"><span class="pre">output</span></tt> attribute before using.</p>
<div class="section" id="writing-features">
<h3>Writing Features<a class="headerlink" href="#writing-features" title="Permalink to this headline">¶</a></h3>
<div class="admonition warning">
<p class="first admonition-title">Warning</p>
<p class="last">Features are currently deprecated, pending a reimplementation in version 0.5</p>
</div>
<p>Features are used to encapsulate common logging patterns. They are implemented as methods added to the <a class="reference internal" href="api.html#twiggy.logger.Logger" title="twiggy.logger.Logger"><tt class="xref py py-class docutils literal"><span class="pre">Logger</span></tt></a> class. They receive an instance as the first argument (ie, <tt class="docutils literal"><span class="pre">self</span></tt>). <a class="reference internal" href="api.html#twiggy.logger.Logger.addFeature" title="twiggy.logger.Logger.addFeature"><tt class="xref py py-meth docutils literal"><span class="pre">Enable</span> <span class="pre">the</span> <span class="pre">feature</span></tt></a> before using.</p>
<p>Features come in two flavors: those that add information to a message&#8217;s fields or set options, and those that cause output.</p>
<p>Features which only add fields/set options should simply call the appropriate method on <tt class="docutils literal"><span class="pre">self</span></tt> and return the resultant object.:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">dimensions</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">shape</span><span class="p">):</span>
    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">(</span><span class="n">height</span><span class="o">=</span><span class="n">shape</span><span class="o">.</span><span class="n">height</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="n">shape</span><span class="o">.</span><span class="n">width</span><span class="p">)</span>
</pre></div>
</div>
<p>Features can also emit messages as usual.  Do not return from these methods.:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">sayhi</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">lang</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">lang</span> <span class="o">==</span> <span class="s">&#39;en&#39;</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">&quot;Hello world&quot;</span><span class="p">)</span>
    <span class="k">elif</span> <span class="n">lang</span> <span class="o">==</span> <span class="s">&#39;fr&#39;</span><span class="p">:</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">&quot;Bonjour tout le monde&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p id="wsgi-support">If the feature should add fields <em>and</em> emit in the same step (like <a class="reference internal" href="api.html#twiggy.logger.BaseLogger.struct" title="twiggy.logger.BaseLogger.struct"><tt class="xref py py-meth docutils literal"><span class="pre">struct()</span></tt></a>), use the <a class="reference internal" href="api.html#twiggy.logger.emit" title="twiggy.logger.emit"><tt class="xref py py-func docutils literal"><span class="pre">emit()</span></tt></a> decorators.  Here&#8217;s a prototype feature that dumps information about a <a class="reference external" href="http://www.python.org/dev/peps/pep-0333/#environ-variables">WSGI environ</a>.:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">twiggy.logger</span> <span class="kn">import</span> <span class="n">emit</span>

<span class="nd">@emit.info</span>
<span class="k">def</span> <span class="nf">dump_wsgi</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">wsgi_environ</span><span class="p">):</span>
    <span class="n">keys</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;SERVER_PROTOCOL&#39;</span><span class="p">,</span> <span class="s">&#39;SERVER_PORT&#39;</span><span class="p">,</span> <span class="s">&#39;SERVER_NAME&#39;</span><span class="p">,</span> <span class="s">&#39;CONTENT_LENGTH&#39;</span><span class="p">,</span> <span class="s">&#39;CONTENT_TYPE&#39;</span><span class="p">,</span> <span class="s">&#39;QUERY_STRING&#39;</span><span class="p">,</span> <span class="s">&#39;PATH_INFO&#39;</span><span class="p">,</span> <span class="s">&#39;SCRIPT_NAME&#39;</span><span class="p">,</span> <span class="s">&#39;REQUEST_METHOD&#39;</span><span class="p">]</span>
    <span class="n">d</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">keys</span><span class="p">:</span>
        <span class="n">d</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">wsgi_environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="s">&#39;&#39;</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">wsgi_environ</span><span class="o">.</span><span class="n">iteritems</span><span class="p">():</span>
        <span class="k">if</span> <span class="n">k</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&#39;HTTP_&#39;</span><span class="p">):</span>
            <span class="n">k</span> <span class="o">=</span> <span class="n">k</span><span class="p">[</span><span class="mi">5</span><span class="p">:]</span><span class="o">.</span><span class="n">title</span><span class="p">()</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;_&#39;</span><span class="p">,</span> <span class="s">&#39;-&#39;</span><span class="p">)</span>
            <span class="n">d</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span>

    <span class="c"># if called on an unnamed logger, add a name</span>
    <span class="k">if</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_fields</span><span class="p">:</span>
        <span class="bp">self</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">(</span><span class="s">&#39;dumpwsgi&#39;</span><span class="p">)</span>

    <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">fieldsDict</span><span class="p">(</span><span class="n">d</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="writing-outputs-and-formats">
<h3>Writing Outputs and Formats<a class="headerlink" href="#writing-outputs-and-formats" title="Permalink to this headline">¶</a></h3>
<p>Outputs do the work of writing a message to an external resource (file, socket, etc.).  User-defined outputs should inherit from <a class="reference internal" href="api.html#twiggy.outputs.Output" title="twiggy.outputs.Output"><tt class="xref py py-class docutils literal"><span class="pre">Output</span></tt></a> or <a class="reference internal" href="api.html#twiggy.outputs.AsyncOutput" title="twiggy.outputs.AsyncOutput"><tt class="xref py py-class docutils literal"><span class="pre">AsyncOutput</span></tt></a> if they wish to support <a class="reference internal" href="glossary.html#term-asynchronous-logging"><em class="xref std std-term">asynchronous logging</em></a> (preferred).</p>
<p>An Output subclass&#8217;s <tt class="docutils literal"><span class="pre">__init__</span></tt> should take a <a class="reference internal" href="api.html#format-function"><em>format</em></a> and any parameters needed to acquire resources (filename, hostname, etc.), but <em>not the resources themselves</em>. These are created in <a class="reference internal" href="api.html#twiggy.outputs.Output._open" title="twiggy.outputs.Output._open"><tt class="xref py py-meth docutils literal"><span class="pre">_open()</span></tt></a>.  Implementations supporting asynchronous logging should also take a <a class="reference internal" href="api.html#twiggy.outputs.AsyncOutput" title="twiggy.outputs.AsyncOutput"><tt class="xref py py-class docutils literal"><span class="pre">msg_buffer</span></tt></a> argument.</p>
<p>Outputs should define the following:</p>
<dl class="method">
<dt>
<tt class="descclassname">Output.</tt><tt class="descname">_open</tt><big>(</big><big>)</big></dt>
<dd><p>Acquire any resources needed for writing (files, sockets, etc.)</p>
</dd></dl>

<dl class="method">
<dt>
<tt class="descclassname">Output.</tt><tt class="descname">_close</tt><big>(</big><big>)</big></dt>
<dd><p>Release any resources acquired in <a class="reference internal" href="api.html#twiggy.outputs.Output._open" title="twiggy.outputs.Output._open"><tt class="xref py py-obj docutils literal"><span class="pre">_open</span></tt></a></p>
</dd></dl>

<dl class="method">
<dt>
<tt class="descclassname">Output.</tt><tt class="descname">_write</tt><big>(</big><em>x</em><big>)</big></dt>
<dd><p>Do the work of writing</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">Parameters:</th><td class="field-body"><strong>x</strong> &#8211; an implementation-dependent object to be written.</td>
</tr>
</tbody>
</table>
</dd></dl>

<p>If the output requires locking to be thread-safe, set the class attribute <a class="reference internal" href="api.html#twiggy.outputs.Output.use_locks" title="twiggy.outputs.Output.use_locks"><tt class="xref py py-attr docutils literal"><span class="pre">use_locks</span></tt></a> to True (the default). Turning off may give slightly higher throughput.</p>
<p>The <a class="reference internal" href="api.html#twiggy.outputs.Output._format" title="twiggy.outputs.Output._format"><tt class="xref py py-attr docutils literal"><span class="pre">format</span></tt></a> callable is Output-specific; it should take a <a class="reference internal" href="api.html#twiggy.message.Message" title="twiggy.message.Message"><tt class="xref py py-class docutils literal"><span class="pre">Message</span></tt></a> and return an appropriate object (string, database row, etc.) to be written. <strong>Do not modify</strong> the received message - it is shared by all outputs.</p>
<p id="conversion-table-example"><a class="reference internal" href="api.html#twiggy.lib.converter.ConversionTable" title="twiggy.lib.converter.ConversionTable"><tt class="xref py py-class docutils literal"><span class="pre">ConversionTables</span></tt></a> are particulary useful for formatting fields. They are commonly used with <a class="reference internal" href="api.html#twiggy.formats.LineFormat" title="twiggy.formats.LineFormat"><tt class="xref py py-class docutils literal"><span class="pre">LineFormat</span></tt></a> to format messages for text-oriented output.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">twiggy.lib.converter</span> <span class="kn">import</span> <span class="n">ConversionTable</span>
<span class="n">conversion</span> <span class="o">=</span> <span class="n">ConversionTable</span><span class="p">()</span>

<span class="n">fields</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;shape&#39;</span><span class="p">:</span> <span class="s">&#39;square&#39;</span><span class="p">,</span>
          <span class="s">&#39;height&#39;</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span>
          <span class="s">&#39;width&#39;</span><span class="p">:</span> <span class="mi">5</span><span class="p">,</span>
          <span class="s">&#39;color&#39;</span><span class="p">:</span> <span class="s">&#39;blue&#39;</span><span class="p">}</span>

<span class="c"># hide shape field name</span>
<span class="c"># uppercase value</span>
<span class="c"># make mandatory</span>
<span class="n">conversion</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">key</span> <span class="o">=</span> <span class="s">&#39;shape&#39;</span><span class="p">,</span>
               <span class="n">convertValue</span> <span class="o">=</span> <span class="nb">str</span><span class="o">.</span><span class="n">upper</span><span class="p">,</span>
               <span class="n">convertItem</span> <span class="o">=</span> <span class="s">&#39;{1}&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">,</span> <span class="c"># stringify 2nd item (value)</span>
               <span class="n">required</span> <span class="o">=</span> <span class="bp">True</span><span class="p">)</span>

<span class="c"># format height value with two decimal places</span>
<span class="c"># show as &quot;&lt;key&gt; is &lt;value&gt;&quot;</span>
<span class="n">conversion</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s">&#39;height&#39;</span><span class="p">,</span> <span class="s">&#39;{0:.2f}&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">,</span> <span class="s">&quot;{0} is {1}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">)</span>

<span class="c"># separate fields in final output by colons</span>
<span class="n">conversion</span><span class="o">.</span><span class="n">aggregate</span> <span class="o">=</span> <span class="s">&#39;:&#39;</span><span class="o">.</span><span class="n">join</span>

<span class="c"># unknown items are sorted by key</span>

<span class="c"># unknown values are stringified</span>
<span class="n">conversion</span><span class="o">.</span><span class="n">genericValue</span> <span class="o">=</span> <span class="nb">str</span>

<span class="c"># show unknown items as &quot;&lt;key&gt;=&lt;value&gt;&quot;</span>
<span class="n">conversion</span><span class="o">.</span><span class="n">genericItem</span> <span class="o">=</span> <span class="s">&quot;{0}={1}&quot;</span><span class="o">.</span><span class="n">format</span>

<span class="c"># convert!</span>
<span class="k">print</span> <span class="n">conversion</span><span class="o">.</span><span class="n">convert</span><span class="p">(</span><span class="n">fields</span><span class="p">)</span>
</pre></div>
</div>
<div class="highlight-none"><div class="highlight"><pre>SQUARE:height is 10.00:color=blue:width=5
</pre></div>
</div>
</div>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="sphinxsidebar">
        <div class="sphinxsidebarwrapper">
            <p class="logo"><a href="index.html">
              <img class="logo" src="_static/twig_sidebar.jpg" alt="Logo"/>
            </a></p>
  <h3><a href="index.html">Table Of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">Reference Guide</a><ul>
<li><a class="reference internal" href="#dynamic-logging">Dynamic Logging</a></li>
<li><a class="reference internal" href="#features">Features!</a></li>
<li><a class="reference internal" href="#stays-out-of-your-way">Stays Out of Your Way</a></li>
<li><a class="reference internal" href="#concurrency">Concurrency</a></li>
<li><a class="reference internal" href="#use-by-libraries">Use by Libraries</a></li>
<li><a class="reference internal" href="#tips-and-tricks">Tips And Tricks</a><ul>
<li><a class="reference internal" href="#alternate-styles">Alternate Styles</a></li>
<li><a class="reference internal" href="#use-fields">Use Fields</a></li>
</ul>
</li>
<li><a class="reference internal" href="#technical-details">Technical Details</a><ul>
<li><a class="reference internal" href="#independence-of-logger-instances">Independence of logger instances</a></li>
<li><a class="reference internal" href="#optimizations">Optimizations</a></li>
</ul>
</li>
<li><a class="reference internal" href="#extending-twiggy">Extending Twiggy</a><ul>
<li><a class="reference internal" href="#writing-features">Writing Features</a></li>
<li><a class="reference internal" href="#writing-outputs-and-formats">Writing Outputs and Formats</a></li>
</ul>
</li>
</ul>
</li>
</ul>

  <h4>Previous topic</h4>
  <p class="topless"><a href="configuration.html"
                        title="previous chapter">Configuring Output</a></p>
  <h4>Next topic</h4>
  <p class="topless"><a href="api.html"
                        title="next chapter">API Reference</a></p>
  <h3>This Page</h3>
  <ul class="this-page-menu">
    <li><a href="_sources/reference_guide.txt"
           rel="nofollow">Show Source</a></li>
  </ul>
<div id="searchbox" style="display: none">
  <h3>Quick search</h3>
    <form class="search" action="search.html" method="get">
      <input type="text" name="q" size="18" />
      <input type="submit" value="Go" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    <p class="searchtip" style="font-size: 90%">
    Enter search terms or a module, class or function name.
    </p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="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="api.html" title="API Reference"
             >next</a> |</li>
        <li class="right" >
          <a href="configuration.html" title="Configuring Output"
             >previous</a> |</li>
        <li><a href="index.html">Twiggy v0.4.4 documentation</a> &raquo;</li> 
      </ul>
    </div>
    <div class="footer">
        &copy; Copyright 2010, <a href="http://i.wearpants.org">Peter Fein</a>.
      Last updated on Jul 10, 2012.
      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.0.7.
    </div>
  </body>
</html>