# cherrypy._cplogging module

## Simple config

Although CherryPy uses the `Python logging module`, it does so behind the scenes so that simple logging is simple, but complicated logging is still possible. “Simple” logging means that you can log to the screen (i.e. console/stdout) or to a file, and that you can easily have separate error and access log files.

Here are the simplified logging settings. You use these by adding lines to your config file or dict. You should set these at either the global level or per application (see next), but generally not both.

> - `log.screen`: Set this to True to have both “error” and “access” messages printed to stdout.

> - `log.access_file`: Set this to an absolute filename where you want “access” messages written.

> - `log.error_file`: Set this to an absolute filename where you want “error” messages written.

Many events are automatically logged; to log your own application events, call `cherrypy.log()`.

## Architecture

### Separate scopes

CherryPy provides log managers at both the global and application layers. This means you can have one set of logging rules for your entire site, and another set of rules specific to each application. The global log manager is found at `cherrypy.log()`, and the log manager for each application is found at `app.log`. If you’re inside a request, the latter is reachable from `cherrypy.request.app.log`; if you’re outside a request, you’ll have to obtain a reference to the `app`: either the return value of `tree.mount()` or, if you used `quickstart()` instead, via `cherrypy.tree.apps['/']`.

By default, the global logs are named “cherrypy.error” and “cherrypy.access”, and the application logs are named “cherrypy.error.2378745” and “cherrypy.access.2378745” (the number is the id of the Application object). This means that the application logs “bubble up” to the site logs, so if your application has no log handlers, the site-level handlers will still log the messages.

### Errors vs. Access

Each log manager handles both “access” messages (one per HTTP request) and “error” messages (everything else). Note that the “error” log is not just for errors! The format of access messages is highly formalized, but the error log isn’t–it receives messages from a variety of sources (including full error tracebacks, if enabled).

If you are logging the access log and error log to the same source, then there is a possibility that a specially crafted error message may replicate an access log message as described in CWE-117. In this case it is the application developer’s responsibility to manually escape data before using CherryPy’s log() functionality, or they may create an application that is vulnerable to CWE-117. This would be achieved by using a custom handler escape any special characters, and attached as described below.

## Custom Handlers

The simple settings above work by manipulating Python’s standard `logging` module. So when you need something more complex, the full power of the standard module is yours to exploit. You can borrow or create custom handlers, formats, filters, and much more. Here’s an example that skips the standard FileHandler and uses a RotatingFileHandler instead:

    #python
    log = app.log

    # Remove the default FileHandlers if present.
    log.error_file = ""
    log.access_file = ""

    maxBytes = getattr(log, "rot_maxBytes", 10000000)
    backupCount = getattr(log, "rot_backupCount", 1000)

    # Make a new RotatingFileHandler for the error log.
    fname = getattr(log, "rot_error_file", "error.log")
    h = handlers.RotatingFileHandler(fname, 'a', maxBytes, backupCount)
    h.setLevel(DEBUG)
    h.setFormatter(_cplogging.logfmt)
    log.error_log.addHandler(h)

    # Make a new RotatingFileHandler for the access log.
    fname = getattr(log, "rot_access_file", "access.log")
    h = handlers.RotatingFileHandler(fname, 'a', maxBytes, backupCount)
    h.setLevel(DEBUG)
    h.setFormatter(_cplogging.logfmt)
    log.access_log.addHandler(h)

The `rot_*` attributes are pulled straight from the application log object. Since “log.*” config entries simply set attributes on the log object, you can add custom attributes to your heart’s content. Note that these handlers are used ‘’instead’’ of the default, simple handlers outlined above (so don’t set the “log.error_file” config entry, for example).

class cherrypy._cplogging.LazyRfc3339UtcTime

  Bases: `object`

class cherrypy._cplogging.LogManager(appid=None, logger_root='cherrypy')

  Bases: `object`

  An object to assist both simple and advanced logging.

  `cherrypy.log` is an instance of this class.

  _add_builtin_file_handler(log, fname)
  _get_builtin_handler(log, key)
  _set_file_handler(log, filename)
  _set_screen_handler(log, enable, stream=None)
  _set_wsgi_handler(log, enable)
  access()

    Write to the access log (in Apache/NCSA Combined Log format).

    See the apache documentation for format details.

    CherryPy calls this automatically for you. Note there are no arguments; it collects the data itself from `cherrypy.request`.

    Like Apache started doing in 2.0.46, non-printable and other special characters in %r (and we expand that to all parts) are escaped using xhh sequences, where hh stands for the hexadecimal representation of the raw byte. Exceptions from this rule are “ and , which are escaped by prepending a backslash, and all whitespace characters, which are written in their C-style notation (n, t, etc).

  property access_file

    The filename for self.access_log.

    If you set this to a string, it’ll add the appropriate FileHandler for you. If you set it to `None` or `''`, it will remove the handler.

  access_log = None

    The actual `logging.Logger` instance for access messages.

  access_log_format = '{h} {l} {u} {t} "{r}" {s} {b} "{f}" "{a}"'
  appid = None

    The id() of the Application object which owns this log manager.

    If this is a global log manager, appid is None.

  error(msg='', context='', severity=20, traceback=False)

    Write the given `msg` to the error log.

    This is not just for errors! Applications may call this at any time to log application-specific information.

    If `traceback` is True, the traceback of the current exception (if any) will be appended to `msg`.

  property error_file

    The filename for self.error_log.

    If you set this to a string, it’ll add the appropriate FileHandler for you. If you set it to `None` or `''`, it will remove the handler.

  error_log = None

    The actual `logging.Logger` instance for error messages.

  logger_root = None

    The “top-level” logger name.

    This string will be used as the first segment in the Logger names. The default is “cherrypy”, for example, in which case the Logger names will be of the form:

        cherrypy.error.<appid>
        cherrypy.access.<appid>

  reopen_files()

    Close and reopen all file handlers.

  property screen

    Turn stderr/stdout logging on or off.

    If you set this to True, it’ll add the appropriate StreamHandler for you. If you set it to False, it will remove the handler.

  time()

    Return now() in Apache Common Log Format (no timezone).

  property wsgi

    Write errors to wsgi.errors.

    If you set this to True, it’ll add the appropriate `WSGIErrorHandler` for you (which writes errors to `wsgi.errors`). If you set it to False, it will remove the handler.

class cherrypy._cplogging.NullHandler(level=0)

  Bases: `Handler`

  A no-op logging handler to silence the logging.lastResort handler.

  createLock()

    Acquire a thread lock for serializing access to the underlying I/O.

  emit(record)

    Do whatever it takes to actually log the specified logging record.

    This version is intended to be implemented by subclasses and so raises a NotImplementedError.

  handle(record)

    Conditionally emit the specified logging record.

    Emission depends on filters which may have been added to the handler. Wrap the actual emission of the record with acquisition/release of the I/O thread lock.

    Returns an instance of the log record that was emitted if it passed all filters, otherwise a false value is returned.

class cherrypy._cplogging.WSGIErrorHandler(level=0)

  Bases: `Handler`

  A handler class which writes logging records to environ[‘wsgi.errors’].

  emit(record)

    Emit a record.

  flush()

    Flushes the stream.