defmodule LogflareEx do alias LogflareEx.Client alias LogflareEx.Batcher alias LogflareEx.BatchedEvent alias LogflareEx.Repo alias LogflareEx.BatcherSup @moduledoc """ Documentation for `LogflareEx`. """ @doc """ Creates a client for interacting with Logflare. See `LogflareEx.Client`. """ defdelegate client(opts), to: __MODULE__.Client, as: :new @doc """ Send a singular event to Logflare. See `send_events/2` No local caching is performed. This is less efficient than batching events. """ @spec send_event(Client.t(), map()) :: {:ok, map()} | {:error, Tesla.Env.t()} def send_event(client, %{} = event) do send_events(client, [event]) end @doc """ Sends events directly to the Logflare API without local caching. All batching configurations on the client will be ignored. It is advised to use `send_batched_events/2` instead to spread out API requests. ### Example ```elixir iex> client = LogflareEx.client() %LogflareEx.Client{...} # singular event iex> LogflareEx.send_event(client, %{my: "event"}) {:ok, %{"message"=> "Logged!}} # multiple events iex> LogflareEx.send_events(client, [%{my: "event"}, ...]) {:ok, %{"message"=> "Logged!}} # a tesla result will be returned on error iex> client |> LogflareEx.send_event(%{my: "event"}) {:error, %Tesla.Env{...}} ``` """ @spec send_events(Client.t(), [map()]) :: {:ok, map()} | {:error, Tesla.Env.t()} def send_events(_client, []), do: {:error, :no_events} def send_events(%Client{source_token: nil, source_name: nil}, _batch), do: {:error, :no_source} def send_events(client, [%{} | _] = batch) do body = Bertex.encode(%{"batch" => batch, "source" => client.source_token}) case Tesla.post(client.tesla_client, "/api/logs", body) do {:ok, %Tesla.Env{status: status, body: body}} when status < 300 -> {:ok, Jason.decode!(body)} {:error, %Tesla.Env{} = result} -> # on_error callback case Map.get(client, :on_error) do {m, f, 1} -> apply(m, f, [result]) cb when is_function(cb) -> cb.(result) _ -> :noop end {:error, result} end end @doc """ Sends a batched event. See `send_batched_events/2` """ @spec send_batched_events(Client.t(), [map()]) :: :ok def send_batched_event(client, %{} = event), do: send_batched_events(client, [event]) @doc """ Sends events in batches. Configuration of the batching is dependent on the provided client. Batched events are cached locally and flushed at regular intervals. ### Example ```elixir # create a client iex> client = LogflareEx.client() %LogflareEx.Client{...} # singular event iex> LogflareEx.send_batched_event(client, %{...}) :ok # list of events iex> LogflareEx.send_batched_event(client, [%{...}, ...]) :ok ``` """ @spec send_batched_events(Client.t(), [map()]) :: :ok def send_batched_events(_client, []), do: :ok def send_batched_events(client, events) when is_list(events) do BatcherSup.ensure_started(client) for event <- events do client |> Map.take([:source_token, :source_name]) |> Map.put(:body, event) |> Batcher.create_event() end :ok end @doc """ Returns a count of all queued events. """ @spec count_queued_events() :: non_neg_integer() def count_queued_events() do Repo.all(BatchedEvent) |> length() end @doc """ Performs a flush for a given client. Attempts to clear the queue of events for the given client. """ @spec flush(Client.t()) :: :ok def flush(client) do BatcherSup.ensure_started(client) Batcher.flush(client) end end