Skip to content
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

Use custom replacements for filtered patterns #9

Merged
merged 2 commits into from
Jun 3, 2021
Merged
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Custom replacements for filter patterns.


## [1.3.0] - 2021-06-02
### Added
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ defmodule ClientFormatterImpl do
@derive {
MetaLogger.Formatter,
formatter_fn: &__MODULE__.format/1,
filter_patterns: [~s("email":".*")]
filter_patterns: [
{~s/"name":".*"/, ~s/"name":"[FILTERED]"/},
"very_secret_word"
]
}

def build(payload) do
Expand All @@ -115,7 +118,7 @@ http_request
### Options

* `:formatter_fn` (required) - The function which is used to format a given payload. The function must return a string or a list of strings.
* `:filter_patterns` (optional) - Regex patterns which will be used to replace sensitive information in a payload.
* `:filter_patterns` (optional) - Regex patterns which will be used to replace sensitive information in a payload. It is a list of strings or tuples (can be mixed). If tuples are given, the first element is used as a regex pattern to match, and the second is as a replacement which will be used to replace it, e.g. `{~s/"name": ".+"/, ~s/"name": "[FILTERED]"/}`.

## Release

Expand Down
10 changes: 7 additions & 3 deletions lib/meta_logger/formatter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ defimpl MetaLogger.Formatter, for: Any do

quote do
defimpl MetaLogger.Formatter, for: unquote(module) do
@replacement "[FILTERED]"
@default_replacement "[FILTERED]"

def format(struct) do
formatter_fn = Keyword.fetch!(unquote(options), :formatter_fn)
Expand All @@ -48,8 +48,12 @@ defimpl MetaLogger.Formatter, for: Any do
end

defp filter(patterns, payload) do
Enum.reduce(patterns, payload, fn pattern, payload ->
String.replace(payload, ~r/#{pattern}/, @replacement)
Enum.reduce(patterns, payload, fn
{pattern, replacement}, payload ->
String.replace(payload, ~r/#{pattern}/, replacement)

pattern, payload when is_bitstring(pattern) ->
String.replace(payload, ~r/#{pattern}/, @default_replacement)
end)
end

Expand Down
9 changes: 9 additions & 0 deletions test/meta_logger/formatter_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ defmodule MetaLogger.FormatterTest do
assert formatted_log == ["[FILTERED]", "the world"]
end

test "when filters given as tuples, uses given replacement instead a default one" do
formatted_log =
%{be: "good", to: ~s/{"name":"John"}/}
|> FormatterProtocolTest.build()
|> Subject.format()

assert formatted_log == ["good", ~s/{"name":"[FILTERED]"}/]
end

test "when there is wrong struct given, raises an error" do
defmodule WrongStruct do
defstruct [:a]
Expand Down
7 changes: 6 additions & 1 deletion test/support/formatter_protocol.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
defmodule FormatterProtocolTest do
@moduledoc false
@derive {MetaLogger.Formatter, formatter_fn: &__MODULE__.format/1, filter_patterns: ["bad"]}
@filter_patterns [
"bad",
{~s/"name":".*"/, ~s/"name":"[FILTERED]"/}
]
@derive {MetaLogger.Formatter,
formatter_fn: &__MODULE__.format/1, filter_patterns: @filter_patterns}
defstruct [:payload]

def build(my_data) do
Expand Down