Skip to content

Commit

Permalink
Handle Task/GenServer exits correctly in Google formatter
Browse files Browse the repository at this point in the history
We were running into a situation where errors caused by GenServers
terminating were not being formatted because they were a slightly
different shape to what was expected in the formatter. This updates the
formatter to handle them.
  • Loading branch information
BrentWheeldon committed Sep 3, 2024
1 parent 5ad0dee commit 25d719c
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 1 deletion.
6 changes: 5 additions & 1 deletion lib/logger_json/formatters/google_cloud.ex
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,15 @@ defmodule LoggerJSON.Formatters.GoogleCloud do
format_reported_error_event(message, ruby_stacktrace, service_context, meta)
end

def format_crash_reason(binary, {error, reason}, service_context, meta) do
def format_crash_reason(binary, {error, reason}, service_context, meta) when is_atom(error) or is_binary(error) do
stacktrace = "** (#{error}) #{inspect(reason)}"
format_reported_error_event(binary, stacktrace, service_context, meta)
end

def format_crash_reason(binary, {error, reason}, service_context, meta) do
format_crash_reason(binary, {inspect(error), reason}, service_context, meta)
end

defp format_reported_error_event(message, stacktrace, service_context, meta) do
%{
"@type": "type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent",
Expand Down
45 changes: 45 additions & 0 deletions test/logger_json/formatters/google_cloud_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,51 @@ defmodule LoggerJSON.Formatters.GoogleCloudTest do
} = log_entry
end

test "logs Task/GenServer termination" do
test_pid = self()

logs =
capture_log(fn ->
{:ok, _} = Supervisor.start_link([{CrashingGenServer, :ok}], strategy: :one_for_one)

{:ok, _} =
Task.start(fn ->
try do
GenServer.call(CrashingGenServer, :boom)
catch
_ -> nil
after
send(test_pid, :done)
end
end)

# Wait for task to finish
receive do
:done -> nil
end

# Let logs flush
Process.sleep(100)
end)

refute logs =~ "FORMATTER CRASH"

[_, log_entry] =
logs
|> String.trim()
|> String.split("\n")
|> Enum.map(&decode_or_print_error/1)

assert %{
"@type" => "type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent",
"message" => message,
"stack_trace" => "** ({{%RuntimeError{message: \"boom\"}" <> _,
"serviceContext" => %{"service" => "nonode@nohost"}
} = log_entry

assert message =~ ~r/Task #PID<\d+.\d+.\d+> started from #{inspect(test_pid)} terminating/
end

test "logs process exits" do
Logger.metadata(crash_reason: {{:EXIT, self()}, :sad_failure})

Expand Down
15 changes: 15 additions & 0 deletions test/support/crashing_gen_server.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule CrashingGenServer do
use GenServer

def start_link(_) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end

def init(state) do
{:ok, state}
end

def handle_call(:boom, _, _) do
raise "boom"
end
end

0 comments on commit 25d719c

Please sign in to comment.