Current section
Files
Jump to
Current section
Files
lib/kmsg.ex
defmodule Kmsg do
@moduledoc """
A logger backend for the printk buffer.
Documentation is available on [hex.pm](https://hexdocs.pm/kmsg)
## Usage
Add Kmsg to your application by adding `{:kmsg, "~> #{Mix.Project.config()[:version]}"}` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
# ...
{:kmsg, "~> #{Mix.Project.config()[:version]}"}
]
end
```
And adding it to your `:logger` configuration in `config.exs`:
```elixir
config :logger,
backends: [
:console,
Kmsg
]
```
## Nerves
Currently this is not compatible with nerves due to the `KmsgTailer` which creates a neverending circulation of Logentries.
I'm working on fixing this.
"""
# Copyright 2019 Hans Bernhard Goedeke
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
@behaviour :gen_event
@kmsg_device "/dev/kmsg"
# @kmsg_device "/dev/stdout"
defstruct [
:format,
:metadata,
:level
]
def init(__MODULE__) do
config = Application.get_env(:logger, __MODULE__, [])
if File.exists?(@kmsg_device) do
{:ok, init(config, %__MODULE__{})}
else
{:error, :ignore}
end
end
def init({__MODULE__, opts}) when is_list(opts) do
config = Keyword.merge(Application.get_env(:logger, __MODULE__, []), opts)
{:ok, init(config, %__MODULE__{})}
end
def handle_call({:configure, options}, state) do
{:ok, :ok, configure(options, state)}
end
def handle_event(
{level, group_leader, {Logger, message, timestamp, metadata}},
state
) do
alias Logger.Formatter
if meet_level?(level, state.level) and node(group_leader) == node() do
formatted = Formatter.format(state.format, level, message, timestamp, metadata)
File.write!(@kmsg_device, formatted)
end
{:ok, state}
end
def handle_event(_, state) do
{:ok, state}
end
def handle_info(_, state) do
{:ok, state}
end
def code_change(_old_vsn, state, _extra) do
{:ok, state}
end
def terminate(_reason, _state) do
:ok
end
## Helpers
defp meet_level?(_lvl, nil), do: true
defp meet_level?(lvl, min) do
Logger.compare_levels(lvl, min) != :lt
end
defp configure(options, state) do
config = Keyword.merge(Application.get_env(:logger, __MODULE__, []), options)
Application.put_env(:logger, __MODULE__, config)
init(config, state)
end
defp init(config, state) do
level = Keyword.get(config, :level)
format = Logger.Formatter.compile(Keyword.get(config, :format))
metadata = Keyword.get(config, :metadata, [])
# max_buffer = Keyword.get(config, :max_buffer, 32)
%__MODULE__{
state
| format: format,
metadata: metadata,
level: level
}
end
end