Packages

Shared functionality of the Bunyan distributed and pluggable logging system

Current section

Files

Jump to
bunyan_shared lib shared readable.ex
Raw

lib/shared/readable.ex

defmodule Bunyan.Shared.Readable do
@moduledoc """
This module creates the basic environment for a Bunyan source plugin,
reasponsible for capturing loggable events and injecting them into the
collector.
To create new reader plugin:
1. `mix new bunyan_source_«name» --module Bunyan.Source.«Name»`
2. Decide what configuration options your plugin needs. Create
a module `Bunyan.Source.«Name».State` that defines a structure
to hold the options. That structure must also contain a field named
`collector`, which this module will populate with a reference to the
collector your code should send messages to.
Also in that module write a function
~~~ elixir
@spec from(keyword) :: %__MODULE__{}
~~~
This is responsible for taking a set of options from the runtime
configuration of the app that uses your plugin and using them to populate
the structure. You'll also do validation here, raising exceptions for bad
or missing options.
3. Delete `lib/bunyan_source_«name».ex`.
4. Create `lib/«name».ex`:
~~~ elixir
defmodule Bunyan.Source.«Name» do
use Bunyan.Shared.Readable
def start(config) do
# your code goes here
end
end
~~~
Your `start` function will be passed the structure you populated in step 2.
It can send messages to the `config.collector` to inject them into the main
logger.
"""
@type collector :: pid() | atom()
@doc """
If called in Bunyan.Source.Api, this generates
~~~ elixir
def child_spec({ collector, config }) do
Supervisor.child_spec({ Bunyan.Source.Api.Server, state }, [])
end
def state_from_config(collector, config) do
Readable.validate_collector(Bunyan.Source.Api, collector)
Bunyan.Source.Api.State.from(config) |> Map.put(:collector, collector)
end
~~~
"""
defmacro __using__(args \\ []) do
caller = __CALLER__.module
state_module = args[:state_module] || Module.concat(caller, State)
server_module = args[:server_module] || Module.concat(caller, Server)
quote do
def child_spec({ collector, config }) do
Supervisor.child_spec({
unquote(server_module),
state_from_config(collector, config)
}, [])
end
defoverridable child_spec: 1
def state_from_config(collector, config) do
unquote(__MODULE__).validate_collector(unquote(caller), collector)
unquote(state_module).from(config) |> Map.put(:collector, collector)
end
end
end
def validate_collector(module, nil) do
raise """
Missing or invalid `collector:` option in the
configuration for #{inspect module}.
"""
end
def validate_collector(module, collector) when is_atom(collector) do
case Process.whereis(collector) do
nil ->
raise """
#{inspect module} cannot find a collector
named #{inspect collector}. Please check the `collector:`
option in the appropriate section of your Bunyan config.
"""
pid ->
validate_collector(module, pid)
end
end
def validate_collector(module, pid) when is_pid(pid) do
cond do
Process.alive?(pid) ->
:ok
true ->
raise """
#{inspect module} cannot find a collector
at pid #{inspect pid}. Please check the `collector:`
option in the appropriate section of your Bunyan config.
"""
end
end
end