Skip to content

Commit c0bcd29

Browse files
committed
Allow using old tuples in config.exs and promote using new/1 in runtime.exs
1 parent 59660c9 commit c0bcd29

File tree

13 files changed

+149
-30
lines changed

13 files changed

+149
-30
lines changed

README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,28 @@ end
3535

3636
and install it running `mix deps.get`.
3737

38-
Then, enable the formatter in your `config.exs`:
38+
Then, enable the formatter in your `runtime.exs`:
3939

4040
```elixir
4141
config :logger, :default_handler,
4242
formatter: LoggerJSON.Formatters.Basic.new(metadata: [:request_id])
4343
```
4444

45-
or during runtime (eg. in your `application.ex`):
45+
or inside your application code (eg. in your `application.ex`):
4646

4747
```elixir
4848
formatter = LoggerJSON.Formatters.Basic.new(metadata: :all)
4949
:logger.update_handler_config(:default, :formatter, formatter)
5050
```
5151

52+
or inside your `config.exs` (notice that `new/1` is not available here
53+
and tuple format must be used):
54+
55+
```elixir
56+
config :logger, :default_handler,
57+
formatter: {LoggerJSON.Formatters.Basic, metadata: [:request_id]}
58+
```
59+
5260
You might also want to format the log messages when migrations are running:
5361

5462
```elixir
@@ -57,6 +65,12 @@ config :domain, MyApp.Repo,
5765
start_apps_before_migration: [:logger_json]
5866
```
5967

68+
And you might want to make logging level configurable using an `LOG_LEVEL` environment variable (in `application.ex`):
69+
70+
```elixir
71+
LoggerJSON.configure_log_level_from_env!()
72+
```
73+
6074
Additionally, you may also be try [redirecting otp reports to Logger](https://hexdocs.pm/logger/Logger.html#module-configuration) (see "Configuration" section).
6175

6276
## Configuration

lib/logger_json.ex

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,22 @@ defmodule LoggerJSON do
3131
3232
and install it running `mix deps.get`.
3333
34-
Then, enable the formatter in your `config.exs`:
34+
Then, enable the formatter in your `runtime.exs`:
3535
3636
config :logger, :default_handler,
37-
formatter: LoggerJSON.Formatters.Basic.new(metadata: :all)
37+
formatter: LoggerJSON.Formatters.Basic.new(metadata: [:request_id])
3838
39-
or during runtime (eg. in your `application.ex`):
39+
or inside your application code (eg. in your `application.ex`):
4040
4141
formatter = LoggerJSON.Formatters.Basic.new(metadata: :all)
4242
:logger.update_handler_config(:default, :formatter, formatter)
4343
44+
or inside your `config.exs` (notice that `new/1` is not available here
45+
and tuple format must be used):
46+
47+
config :logger, :default_handler,
48+
formatter: {LoggerJSON.Formatters.Basic, metadata: [:request_id]}
49+
4450
## Configuration
4551
4652
Configuration can be set using `new/1` helper of the formatter module,

lib/logger_json/formatter.ex

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,35 @@ defmodule LoggerJSON.Formatter do
66
| {atom(), term()}
77
]
88

9+
@type config :: term()
10+
911
@type encoder_opts :: JSON.encoder() | [Jason.encode_opt()] | term()
1012

1113
@doc """
12-
Creates a new configuration for the formatter.
14+
Initializes a new formatter configuration.
15+
16+
## Compile‑time vs. Runtime Configuration
17+
18+
This function can’t be used in `config.exs` because that file is evaluated
19+
before your application modules are compiled and loaded, so `new/1` isn’t defined yet.
20+
You can only call it in `config/runtime.exs` or from your application code.
21+
22+
If you must set up the formatter in `config.exs`, use the tuple format:
23+
the first element is the module implementing `LoggerJSON.Formatter`,
24+
and the second is the options passed to `new/1`. For example:
25+
26+
config :logger, :default_handler,
27+
formatter: {LoggerJSON.Formatters.Basic, metadata: [:request_id]}
28+
29+
Note that tuple‑based configs are resolved for each log entry,
30+
which can increase logging overhead.
1331
"""
14-
@callback new(opts) :: {module, term()}
32+
@callback new(opts :: opts()) :: {module(), config()}
1533

1634
@doc """
1735
Formats a log event.
1836
"""
19-
@callback format(event :: :logger.log_event(), opts :: opts()) :: iodata()
37+
@callback format(event :: :logger.log_event(), config_or_opts :: opts() | config()) :: iodata()
2038

2139
@encoder Application.compile_env(:logger_json, :encoder, Jason)
2240
@encoder_protocol Application.compile_env(:logger_json, :encoder_protocol) || Module.concat(@encoder, "Encoder")

lib/logger_json/formatters/basic.ex

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,27 @@ defmodule LoggerJSON.Formatters.Basic do
2727

2828
@impl Formatter
2929
def new(opts \\ []) do
30+
{__MODULE__, config(opts)}
31+
end
32+
33+
defp config(%{} = map), do: map
34+
35+
defp config(opts) do
3036
opts = Keyword.new(opts)
3137
encoder_opts = Keyword.get_lazy(opts, :encoder_opts, &Formatter.default_encoder_opts/0)
3238
metadata_keys_or_selector = Keyword.get(opts, :metadata, [])
3339
metadata_selector = update_metadata_selector(metadata_keys_or_selector, @processed_metadata_keys)
3440
redactors = Keyword.get(opts, :redactors, [])
35-
{__MODULE__, %{encoder_opts: encoder_opts, metadata: metadata_selector, redactors: redactors}}
41+
%{encoder_opts: encoder_opts, metadata: metadata_selector, redactors: redactors}
3642
end
3743

3844
@impl Formatter
39-
def format(%{level: level, meta: meta, msg: msg}, config) do
45+
def format(%{level: level, meta: meta, msg: msg}, config_or_opts) do
4046
%{
4147
encoder_opts: encoder_opts,
4248
metadata: metadata_selector,
4349
redactors: redactors
44-
} = config
50+
} = config(config_or_opts)
4551

4652
message =
4753
format_message(msg, meta, %{

lib/logger_json/formatters/datadog.ex

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,29 @@ defmodule LoggerJSON.Formatters.Datadog do
5252

5353
@impl Formatter
5454
def new(opts \\ []) do
55+
{__MODULE__, config(opts)}
56+
end
57+
58+
defp config(%{} = map), do: map
59+
60+
defp config(opts) do
5561
opts = Keyword.new(opts)
5662
encoder_opts = Keyword.get_lazy(opts, :encoder_opts, &Formatter.default_encoder_opts/0)
5763
redactors = Keyword.get(opts, :redactors, [])
5864
hostname = Keyword.get(opts, :hostname, :system)
5965
metadata_keys_or_selector = Keyword.get(opts, :metadata, [])
6066
metadata_selector = update_metadata_selector(metadata_keys_or_selector, @processed_metadata_keys)
61-
{__MODULE__, %{encoder_opts: encoder_opts, metadata: metadata_selector, redactors: redactors, hostname: hostname}}
67+
%{encoder_opts: encoder_opts, metadata: metadata_selector, redactors: redactors, hostname: hostname}
6268
end
6369

6470
@impl Formatter
65-
def format(%{level: level, meta: meta, msg: msg}, config) do
71+
def format(%{level: level, meta: meta, msg: msg}, config_or_opts) do
6672
%{
6773
encoder_opts: encoder_opts,
6874
metadata: metadata_selector,
6975
redactors: redactors,
7076
hostname: hostname
71-
} = config
77+
} = config(config_or_opts)
7278

7379
message =
7480
format_message(msg, meta, %{

lib/logger_json/formatters/elastic.ex

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,21 +145,27 @@ defmodule LoggerJSON.Formatters.Elastic do
145145

146146
@impl Formatter
147147
def new(opts \\ []) do
148+
{__MODULE__, config(opts)}
149+
end
150+
151+
defp config(%{} = map), do: map
152+
153+
defp config(opts) do
148154
opts = Keyword.new(opts)
149155
encoder_opts = Keyword.get_lazy(opts, :encoder_opts, &Formatter.default_encoder_opts/0)
150156
metadata_keys_or_selector = Keyword.get(opts, :metadata, [])
151157
metadata_selector = update_metadata_selector(metadata_keys_or_selector, @processed_metadata_keys)
152158
redactors = Keyword.get(opts, :redactors, [])
153-
{__MODULE__, %{encoder_opts: encoder_opts, metadata: metadata_selector, redactors: redactors}}
159+
%{encoder_opts: encoder_opts, metadata: metadata_selector, redactors: redactors}
154160
end
155161

156162
@impl Formatter
157-
def format(%{level: level, meta: meta, msg: msg}, config) do
163+
def format(%{level: level, meta: meta, msg: msg}, config_or_opts) do
158164
%{
159165
encoder_opts: encoder_opts,
160166
metadata: metadata_selector,
161167
redactors: redactors
162-
} = config
168+
} = config(config_or_opts)
163169

164170
message =
165171
format_message(msg, meta, %{

lib/logger_json/formatters/google_cloud.ex

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,12 @@ defmodule LoggerJSON.Formatters.GoogleCloud do
110110

111111
@impl Formatter
112112
def new(opts \\ []) do
113+
{__MODULE__, config(opts)}
114+
end
115+
116+
defp config(%{} = map), do: map
117+
118+
defp config(opts) do
113119
opts = Keyword.new(opts)
114120
encoder_opts = Keyword.get_lazy(opts, :encoder_opts, &Formatter.default_encoder_opts/0)
115121
redactors = Keyword.get(opts, :redactors, [])
@@ -119,15 +125,14 @@ defmodule LoggerJSON.Formatters.GoogleCloud do
119125
metadata_selector = update_metadata_selector(metadata_keys_or_selector, @processed_metadata_keys)
120126
reported_levels = Keyword.get(opts, :reported_levels, @default_levels_reported_as_errors)
121127

122-
{__MODULE__,
123-
%{
124-
encoder_opts: encoder_opts,
125-
redactors: redactors,
126-
service_context: service_context,
127-
project_id: project_id,
128-
metadata: metadata_selector,
129-
reported_levels: reported_levels
130-
}}
128+
%{
129+
encoder_opts: encoder_opts,
130+
redactors: redactors,
131+
service_context: service_context,
132+
project_id: project_id,
133+
metadata: metadata_selector,
134+
reported_levels: reported_levels
135+
}
131136
end
132137

133138
defp get_default_project_id do
@@ -137,15 +142,15 @@ defmodule LoggerJSON.Formatters.GoogleCloud do
137142
end
138143

139144
@impl Formatter
140-
def format(%{level: level, meta: meta, msg: msg}, config) do
145+
def format(%{level: level, meta: meta, msg: msg}, config_or_opts) do
141146
%{
142147
encoder_opts: encoder_opts,
143148
redactors: redactors,
144149
service_context: service_context,
145150
project_id: project_id,
146151
metadata: metadata_selector,
147152
reported_levels: reported_levels
148-
} = config
153+
} = config(config_or_opts)
149154

150155
message =
151156
format_message(msg, meta, %{

lib/logger_json/redactor.ex

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,25 @@ defmodule LoggerJSON.Redactor do
77
"""
88

99
@doc """
10-
Creates a new redactor.
10+
Initializes a new redactor configuration.
11+
12+
## Compile‑time vs. Runtime Configuration
13+
14+
This function can’t be used in `config.exs` because that file is evaluated
15+
before your application modules are compiled and loaded, so `new/1` isn’t defined yet.
16+
You can only call it in `config/runtime.exs` or from your application code.
17+
18+
If you must set up the redactor in `config.exs`, use the tuple format:
19+
the first element is the module implementing `LoggerJSON.Redactor`,
20+
and the second is the options passed to `new/1`. For example:
21+
22+
config :logger, :default_handler,
23+
formatter: {LoggerJSON.Formatters.Basic, redactors: [
24+
{MyRedactor, [option1: :value1]}
25+
]}
26+
27+
Note that tuple‑based configs are resolved for each log entry,
28+
which can increase logging overhead.
1129
"""
1230
@callback new(opts :: term()) :: {module(), term()}
1331

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ defmodule LoggerJSON.Mixfile do
22
use Mix.Project
33

44
@source_url "https://github.com/Nebo15/logger_json"
5-
@version "7.0.0"
5+
@version "7.0.1"
66

77
def project do
88
[

test/logger_json/formatters/basic_test.exs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,16 @@ defmodule LoggerJSON.Formatters.BasicTest do
270270
end
271271
end
272272

273+
test "accepts opts as a tuple" do
274+
:logger.update_handler_config(:default, :formatter, {Basic, metadata: :all})
275+
276+
assert capture_log(fn ->
277+
Logger.debug("hello")
278+
end)
279+
|> decode_or_print_error()
280+
|> Map.has_key?("message")
281+
end
282+
273283
test "reads metadata from the given application env" do
274284
Application.put_env(:logger_json, :test_basic_metadata_key, [:foo])
275285
formatter = Basic.new(metadata: {:from_application_env, {:logger_json, :test_basic_metadata_key}})

0 commit comments

Comments
 (0)