diff --git a/lib/logflare/sources/source/webhook_notification_server/discord_client.ex b/lib/logflare/sources/source/webhook_notification_server/discord_client.ex index 5f17e009a0..8029e12c34 100644 --- a/lib/logflare/sources/source/webhook_notification_server/discord_client.ex +++ b/lib/logflare/sources/source/webhook_notification_server/discord_client.ex @@ -2,6 +2,8 @@ defmodule Logflare.Sources.Source.WebhookNotificationServer.DiscordClient do @moduledoc false require Logger + import Logflare.Utils.Guards + alias LogflareWeb.Router.Helpers, as: Routes alias LogflareWeb.Endpoint @@ -96,7 +98,14 @@ defmodule Logflare.Sources.Source.WebhookNotificationServer.DiscordClient do defp discord_event_message(x) do timestamp = DateTime.from_unix!(x.body["timestamp"], :microsecond) |> DateTime.to_string() - {message, _} = String.split_at(x.body["event_message"], 1018) + + event_message = + case x.body["event_message"] do + msg when is_non_empty_binary(msg) -> msg + _ -> Jason.encode!(x.body, pretty: true) + end + + {message, _} = String.split_at(event_message, 1018) %{name: timestamp, value: "```#{message}```"} end diff --git a/test/logflare/sources/source/webhook_notification_server/discord_client_test.exs b/test/logflare/sources/source/webhook_notification_server/discord_client_test.exs new file mode 100644 index 0000000000..b083d6c5e1 --- /dev/null +++ b/test/logflare/sources/source/webhook_notification_server/discord_client_test.exs @@ -0,0 +1,82 @@ +defmodule Logflare.Sources.Source.WebhookNotificationServer.DiscordClientTest do + use Logflare.DataCase, async: false + + import Mimic + + alias Logflare.Sources.Source.WebhookNotificationServer.DiscordClient + + setup :set_mimic_global + + setup do + insert(:plan) + user = insert(:user) + + source = + insert(:source, + user: user, + webhook_notification_url: "https://discord.com/api/webhooks/test" + ) + + [source: source] + end + + describe "post/4" do + test "json stringifies body when event_message is nil or absent", %{source: source} do + for body <- [ + %{"timestamp" => 1_000_000, "event_message" => nil, "foo" => "bar"}, + %{"timestamp" => 1_000_000, "count" => 42} + ] do + ref = make_ref() + + stub(Tesla, :post, fn _client, _url, payload -> + send(self(), {ref, payload}) + {:ok, %Tesla.Env{status: 200}} + end) + + event = %Logflare.LogEvent{body: body, source_id: source.id} + client = DiscordClient.new() + + assert {:ok, _} = DiscordClient.post(client, source, 1, [event]) + assert_receive {^ref, payload}, 1000 + + [field] = payload.embeds |> hd() |> Map.get(:fields) + assert field.value =~ ~s("timestamp") + end + end + + test "includes event_message when present", %{source: source} do + ref = make_ref() + + stub(Tesla, :post, fn _client, _url, payload -> + send(self(), {ref, payload}) + {:ok, %Tesla.Env{status: 200}} + end) + + event = build(:log_event, source: source, event_message: "hello world") + client = DiscordClient.new() + + assert {:ok, _} = DiscordClient.post(client, source, 1, [event]) + assert_receive {^ref, payload}, 1000 + + [field] = payload.embeds |> hd() |> Map.get(:fields) + assert field.value == "```hello world```" + end + + test "truncates long event_message to under 1030 chars", %{source: source} do + ref = make_ref() + + stub(Tesla, :post, fn _client, _url, payload -> + send(self(), {ref, payload}) + {:ok, %Tesla.Env{status: 200}} + end) + + event = build(:log_event, source: source, event_message: String.duplicate("x", 2000)) + client = DiscordClient.new() + + assert {:ok, _} = DiscordClient.post(client, source, 1, [event]) + assert_receive {^ref, %{embeds: [%{fields: fields} | _]}}, 1000 + + assert String.length(fields |> hd() |> Map.get(:value)) < 1030 + end + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs index 3f43edc962..7a2bbb2b9d 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -25,6 +25,7 @@ Mimic.copy(Stripe.Invoice) Mimic.copy(Stripe.PaymentMethod) Mimic.copy(Stripe.Subscription) Mimic.copy(Stripe.SubscriptionItem.Usage) +Mimic.copy(Tesla) Mimic.copy(Tesla.Adapter.Finch) Mimic.copy(Logflare.Admin)