Changes between Initial Version and Version 1 of LogService


Ignore:
Timestamp:
10/25/2012 05:37:17 PM (5 years ago)
Author:
apoirier
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • LogService

    v1 v1  
     1{{{ 
     2#!rst 
     3The log service 
     4=============== 
     5 
     6It's often useful to log some information during the execution of a Web 
     7application to trace the execution of the requests and to provide useful 
     8information for debugging when something goes wrong. The most common use-case is 
     9to log the exceptions tracebacks to a file on the server that provide the context 
     10where the error occurred so that we can fix the problem without disclosing 
     11sensitive information to the end-users. 
     12 
     13Python ships with a `logging`_ module that provides everything we need in a Web 
     14development context. However, it is relatively complex to configure and it's 
     15configuration is a singleton, which is problematic in a multi-applications setup 
     16(that is, when the same ``nagare-admin serve`` process serves more than one 
     17application). 
     18 
     19In order to solve these problems, Nagare provides its own ``log`` service 
     20(see :apidoc:`log`), which is built on top of the `logging`_ module but greatly 
     21simplifies its usage and configuration for common use-cases. 
     22 
     23 
     24Basic Usages 
     25------------ 
     26 
     27Using The default logger 
     28~~~~~~~~~~~~~~~~~~~~~~~~ 
     29 
     30By default, when you serve Web applications with the ``nagare-admin serve`` 
     31utility, Nagare creates a dedicated logger, handler and formatter for each 
     32application, and activates them: this is the purpose of the 
     33:apidoc:`log#log.configure` and :apidoc:`log#log.activate` functions. 
     34 
     35You can use the module level functions of the ``log`` module to write messages 
     36to the default logger of the *currently running* application, as shown in the 
     37example below: 
     38 
     39.. code-block:: python 
     40    :hl_lines: 8 
     41 
     42    from nagare import presentation, log 
     43 
     44    class Root(object): 
     45        pass 
     46 
     47    @presentation.render_for(Root) 
     48    def render(self, h, *args): 
     49        log.info('Rendering the Root component') 
     50        # some rendering code... 
     51        return h.root 
     52 
     53    app = Root 
     54 
     55 
     56Then, each time the default view of the ``Root`` component is rendered, this 
     57line should appear in the console shell (which is the output of the default 
     58logger): 
     59 
     60.. code-block:: text 
     61 
     62    2012-06-14 10:22:38,379 - nagare.application.myapp - INFO - Rendering the root component 
     63 
     64As you see, the messages are issued in the ``nagare.application.myapp`` 
     65namespace, which is the namespace of the messages coming from the Nagare 
     66application called ``myapp``. 
     67 
     68Here is the full listing of the module-level functions of the ``nagare.log`` 
     69module: 
     70 
     71====================================== ================================================================= 
     72              Function                                             Effect 
     73====================================== ================================================================= 
     74``log.debug(msg, *args, **kw)``        Logs a message with ``DEBUG`` level on the application logger 
     75``log.info(msg, *args, **kw)``         Logs a message with ``INFO`` level on the application logger 
     76``log.warning(msg, *args, **kw)``      Logs a message with ``WARNING`` level on the application logger 
     77``log.error(msg, *args, **kw)``        Logs a message with ``ERROR`` level on the application logger 
     78``log.critical(msg, *args, **kw)``     Logs a message with ``CRITICAL`` level on the application logger 
     79``log.exception(msg, *args, **kw)``    Logs a message with ``ERROR`` level on the application logger, 
     80                                       and also logs the current exception information 
     81``log.log(level, msg, *args, **kw)``   Logs a message with the specified level on the application 
     82                                       logger 
     83====================================== ================================================================= 
     84 
     85All these functions accept variable arguments and keyword arguments, which are 
     86documented in the ``logging`` module, `here <http://docs.python.org/library/logging.html#logging.Logger.debug>`_. 
     87 
     88Overriding the default configuration 
     89~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     90 
     91The ``[[logger]]``, ``[[hander]]`` and ``[[formatter]]`` sub-sections of the 
     92``[logging]`` section in the application configuration file are dedicated to 
     93configure the default application logger. 
     94 
     95The default logging setup is equivalent to the following ``[logging]`` section, 
     96where ``<name>`` is replaced by the name of the application (please 
     97refer to the ``logging``'s module `configuration file format`_ for a better 
     98understanding of the configuration of loggers, handlers and formatters): 
     99 
     100.. code-block:: ini 
     101 
     102    [logging] 
     103 
     104    [[logger]] 
     105    qualname=nagare.application.<name> 
     106    level=INFO 
     107    propagate=1 
     108 
     109    [[handler]] 
     110    class=StreamHandler 
     111    args=(sys.stderr,) 
     112 
     113    [[formatter]] 
     114    format=%(asctime)s - %(name)s - %(levelname)s - %(message)s 
     115 
     116As you can see, by default, the log messages with a level greater or equal to 
     117``INFO`` are printed to ``sys.stderr`` via a ``StreamHandler``. 
     118 
     119It's possible to override this default ``logging`` configuration by adding your 
     120own ``[logging]`` section to the application configuration file. Here, the 
     121logging level of the application is set to ``DEBUG``: 
     122 
     123.. code-block:: ini 
     124 
     125    [logging] 
     126    [[logger]] 
     127    level=DEBUG 
     128 
     129Here, a new handler is defined to log the messages to the file ``/tmp/myapp.log``. 
     130We use a ``RotatingFileHandler`` instead of the classical ``FileHandler`` since 
     131we want the file to be log-rotated in order to prevent it from becoming too large: 
     132 
     133.. code-block:: ini 
     134 
     135    [logging] 
     136    [[handler]] 
     137    class=handlers.RotatingFileHandler 
     138    args="('/tmp/myapp.log', 'a', 10485760, 10, 'UTF-8')" 
     139 
     140Using the Nagare IDE 
     141~~~~~~~~~~~~~~~~~~~~ 
     142 
     143When the Nagare IDE is launched at the same time than your application 
     144(i.e ``nagare-admin serve <name> ide``), a second handler is bound to the default 
     145logger so that all the messages are also sent to the 
     146`IDE log panel <http://www.nagare.org/trac/wiki/NagareIde#logger>`_. 
     147 
     148Advanced Usages 
     149--------------- 
     150 
     151Creating other application loggers 
     152~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     153 
     154As seen above, Nagare makes it easy to log messages in an application. However, 
     155as your application becomes more complex and is broken down in several modules 
     156and packages, it may become hard to track down where you sent a particular message 
     157or to analyze the log file which is now filled with numerous log messages. 
     158 
     159In this situation, it's generally useful to organize the log messages into 
     160namespaces, so that we can enable/disable the logging of messages in some 
     161namespaces or send messages with different namespaces to different handlers. 
     162 
     163For this purpose, Nagare offers a ``log.get_logger(namespace)`` function that 
     164creates a logger which puts the messages into the specified namespace. To create a 
     165new logger for your application, use a relative name starting with a dot. In this 
     166case, the new namespace is relative to the application namespace, e.g. 
     167``nagare.application.myapp``. 
     168 
     169The logger object offers the same functions as the ``log`` module for writing 
     170messages, that is ``logger.debug``, ``logger.info``, ``logger.warning``, 
     171``logger.error``, ``logger.critical``, ``logger.exception`` and ``logger.log``, 
     172with the same parameters. 
     173 
     174In this example, we will log all the messages generated in the views to a 
     175specific ``nagare.application.myapp.ui`` namespace: 
     176 
     177.. code-block:: python 
     178 
     179    from nagare import log 
     180 
     181    @presentation.render_for(Root) 
     182    def render(self, h, *args): 
     183        log.get_logger('.ui').debug('Rendering the Root component') 
     184        # some rendering code... 
     185        return h.root 
     186 
     187and you can see, the message is now attached to the ``nagare.application.myapp.myapp.ui`` 
     188namespace: 
     189 
     190.. code-block:: text 
     191 
     192    2012-06-14 10:22:38,379 - nagare.application.myapp.ui - INFO - Rendering the root component 
     193 
     194Being under the ``nagare.application.myapp`` namespace, this logger propagates 
     195the messages to the default logger. Also this logger inherits the default logger 
     196configuration, which can be overridden: 
     197 
     198.. code-block:: ini 
     199 
     200    [[logging]] 
     201    [loggers] 
     202    keys=ui   # Declare the new logger 
     203 
     204    [[logger_ui]] 
     205    qualname=.ui    # Relative namespace 
     206    level=CRITICAL 
     207    # No specific handler: propagate the messages to the default application logger 
     208    handlers= 
     209 
     210Here the log level of the logger is set to ``CRITICAL``. 
     211 
     212Or a more complex configuration can be created, for example to log the messages 
     213to a specific log file: 
     214 
     215.. code-block:: ini 
     216 
     217    [logging] 
     218    [[loggers]] 
     219    keys=ui   # Declare the new logger 
     220 
     221    [[handlers]] 
     222    keys=logfile   # Declare the new handler 
     223 
     224    [[formatters]] 
     225    keys=simple   # Declare the new formatter 
     226 
     227    [[logger_ui]] 
     228    qualname=.ui    # Relative namespace 
     229    handlers=logfile 
     230    propagate=0   # Don't propagate the messages to the default application logger 
     231 
     232    [[handler_logfile]] 
     233    class=handlers.RotatingFileHandler 
     234    args="('/tmp/myapp_ui.log', 'a', 10485760, 10, 'UTF-8')"  # Specific log file 
     235    formatter=simple 
     236 
     237    [[formatter_simple]] 
     238    format=%(levelname)s: %(message)s 
     239 
     240Creating other loggers 
     241~~~~~~~~~~~~~~~~~~~~~~ 
     242 
     243Any other general loggers can be created the same way, by just giving a full 
     244absolute namespace. 
     245 
     246For example the `SQLAlchemy documentation <http://docs.sqlalchemy.org/en/rel_0_7/core/engines.html#configuring-logging>`_ 
     247states the name of the SQL query logger is ``sqlalchemy.engine``. So this 
     248logging configuration will display all the generated SQL queries: 
     249 
     250.. code-block:: ini 
     251 
     252    [logging] 
     253    [[loggers]] 
     254    keys=sa 
     255 
     256    [[handlers]] 
     257    keys=stderr 
     258 
     259    [[formatters]] 
     260    keys=multilines 
     261 
     262    [[logger_sa]] 
     263    qualname=sqlalchemy.engine   # The absolute SQLAlchemy logger namespace 
     264    level=INFO 
     265    handlers=stderr 
     266 
     267    [[handler_stderr]] 
     268    class=StreamHandler 
     269    args=(sys.stderr,) 
     270    formatter=multilines 
     271 
     272    [[formatter_multilines]] 
     273    format={ %(message)s } 
     274 
     275 
     276.. _`logging`: http://docs.python.org/library/logging.html 
     277.. _`Configuration file format`: http://docs.python.org/library/logging.config.html#configuration-file-format 
     278 
     279.. wikiname: NagareLogging 
     280}}}