28. Logging
Log Creation
The 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
to get the standard log for your pod:
Pod.of(this).log.err("...")
You can also use 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
The following methods are used to generate log records:
Log.err
: something bad happenedLog.warn
: something happened which might be badLog.info
: something interesting happenedLog.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
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
Each Log is configured to log events at or above a given 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 to change default levels).
You can get/set the current severity level of a Log via the level
field. Some code examples:
log.level = LogLevel.warn log.level < LogLevel.err // returns true log.level < LogLevel.info // returns false
Log Handlers
Log handlers are functions designed to process LogRecs
. The following Log
methods are used to manage the handlers in a VM:
Log.handlers
: list the installed handler functionsLog.addHandler
: install a handler functionLog.removeHandler
: uninstall a handler function
Handlers must be an instance of an immutable Func (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
method.
Here is a simple example of an installing a handler:
Log.addHandler |rec| { echo("My Handler: $rec") }
Log Setup
By default all log levels will default to info
. You can programatically change the level via 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