Current section
Files
Jump to
Current section
Files
lib/toprox.ex
defmodule Toprox do
@moduledoc """
A simple proxy for different Logger backends which allows to filter messages based on metadata.
## Usage
In `config.exs`:
config :logger, backends: [
{Toprox, :graylog},
]
config :logger, :graylog,
level: :info,
backend: {
Logger.Backends.Gelf, [
host: "graylog.example.com",
port: 12201,
application: "MyApplication",
compression: :gzip,
metadata: [:request_id, :function, :module, :file, :line]
]
}
In code:
Logger.info "Info", topic: :graylog
"""
@behaviour :gen_event
@doc false
def init({__MODULE__, name}) do
{:ok, configure(name, [])}
end
@doc false
def handle_call({:configure, opts}, %{name: name} = state) do
{:ok, :ok, configure(name, opts, state)}
end
@doc false
def handle_event({level, _gl, {Logger, _msg, _ts, md}} = event, %{module: module} = state) do
if level?(level, state.level) and topic?(state.name, md[:topic]) do
{:ok, new_backend_state} = module.handle_event(event, state.backend_state)
{:ok, %{state | backend_state: new_backend_state}}
else
{:ok, state}
end
end
@doc false
def handle_event(:flush, %{module: module} = state) do
{:ok, new_backend_state} = module.handle_event(:flush, state.backend_state)
{:ok, %{state | backend_state: new_backend_state}}
end
@doc false
def handle_info(info, %{module: module} = state) do
{:ok, new_backend_state} = module.handle_info(info, state.backend_state)
{:ok, %{state | backend_state: new_backend_state}}
end
## Helpers
defp level?(_, nil), do: true
defp level?(level, min), do: Logger.compare_levels(level, min) != :lt
defp topic?(name, topic) when is_list(topic), do: name in topic
defp topic?(name, topic), do: name == topic
defp configure(name, opts) do
state = %{name: nil, level: nil, module: nil, backend_state: nil}
configure(name, opts, state)
end
defp configure(name, opts, state) do
env = Application.get_env(:logger, name, [])
opts = Keyword.merge(env, opts)
Application.put_env(:logger, name, opts)
level = Keyword.get(opts, :level, :debug)
{module, backend_opts} = Keyword.get(opts, :backend)
backend_opts = Keyword.put(backend_opts, :level, level)
Application.put_env(:logger, :"_proxy_#{name}", backend_opts)
{:ok, backend_state} = module.init({module, :"_proxy_#{name}"})
%{state | name: name, level: level, module: module, backend_state: backend_state}
end
end