Skip to content

Configuring Fastlog

hyperthunk edited this page Jun 16, 2011 · 2 revisions

Fastlog is configured in the usual manner for OTP applications, using either the <appname>.app file for an individual application or overridden values for a release in an app.config file. Fastlog config can be included at the top level of a release, or nested for each component application.

%% app.config
[
    %% top level logger configuration
    {fastlog, [{level, warn}]},

    {webapp, [
        {webconfig, [
            {ip, "127.0.0.1"},
            {port, 8080}
        ]},
        {fastlog, [
            {'web.*',       [{level, warn}]},
            {'web.request.*', [{level, info}]}
        ]}
    ]},

    {backend, [
        {fastlog, [
            {'my.app.*', [
                {level, error},
                {handler, my_custom_logging_module},
                {pattern, "[%p on %n][%L] [%m] [%f/%a - line:%l] %s"}
            ]}
        ]}
    ]}
].

Configuring an application to use fastlog couldn't be easier. You can either call fastlog:configure/1 passing the application name, or pass the config (proplist) to fastlog:configure/1 yourself.

Configuration Elements

Fastlog supports the following configuration elements, as summarised in the following list.

  • level The logging level to use for this (named) level.
  • handler The logging implementation (module) to use.
  • pattern The pattern to use when logging.

Logging Levels

Logging levels are set on a per-logger basis. As you will see from the previous example configuration, a logger's name can include a wildcard, in the form of *. This will match any call to fastlog:log/3 where the logger name passed exactly matches all the values up to the wildcard, and will match on any that follow.

Handler Modules

The default handler simply calls the standard OTP error_logger module. A custom logging module must export log/3, which has the signature log/3 :: (Level::atom(), Format::string(), Args::list(term())) -> ok. You can do anything you like in a custom logging module (i.e., send emails, sms messages or whatever), but fastlog only provides error_logger support out of the box. Your logging handler will only be called when the framework has determined that the required level is turned on for the log request being made, so your implementation should only concern itself with outputting the data somewhere.

Patterns

Patterns are primarily intended for use with fastlog's parse-transform support, although you can take advantage of them manually if you wish. Patterns only come into play when you pass a #'fastlog.entry'{} record to one of the logging methods. When this happens (and your chosen log level is active), fastlog uses the pattern to format the data in the record in order to produce a format string that will be passed to the log handler (which by default delegates to error_logger's info, error and warn '_msg/2' functions).

Patterns are compiled into anonymous functions during the logger configuration stage (i.e., when you call fastlog:add_logger), which are compiled to beam code that uses direct record access to pull the data into the correct position in the Args list being passed to the logging handler. This makes for efficient logging, as the funs are compiled only once and do no computation whatsoever (apart from accessing record fields) when they are run.

Patterns accept the following pattern strings, which are preceded by the % character, and are swapped out during the compilation phase.

  • %L The (current, active) level of the logging handling the message
  • %N The name of the logger handling the message
  • %m The originating module (i.e., the original call-site)
  • %f The name of the function in which the original call-site resides
  • %a The arity of the function in which the original call-site resides
  • %l The line number, within the function in which the original call-site resides
  • %p The pid of the running process in which the original call-site resides
  • %n The node in which the running process for the original call-site resides
  • %s The (string) message passed to the logging function

When the %s placeholder is evaluated, the message format is passed verbatim, allowing you to add your own formatting based on any additional arguments you're passing to the logging function. For example, consider the following test-case:

multiple_indexes_in_pattern(_Config) ->
    Fun = fastlog_utils:compile_pattern("[%p on %n][%L] [%m] [%f/%a - line:%l] %s"),
    {F,I} = Fun(debug, #'fastlog.entry'{
	    message="Hello ~s World\n",
	    args=["cruel"],
	    dest=?MODULE,
	    site=#'fastlog.callsite'{
	    	node=node(),
			pid=self(),
			module=?MODULE,
			function=multiple_indexes_in_pattern,
			arity=1,
			line=53}
	}),
    ?assertThat(F, equal_to("[~p on ~p][~p] [~p] "
	    "[~p/~p - line:~p] Hello ~s World\n")),
    ?assertThat(I, equal_to([self(), node(), debug, ?MODULE, 
		multiple_indexes_in_pattern, 1, 53, "cruel"])).
Clone this wiki locally