Packages

A simple library for logging over the network.

Current section

Files

Jump to
network_logger lib network_logger.ex
Raw

lib/network_logger.ex

defmodule Logger.Backends.Network do
alias Logger.Backends.Network.TCPClient
@default_format "$time $metadata[$level] $message\n"
def init(_) do
if user = Process.whereis(:user) do
Process.group_leader(self(), user)
{:ok, configure([])}
else
{:error, :ignore}
end
end
def handle_call({:configure, options}, state) do
{:ok, :ok, configure(options, state)}
end
def handle_event({_level, gl, _event}, state) when node(gl) != node() do
{:ok, state}
end
def handle_event({level, _gl, {Logger, msg, ts, md}}, %{level: min_level} = state) do
if is_nil(min_level) or Logger.compare_levels(level, min_level) != :lt do
log_event(level, msg, ts, md, state)
end
{:ok, state}
end
def terminate(_reason, %{output: {:udp, _host, _port, socket}}) do
:gen_udp.close(socket)
:ok
end
def terminate(_reason, %{output: {:tcp, client}}) do
TCPClient.stop client
:ok
end
## Helpers
defp configure(options, %{output: {:udp, _host, _port, socket}}) do
:gen_udp.close(socket)
configure(options)
end
defp configure(options, %{output: {:tcp, client}}) do
TCPClient.stop client
configure(options)
end
defp configure(options, _state) do
configure(options)
end
defp configure(options) do
network_logger = Keyword.merge(Application.get_env(:logger, :network_logger, []), options)
Application.put_env(:logger, :network_logger, network_logger)
level = Keyword.get(network_logger, :level)
metadata = Keyword.get(network_logger, :metadata, [])
output = Keyword.get(network_logger, :output, :console)
format = Keyword.get(network_logger, :format, @default_format)
|> Logger.Formatter.compile()
output = case output do
:console -> :console
{:udp, host, port} ->
{:ok, socket} = :gen_udp.open 0
host = host |> to_charlist
{:udp, host, port, socket}
{:tcp, host, port} ->
host = host |> to_charlist
{:ok, tcp_client} = TCPClient.start_link(host, port)
{:tcp, tcp_client}
end
%{metadata: metadata, level: level, output: output, format: format}
end
defp log_event(level, msg, ts, md, %{metadata: metadata, format: format, output: :console}) do
IO.puts format_event(level, msg, ts, md, metadata, format)
end
defp log_event(level, msg, ts, md, %{metadata: metadata, format: format, output: {:udp, host, port, socket}}) do
log_msg = format_event(level, msg, ts, md, metadata, format)
:gen_udp.send socket, host, port, [log_msg]
end
defp log_event(level, msg, ts, md, %{metadata: metadata, format: format, output: {:tcp, client}}) do
log_msg = format_event(level, msg, ts, md, metadata, format)
TCPClient.log_msg client, log_msg
end
# defp log_event(level, msg, ts, md, state) do
# # unkonwn opts
# IO.puts "unknown opts: #{inspect level}, #{inspect msg}, #{inspect ts}, #{inspect md}, #{inspect state}"
# end
defp format_event(level, msg, ts, metadata, keys, format) do
Logger.Formatter.format(format, level, msg, ts, take_metadata(metadata, keys))
end
defp take_metadata(metadata, keys) do
metadatas = Enum.reduce(keys, [], fn key, acc ->
case Keyword.fetch(metadata, key) do
{:ok, val} -> [{key, val} | acc]
:error -> acc
end
end)
Enum.reverse(metadatas)
end
end