**************************************************************************
** title:      Logging
** author:     Brian Frank
** created:    22 Dec 07
** copyright:  Copyright (c) 2007, Brian Frank and Andy Frank
** license:    Licensed under the Academic Free License version 3.0
**************************************************************************

Log Creation [#creation]
************************
The `sys::Log` class standardizes how to embed logging statements into
Fantom applications.  Every 'Log' instance in the VM has a unique name
which by convention always starts with the pod name and uses dot
separators.  Once a Log instance has been created for a specified
name, it remains bound to that name for the lifetime of the VM.  Logs
are const, immutable instances shared by all threads.

Most of the time, you should just use [Pod.log]`sys::Pod.log` to
get the standard log for your pod:

  Pod.of(this).log.err("...")

You can also use [Log.get]`sys::Log.get` which will create the Log
on the first call, and look it up on subsequent calls:

  // get or create a log named "acme"
  const static Log log = Log.get("acme")

  // find an existing log
  Log.find("acme")          // throw exception if not found
  Log.find("acme", false)   // return null if not found

  // list all the active logs
  Log.list


Log Statements [#statements]
****************************
The following methods are used to generate log records:

  - [Log.err]`sys::Log.err`: something bad happened
  - [Log.warn]`sys::Log.warn`: something happened which might be bad
  - [Log.info]`sys::Log.info`: something interesting happened
  - [Log.debug]`sys::Log.debug`: something happened which is
    interesting only if you happen to be debugging

All logging methods take a 'Str' message, and an optional 'Err'.
Some simple examples:

  log.err("The freaking file didn't load", err)
  log.info("CatchRoadRoader service started on port $port")

When writing debug log statements, we expect that they will be turned
off most of the time.  Therefore be aware of the hidden costs of
string concatenation.  You can use the [isDebug]`sys::Log.isDebug`
method to skip creating a log message:

  // this code performs string concatenation on every call
  log.debug("The values are x=$x, y=$y, and z=$z")

  // this code performs string concatenation only when needed
  if (log.isDebug)
    log.debug("The values are x=$x, y=$y, and z=$z")


Log Levels [#levels]
********************
Each Log is configured to log events at or above a given
[LogLevel]`sys::LogLevel`.  These levels from least to most
severe:

  - **debug**: log everything
  - **info**: log everything but debug
  - **warn**: log everything but debug, info
  - **err**: log only errors
  - **silent**: log nothing

All logs default to level 'info' (see [setup]`#setup` to change default levels).

You can get/set the current severity level of a Log via the
[level]`sys::Log.level` field.  Some code examples:

  log.level = LogLevel.warn
  log.level < LogLevel.err    // returns true
  log.level < LogLevel.info     // returns false

Log Handlers [#handlers]
************************
Log handlers are functions designed to process [LogRecs]`sys::LogRec`.
The following 'Log' methods are used to manage the handlers in a VM:

  - [Log.handlers]`sys::Log.handlers`: list the installed handler functions
  - [Log.addHandler]`sys::Log.addHandler`: install a handler function
  - [Log.removeHandler]`sys::Log.removeHandler`: uninstall a handler function

Handlers must be an instance of an [immutable Func]`Functions#immutable` (they
are shared by all threads).  On startup there is always one handler installed
which will print each record to the console via the [LogRec.print]`sys::LogRec.print`
method.

Here is a simple example of an installing a handler:

  Log.addHandler |rec| { echo("My Handler: $rec") }

Log Setup [#setup]
******************
By default all log levels will default to 'info'.  You can programatically
change the level via [Log.level]`sys::Log.level`.   You can also use
the "etc/sys/log.props" file to setup the default level for any log.  The
"log.props" file is a standard props file where the log name is the key
and the value is a String 'LogLevel':

  web=debug
  acmeWombat.requests=silent
  acmeWombat.responses=warn

