Skip to content

Add support for "metadata_filter". #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ Configuration

This logger backend provides follow options:

| name | description |
| ------------- | ----------- |
| path | log file path. this option is "MUST" |
| level | minimum logging level. default is `:info` |
| metadata | included metadata keys list. detault is empty list |
| name | description |
| ----------------- | ----------- |
| path | log file path. this option is "MUST" |
| level | minimum logging level. default is `:info` |
| metadata | included metadata keys list. detault is empty list |
| metadata_filter | metadata terms which must be present in order to log, for example: [status: 404]. detault is empty list |
| metadata\_triming | if false, ignoring previous metadata options and all metadata are output. default is true. It is recommended true in production environment. |
| json\_encoder | using json encoder. default [jason](https://github.com/michalmuskala/jason) |
| uuid | If true, add uuid field to record. Default is false. |
| json\_encoder | using json encoder. default [jason](https://github.com/michalmuskala/jason) |
| uuid | If true, add uuid field to record. Default is false. |

You need to add logger backend setting

Expand All @@ -27,6 +28,7 @@ config :logger, :log_name,
path: "/var/log/my_app/app.log",
level: :info,
metadata: [:request_id, :user_id, :method, :path, :req_params],
metadata_filter: [status: 404],
json_encoder: Poison, # default is Jason
uuid: true
```
Expand All @@ -36,10 +38,23 @@ Use case

This module is assumed to be used with a custom plug logger.

Example 1:

```elixir
Logger.info("request", [
method: conn.method,
path: conn.request_path,
req_params: conn.params,
])
```

Example 2:

```elixir
Logger.error("not found", [
method: conn.method,
path: conn.request_path,
req_params: conn.params,
status: 404
])
```
33 changes: 23 additions & 10 deletions lib/logger_json_file_backend.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ defmodule LoggerJSONFileBackend do
end

@impl :gen_event
def handle_event({level, _gl, {Logger, msg, ts, md}}, %{level: min_level}=state) do
if is_nil(min_level) or Logger.compare_levels(level, min_level) != :lt do
def handle_event({level, _gl, {Logger, msg, ts, md}}, %{level: min_level, metadata_filter: metadata_filter}=state) do
if (is_nil(min_level) or Logger.compare_levels(level, min_level) != :lt) and metadata_matches?(md, metadata_filter) do
log_event(level, msg, ts, md, state)
else
{:ok, state}
Expand Down Expand Up @@ -116,8 +116,20 @@ defmodule LoggerJSONFileBackend do
end
end

@doc false
@spec metadata_matches?(Keyword.t, nil|Keyword.t) :: true|false
def metadata_matches?(_md, nil), do: true
def metadata_matches?(_md, []), do: true # all of the filter keys are present
def metadata_matches?(md, [{key, val}|rest]) do
case Keyword.fetch(md, key) do
{:ok, ^val} ->
metadata_matches?(md, rest)
_ -> false #fail on first mismatch
end
end

defp configure(name, opts) do
state = %{name: nil, path: nil, io_device: nil, inode: nil, level: nil, metadata: nil, json_encoder: nil, triming: false, uuid: false}
state = %{name: nil, path: nil, io_device: nil, inode: nil, level: nil, metadata: nil, metadata_filter: nil, json_encoder: nil, triming: false, uuid: false}
configure(name, opts, state)
end

Expand All @@ -126,13 +138,14 @@ defmodule LoggerJSONFileBackend do
opts = Keyword.merge(env, opts)
Application.put_env(:logger, name, opts)

level = Keyword.get(opts, :level, :info)
metadata = Keyword.get(opts, :metadata, [])
path = Keyword.get(opts, :path)
json_encoder = Keyword.get(opts, :json_encoder, Jason)
triming = Keyword.get(opts, :metadata_triming, true)
uuid = Keyword.get(opts, :uuid, false)
level = Keyword.get(opts, :level, :info)
metadata = Keyword.get(opts, :metadata, [])
metadata_filter = Keyword.get(opts, :metadata_filter)
path = Keyword.get(opts, :path)
json_encoder = Keyword.get(opts, :json_encoder, Jason)
triming = Keyword.get(opts, :metadata_triming, true)
uuid = Keyword.get(opts, :uuid, false)

%{state | name: name, path: path, level: level, metadata: metadata, json_encoder: json_encoder, triming: triming, uuid: uuid}
%{state | name: name, path: path, level: level, metadata: metadata, metadata_filter: metadata_filter, json_encoder: json_encoder, triming: triming, uuid: uuid}
end
end
10 changes: 5 additions & 5 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
%{
"earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], [], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.14.3", "e61cec6cf9731d7d23d254266ab06ac1decbb7651c3d1568402ec535d387b6f7", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"earmark": {:hex, :earmark, "1.0.3", "89bdbaf2aca8bbb5c97d8b3b55c5dd0cff517ecc78d417e87f1d0982e514557b", [:mix], [], "hexpm", "0fdcd651f9689e81cda24c8e5d06947c5aca69dbd8ce3d836b02bcd0c6004592"},
"ex_doc": {:hex, :ex_doc, "0.14.3", "e61cec6cf9731d7d23d254266ab06ac1decbb7651c3d1568402ec535d387b6f7", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm", "6bf36498c4c67fdbe6d4ad73a112098cbcc09b147b859219b023fc2636729bf6"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fdf843bca858203ae1de16da2ee206f53416bbda5dc8c9e78f43243de4bc3afe"},
"json": {:hex, :json, "0.3.3", "373eb4f7321f898ad6772999f30daf65f9f38e1d3dd4d798d7a82d3b123fe1d3", [:mix], [], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
"uuid": {:hex, :uuid, "1.1.7", "007afd58273bc0bc7f849c3bdc763e2f8124e83b957e515368c498b641f7ab69", [:mix], [], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"},
"uuid": {:hex, :uuid, "1.1.7", "007afd58273bc0bc7f849c3bdc763e2f8124e83b957e515368c498b641f7ab69", [:mix], [], "hexpm", "5c4eba9164d3567732280e6bc4edb115a82d5809c33f862098938b608a82caff"},
}
24 changes: 24 additions & 0 deletions test/logger_json_file_backend_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,30 @@ defmodule LoggerJSONFileBackendTest do
assert not Map.has_key?(json_log, "uuid")
end

test "test metadata_filter" do
refute File.exists?(path())
config [path: "test/logs/test.log", level: :info, metadata: [:foo, :pid], metadata_filter: [status: 404], metadata_triming: true, json_encoder: Jason, uuid: false]
#
Logger.error("Not found", [foo: "bar", status: 404])
assert File.exists?(path())
json_log = Jason.decode! log()
assert json_log["level"] == "error"
assert json_log["message"] == "Not found"
path() && File.rm_rf!(Path.dirname(path()))
#
Logger.info("OK")
refute File.exists?(path())
#
Logger.info("OK", [status: 200])
refute File.exists?(path())
#
Logger.error("Not found again", [status: 404])
assert File.exists?(path())
json_log = Jason.decode! log()
assert json_log["level"] == "error"
assert json_log["message"] == "Not found again"
end

test "can log structured object" do
Logger.info("msg body", [foo: %{bar: [:baz]}])
json_log = Jason.decode! log()
Expand Down