From 3517aacf1911bc93ec52044bbbb9b300eef4c5d6 Mon Sep 17 00:00:00 2001 From: Gonzalo <456459+grzuy@users.noreply.github.com> Date: Mon, 9 Sep 2024 12:56:57 -0300 Subject: [PATCH] feat: Tower.Event similarity_id --- lib/tower/event.ex | 8 ++++++++ test/tower_test.exs | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/lib/tower/event.ex b/lib/tower/event.ex index e73314c..671f8e6 100644 --- a/lib/tower/event.ex +++ b/lib/tower/event.ex @@ -8,6 +8,7 @@ defmodule Tower.Event do defstruct [ :id, + :similarity_id, :datetime, :level, :kind, @@ -31,6 +32,7 @@ defmodule Tower.Event do """ @type t :: %__MODULE__{ id: Uniq.UUID.t(), + similarity_id: non_neg_integer(), datetime: DateTime.t(), level: level(), kind: error_kind() | non_error_kind(), @@ -41,6 +43,7 @@ defmodule Tower.Event do metadata: map() } + @similarity_source_attributes [:level, :kind, :reason, :stacktrace, :metadata] @logger_time_unit :microsecond @doc false @@ -120,6 +123,7 @@ defmodule Tower.Event do |> Map.merge(map) |> Map.merge(attributes_from_options(options)) ) + |> put_similarity_id() end defp attributes_from_options(options) do @@ -150,4 +154,8 @@ defmodule Tower.Event do defp plug_conn(options) do Keyword.get(options, :plug_conn, Keyword.get(options, :log_event)[:meta][:conn]) end + + defp put_similarity_id(%__MODULE__{} = event) do + struct!(event, similarity_id: :erlang.phash2(Map.take(event, @similarity_source_attributes))) + end end diff --git a/test/tower_test.exs b/test/tower_test.exs index 2611c75..2b77feb 100644 --- a/test/tower_test.exs +++ b/test/tower_test.exs @@ -552,6 +552,45 @@ defmodule TowerTest do assert datetime1 > datetime2 end + test "protects reporters from repeated events" do + capture_log(fn -> + for _ <- 1..2 do + in_unlinked_process(fn -> + 1 / 0 + end) + end + + in_unlinked_process(fn -> + raise "something else" + end) + end) + + assert_eventually( + [ + %{ + similarity_id: other_similarity_id, + level: :error, + kind: :error, + reason: %RuntimeError{message: "something else"} + }, + %{ + similarity_id: similarity_id, + level: :error, + kind: :error, + reason: %ArithmeticError{message: "bad argument in arithmetic expression"} + }, + %{ + similarity_id: similarity_id, + level: :error, + kind: :error, + reason: %ArithmeticError{message: "bad argument in arithmetic expression"} + } + ] = reported_events() + ) + + assert similarity_id != other_similarity_id + end + defp in_unlinked_process(fun) when is_function(fun, 0) do {:ok, pid} = Task.Supervisor.start_link()