Packages

A logger interface library

Current section

Files

Jump to
logi_ex lib logi channel.ex
Raw

lib/logi/channel.ex

defmodule Logi.Channel do
@moduledoc """
Log Message Channels.
A channel (logically) receives log messages from loggers and delivers the messages to installed sinks.
## Examples
```elixir
# CREATE CHANNEL
iex> :ok = Logi.Channel.create :sample_log
iex> Logi.Channel.which_channels
[:sample_log, :logi_default_log] # 'logi_default_log' is created automatically when 'logi' application was started
# INSTALL SINK
iex> write_fun = fn (_, format, data) -> :io.format("[my_sink] " <> format <> "\\n", data) end
iex> sink = Logi.BuiltIn.Sink.Fun.new :sample_sink, write_fun
iex> {:ok, _} = Logi.Channel.install_sink :sample_log, sink, :info # Installs `sink` with `:info` level
iex> Logi.Channel.which_sinks :sample_log
[:sample_sink]
# OUTPUT LOG MESSAGE
iex> require Logi
iex> Logi.debug "hello world", [], [logger: :sample_log]
# The message is not emitted (the severity is too low).
iex> Logi.info "hello world", [], [logger: :sample_log]
#OUTPUT# [my_sink] hello world
iex> Logi.alert "hello world", [], [logger: :sample_log]
#OUTPUT# [my_sink] hello world
iex> Logi.info "hello world" # If `logger` option is omitted, the default channel will be used
# The message is not emitted (no sinks are installed to the default channel).
```
"""
@typedoc "The identifier of a channel"
@type id :: atom
@typedoc """
Options for `install_sink_opt/3`.
## if_exists
- The confliction handling policy.
- If a sink with the same identifier already exists,
- `:error`: the function returns an error `{:error, {:already_installed, existing_sink}}`.
- `:ignore`: the new sink is ignored. Then the function returns `{:ok, existing_sink}`.
- `:supersede`: the new sink supersedes it. Then the function returns `{:ok, old_sink}`.
- Default: `:supersede`
"""
@type install_sink_options :: [
{:if_exists, :error | :ignore | :supersede}
]
@typedoc "The information of an installed sink."
@type installed_sink :: %{
:sink => Logi.Sink.sink,
:condition => Logi.Confliction.condition,
:sink_sup => Logi.SinkProc.sink_sup,
:writer => Logi.SinkWriter.writer | :undefined
}
@doc """
The default channel.
This channel is created automatically when `logi_ex` application was started.
NOTE: The default channel ID is the same as the default logger ID (`Logi.default_logger/0`).
"""
@spec default_channel :: id
def default_channel do
:logi_channel.default_channel
end
@doc """
Creates a new channel.
If the channel already exists, nothing happens.
If there exists a process or a ETS table with the same name as `channel`, the function crashes.
"""
@spec create(id) :: :ok
def create(channel) do
:logi_channel.create channel
end
@doc """
Deletes a channel.
If the channel does not exists, it is silently ignored.
"""
@spec delete(id) :: :ok
def delete(channel) do
:logi_channel.delete channel
end
@doc "Returns a list of all existing channels."
@spec which_channels :: [id]
def which_channels do
:logi_channel.which_channels
end
@doc "Equivalent to `Logi.Channel.install_sink Logi.Channel.default_channel, sink, condition`."
@spec install_sink(Logi.Sink.sink, Logi.Condition.condition) :: {:ok, old} | {:error, reason} when
old: :undefined | installed_sink,
reason: {:cannot_start, any}
def install_sink(sink, condition) do
:logi_channel.install_sink sink, condition
end
@doc "Equivalent to `Logi.Channel.install_sink_opt channel, sink, condition, []`."
@spec install_sink(id, Logi.Sink.sink, Logi.Condition.condition) :: {:ok, old} | {:error, reason} when
old: :undefined | installed_sink,
reason: {:cannot_start, any}
def install_sink(channel, sink, condition) do
:logi_channel.install_sink channel, sink, condition
end
@doc "Equivalent to `Logi.Channel.install_sink_opt Logi.Channel.default_channel, sink, condition, options`."
@spec install_sink_opt(Logi.Sink.sink, Logi.Condition.condition, install_sink_options) :: {:ok, old} | {:error, reason} when
old: :undefined | installed_sink,
reason: {:cannot_start, any} | {:already_installed, installed_sink}
def install_sink_opt(sink, condition, options) do
:logi_channel.install_sink_opt sink, condition, options
end
@doc """
Installs `sink`.
If failed to start a sink process specified by `logi_sink:get_spec(sink)`,
the function returns `{:cannot_start, failure_reason}`.
If there does not exist a sink which has the same identifier with a new one,
the function returns `{:ok, :undefined}`.
Otherwise the result value depends on the value of the `:if_exists` option
(see the description of `t:install_sink_options/0` for details).
"""
@spec install_sink_opt(id, Logi.Sink.sink, Logi.Condition.condition, install_sink_options) :: {:ok, old} | {:error, reason} when
old: :undefined | installed_sink,
reason: {:cannot_start, any} | {:already_installed, installed_sink}
def install_sink_opt(channel, sink, condition, options) do
:logi_channel.install_sink_opt channel, sink, condition, options
end
@doc "Equivalent to `Logi.Channel.uninstall_sink Logi.Channel.default_channel, sink_id`."
@spec uninstall_sink(Logi.Sink.id) :: {:ok, installed_sink} | :error
def uninstall_sink(sink_id) do
:logi_channel.uninstall_sink sink_id
end
@doc """
Uninstalls the sink which has the identifier `sink_id` from `channel`.
The function returns `{:ok, sink}` if the specified sink exists in the channel, `:error` otherwise.
"""
@spec uninstall_sink(id, Logi.Sink.id) :: {:ok, installed_sink} | :error
def uninstall_sink(channel, sink_id) do
:logi_channel.uninstall_sink channel, sink_id
end
@doc "Equivalent to `Logi.Channel.set_sink_condition Logi.Channel.default_channel, sink_id, condition`."
@spec set_sink_condition(Logi.Sink.id, Logi.Condition.condition) :: {:ok, old} | :error when
old: Logi.Condition.condition
def set_sink_condition(sink_id, condition) do
:logi_channel.set_sink_condition sink_id, condition
end
@doc """
Sets the applicable condition of the `sink_id`.
The function returns `{:ok, old}` if the specified sink exists in the channel, `:error` otherwise.
"""
@spec set_sink_condition(id, Logi.Sink.id, Logi.Condition.condition) :: {:ok, old} | :error when
old: Logi.Condition.condition
def set_sink_condition(channel, sink_id, condition) do
:logi_channel.set_sink_condition channel, sink_id, condition
end
@doc "Equivalent to `Logi.Channel.find_sink Logi.Channel.id, sink_id`."
@spec find_sink(Logi.Sink.id) :: {:ok, installed_sink} | :error
def find_sink(sink_id) do
:logi_channel.find_sink sink_id
end
@doc """
Searches for `sink_id` in `channel`.
The function returns `{:ok, sink}`, or `:error` if `sink_id` is not present.
"""
@spec find_sink(id, Logi.Sink.id) :: {:ok, installed_sink} | :error
def find_sink(channel_id, sink_id) do
:logi_channel.find_sink channel_id, sink_id
end
@doc "Returns a list of installed sinks."
@spec which_sinks(id) :: [Logi.Sink.id]
def which_sinks(channel \\ Logi.Channel.default_channel) do
:logi_channel.which_sinks channel
end
@doc "Equivalent to `Logi.Channel.whereis_sink_proc Logi.Channel.default_channel, path`."
@spec whereis_sink_proc([Logi.Sink.id]) :: pid | :undefined
def whereis_sink_proc(path) do
:logi_channel.whereis_sink_proc path
end
@doc "Returns the pid associated with `path`."
@spec whereis_sink_proc(id, [Logi.Sink.id]) :: pid | :undefined
def whereis_sink_proc(channel, path) do
:logi_channel.whereis_sink_proc channel, path
end
end