Log4jl - a versatile logging framework for Julia
Log4jl is a comprehensive and flexible logging framework for Julia programs.
To create logger call
@Log4jl.logger macro after importing
This macro call initializes and configures the logging framework. Also it creates logger object which cab be used by any of logging functions or macros to perform logging operations.
using Log4jl const logger = @Log4jl.logger error(logger, "Error in my code") # or @Log4jl logger = @Log4jl.logger @error "Error in my code"
See usage in example/simple.jl.
In order to create logger instance, call macro
@Log4jl.logger [<name>] [MSG=<message_type>] [URI=<config_location>] [begin <config_code_block> end]. It accepts following parameters:
name: a string which specifies a logger name from a configuration
MSG=<message_type>: a message type used for configuring a logger
URI=<config_location>: a configuration location
begin <configuration> end: a configuration program block (must return
If the root logger is required use macro
Log4jl.rootlogger with the same parameters as for
Log4jl.logger with one exception: root logger does not have a name.
# get the root logger const logger = @Log4jl.rootlogger # get the configured logger by name (uses FQMN by default) const logger = @Log4jl.logger # get the configured logger by name explicitly const logger = @Log4jl.logger "TestLogger" # get the configured logger by name that will use parameterized messages const logger = @Log4jl.logger "TestLogger" MSG=ParameterizedMessage # get the configured logger by from file specified in the parameter const logger = @Log4jl.logger URI="myconfig.xml" # get the configured logger from a programmatic configuration const logger = @Log4jl.logger begin Configuration("Custom", PROPERTIES(), APPENDERS(), LOGCONFIGS() ) end
The default configuration file is
log4jl.*. An extension of the configuration file determines format in which configuration is described.
Configuration file should be located in:
- For stand-alone module: a directory where a source code file of the module is located.
- For package: a package root directory.
Log4jl Internal Properties
Log4jl can be configured with properties which can be set through environmental variables.
|LOG4JL_LINE_SEPARATOR||Default new line separator sequence||[(0x0d - win) 0x0a]|
|LOG4JL_DEFAULT_STATUS_LEVEL||Default logger status level to use if not specified in configuration.||ERROR|
|LOG4JL_INTERNAL_STATUS_LEVEL||Default status level of internal
|LOG4JL_LOG_EVENT||Type of the default logger event generator which converts messages into logging events.||Log4jlEvent|
|LOG4JL_CONTEXT_SELECTOR||Type of the default logger context selector.||ModuleContextSelector|
There are many well known use cases where applications may share an environment with other applications and each has a need to have its own, separate logging environment.
There are a few ways to archive logging separation using different
SingleContextSelector: This selector creates a single
LoggerContextusing a single configuration that will be shared across all applications.
ModuleContextSelector: This selector creates a one
LoggerContextper module. This allows each module be configured to share the same configuration or can be individually configured. However, if configuration is not provided or has error then the parent module context is used for the current module. If there exist no parent module then new context is created with default configuration.
Context selection can be done by setting environment variable
LOG4JL_CONTEXT_SELECTOR with a name of context selector type.
Custom Log Levels
Log4jl supports custom log levels. Custom log levels can be defined in code or in configuration. To define a custom log level in code, use the
Level.add function. This function creates a new level for the specified name and generates appropriate convenience functions. After a log level is defined you can log messages at this level by calling corresponding log function:
# This creates the "VERBOSE" level if it does not exist yet. Log4jl.Level.add(:VERBOSE, 550) # Create a logger const logger = @logger # Use the custom VERBOSE level Log4jl.verbose(logger, "a verbose message")
When defining a custom log level, the intLevel parameter (550 in the example above) determines where the custom level exists in relation to the standard levels built-in to Log4jl. For reference, the table below shows the intLevel of the built-in log levels.
Standard log levels built-in to Log4jl
Defining Custom Log Levels in Configuration
Custom log levels can also be defined in configuration. This is convenient for using a custom level in a logger filter or an appender filter. Similar to defining log levels in code, a custom level must be defined first, before it can be used. If a logger or appender is configured with an undefined level, that logger or appender will be invalid and will not process any log events.
customlevels section of configuration element defines a custom levels. Internally it calls the same
Level.add function discussed above.
|name||string||The name of the custom level. The convention is to use all upper-case names.|
|intLevel||integer||Determines where the custom level exists in relation to the standard levels built-in to Log4jl (see the table above).|
The following example shows a configuration that defines some custom log levels and uses a custom log level to filter log events sent to the console.
configuration: status: trace name: YAMLTest customlevels: diag: 350 verbose: 150 appenders: ColorConsole: name: STDOUT loggers: logger: - name: X.Y level: diag appenderref: - ref: STDOUT
Filters allow logged
Events to be evaluated to determine if or how they should be published. A
Filter will be called on one of its
filter methods and will return a
FilterResult, which is an
Enum that has one of 3 values:
ACCEPT: no filters called, accept event
DENY: ignore event, return to caller
NEUTRAL: pass event to other filters
Filters may be configured in one of four locations:
- Context-wide Filters are configured directly in the configuration. Events that are rejected by these filters will not be passed to loggers for further processing. Once an event has been accepted by a context-wide filter it will not be evaluated by any other context-wide filters nor will the Logger's Level be used to filter the event. The event will be evaluated by logger and appender filters however.
- Logger Filters are configured on a specified
Logger. These are evaluated after the context-wide filters and the log
Logger. Events that are rejected by these filters will be discarded and the event will not be passed to a parent
Loggerregardless of the additivity setting.
- Appender Reference Filters are used to determine if a
Loggershould route the event to an appender.
- Appender Filters are used to determine if a specific
Appendershould handle the formatting and publication of the event.
- Loggers are wrappers around configuration
- Loggers would change behavior if configuration is changed
- Logger hierarchy based on hierarchy of configurations
- Global logger context keeps track of all loggers
- Root logger has no name and additivity, its default level is ERROR
- Logging functions support:
- plaint text
LOG4JL_CONFIG_DEFAULT_PREFIX: prefix of the configuration file. Default value is 'log4jl'.
LOG4JL_CONFIG_EXTS: Map of configuration file extensions.
LOG4JL_CONFIG_TYPES: Map of configuration types.
- 'isenabled' checks if logger allowed to process event at specified level
- On-fly reconfiguration
- Multi-threading/processing support
- Configuration formats: JSON, XML, TOML
- Handle configuration recursion
- For custom formated messages, create two functions with the same name and following signatures:
- <message_type_function>(msg::AbstractString, params...) => Message
- <message_type_function>(msg::Any) => Message
- A logger context selector is initialized as object and assigned to global constant
LOG4JL_CONTEXT_SELECTORfrom an environment variable with the same name. Default context selector type is
- Default status level is initialized as
LOG4JL_DEFAULT_STATUS_LEVELglobal constant from an environment variable with the same name. Default status level is
- A logger event type is is initialized as
LOG4JL_LOG_EVENTglobal constant from an environment variable with the same name. Default logger event type is
- A logger context selector is initialized as object and assigned to global constant
Log4jl.loggeris called with(out) parameters
- Parameters parsed
- Context selector is used to create a logging context
- Configuration is created a. Programmatic configuration is evaluated b. Configuration file is located, loaded and parsed
- Logging context is initialized with the created configuration
- Logging context is started
- Shutdown hook is created.
- Configuration is started
- Configuration is setup (properties and appenders are created)
- Configuration is configured (loggers are created and referenced to appenders)
- All appenders are started
- Logging context used to create a logger wrapper
- Logger object is returned
- Logger object is used in logging functions.
TODO: proper shutdown when
workspace is called.