From f7aba76f638a00b1a7c86448bf3f90b69b6eb56d Mon Sep 17 00:00:00 2001 From: Blake Kostner Date: Tue, 8 Aug 2023 13:47:24 -0600 Subject: [PATCH] fix: add additional protective wrapping to crash log handling (#5) --- lib/logger_json/formatters/datadog_logger.ex | 16 +++++++++++++- .../formatters/datadog_logger_test.exs | 21 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/lib/logger_json/formatters/datadog_logger.ex b/lib/logger_json/formatters/datadog_logger.ex index 0f84fce..435e773 100644 --- a/lib/logger_json/formatters/datadog_logger.ex +++ b/lib/logger_json/formatters/datadog_logger.ex @@ -120,7 +120,7 @@ defmodule LoggerJSON.Formatters.DatadogLogger do # errors to automatically be aggregated by error tracking. defp format_process_crash(metadata) do case Keyword.get(metadata, :crash_reason) do - {reason, stacktrace} -> + {reason, stacktrace} when is_list(stacktrace) -> initial_call = Keyword.get(metadata, :initial_call) json_map( @@ -130,6 +130,20 @@ defmodule LoggerJSON.Formatters.DatadogLogger do kind: format_exception_kind(reason) ) + # This should never happen unless you are manually faking + # a crash reason. Non the less, we've had errors appear + # in the past where `Exception.format_stacktrace/1` has + # not received a list of stacktrace entries. + {reason, not_a_stacktrace} -> + initial_call = Keyword.get(metadata, :initial_call) + + json_map( + initial_call: format_initial_call(initial_call), + stack: inspect(not_a_stacktrace), + message: format_exception_message(reason), + kind: format_exception_kind(reason) + ) + nil -> nil end diff --git a/test/unit/logger_json/formatters/datadog_logger_test.exs b/test/unit/logger_json/formatters/datadog_logger_test.exs index acc109b..877447d 100644 --- a/test/unit/logger_json/formatters/datadog_logger_test.exs +++ b/test/unit/logger_json/formatters/datadog_logger_test.exs @@ -435,6 +435,27 @@ defmodule LoggerJSONDatadogTest do assert log["error"]["stack"] =~ "stacktrace test" end + test "inspects any non stacktrace crash reason data" do + Logger.configure_backend(LoggerJSON, metadata: [:crash_reason]) + + Logger.metadata( + crash_reason: { + :exit, + {Task.Supervised, :stream, [5000]} + } + ) + + log = + fn -> Logger.debug("hello") end + |> capture_log() + |> Jason.decode!() + + assert is_nil(log["error"]["initial_call"]) + assert log["error"]["kind"] == "exit" + assert log["error"]["message"] == "exit" + assert log["error"]["stack"] =~ "{Task.Supervised, :stream, [5000]}" + end + test "logs erlang style crash reasons" do Logger.configure_backend(LoggerJSON, metadata: [:crash_reason]) Logger.metadata(crash_reason: {:socket_closed_unexpectedly, []})