Skip to content

Commit 714ab4b

Browse files
committed
Code for step 3
1 parent 14b439b commit 714ab4b

File tree

5 files changed

+122
-4
lines changed

5 files changed

+122
-4
lines changed

Diff for: config/config.exs

+7-3
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ config :auto_finder, AutoFinderWeb.Endpoint,
1919
live_view: [signing_salt: "60QXfDxg"]
2020

2121
# Configures Elixir's Logger
22-
config :logger, :console,
23-
format: "$time $metadata[$level] $message\n",
24-
metadata: [:request_id]
22+
config :logger, backends: [LoggerJSON]
23+
config :auto_finder, AutoFinder.Repo, loggers: [{LoggerJSON.Ecto, :log, [:info]}]
24+
25+
config :logger_json, :backend,
26+
metadata: [:file, :line, :function, :module, :application, :httpRequest, :query],
27+
formatter: AutoFinder.LoggerFormatter
2528

2629
# Use Jason for JSON parsing in Phoenix
2730
config :phoenix, :json_library, Jason
31+
config :phoenix, :logger, false
2832

2933
# Import environment specific config. This must remain at the bottom
3034
# of this file so it overrides the configuration defined above.

Diff for: config/dev.exs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ config :auto_finder, AutoFinder.Repo,
55
username: "postgres",
66
password: "postgres",
77
database: "auto_finder_dev",
8-
hostname: "localhost",
8+
hostname: "postgres",
99
show_sensitive_data_on_connection_error: true,
1010
pool_size: 10
1111

Diff for: lib/auto_finder/application.ex

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ defmodule AutoFinder.Application do
1616
# {AutoFinder.Worker, arg},
1717
]
1818

19+
# Attach Telemetry handler for Ecto events
20+
:ok =
21+
:telemetry.attach(
22+
"logger-json-ecto",
23+
[:auto_finder, :repo, :query],
24+
&LoggerJSON.Ecto.telemetry_logging_handler/4,
25+
:info
26+
)
27+
1928
# See https://hexdocs.pm/elixir/Supervisor.html
2029
# for other strategies and supported options
2130
opts = [strategy: :one_for_one, name: AutoFinder.Supervisor]

Diff for: lib/auto_finder_web/endpoint.ex

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ defmodule AutoFinderWeb.Endpoint do
1414
websocket: true,
1515
longpoll: false
1616

17+
plug LoggerJSON.Plug
18+
1719
# Serve at "/" the static files from "priv/static" directory.
1820
#
1921
# You should set gzip to true if you are running phx.digest

Diff for: lib/log_formatter.ex

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
defmodule AutoFinder.LoggerFormatter do
2+
@moduledoc """
3+
Custom Formatter
4+
"""
5+
import Jason.Helpers, only: [json_map: 1]
6+
7+
@behaviour LoggerJSON.Formatter
8+
9+
@processed_metadata_keys ~w[pid file line function module application]a
10+
11+
@severity_levels [
12+
debug: "DEBUG",
13+
info: "INFO",
14+
warning: "WARNING",
15+
warn: "WARNING",
16+
error: "ERROR"
17+
]
18+
19+
for {level, gcp_level} <- @severity_levels do
20+
def format_event(unquote(level), msg, ts, md, md_keys) do
21+
Map.merge(
22+
%{
23+
time: format_timestamp(ts),
24+
severity: unquote(gcp_level),
25+
message: IO.iodata_to_binary(msg)
26+
},
27+
format_metadata(md, md_keys)
28+
)
29+
end
30+
end
31+
32+
def format_event(_level, msg, ts, md, md_keys) do
33+
Map.merge(
34+
%{
35+
time: format_timestamp(ts),
36+
severity: "DEFAULT",
37+
message: IO.iodata_to_binary(msg)
38+
},
39+
format_metadata(md, md_keys)
40+
)
41+
end
42+
43+
defp format_metadata(md, md_keys) do
44+
LoggerJSON.take_metadata(md, md_keys, @processed_metadata_keys)
45+
|> maybe_put(:error, format_process_crash(md))
46+
end
47+
48+
defp maybe_put(map, _key, nil), do: map
49+
defp maybe_put(map, key, value), do: Map.put(map, key, value)
50+
51+
defp format_process_crash(md) do
52+
if crash_reason = Keyword.get(md, :crash_reason) do
53+
initial_call = Keyword.get(md, :initial_call)
54+
55+
json_map(
56+
initial_call: format_initial_call(initial_call),
57+
reason: format_crash_reason(crash_reason)
58+
)
59+
end
60+
end
61+
62+
defp format_initial_call(nil), do: nil
63+
64+
defp format_initial_call({module, function, arity}),
65+
do: "#{module}.#{function}/#{arity}"
66+
67+
defp format_crash_reason({:throw, reason}) do
68+
Exception.format(:throw, reason)
69+
end
70+
71+
defp format_crash_reason({:exit, reason}) do
72+
Exception.format(:exit, reason)
73+
end
74+
75+
defp format_crash_reason({%{} = exception, stacktrace}) do
76+
Exception.format(:error, exception, stacktrace)
77+
end
78+
79+
defp format_crash_reason(other) do
80+
inspect(other)
81+
end
82+
83+
# RFC3339 UTC "Zulu" format
84+
defp format_timestamp({date, time}) do
85+
[format_date(date), ?T, format_time(time), ?Z]
86+
|> IO.iodata_to_binary()
87+
end
88+
89+
defp format_time({hh, mi, ss, ms}) do
90+
[pad2(hh), ?:, pad2(mi), ?:, pad2(ss), ?., pad3(ms)]
91+
end
92+
93+
defp format_date({yy, mm, dd}) do
94+
[Integer.to_string(yy), ?-, pad2(mm), ?-, pad2(dd)]
95+
end
96+
97+
defp pad3(int) when int < 10, do: [?0, ?0, Integer.to_string(int)]
98+
defp pad3(int) when int < 100, do: [?0, Integer.to_string(int)]
99+
defp pad3(int), do: Integer.to_string(int)
100+
101+
defp pad2(int) when int < 10, do: [?0, Integer.to_string(int)]
102+
defp pad2(int), do: Integer.to_string(int)
103+
end

0 commit comments

Comments
 (0)