diff --git a/config/test.exs b/config/test.exs
index 28daf46fb..e9a6560a6 100644
--- a/config/test.exs
+++ b/config/test.exs
@@ -49,3 +49,5 @@ config :logger,
],
level: :error
]
+
+config :tesla, Logflare.Backends.Adaptor.WebhookAdaptor.Client, adapter: Tesla.Mock
diff --git a/lib/logflare/backends.ex b/lib/logflare/backends.ex
index 12a6c8a14..b9ea40a51 100644
--- a/lib/logflare/backends.ex
+++ b/lib/logflare/backends.ex
@@ -5,6 +5,7 @@ defmodule Logflare.Backends do
alias Logflare.Backends.Adaptor.WebhookAdaptor
alias Logflare.Backends.Adaptor.PostgresAdaptor
alias Logflare.Backends.Adaptor.BigQueryAdaptor
+ alias Logflare.Backends.Adaptor.DatadogAdaptor
alias Logflare.Backends.Backend
alias Logflare.Backends.SourceDispatcher
alias Logflare.Backends.SourceRegistry
@@ -25,7 +26,8 @@ defmodule Logflare.Backends do
@adaptor_mapping %{
webhook: WebhookAdaptor,
postgres: PostgresAdaptor,
- bigquery: BigQueryAdaptor
+ bigquery: BigQueryAdaptor,
+ datadog: DatadogAdaptor
}
defdelegate child_spec(arg), to: __MODULE__.Supervisor
diff --git a/lib/logflare/backends/adaptor.ex b/lib/logflare/backends/adaptor.ex
index 36b9c01e0..7ab07f9ab 100644
--- a/lib/logflare/backends/adaptor.ex
+++ b/lib/logflare/backends/adaptor.ex
@@ -29,6 +29,7 @@ defmodule Logflare.Backends.Adaptor do
@spec get_adaptor(Backend.t()) :: module()
def get_adaptor(%Backend{type: type}) do
case type do
+ :datadog -> __MODULE__.DatadogAdaptor
:webhook -> __MODULE__.WebhookAdaptor
:postgres -> __MODULE__.PostgresAdaptor
:bigquery -> __MODULE__.BigQueryAdaptor
diff --git a/lib/logflare/backends/adaptor/datadog_adaptor.ex b/lib/logflare/backends/adaptor/datadog_adaptor.ex
new file mode 100644
index 000000000..1e3a30ace
--- /dev/null
+++ b/lib/logflare/backends/adaptor/datadog_adaptor.ex
@@ -0,0 +1,86 @@
+defmodule Logflare.Backends.Adaptor.DatadogAdaptor do
+ @moduledoc """
+ Wrapper module for `Logflare.Backends.Adaptor.WebhookAdaptor` to provide API
+ for DataDog logs ingestion endpoint.
+ """
+
+ use TypedStruct
+
+ alias Logflare.Backends.Adaptor.WebhookAdaptor
+
+ # https://docs.datadoghq.com/api/latest/logs/#send-logs
+ @api_url_mapping %{
+ "US1" => "https://http-intake.logs.datadoghq.com/api/v2/logs",
+ "US3" => "https://http-intake.logs.us3.datadoghq.com/api/v2/logs",
+ "US5" => "https://http-intake.logs.us5.datadoghq.com/api/v2/logs",
+ "EU" => "https://http-intake.logs.datadoghq.eu/api/v2/logs",
+ "AP1" => "https://http-intake.logs.ap1.datadoghq.com/api/v2/logs",
+ "US1-FED" => "https://http-intake.logs.ddog-gov.com/api/v2/logs"
+ }
+
+ def api_url_mapping, do: @api_url_mapping
+
+ typedstruct enforce: true do
+ field(:api_key, String.t())
+ end
+
+ @behaviour Logflare.Backends.Adaptor
+
+ def child_spec(arg) do
+ %{
+ id: __MODULE__,
+ start: {__MODULE__, :start_link, [arg]}
+ }
+ end
+
+ @impl Logflare.Backends.Adaptor
+ def start_link({source, backend}) do
+ backend = %{
+ backend
+ | config: %{
+ url: Map.get(@api_url_mapping, backend.config.region),
+ headers: %{"dd-api-key" => backend.config.api_key}
+ }
+ }
+
+ WebhookAdaptor.start_link({source, backend})
+ end
+
+ @impl Logflare.Backends.Adaptor
+ def ingest(pid, log_events, opts) do
+ new_events =
+ Enum.map(log_events, &translate_event/1)
+
+ WebhookAdaptor.ingest(pid, new_events, opts)
+ end
+
+ @impl Logflare.Backends.Adaptor
+ def execute_query(_ident, _query), do: {:error, :not_implemented}
+
+ @impl Logflare.Backends.Adaptor
+ def cast_config(params) do
+ {%{}, %{api_key: :string, region: :string}}
+ |> Ecto.Changeset.cast(params, [:api_key, :region])
+ end
+
+ @impl Logflare.Backends.Adaptor
+ def validate_config(changeset) do
+ changeset
+ |> Ecto.Changeset.validate_required([:api_key, :region])
+ |> Ecto.Changeset.validate_inclusion(:region, Map.keys(@api_url_mapping))
+ end
+
+ defp translate_event(%Logflare.LogEvent{} = le) do
+ formatted_ts =
+ DateTime.from_unix!(le.body["timestamp"], :microsecond) |> DateTime.to_iso8601()
+
+ %Logflare.LogEvent{
+ le
+ | body: %{
+ message: formatted_ts <> " " <> Jason.encode!(le.body),
+ ddsource: "Logflare by Supabase",
+ service: le.source.name
+ }
+ }
+ end
+end
diff --git a/lib/logflare/backends/backend.ex b/lib/logflare/backends/backend.ex
index 242d879ce..34b3c6269 100644
--- a/lib/logflare/backends/backend.ex
+++ b/lib/logflare/backends/backend.ex
@@ -10,7 +10,7 @@ defmodule Logflare.Backends.Backend do
alias Logflare.User
alias Logflare.Rule
- @adaptor_types [:bigquery, :webhook, :postgres]
+ @adaptor_types [:bigquery, :webhook, :postgres, :datadog, :elastic]
typed_schema "backends" do
field(:name, :string)
diff --git a/lib/logflare_web/live/backends/components/backend_form.heex b/lib/logflare_web/live/backends/components/backend_form.heex
index 475ca7422..00e4b461d 100644
--- a/lib/logflare_web/live/backends/components/backend_form.heex
+++ b/lib/logflare_web/live/backends/components/backend_form.heex
@@ -31,7 +31,7 @@
- <%= select(f, :type, ["Select a backend type...", Webhook: :webhook, Postgres: :postgres, BigQuery: :bigquery],
+ <%= select(f, :type, ["Select a backend type...", Webhook: :webhook, Postgres: :postgres, BigQuery: :bigquery, Datadog: :datadog],
phx_change: :change_form_type,
class: "form-control form-control-margin",
id: "type"
@@ -129,6 +129,26 @@
A BigQuery Dataset ID where data will be stored.
+ <% "datadog" -> %>
+
+ <%= label(f_config, :api_key, "API Key") %>
+ <%= text_input(f_config, :api_key, class: "form-control", type: "password") %>
+
+ The API Key obtained from the Datadog dashboard.
+ https://us1.datadoghq.com/organization-settings/api-keys
+
+
+
+
+ <%= label(f_config, :region, "Region") %>
+ <%= select(f_config, :region, ["Select a region..." | Map.keys(Logflare.Backends.Adaptor.DatadogAdaptor.api_url_mapping())],
+ class: "form-control form-control-margin",
+ id: "datadog-region"
+ ) %>
+
+ Region that the Datadog account is in.
+
+
<% _ -> %>
Select a Backend Type
<% end %>
diff --git a/lib/logflare_web/live/source_backends_live.ex b/lib/logflare_web/live/source_backends_live.ex
index a65c657c5..a9194d1ce 100644
--- a/lib/logflare_web/live/source_backends_live.ex
+++ b/lib/logflare_web/live/source_backends_live.ex
@@ -12,7 +12,7 @@ defmodule LogflareWeb.SourceBackendsLive do
connected: <%= Enum.count(@attached_backend_ids) %>
<.form :let={f} as={:source} for={%{}} action="#" phx-submit="save">
<% grouped = Enum.group_by(@backends, & &1.type) %>
- <%= for type <- [:bigquery, :postgres, :webhook],
+ <%= for type <- [:bigquery, :postgres, :webhook, :datadog],
backends = Map.get(grouped, type, []) do %>
@@ -20,6 +20,7 @@ defmodule LogflareWeb.SourceBackendsLive do
:bigquery -> "BigQuery"
:postgres -> "PostgreSQL"
:webhook -> "Webhook"
+ :datadog -> "Datadog"
end %>
diff --git a/mix.lock b/mix.lock
index cdaba4520..8732544d0 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,6 +1,6 @@
%{
"atomic_map": {:hex, :atomic_map, "0.9.3", "3c7f1302e0590164732d08ca999708efbb2cd768abf2911cf140280ce2dc499d", [:mix], [], "hexpm", "c237babf301bd2435bd85b96cffc973022b4cbb7721537059ee0dd3bb74938d2"},
- "bandit": {:hex, :bandit, "1.1.0", "1414e65916229d4ee0914f6d4e7f8ec16c6f2d90e01ad5174d89e90baa577625", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4891fb2f48a83445da70a4e949f649a9b4032310f1f640f4a8a372bc91cece18"},
+ "bandit": {:hex, :bandit, "1.4.2", "a1475c8dcbffd1f43002797f99487a64c8444753ff2b282b52409e279488e1f5", [:mix], [{:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "3db8bacea631bd926cc62ccad58edfee4252d1b4c5cccbbad9825df2722b884f"},
"benchee": {:hex, :benchee, "1.3.0", "f64e3b64ad3563fa9838146ddefb2d2f94cf5b473bdfd63f5ca4d0657bf96694", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "34f4294068c11b2bd2ebf2c59aac9c7da26ffa0068afdf3419f1b176e16c5f81"},
"benchee_async": {:hex, :benchee_async, "0.1.2", "38e686bd9cdf7ae8767a08c0df6932b625b166fd97267d0437c715f9ff424bc1", [:mix], [], "hexpm", "73b0bd95173f86c61d41570adaeb151efe70c0cc273eec6501d391b35e3599dd"},
"bertex": {:hex, :bertex, "1.3.0", "0ad0df9159b5110d9d2b6654f72fbf42a54884ef43b6b651e6224c0af30ba3cb", [:mix], [], "hexpm", "0a5d5e478bb5764b7b7bae37cae1ca491200e58b089df121a2fe1c223d8ee57a"},
@@ -15,7 +15,7 @@
"configcat": {:hex, :configcat, "2.0.1", "cffd7e6ba7a4c41e1e6bbb706379192a1be7cd848bb6b098d4ed054b13c18f9d", [:mix], [{:elixir_uuid, "~> 1.2", [hex: :elixir_uuid, repo: "hexpm", optional: false]}, {:httpoison, "~> 1.7", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "3e4a239a613d2acbcee7103a6a426c4ae52882ae65bf48cdb5c1247877b65112"},
"contex": {:hex, :contex, "0.3.0", "d390713efee604702600ba801a481bcb8534a9af43e118b29d9d37fe4495fcba", [:mix], [{:nimble_strftime, "~> 0.1.0", [hex: :nimble_strftime, repo: "hexpm", optional: false]}], "hexpm", "3fa7535cc3b265691a4eabc2707fe8622aa60a2565145a14da9aebd613817652"},
"cors_plug": {:hex, :cors_plug, "2.0.3", "316f806d10316e6d10f09473f19052d20ba0a0ce2a1d910ddf57d663dac402ae", [:mix], [{:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ee4ae1418e6ce117fc42c2ba3e6cbdca4e95ecd2fe59a05ec6884ca16d469aea"},
- "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"},
+ "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"},
"cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
"credo": {:hex, :credo, "1.7.1", "6e26bbcc9e22eefbff7e43188e69924e78818e2fe6282487d0703652bc20fd62", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e9871c6095a4c0381c89b6aa98bc6260a8ba6addccf7f6a53da8849c748a58a2"},
@@ -102,7 +102,7 @@
"phoenix_view": {:hex, :phoenix_view, "2.0.3", "4d32c4817fce933693741deeb99ef1392619f942633dde834a5163124813aad3", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "cd34049af41be2c627df99cd4eaa71fc52a328c0c3d8e7d4aa28f880c30e7f64"},
"plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"},
"plug_caisson": {:hex, :plug_caisson, "0.2.1", "aa6a45a4f0e674459b8881d742cc0e8c7d5d0e008a29fe84dc10ab95d6fcfa74", [:mix], [{:brotli, "~> 0.3.2", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "661887bca916122c31717842fa6496c5a4d92c22b5dbef6bd6973d28188939cc"},
- "plug_cowboy": {:hex, :plug_cowboy, "2.6.2", "753611b23b29231fb916b0cdd96028084b12aff57bfd7b71781bd04b1dbeb5c9", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "951ed2433df22f4c97b85fdb145d4cee561f36b74854d64c06d896d7cd2921a7"},
+ "plug_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"},
"plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"},
"poison": {:hex, :poison, "5.0.0", "d2b54589ab4157bbb82ec2050757779bfed724463a544b6e20d79855a9e43b24", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "11dc6117c501b80c62a7594f941d043982a1bd05a1184280c0d9166eb4d8d3fc"},
"postgrex": {:hex, :postgrex, "0.17.3", "c92cda8de2033a7585dae8c61b1d420a1a1322421df84da9a82a6764580c503d", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "946cf46935a4fdca7a81448be76ba3503cff082df42c6ec1ff16a4bdfbfb098d"},
@@ -128,6 +128,7 @@
"telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"},
"tesla": {:hex, :tesla, "1.9.0", "8c22db6a826e56a087eeb8cdef56889731287f53feeb3f361dec5d4c8efb6f14", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "7c240c67e855f7e63e795bf16d6b3f5115a81d1f44b7fe4eadbf656bae0fef8a"},
"thousand_island": {:hex, :thousand_island, "1.2.0", "4f548ae771ab5f96bc7e199f9824c0c2ce6d365f8c93f5f64dbbb33988e484bf", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "521671fea179672addb6af46455fc2a77be1edda4c0ed351633e0ef37a4b3584"},
+ "test_server": {:hex, :test_server, "0.1.16", "403d6cebaa7ad1d08c0ca9475af48836c45ae0f64cda9f4e88b0f17310c5c452", [:mix], [{:bandit, ">= 1.4.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 2.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:x509, "~> 0.6", [hex: :x509, repo: "hexpm", optional: false]}], "hexpm", "f27cfc858d494e4df413a962fbe4d7aa3daf1a3824307f0b046bb8cec6ac8e42"},
"timber_logfmt": {:git, "https://github.com/Logflare/logfmt-elixir.git", "9766367ccb3014b47b0a621a489261011dcea769", []},
"timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"},
"toml": {:hex, :toml, "0.7.0", "fbcd773caa937d0c7a02c301a1feea25612720ac3fa1ccb8bfd9d30d822911de", [:mix], [], "hexpm", "0690246a2478c1defd100b0c9b89b4ea280a22be9a7b313a8a058a2408a2fa70"},
@@ -144,4 +145,5 @@
"warpath": {:hex, :warpath, "0.5.0", "906ca2efe1bbd07f2dafc2159897e2cb3068e567210c81c2d9858addc172df50", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "a9b4f518bfce91818fd52bc8e7656259844167436f14c0c1a01a6ca7e061f671"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
"websock_adapter": {:hex, :websock_adapter, "0.5.5", "9dfeee8269b27e958a65b3e235b7e447769f66b5b5925385f5a569269164a210", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "4b977ba4a01918acbf77045ff88de7f6972c2a009213c515a445c48f224ffce9"},
+ "x509": {:hex, :x509, "0.8.8", "aaf5e58b19a36a8e2c5c5cff0ad30f64eef5d9225f0fd98fb07912ee23f7aba3", [:mix], [], "hexpm", "ccc3bff61406e5bb6a63f06d549f3dba3a1bbb456d84517efaaa210d8a33750f"},
}
diff --git a/test/logflare/backends/adaptor/datadog_adaptor_test.exs b/test/logflare/backends/adaptor/datadog_adaptor_test.exs
new file mode 100644
index 000000000..c5bc22410
--- /dev/null
+++ b/test/logflare/backends/adaptor/datadog_adaptor_test.exs
@@ -0,0 +1,91 @@
+defmodule Logflare.Backends.Adaptor.DatadogAdaptorTest do
+ use Logflare.DataCase, async: false
+
+ alias Logflare.Backends.Adaptor
+
+ @subject Logflare.Backends.Adaptor.DatadogAdaptor
+
+ doctest @subject
+
+ describe "cast and validate" do
+ test "API key is required" do
+ changeset = Adaptor.cast_and_validate_config(@subject, %{})
+
+ refute changeset.valid?
+
+ assert Adaptor.cast_and_validate_config(@subject, %{
+ "api_key" => "foobarbaz",
+ "region" => "US1"
+ }).valid?
+
+ refute Adaptor.cast_and_validate_config(@subject, %{
+ "api_key" => "foobarbaz"
+ }).valid?
+ end
+ end
+
+ describe "logs ingestion" do
+ setup do
+ user = insert(:user)
+ source = insert(:source, user: user)
+
+ backend =
+ insert(:backend,
+ type: :datadog,
+ sources: [source],
+ config: %{api_key: "foo-bar", region: "US1"}
+ )
+
+ pid = start_supervised!({@subject, {source, backend}})
+ :timer.sleep(500)
+ [pid: pid, backend: backend, source: source]
+ end
+
+ test "sent logs are delivered", %{pid: pid, source: source, backend: backend} do
+ this = self()
+ ref = make_ref()
+
+ Tesla.Mock.mock_global(fn _req ->
+ send(this, ref)
+ %Tesla.Env{status: 200, body: ""}
+ end)
+
+ le = build(:log_event, source: source)
+
+ assert :ok == @subject.ingest(pid, [le], source_id: source.id, backend_id: backend.id)
+ assert_receive ^ref, 2000
+ end
+
+ test "service field is set to source name", %{pid: pid, source: source, backend: backend} do
+ this = self()
+ ref = make_ref()
+
+ Tesla.Mock.mock_global(fn req ->
+ send(this, {ref, Jason.decode!(req.body)})
+ %Tesla.Env{status: 200, body: ""}
+ end)
+
+ le = build(:log_event, source: source)
+
+ assert :ok == @subject.ingest(pid, [le], source_id: source.id, backend_id: backend.id)
+ assert_receive {^ref, [log_entry]}, 2000
+ assert log_entry["service"] == source.name
+ end
+
+ test "message is JSON encoded log event", %{pid: pid, source: source, backend: backend} do
+ this = self()
+ ref = make_ref()
+
+ Tesla.Mock.mock_global(fn req ->
+ send(this, {ref, Jason.decode!(req.body)})
+ %Tesla.Env{status: 200, body: ""}
+ end)
+
+ le = build(:log_event, source: source)
+
+ assert :ok == @subject.ingest(pid, [le], source_id: source.id, backend_id: backend.id)
+ assert_receive {^ref, [log_entry]}, 2000
+ assert log_entry["message"] =~ Jason.encode!(le.body)
+ end
+ end
+end