Packages
file_only_logger
0.1.37
0.2.70
0.2.69
0.2.65
0.2.64
0.2.63
0.2.62
0.2.61
0.2.60
0.2.59
0.2.58
0.2.57
0.2.56
0.2.55
0.2.54
0.2.53
0.2.52
0.2.51
0.2.50
0.2.49
0.2.48
0.2.47
0.2.45
0.2.44
0.2.43
0.2.42
0.2.41
0.2.40
0.2.39
0.2.38
0.2.37
0.2.36
0.2.35
0.2.34
0.2.33
0.2.31
0.2.30
0.2.29
0.2.28
0.2.27
0.2.26
0.2.25
0.2.24
0.2.23
0.2.22
0.2.21
0.2.20
0.2.19
0.2.18
0.2.17
0.2.16
0.2.15
0.2.14
0.2.13
0.2.12
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.1.58
0.1.57
0.1.55
0.1.54
0.1.53
0.1.52
0.1.51
0.1.50
0.1.49
0.1.47
0.1.46
0.1.45
0.1.44
0.1.43
0.1.42
0.1.41
0.1.40
0.1.39
0.1.38
0.1.37
0.1.36
0.1.35
0.1.34
0.1.33
0.1.32
0.1.31
0.1.30
0.1.28
0.1.27
0.1.26
0.1.25
0.1.24
0.1.23
0.1.22
0.1.21
0.1.20
0.1.19
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.0
A simple logger that writes messages to log files only (not to the console).
Current section
Files
Jump to
Current section
Files
lib/file/only/logger/proxy.ex
defmodule File.Only.Logger.Proxy do
@moduledoc """
Implements logging messages to files only (not to the console).
"""
use PersistConfig
require Logger
alias __MODULE__.Try
@after_compile get_env(:after_compile)
@levels get_env(:levels)
@lib Mix.Project.config()[:app]
@limit get_env(:limit)
@doc """
Returns `true` if `value` is a positive integer, otherwise `false`.
"""
defguard is_pos_int(value) when is_integer(value) and value > 0
@doc """
Writes `message` to the configured log file of logging level `level`.
## Examples
iex> alias File.Only.Logger.Proxy
iex> Proxy.log(:info, "*** INFO message ***")
:ok
iex> alias File.Only.Logger.Proxy
iex> Proxy.log(:debug, fn -> "*** DEBUG message ***" end)
:ok
iex> alias File.Only.Logger.Proxy
iex> Proxy.log(:critical, %{critical: :message})
:ok
"""
@spec log(Logger.level(), String.t()) :: :ok
def log(level, message) when level in @levels,
do: log(level, message, Logger.compare_levels(level, level()))
@doc """
Returns string "<module>.<function>/<arity>" e.g. "My.Math.sqrt/1" from the
given `env` (`Macro.Env`).
## Examples
iex> defmodule My.Math do
...> alias File.Only.Logger.Proxy
...> def sqrt(_number) do
...> Proxy.fun(__ENV__)
...> end
...> end
iex> My.Math.sqrt(9)
"File.Only.Logger.ProxyTest.My.Math.sqrt/1"
"""
@spec fun(Macro.Env.t()) :: String.t()
def fun(%Macro.Env{function: {name, arity}, module: module} = _env) do
if to_string(name) |> String.contains?(" "),
do: "#{inspect(module)}.'#{name}'/#{arity}",
else: "#{inspect(module)}.#{name}/#{arity}"
end
def fun(%Macro.Env{function: nil}), do: "'not inside a function'"
@doc ~S'''
May prefix `string` with "\n\s\s" if longer than `limit` - `offset`.
## Examples
iex> alias File.Only.Logger.Proxy
iex> supercal = "supercalifragilisticexpialidocious"
iex> heredoc = """
...> Feeling: #{supercal}
...> """
iex> Proxy.maybe_break(heredoc, 9)
"Feeling: supercalifragilisticexpialidocious\n"
iex> alias File.Only.Logger.Proxy
iex> supercal = "supercalifragilisticexpialidocious"
iex> heredoc = """
...> Feeling: #{supercal}ly #{supercal}
...> """
iex> Proxy.maybe_break(heredoc, 9) |> String.starts_with?("\n\s\sFeeling")
true
'''
@spec maybe_break(String.t(), pos_integer, pos_integer) :: String.t()
def maybe_break(string, offset, limit \\ @limit)
when is_binary(string) and is_pos_int(offset) and is_pos_int(limit) do
if String.length(string) > limit - offset, do: "\n #{string}", else: string
end
@doc """
Returns the application for the current process or module.
Returns `:undefined` if the current process does not belong to any
application or the current module is not listed in any application spec.
## Examples
iex> alias File.Only.Logger.Proxy
iex> Proxy.app
:file_only_logger
"""
@spec app :: atom
def app do
case :application.get_application() do
{:ok, app} -> app
:undefined -> Application.get_application(__MODULE__) || :undefined
end
end
@doc """
Returns the current library name.
## Examples
iex> alias File.Only.Logger.Proxy
iex> Proxy.lib
:file_only_logger
"""
@spec lib :: atom
def lib, do: @lib
@doc """
Returns the given `module` as a string.
## Examples
iex> alias File.Only.Logger.Proxy
iex> Proxy.mod(__MODULE__)
"File.Only.Logger.ProxyTest"
iex> alias File.Only.Logger.Proxy
iex> Proxy.mod(Elixir.Date.Range)
"Date.Range"
"""
@spec mod(module) :: String.t()
def mod(module), do: inspect(module)
@doc ~S'''
Returns a formatted heredoc to trace a message given `env` (`Macro.Env`).
## Examples
iex> alias File.Only.Logger.Proxy
iex> heredoc = """
...> • App: file_only_logger
...> • Library: file_only_logger
...> • Function:\s
...> File.Only.Logger.ProxyTest.
...> """
...> |> String.trim_trailing()
iex> Proxy.from(__ENV__) =~ heredoc
true
'''
@spec from(Macro.Env.t()) :: String.t()
def from(env) do
"""
• App: #{app()}
• Library: #{lib()}
• Function: #{fun(env) |> maybe_break(12)}
"""
|> String.trim_trailing()
end
@doc ~S'''
Returns a formatted heredoc to trace a message given `env` (`Macro.Env`) and
`module`.
## Examples
iex> alias File.Only.Logger.Proxy
iex> heredoc = """
...> • App: file_only_logger
...> • Library: file_only_logger
...> • Module: File.Only.Logger.ProxyTest
...> • Function:\s
...> File.Only.Logger.ProxyTest.
...> """
...> |> String.trim_trailing()
iex> Proxy.from(__ENV__, __MODULE__) =~ heredoc
true
'''
@spec from(Macro.Env.t(), module) :: String.t()
def from(env, module) do
"""
• App: #{app()}
• Library: #{lib()}
• Module: #{mod(module)}
• Function: #{fun(env) |> maybe_break(12)}
"""
|> String.trim_trailing()
end
## Private functions
@spec level :: Logger.level() | :all | :none
defp level, do: get_env(:level, :all)
@spec log(Logger.level(), String.t(), :lt | :eq | :gt) :: :ok
defp log(level, message, compare) when compare in [:gt, :eq] do
removed = Try.remove_backend()
:ok = Logger.log(level, message)
if removed == :ok, do: Try.add_backend()
:ok
end
defp log(_level, _message, _compare), do: :ok
end