Skip to content

Commit 5ad0dee

Browse files
bvobartBart van Oort
andauthored
Remap duration_us to spec-compliant fields for Elastic and DataDog formatters (#132)
* fix(elastic): encode LoggerJSON.Plug's duration_us field as event.duration (in nanoseconds) * fix(datadog): encode LoggerJSON.Plug's duration_us field as (in nanoseconds) --------- Co-authored-by: Bart van Oort <bart.van.oort@opinity.nl>
1 parent 4667ec4 commit 5ad0dee

File tree

4 files changed

+59
-4
lines changed

4 files changed

+59
-4
lines changed

lib/logger_json/formatters/datadog.ex

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ defmodule LoggerJSON.Formatters.Datadog do
197197
defp safe_chardata_to_string(other), do: other
198198

199199
if Code.ensure_loaded?(Plug.Conn) do
200-
defp format_http_request(%{conn: %Plug.Conn{} = conn} = meta) do
200+
defp format_http_request(%{conn: %Plug.Conn{} = conn, duration_us: duration_us} = meta) do
201201
request_url = Plug.Conn.request_url(conn)
202202
user_agent = LoggerJSON.Formatter.Plug.get_header(conn, "user-agent")
203203
remote_ip = LoggerJSON.Formatter.Plug.remote_ip(conn)
@@ -223,8 +223,14 @@ defmodule LoggerJSON.Formatters.Datadog do
223223
),
224224
network: Jason.Helpers.json_map(client: Jason.Helpers.json_map(ip: remote_ip))
225225
}
226+
|> maybe_put(:duration, to_nanosecs(duration_us))
226227
end
228+
229+
defp format_http_request(%{conn: %Plug.Conn{} = conn}), do: format_http_request(%{conn: conn, duration_us: nil})
227230
end
228231

229232
defp format_http_request(_meta), do: nil
233+
234+
defp to_nanosecs(duration_us) when is_number(duration_us), do: duration_us * 1000
235+
defp to_nanosecs(_), do: nil
230236
end

lib/logger_json/formatters/elastic.ex

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ defmodule LoggerJSON.Formatters.Elastic do
261261
# - http.*: https://www.elastic.co/guide/en/ecs/8.11/ecs-http.html
262262
# - url.path: https://www.elastic.co/guide/en/ecs/8.11/ecs-url.html
263263
# - user_agent.original: https://www.elastic.co/guide/en/ecs/8.11/ecs-user_agent.html
264-
defp format_http_request(%{conn: %Plug.Conn{} = conn}) do
264+
# - event.duration (note: ns, not μs): https://www.elastic.co/guide/en/ecs/current/ecs-event.html#field-event-duration
265+
defp format_http_request(%{conn: %Plug.Conn{} = conn, duration_us: duration_us}) do
265266
%{
266267
"client.ip": LoggerJSON.Formatter.Plug.remote_ip(conn),
267268
"http.version": Plug.Conn.get_http_protocol(conn),
@@ -271,7 +272,10 @@ defmodule LoggerJSON.Formatters.Elastic do
271272
"url.path": conn.request_path,
272273
"user_agent.original": LoggerJSON.Formatter.Plug.get_header(conn, "user-agent")
273274
}
275+
|> maybe_put(:"event.duration", to_nanosecs(duration_us))
274276
end
277+
278+
defp format_http_request(%{conn: %Plug.Conn{} = conn}), do: format_http_request(%{conn: conn, duration_us: nil})
275279
end
276280

277281
defp format_http_request(_meta), do: nil
@@ -289,4 +293,7 @@ defmodule LoggerJSON.Formatters.Elastic do
289293
end
290294

291295
defp safe_chardata_to_string(other), do: other
296+
297+
defp to_nanosecs(duration_us) when is_number(duration_us), do: duration_us * 1000
298+
defp to_nanosecs(_), do: nil
292299
end

test/logger_json/formatters/datadog_test.exs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ defmodule LoggerJSON.Formatters.DatadogTest do
307307
|> Plug.Conn.put_req_header("x-forwarded-for", "127.0.0.1")
308308
|> Plug.Conn.send_resp(200, "Hi!")
309309

310-
Logger.metadata(conn: conn)
310+
Logger.metadata(conn: conn, duration_us: 1337)
311311

312312
log =
313313
capture_log(fn ->
@@ -332,6 +332,47 @@ defmodule LoggerJSON.Formatters.DatadogTest do
332332
},
333333
"useragent" => "Mozilla/5.0"
334334
}
335+
336+
assert log["duration"] == 1_337_000
337+
end
338+
339+
test "logs exception http context" do
340+
conn =
341+
Plug.Test.conn("patch", "/", "")
342+
|> Plug.Conn.put_req_header("user-agent", "Mozilla/5.0")
343+
|> Plug.Conn.put_req_header("referer", "http://www.example.com/")
344+
|> Plug.Conn.put_req_header("x-forwarded-for", "127.0.0.1")
345+
|> Plug.Conn.send_resp(503, "oops")
346+
347+
Logger.metadata(crash_reason: {{:EXIT, self()}, :foo}, conn: conn)
348+
349+
log =
350+
capture_log(fn ->
351+
Logger.debug("Hello")
352+
end)
353+
|> decode_or_print_error()
354+
355+
assert log["error"] == %{"message" => "Hello"}
356+
357+
assert log["network"] == %{"client" => %{"ip" => "127.0.0.1"}}
358+
359+
assert log["http"] == %{
360+
"referer" => "http://www.example.com/",
361+
"method" => "PATCH",
362+
"request_id" => nil,
363+
"status_code" => 503,
364+
"url" => "http://www.example.com/",
365+
"url_details" => %{
366+
"host" => "www.example.com",
367+
"path" => "/",
368+
"port" => 80,
369+
"queryString" => "",
370+
"scheme" => "http"
371+
},
372+
"useragent" => "Mozilla/5.0"
373+
}
374+
375+
assert log["duration"] == nil
335376
end
336377

337378
test "logs throws" do

test/logger_json/formatters/elastic_test.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ defmodule LoggerJSON.Formatters.ElasticTest do
368368
|> Plug.Conn.put_req_header("x-forwarded-for", "")
369369
|> Plug.Conn.send_resp(200, "Hi!")
370370

371-
Logger.metadata(conn: conn)
371+
Logger.metadata(conn: conn, duration_us: 1337)
372372

373373
log_entry =
374374
capture_log(fn ->
@@ -378,6 +378,7 @@ defmodule LoggerJSON.Formatters.ElasticTest do
378378

379379
assert %{
380380
"client.ip" => "",
381+
"event.duration" => 1_337_000,
381382
"http.version" => "HTTP/1.1",
382383
"http.request.method" => "GET",
383384
"http.request.referrer" => "http://www.example2.com/",

0 commit comments

Comments
 (0)