Skip to content

Commit dfad66d

Browse files
authored
Log HTTP method & request path (#53)
Add HTTP method and request path in ECS logs when JWT errors occur.
1 parent 7f43ab0 commit dfad66d

File tree

3 files changed

+77
-2
lines changed

3 files changed

+77
-2
lines changed

neurow/lib/neurow/ecs_log_formatter.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ defmodule Neurow.EcsLogFormatter do
3939
|> with_optional_attribute(metadata[:error_code], "error.code")
4040
|> with_optional_attribute(metadata[:client_ip], "client.ip")
4141
|> with_optional_attribute(metadata[:authorization_header], "http.request.authorization")
42+
|> with_optional_attribute(metadata[:http_method], "http.request.method")
43+
|> with_optional_attribute(metadata[:http_path], "http.request.path")
4244
|> with_optional_attribute(metadata[:user_agent_header], "user_agent.original")
4345
|> :jiffy.encode()
4446
|> newline()

neurow/lib/neurow/jwt_auth_plug.ex

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,13 @@ defmodule Neurow.JwtAuthPlug do
221221

222222
defp unauthorized(conn, error_code, error_message, options) do
223223
Logger.error(
224-
"JWT authentication error: #{error_code} - #{error_message}, path: '#{conn.request_path}'",
224+
"JWT authentication error: #{error_code} - #{error_message}, method: '#{conn.method}', path: '#{conn.request_path}'",
225225
category: "security",
226226
error_code: "jwt_authentication.#{error_code}",
227227
authorization_header: conn |> get_req_header("authorization") |> List.first(),
228228
user_agent_header: conn |> get_req_header("user-agent") |> List.first(),
229+
http_path: conn.request_path,
230+
http_method: conn.method,
229231
trace_id: conn |> get_req_header("x-request-id") |> List.first(),
230232
client_ip: conn |> get_req_header("x-forwarded-for") |> List.first()
231233
)
@@ -241,10 +243,13 @@ defmodule Neurow.JwtAuthPlug do
241243
end
242244

243245
Logger.error(
244-
"JWT authentication error: #{error_code} - #{error_message}, path: '#{conn.request_path}', audience: '#{options |> Options.audience()}', token: '#{jwt_token}'",
246+
"JWT authentication error: #{error_code} - #{error_message}, method: '#{conn.method}', path: '#{conn.request_path}', audience: '#{options |> Options.audience()}', token: '#{jwt_token}'",
245247
category: "security",
246248
error_code: "jwt_authentication.#{error_code}",
249+
authorization_header: conn |> get_req_header("authorization") |> List.first(),
247250
user_agent_header: conn |> get_req_header("user-agent") |> List.first(),
251+
http_method: conn.method,
252+
http_path: conn.request_path,
248253
trace_id: conn |> get_req_header("x-request-id") |> List.first(),
249254
client_ip: conn |> get_req_header("x-forwarded-for") |> List.first()
250255
)

neurow/test/neurow/ecs_log_formatter_test.exs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,74 @@ defmodule Neurow.EcsLogFormatterTest do
169169
}
170170
end
171171

172+
test "supports optional http_method metadata" do
173+
metadata = %{
174+
time: 1_728_556_213_722_376,
175+
mfa: {Neurow.EcsLogFormatterTest, :fake_function, 4},
176+
file: "test/neurow/ecs_log_formatter_test.exs",
177+
line: 10,
178+
http_method: "POST"
179+
}
180+
181+
json_log =
182+
Neurow.EcsLogFormatter.format(:info, "Hello, world!", nil, metadata)
183+
|> :jiffy.decode([:return_maps])
184+
185+
assert json_log == %{
186+
"@timestamp" => "2024-10-10T10:30:13.722376Z",
187+
"log.level" => "info",
188+
"log.name" => "Elixir.Neurow.EcsLogFormatterTest.fake_function/4",
189+
"log.source" => %{
190+
"file" => %{
191+
"name" => "test/neurow/ecs_log_formatter_test.exs",
192+
"line" => 10
193+
}
194+
},
195+
"ecs.version" => "8.11.0",
196+
"message" => "Hello, world!",
197+
"category" => "app",
198+
"service" => %{
199+
"name" => "neurow",
200+
"version" => "unknown"
201+
},
202+
"http.request.method" => "POST"
203+
}
204+
end
205+
206+
test "supports optional http_path metadata" do
207+
metadata = %{
208+
time: 1_728_556_213_722_376,
209+
mfa: {Neurow.EcsLogFormatterTest, :fake_function, 4},
210+
file: "test/neurow/ecs_log_formatter_test.exs",
211+
line: 10,
212+
http_path: "/foobar"
213+
}
214+
215+
json_log =
216+
Neurow.EcsLogFormatter.format(:info, "Hello, world!", nil, metadata)
217+
|> :jiffy.decode([:return_maps])
218+
219+
assert json_log == %{
220+
"@timestamp" => "2024-10-10T10:30:13.722376Z",
221+
"log.level" => "info",
222+
"log.name" => "Elixir.Neurow.EcsLogFormatterTest.fake_function/4",
223+
"log.source" => %{
224+
"file" => %{
225+
"name" => "test/neurow/ecs_log_formatter_test.exs",
226+
"line" => 10
227+
}
228+
},
229+
"ecs.version" => "8.11.0",
230+
"message" => "Hello, world!",
231+
"category" => "app",
232+
"service" => %{
233+
"name" => "neurow",
234+
"version" => "unknown"
235+
},
236+
"http.request.path" => "/foobar"
237+
}
238+
end
239+
172240
test "multiline messages are inlined" do
173241
metadata = %{
174242
time: 1_728_556_213_722_376,

0 commit comments

Comments
 (0)