A comprehensive JSON logger Plug.
- Plug
- Poison
The support policy is to support the last 2 major versions of Erlang and the three last minor versions of Elixir.
-
add plug_logger_json to your list of dependencies in
mix.exs
:def deps do [{:plug_logger_json, "~> 0.7.0"}] end
-
ensure plug_logger_json is started before your application (Skip if using Elixir 1.4 or greater):
def application do [applications: [:plug_logger_json]] end
-
Replace
Plug.Logger
with either:Plug.LoggerJSON, log: Logger.level
,Plug.LoggerJSON, log: Logger.level, extra_attributes_fn: &MyPlug.extra_attributes/1
in your plug pipeline (inendpoint.ex
for Phoenix apps),
Add to your config/config.exs
or config/env_name.exs
if you want to filter params or headers or suppress any logged keys:
config :plug_logger_json,
filtered_keys: ["password", "authorization"],
suppressed_keys: ["api_version", "log_type"]
In your config/config.exs
or config/env_name.exs
:
config :logger, :console,
format: "$message\n",
level: :info, # You may want to make this an env variable to change verbosity of the logs
metadata: [:request_id]
Do the following:
-
update deps in
mix.exs
with the following:def deps do [{:logger_file_backend, "~> 0.0.10"}] end
-
add to your
config/config.exs
orconfig/env_name.exs
:config :logger, format: "$message\n", backends: [{LoggerFileBackend, :log_file}, :console] config :logger, :log_file, format: "$message\n", level: :info, metadata: [:request_id], path: "log/my_pipeline.log"
-
ensure you are using
Plug.Parsers
(Phoenix adds this toendpoint.ex
by default) to parse params as well as request body:plug Plug.Parsers, parsers: [:urlencoded, :multipart, :json], pass: ["*/*"], json_decoder: Poison
In router.ex
of your Phoenix project or in your plug pipeline:
-
add
require Logger
, -
add
use Plug.ErrorHandler
, -
add the following two private functions:
defp handle_errors(%Plug.Conn{status: 500} = conn, %{kind: kind, reason: reason, stack: stacktrace}) do Plug.LoggerJSON.log_error(kind, reason, stacktrace) send_resp(conn, 500, Poison.encode!(%{errors: %{detail: "Internal server error"}})) end defp handle_errors(_, _), do: nil
Additional data can be logged alongside the request by specifying a function to call which returns a map:
def extra_attributes(conn) do
map = %{
"user_id" => get_in(conn.assigns, [:user, :user_id]),
"other_id" => get_in(conn.private, [:private_resource, :id]),
"should_not_appear" => conn.private[:does_not_exist]
}
map
|> Enum.filter(&(&1 !== nil))
|> Enum.into(%{})
end
plug Plug.LoggerJSON,
log: Logger.level(),
extra_attributes_fn: &MyPlug.extra_attributes/1
In this example, the :user_id
is retrieved from conn.assigns.user.user_id
and added to the log if it exists. In the example, any values that are nil
are filtered from the map. It is a requirement that the value is serialiazable as JSON by the Poison library, otherwise an error will be raised when attempting to encode the value.
LoggerJSON
plug supports two levels of logging:
-
info
/error
will log:- api_version,
- date_time,
- duration,
- log_type,
- method,
- path,
- request_id,
- status
-
warn
/debug
will log everything from info and:- client_ip,
- client_version,
- params / request_body.
The above are default. It is possible to override them by setting a include_debug_logging
option to:
false
– means the extra debug fields (client_ip, client_version, and params) WILL NOT get logged.true
– means the extra fields WILL get logged.- Not setting this option will keep the defaults above.
Example:
plug Plug.LoggerJSON,
log: Logger.level,
include_debug_logging: true
Before submitting your pull request, please run:
mix credo --strict
,mix coveralls
,mix dialyzer
,- update changelog.
Please squash your pull request's commits into a single commit with a message and detailed description explaining the commit.