Current section
Files
Jump to
Current section
Files
lib/bunyan.ex
defmodule Bunyan do
@moduledoc """
A JSON logger.
This module wraps the standard Elixir `Logger` and enables log messages to be
generated in JSON format.
If used after `Plug.RequestId`, the output will contain the connection's
request_id.
"""
@type message :: IO.chardata | String.Chars.t
@levels [:error, :warn, :info, :debug]
require Logger
alias Bunyan.Timestamp
@doc """
Logs a debug message.
Returns the atom `:ok` or an `{:error, reason}` tuple.
## Examples
Bunyan.debug "--> Here! <--"
Bunyan.debug fn -> "expensive to calculate debug" end
"""
@spec debug(message | (() -> message), Keyword.t) :: :ok | {:error, :noproc} | {:error, term}
def debug(chardata_or_fn, metadata \\ []) when is_list(metadata) do
Logger.debug(json(:debug, chardata_or_fn, metadata), metadata)
end
@doc """
Logs info.
Returns the atom `:ok` or an `{:error, reason}` tuple.
## Examples
Bunyan.info "It's Friday"
Bunyan.info fn -> "expensive to calculate info" end
"""
@spec info(message | (() -> message), Keyword.t) :: :ok | {:error, :noproc} | {:error, term}
def info(chardata_or_fn, metadata \\ []) when is_list(metadata) do
Logger.info(json(:info, chardata_or_fn, metadata), metadata)
end
@doc """
Logs a warning message.
Returns the atom `:ok` or an `{:error, reason}` tuple.
## Examples
Bunyan.warn "Watch out!"
Bunyan.warn fn -> "expensive to calculate warning" end
"""
@spec warn(message | (() -> message), Keyword.t) :: :ok | {:error, :noproc} | {:error, term}
def warn(chardata_or_fn, metadata \\ []) when is_list(metadata) do
Logger.warn(json(:warn, chardata_or_fn, metadata), metadata)
end
@doc """
Logs an error message.
Returns the atom `:ok` or an `{:error, reason}` tuple.
## Examples
Bunyan.error "Oh no!!"
Bunyan.error fn -> "expensive to calculate error" end
"""
@spec error(message | (() -> message), Keyword.t) :: :ok | {:error, :noproc} | {:error, term}
def error(chardata_or_fn, metadata \\ []) when is_list(metadata) do
Logger.error(json(:error, chardata_or_fn, metadata), metadata)
end
defp json(level, chardata_or_fn, _metadata) when level in @levels do
%{
"level" => level,
"timestamp" => Timestamp.format_string(:os.timestamp),
"logger_name" => "Bunyan",
"message" => chardata_or_fn |> to_message
}
|> merge_request_id(Logger.metadata[:request_id])
|> Poison.encode!
end
defp to_message(data) when is_function(data), do: data.()
defp to_message(data) when is_list(data) or is_binary(data), do: to_string(data)
defp merge_request_id(log, nil), do: log
defp merge_request_id(log, request_id) do
Map.put(log, :request_id, request_id)
end
end