Skip to content

Commit

Permalink
feat: add datadog error tracking attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
btkostner committed Jul 31, 2023
2 parents 45c4a82 + e7a6efa commit 05c3bc3
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 4 deletions.
34 changes: 33 additions & 1 deletion lib/logger_json/formatters/datadog_logger.ex
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ defmodule LoggerJSON.Formatters.DatadogLogger do
LoggerJSON.take_metadata(md, md_keys, @processed_metadata_keys)
|> convert_tracing_keys(md)
|> JasonSafeFormatter.format()
|> FormatterUtils.maybe_put(:error, FormatterUtils.format_process_crash(md))
|> FormatterUtils.maybe_put(:error, format_process_crash(md))
end

# To connect logs and traces, span_id and trace_id keys are respectively dd.span_id and dd.trace_id
Expand Down Expand Up @@ -113,6 +113,38 @@ defmodule LoggerJSON.Formatters.DatadogLogger do
_ -> ""
end

# This follows the DataDog standard attributes for error tracking, allowing
# errors to automatically be aggregated by error tracking.
defp format_process_crash(metadata) do
case Keyword.get(metadata, :crash_reason) do
{reason, stacktrace} ->
initial_call = Keyword.get(metadata, :initial_call)

json_map(
initial_call: format_initial_call(initial_call),
stack: Exception.format_stacktrace(stacktrace),
message: format_exception_message(reason),
kind: format_exception_kind(reason)
)

nil ->
nil
end
end

defp format_initial_call(nil), do: nil

defp format_initial_call({module, function, arity}),
do: FormatterUtils.format_function(module, function, arity)

defp format_exception_message(%{message: message}), do: message
defp format_exception_message(other), do: JasonSafeFormatter.format(other)

defp format_exception_kind(:throw), do: "throw"
defp format_exception_kind(:exit), do: "exit"
defp format_exception_kind(%exception{}), do: inspect(exception)
defp format_exception_kind(other), do: inspect(other)

defp method_name(metadata) do
function = Keyword.get(metadata, :function)
module = Keyword.get(metadata, :module)
Expand Down
17 changes: 14 additions & 3 deletions test/unit/logger_json/formatters/datadog_logger_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -413,14 +413,25 @@ defmodule LoggerJSONDatadogTest do

test "logs crash reason when present" do
Logger.configure_backend(LoggerJSON, metadata: [:crash_reason])
Logger.metadata(crash_reason: {%RuntimeError{message: "oops"}, []})

Logger.metadata(
crash_reason:
{%RuntimeError{message: "oops"},
[
{Exception, :exception, [[message: "stacktrace test"]], []},
{LoggerJSONDatadogTest, :"test logs crash reason when present", 1,
[file: 'test/unit/logger_json/formatters/datadog_logger_test.exs', line: 414]}
]}
)

log =
capture_log(fn -> Logger.debug("hello") end)
|> Jason.decode!()

assert is_nil(log["error"]["initial_call"])
assert log["error"]["reason"] == "** (RuntimeError) oops"
assert log["error"]["kind"] == "RuntimeError"
assert log["error"]["message"] == "oops"
assert log["error"]["stack"] =~ "stacktrace test"
end

test "logs erlang style crash reasons" do
Expand All @@ -432,7 +443,7 @@ defmodule LoggerJSONDatadogTest do
|> Jason.decode!()

assert is_nil(log["error"]["initial_call"])
assert log["error"]["reason"] == "{:socket_closed_unexpectedly, []}"
assert log["error"]["message"] == "socket_closed_unexpectedly"
end

test "logs initial call when present" do
Expand Down

0 comments on commit 05c3bc3

Please sign in to comment.