Getting lager handler info

2014-11-28 11:08:49 +0000 erlang lager

We use lager for our logging at Electric Imp. This morning I had cause to tweak the configuration at runtime on one of our staging boxes, but first I needed to figure out which handlers were already installed.

The following was done on a dev box, for demonstration purposes. The configuration is slightly different in production.


Lager uses gen_event to distribute log events, so I started with:

    (imp_server@roger-pc) 1> gen_event:which_handlers(lager_event).

Here you can see that we have several different backends registered:

However, this doesn’t tell us anything about the handler configuration. For that, we have to dig a little deeper.

lager_event state

One option is to use sys:get_state(lager_event), which queries the state of the lager_event event manager. In our example, it looks something like the following:

(imp_server@roger-pc) 2> sys:get_state(lager_event).


This shows the state of the event handlers, which is not necessarily the same as the initial configuration parameters. It’s still useful, though.


More useful, however, is the realisation that lager event handlers are supervised. This means that the supervisor must have a copy of the original configuration parameters – otherwise it couldn’t restart them properly.

Unfortunately, we can’t get hold of that information directly. What we can do is recognise that lager_handler_watcher_sup supervises lager_handler_watcher processes, and those, too, must have the original configuration somewhere:

We can get hold of the watchers:

(imp_server@roger-pc) 3> Watchers = supervisor:which_children(lager_handler_watcher_sup).

And then we can inspect any one of those to get the original configuration:

(imp_server@roger-pc) 4> sys:get_state(pid(0,91,0)).

And there’s the backend and configuration: lager_folsom_backend,[imp_server,warning]. Note that this relies on the internal state of lager_handler_watcher, which might change.

We can make this prettier by use of the following:

    {state, Module, Config, Event} = sys:get_state(Pid),
    {Event, Module, Config}
 end || {_, Pid, _, _} <- supervisor:which_children(lager_handler_watcher_sup)].

This outputs something like the following (I’ve ellided some of the details):

[{lager_event,{lager_file_backend,"log/error.log"}, ...},
 {lager_event,{lager_file_backend,"log/console.log"}, ...},
 {lager_event,{lager_syslog_backend,{"imp_server",local7}}, ...},
 {lager_event,lager_rabbitmq_backend, ...},

Of interest here is that you can see all of our backends, with configuration, but also error_logger_lager_h, which is responsible for turning error_logger events into lager_event events; and also the configuration for lager_backend_throttle, which controls when it starts exerting back pressure.

Awesome. We’re done.