diff --git a/lib/angen/helpers/fake_data/fake_logging.ex b/lib/angen/helpers/fake_data/fake_logging.ex index 92ce8ea..f4e2ac8 100644 --- a/lib/angen/helpers/fake_data/fake_logging.ex +++ b/lib/angen/helpers/fake_data/fake_logging.ex @@ -69,8 +69,7 @@ defmodule Angen.FakeData.FakeLogging do "spectator" => rand_int(0, config.max_users / 2, 10), "player" => rand_int(0, config.max_users / 3, 10), } - |> add_total_key(:total_non_bot, [:bot]) - |> add_total_key(:total_bot, [:non_bot]) + |> add_bot_totals lobby = %{ "in_progress" => rand_int(0, config.max_users / 2, 10), @@ -168,27 +167,25 @@ defmodule Angen.FakeData.FakeLogging do ) |> Enum.count + minutes = %{ + "lobby" => rand_int(config.max_users * 20, config.max_users * 600, get_in(last_day, ~w(minutes lobby))), + "menu" => rand_int(config.max_users * 20, config.max_users * 600, get_in(last_day, ~w(minutes menu))), + "player" => rand_int(config.max_users * 20, config.max_users * 600, get_in(last_day, ~w(minutes player))), + "spectator" => rand_int(config.max_users * 20, config.max_users * 600, get_in(last_day, ~w(minutes spectator))), + "bot" => rand_int(config.max_users * 20, config.max_users * 600, get_in(last_day, ~w(minutes bot))) + } + |> add_bot_totals + %{ "average_user_counts" => %{ "lobby" => rand_int_sequence(config.max_users / 10, config.max_users / 3, 0, 24), "menu" => rand_int_sequence(config.max_users / 10, config.max_users / 3, 0, 24), "player" => rand_int_sequence(config.max_users / 10, config.max_users / 3, 0, 24), "spectator" => rand_int_sequence(config.max_users / 10, config.max_users / 3, 0, 24), - "total" => rand_int_sequence(config.max_users / 10, config.max_users / 3, 0, 24) - }, - "minutes" => add_total_key(%{ - "lobby" => rand_int(config.max_users * 20, config.max_users * 600, get_in(last_day, ~w(minutes lobby))), - "menu" => rand_int(config.max_users * 20, config.max_users * 600, get_in(last_day, ~w(minutes menu))), - "player" => rand_int(config.max_users * 20, config.max_users * 600, get_in(last_day, ~w(minutes player))), - "spectator" => rand_int(config.max_users * 20, config.max_users * 600, get_in(last_day, ~w(minutes spectator))) - }, "total", []), - "peak_user_counts" => %{ - "lobby" => rand_int_sequence(config.max_users / 10, config.max_users / 4, 0, 24), - "menu" => rand_int_sequence(config.max_users / 10, config.max_users / 4, 0, 24), - "player" => rand_int_sequence(config.max_users / 10, config.max_users / 4, 0, 24), - "spectator" => rand_int_sequence(config.max_users / 10, config.max_users / 4, 0, 24), - "total" => rand_int_sequence(config.max_users / 10, config.max_users / 4, 0, 24) + "total_inc_bot" => rand_int_sequence(config.max_users / 10, config.max_users / 3, 0, 24), + "total_non_bot" => rand_int_sequence(config.max_users / 10, config.max_users / 3, 0, 24) }, + "minutes" => minutes, "peak_user_counts" => %{ "bot" => rand_int(10, config.max_users / 3, get_in(last_day, ~w(stats peak_user_counts bot))), "lobby" => rand_int(10, config.max_users / 3, get_in(last_day, ~w(stats peak_user_counts lobby))), @@ -196,7 +193,7 @@ defmodule Angen.FakeData.FakeLogging do "player" => rand_int(10, config.max_users / 3, get_in(last_day, ~w(stats peak_user_counts player))), "spectator" => rand_int(10, config.max_users / 3, get_in(last_day, ~w(stats peak_user_counts spectator))), "total" => rand_int(10, config.max_users / 3, get_in(last_day, ~w(stats peak_user_counts total))), - }, + } |> add_bot_totals, "stats" => %{ "accounts_created" => accounts_created, "unique_users" => rand_int(config.max_users / 10, config.max_users, get_in(last_day, ~w(stats unique_users))), @@ -204,4 +201,10 @@ defmodule Angen.FakeData.FakeLogging do } } end + + defp add_bot_totals(m) do + m + |> add_total_key("total_non_bot", ["bot"]) + |> add_total_key("total_inc_bot", ["total_non_bot"]) + end end diff --git a/lib/angen/helpers/styling_helpers.ex b/lib/angen/helpers/styling_helpers.ex index 7faf187..2ac67a7 100644 --- a/lib/angen/helpers/styling_helpers.ex +++ b/lib/angen/helpers/styling_helpers.ex @@ -56,7 +56,7 @@ defmodule Angen.Helper.StylingHelper do def icon(:up), do: "fa-level-up" def icon(:back), do: "fa-arrow-left" - def icon(:list, _fa_type), do: "fa-bars" + def icon(:list), do: "fa-bars" def icon(:show), do: "fa-eye" def icon(:search), do: "fa-search" def icon(:new), do: "fa-plus" diff --git a/lib/angen/helpers/timex_helper.ex b/lib/angen/helpers/timex_helper.ex index eed0120..8377569 100644 --- a/lib/angen/helpers/timex_helper.ex +++ b/lib/angen/helpers/timex_helper.ex @@ -425,7 +425,8 @@ defmodule Angen.Helper.TimexHelper do Timex.compare(a, b) == -1 end - def represent_minutes(nil), do: "" + def represent_minutes(nil), do: "0 minutes" + def represent_minutes(0), do: "0 minutes" def represent_minutes(s) do now = Timex.now() diff --git a/lib/angen/logging/tasks/persist_server_day_task.ex b/lib/angen/logging/tasks/persist_server_day_task.ex index 52cab81..998876f 100644 --- a/lib/angen/logging/tasks/persist_server_day_task.ex +++ b/lib/angen/logging/tasks/persist_server_day_task.ex @@ -11,7 +11,7 @@ defmodule Angen.Logging.PersistServerDayTask do @log_keep_days 30 - @client_states ~w(lobby bot menu player spectator total)a + @client_states ~w(lobby bot menu player spectator total_non_bot total_inc_bot)a # [] List means 1 hour segments # %{} Dict means total for the day for that key @@ -39,7 +39,8 @@ defmodule Angen.Logging.PersistServerDayTask do lobby: 0, menu: 0, bot: 0, - total: 0 + total_non_bot: 0, + total_inc_bot: 0 }, # The number of minutes users (combined) spent in that state during the segment @@ -49,7 +50,8 @@ defmodule Angen.Logging.PersistServerDayTask do spectator: [], lobby: [], menu: [], - total: [] + total_non_bot: [], + total_inc_bot: [] }, peak_user_counts: %{ bot: [], @@ -57,7 +59,8 @@ defmodule Angen.Logging.PersistServerDayTask do spectator: [], lobby: [], menu: [], - total: [] + total_non_bot: [], + total_inc_bot: [] } } @@ -82,7 +85,8 @@ defmodule Angen.Logging.PersistServerDayTask do spectator: 0, lobby: 0, menu: 0, - total: 0 + total_non_bot: 0, + total_inc_bot: 0 }, # The number of minutes users (combined) spent in that state during the segment @@ -92,7 +96,8 @@ defmodule Angen.Logging.PersistServerDayTask do spectator: 0, lobby: 0, menu: 0, - total: 0 + total_non_bot: 0, + total_inc_bot: 0 }, peak_user_counts: %{ bot: 0, @@ -100,7 +105,8 @@ defmodule Angen.Logging.PersistServerDayTask do spectator: 0, lobby: 0, menu: 0, - total: 0 + total_non_bot: 0, + total_inc_bot: 0 } } @@ -196,7 +202,7 @@ defmodule Angen.Logging.PersistServerDayTask do search: [ after: start_time, before: end_time, - node: node + # node: node ], select: [:data], limit: :infinity @@ -208,6 +214,7 @@ defmodule Angen.Logging.PersistServerDayTask do defp extend_segment(segment, logs) do extend = calculate_segment_parts(logs) + %{ # Daily totals stats: %{ @@ -222,7 +229,9 @@ defmodule Angen.Logging.PersistServerDayTask do spectator: segment.minutes.spectator + extend.minutes.spectator, lobby: segment.minutes.lobby + extend.minutes.lobby, menu: segment.minutes.menu + extend.minutes.menu, - total: segment.minutes.total + extend.minutes.total + bot: segment.minutes.bot + extend.minutes.bot, + total_non_bot: segment.minutes.total_non_bot + extend.minutes.total_non_bot, + total_inc_bot: segment.minutes.total_inc_bot + extend.minutes.total_inc_bot }, # The number of minutes users (combined) spent in that state during the segment @@ -232,14 +241,18 @@ defmodule Angen.Logging.PersistServerDayTask do segment.average_user_counts.spectator ++ [extend.average_user_counts.spectator], lobby: segment.average_user_counts.lobby ++ [extend.average_user_counts.lobby], menu: segment.average_user_counts.menu ++ [extend.average_user_counts.menu], - total: segment.average_user_counts.total ++ [extend.average_user_counts.total] + bot: segment.average_user_counts.bot ++ [extend.average_user_counts.bot], + total_non_bot: segment.average_user_counts.total_non_bot ++ [extend.average_user_counts.total_non_bot], + total_inc_bot: segment.average_user_counts.total_inc_bot ++ [extend.average_user_counts.total_inc_bot] }, peak_user_counts: %{ player: segment.peak_user_counts.player ++ [extend.peak_user_counts.player], spectator: segment.peak_user_counts.spectator ++ [extend.peak_user_counts.spectator], lobby: segment.peak_user_counts.lobby ++ [extend.peak_user_counts.lobby], menu: segment.peak_user_counts.menu ++ [extend.peak_user_counts.menu], - total: segment.peak_user_counts.total ++ [extend.peak_user_counts.total] + bot: segment.peak_user_counts.bot ++ [extend.peak_user_counts.bot], + total_non_bot: segment.peak_user_counts.total_non_bot ++ [extend.peak_user_counts.total_non_bot], + total_inc_bot: segment.peak_user_counts.total_inc_bot ++ [extend.peak_user_counts.total_inc_bot] } } end @@ -251,7 +264,8 @@ defmodule Angen.Logging.PersistServerDayTask do count = Enum.count(logs) empty_user_maps = %{ - total: 0, + total_non_bot: 0, + total_inc_bot: 0, bot: 0, player: 0, spectator: 0, @@ -264,7 +278,8 @@ defmodule Angen.Logging.PersistServerDayTask do logs |> Enum.reduce(empty_user_maps, fn log, acc -> %{ - total: acc.total + Map.get(log["client"], "total", 0), + total_non_bot: acc.bot + Map.get(log["client"], "total_non_bot", 0), + total_inc_bot: acc.bot + Map.get(log["client"], "total_inc_bot", 0), bot: acc.bot + Map.get(log["client"], "bot", 0), player: acc.player + Map.get(log["client"], "player", 0), spectator: acc.spectator + Map.get(log["client"], "spectator", 0), @@ -291,7 +306,8 @@ defmodule Angen.Logging.PersistServerDayTask do spectator: sum_counts(logs, ~w(client spectator)) / count, lobby: sum_counts(logs, ~w(client lobby)) / count, menu: sum_counts(logs, ~w(client menu)) / count, - total: sum_counts(logs, ~w(client total)) / count + total_inc_bot: sum_counts(logs, ~w(client total_inc_bot)) / count, + total_non_bot: sum_counts(logs, ~w(client total_non_bot)) / count }, peak_user_counts: %{ bot: max_counts(logs, ~w(client bot)), @@ -299,7 +315,8 @@ defmodule Angen.Logging.PersistServerDayTask do spectator: max_counts(logs, ~w(client spectator)), lobby: max_counts(logs, ~w(client lobby)), menu: max_counts(logs, ~w(client menu)), - total: max_counts(logs, ~w(client total)) + total_inc_bot: max_counts(logs, ~w(client total_inc_bot)), + total_non_bot: max_counts(logs, ~w(client total_non_bot)) } } end @@ -308,7 +325,9 @@ defmodule Angen.Logging.PersistServerDayTask do end_of_day = Timex.shift(date, days: 1) Map.put(data, :telemetry, %{ - simple_clientapp: Telemetry.simple_clientapp_events_summary(after: date, before: end_of_day) + simple_clientapp: Telemetry.simple_clientapp_events_summary(after: date, before: end_of_day), + + simple_lobby: Telemetry.simple_lobby_events_summary(after: date, before: end_of_day) }) end diff --git a/lib/angen/logging/tasks/persist_server_minute_task.ex b/lib/angen/logging/tasks/persist_server_minute_task.ex index 7f06635..938ff30 100644 --- a/lib/angen/logging/tasks/persist_server_minute_task.ex +++ b/lib/angen/logging/tasks/persist_server_minute_task.ex @@ -71,7 +71,7 @@ defmodule Angen.Logging.PersistServerMinuteTask do {key, Enum.count(values)} end) |> add_total_key(:total_non_bot, [:bot]) - |> add_total_key(:total_bot, [:non_bot]) + |> add_total_key(:total_inc_bot, [:total_non_bot]) end @spec get_lobby_states() :: map() diff --git a/lib/angen/telemetry.ex b/lib/angen/telemetry.ex index d930f5b..e55623c 100644 --- a/lib/angen/telemetry.ex +++ b/lib/angen/telemetry.ex @@ -73,7 +73,7 @@ defmodule Angen.Telemetry do # SimpleClientappEvents alias Angen.Telemetry.{SimpleClientappEvent, SimpleClientappEventLib, SimpleClientappEventQueries} - @doc section: :event_type + @doc section: :simple_clientapp_event @spec log_simple_clientapp_event(String.t(), Teiserver.user_id()) :: :ok | {:error, String.t()} defdelegate log_simple_clientapp_event(name, user_id), to: SimpleClientappEventLib @@ -81,9 +81,31 @@ defmodule Angen.Telemetry do @spec simple_clientapp_event_query(Angen.query_args()) :: Ecto.Query.t() defdelegate simple_clientapp_event_query(args), to: SimpleClientappEventQueries + @doc section: :simple_clientapp_event @spec list_simple_clientapp_events(Teiserver.query_args()) :: [SimpleClientappEvent.t()] defdelegate list_simple_clientapp_events(args), to: SimpleClientappEventLib + @doc section: :simple_clientapp_event @spec simple_clientapp_events_summary(list) :: map() defdelegate simple_clientapp_events_summary(args), to: SimpleClientappEventQueries + + + # SimpleLobbyEvents + alias Angen.Telemetry.{SimpleLobbyEvent, SimpleLobbyEventLib, SimpleLobbyEventQueries} + + @doc section: :simple_lobby_event + @spec log_simple_lobby_event(String.t(), Teiserver.match_id(), Teiserver.user_id()) :: :ok | {:error, String.t()} + defdelegate log_simple_lobby_event(name, match_id, user_id \\ nil), to: SimpleLobbyEventLib + + @doc false + @spec simple_lobby_event_query(Angen.query_args()) :: Ecto.Query.t() + defdelegate simple_lobby_event_query(args), to: SimpleLobbyEventQueries + + @doc section: :simple_lobby_event + @spec list_simple_lobby_events(Teiserver.query_args()) :: [SimpleLobbyEvent.t()] + defdelegate list_simple_lobby_events(args), to: SimpleLobbyEventLib + + @doc section: :simple_lobby_event + @spec simple_lobby_events_summary(list) :: map() + defdelegate simple_lobby_events_summary(args), to: SimpleLobbyEventQueries end diff --git a/lib/angen/telemetry/libs/simple_clientapp_event_lib.ex b/lib/angen/telemetry/libs/simple_clientapp_event_lib.ex index 870200b..9ba5b08 100644 --- a/lib/angen/telemetry/libs/simple_clientapp_event_lib.ex +++ b/lib/angen/telemetry/libs/simple_clientapp_event_lib.ex @@ -22,14 +22,6 @@ defmodule Angen.Telemetry.SimpleClientappEventLib do case create_simple_clientapp_event(attrs) do {:ok, _event} -> :ok {:error, changeset} -> - IO.puts "#{__MODULE__}:#{__ENV__.line}" - IO.inspect attrs - IO.puts "" - - IO.puts "#{__MODULE__}:#{__ENV__.line}" - IO.inspect changeset - IO.puts "" - {:error, changeset.errors |> Enum.map_join(", ", fn {key, {message, _}} -> diff --git a/lib/angen/telemetry/libs/simple_lobby_event_lib.ex b/lib/angen/telemetry/libs/simple_lobby_event_lib.ex new file mode 100644 index 0000000..9db2e62 --- /dev/null +++ b/lib/angen/telemetry/libs/simple_lobby_event_lib.ex @@ -0,0 +1,164 @@ +defmodule Angen.Telemetry.SimpleLobbyEventLib do + @moduledoc """ + Library of simple_lobby_event related functions. + """ + use TeiserverMacros, :library + alias Angen.Telemetry + alias Angen.Telemetry.{SimpleLobbyEvent, SimpleLobbyEventQueries} + + @doc """ + A wrapper around create_simple_lobby_event which handles grabbing the event_type_id + """ + @spec log_simple_lobby_event(String.t(), Teiserver.match_id(), Teiserver.user_id()) :: :ok | {:error, String.t()} + def log_simple_lobby_event(name, match_id, user_id \\ nil) do + type_id = Telemetry.get_or_add_event_type_id(name, "simple_lobby") + + attrs = %{ + event_type_id: type_id, + match_id: match_id, + user_id: user_id, + inserted_at: Timex.now() + } + + case create_simple_lobby_event(attrs) do + {:ok, _event} -> :ok + {:error, changeset} -> + {:error, + changeset.errors + |> Enum.map_join(", ", fn {key, {message, _}} -> + "#{key}: #{message}" + end) + } + end + end + + @doc """ + Returns the list of simple_lobby_events. + + ## Examples + + iex> list_simple_lobby_events() + [%SimpleLobbyEvent{}, ...] + + """ + @spec list_simple_lobby_events(Teiserver.query_args()) :: [SimpleLobbyEvent.t()] + def list_simple_lobby_events(query_args) do + query_args + |> SimpleLobbyEventQueries.simple_lobby_event_query() + |> Repo.all() + end + + @doc """ + Gets a single simple_lobby_event. + + Raises `Ecto.NoResultsError` if the SimpleLobbyEvent does not exist. + + ## Examples + + iex> get_simple_lobby_event!(123) + %SimpleLobbyEvent{} + + iex> get_simple_lobby_event!(456) + ** (Ecto.NoResultsError) + + """ + @spec get_simple_lobby_event!(SimpleLobbyEvent.id()) :: SimpleLobbyEvent.t() + @spec get_simple_lobby_event!(SimpleLobbyEvent.id(), Teiserver.query_args()) :: SimpleLobbyEvent.t() + def get_simple_lobby_event!(simple_lobby_event_id, query_args \\ []) do + (query_args ++ [id: simple_lobby_event_id]) + |> SimpleLobbyEventQueries.simple_lobby_event_query() + |> Repo.one!() + end + + @doc """ + Gets a single simple_lobby_event. + + Returns nil if the SimpleLobbyEvent does not exist. + + ## Examples + + iex> get_simple_lobby_event(123) + %SimpleLobbyEvent{} + + iex> get_simple_lobby_event(456) + nil + + """ + @spec get_simple_lobby_event(SimpleLobbyEvent.id()) :: SimpleLobbyEvent.t() | nil + @spec get_simple_lobby_event(SimpleLobbyEvent.id(), Teiserver.query_args()) :: SimpleLobbyEvent.t() | nil + def get_simple_lobby_event(simple_lobby_event_id, query_args \\ []) do + (query_args ++ [id: simple_lobby_event_id]) + |> SimpleLobbyEventQueries.simple_lobby_event_query() + |> Repo.one() + end + + @doc """ + Creates a simple_lobby_event. + + ## Examples + + iex> create_simple_lobby_event(%{field: value}) + {:ok, %SimpleLobbyEvent{}} + + iex> create_simple_lobby_event(%{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + @spec create_simple_lobby_event(map) :: {:ok, SimpleLobbyEvent.t()} | {:error, Ecto.Changeset.t()} + def create_simple_lobby_event(attrs) do + %SimpleLobbyEvent{} + |> SimpleLobbyEvent.changeset(attrs) + |> Repo.insert() + end + + @doc """ + Updates a simple_lobby_event. + + ## Examples + + iex> update_simple_lobby_event(simple_lobby_event, %{field: new_value}) + {:ok, %SimpleLobbyEvent{}} + + iex> update_simple_lobby_event(simple_lobby_event, %{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + @spec update_simple_lobby_event(SimpleLobbyEvent.t(), map) :: + {:ok, SimpleLobbyEvent.t()} | {:error, Ecto.Changeset.t()} + def update_simple_lobby_event(%SimpleLobbyEvent{} = simple_lobby_event, attrs) do + simple_lobby_event + |> SimpleLobbyEvent.changeset(attrs) + |> Repo.update() + end + + @doc """ + Deletes a simple_lobby_event. + + ## Examples + + iex> delete_simple_lobby_event(simple_lobby_event) + {:ok, %SimpleLobbyEvent{}} + + iex> delete_simple_lobby_event(simple_lobby_event) + {:error, %Ecto.Changeset{}} + + """ + @spec delete_simple_lobby_event(SimpleLobbyEvent.t()) :: {:ok, SimpleLobbyEvent.t()} | {:error, Ecto.Changeset.t()} + def delete_simple_lobby_event(%SimpleLobbyEvent{} = simple_lobby_event) do + Repo.delete(simple_lobby_event) + end + + @doc """ + Returns an `%Ecto.Changeset{}` for tracking simple_lobby_event changes. + + ## Examples + + iex> change_simple_lobby_event(simple_lobby_event) + %Ecto.Changeset{data: %SimpleLobbyEvent{}} + + """ + @spec change_simple_lobby_event(SimpleLobbyEvent.t(), map) :: Ecto.Changeset.t() + def change_simple_lobby_event(%SimpleLobbyEvent{} = simple_lobby_event, attrs \\ %{}) do + SimpleLobbyEvent.changeset(simple_lobby_event, attrs) + end +end diff --git a/lib/angen/telemetry/queries/simple_lobby_event_queries.ex b/lib/angen/telemetry/queries/simple_lobby_event_queries.ex new file mode 100644 index 0000000..16368e6 --- /dev/null +++ b/lib/angen/telemetry/queries/simple_lobby_event_queries.ex @@ -0,0 +1,105 @@ +defmodule Angen.Telemetry.SimpleLobbyEventQueries do + @moduledoc false + use TeiserverMacros, :queries + alias Angen.Telemetry.SimpleLobbyEvent + require Logger + + @spec simple_lobby_event_query(Teiserver.query_args()) :: Ecto.Query.t() + def simple_lobby_event_query(args) do + query = from(simple_lobby_events in SimpleLobbyEvent) + + query + |> do_where(id: args[:id]) + |> do_where(args[:where]) + |> do_where(args[:search]) + |> do_order_by(args[:order_by]) + |> QueryHelper.query_select(args[:select]) + |> QueryHelper.limit_query(args[:limit] || 50) + end + + @spec do_where(Ecto.Query.t(), list | map | nil) :: Ecto.Query.t() + defp do_where(query, nil), do: query + + defp do_where(query, params) do + params + |> Enum.reduce(query, fn {key, value}, query_acc -> + _where(query_acc, key, value) + end) + end + + @spec _where(Ecto.Query.t(), Atom.t(), any()) :: Ecto.Query.t() + def _where(query, _, ""), do: query + def _where(query, _, nil), do: query + + def _where(query, :id, id) do + from(simple_lobby_events in query, + where: simple_lobby_events.id in ^List.wrap(id) + ) + end + + def _where(query, :type_id, type_id) do + from(simple_lobby_events in query, + where: simple_lobby_events.type_id in ^List.wrap(type_id) + ) + end + + def _where(query, :user_id, user_id) do + from(simple_lobby_events in query, + where: simple_lobby_events.user_id in ^List.wrap(user_id) + ) + end + + def _where(query, :lobby_id, lobby_id) do + from(simple_lobby_events in query, + where: simple_lobby_events.lobby_id in ^List.wrap(lobby_id) + ) + end + + def _where(query, :after, timestamp) do + from simple_lobby_events in query, + where: simple_lobby_events.inserted_at > ^Timex.to_datetime(timestamp) + end + + def _where(query, :before, timestamp) do + from simple_lobby_events in query, + where: simple_lobby_events.inserted_at < ^Timex.to_datetime(timestamp) + end + + @spec do_order_by(Ecto.Query.t(), list | nil) :: Ecto.Query.t() + defp do_order_by(query, nil), do: query + + defp do_order_by(query, params) do + params + |> List.wrap() + |> Enum.reduce(query, fn key, query_acc -> + _order_by(query_acc, key) + end) + end + + @spec _order_by(Ecto.Query.t(), any()) :: Ecto.Query.t() + def _order_by(query, "Newest first") do + from(simple_lobby_events in query, + order_by: [desc: simple_lobby_events.inserted_at] + ) + end + + def _order_by(query, "Oldest first") do + from(simple_lobby_events in query, + order_by: [asc: simple_lobby_events.inserted_at] + ) + end + + @spec simple_lobby_events_summary(list) :: map() + def simple_lobby_events_summary(args) do + query = + from simple_lobby_events in SimpleLobbyEvent, + join: event_types in assoc(simple_lobby_events, :event_type), + group_by: event_types.name, + select: {event_types.name, count(simple_lobby_events.event_type_id)} + + query + |> do_where(args) + |> Repo.all() + |> Map.new() + end +end diff --git a/lib/angen/telemetry/schemas/complex_lobby_event.ex b/lib/angen/telemetry/schemas/complex_lobby_event.ex index 3906b9f..18a1072 100644 --- a/lib/angen/telemetry/schemas/complex_lobby_event.ex +++ b/lib/angen/telemetry/schemas/complex_lobby_event.ex @@ -15,7 +15,7 @@ defmodule Angen.Telemetry.ComplexLobbyEvent do schema "telemetry_complex_lobby_events" do belongs_to(:user, Teiserver.Account.User, type: Ecto.UUID) - belongs_to(:match_id, Teiserver.Game.Match) + belongs_to(:match, Teiserver.Game.Match, type: Ecto.UUID) belongs_to(:event_type, Angen.Telemetry.EventType) field(:inserted_at, :utc_datetime) diff --git a/lib/angen/telemetry/schemas/complex_match_event.ex b/lib/angen/telemetry/schemas/complex_match_event.ex index 4320288..8e743b9 100644 --- a/lib/angen/telemetry/schemas/complex_match_event.ex +++ b/lib/angen/telemetry/schemas/complex_match_event.ex @@ -16,7 +16,7 @@ defmodule Angen.Telemetry.ComplexMatchEvent do schema "telemetry_complex_anon_events" do belongs_to(:user, Teiserver.Account.User, type: Ecto.UUID) - belongs_to(:match_id, Teiserver.Game.Match) + belongs_to(:match, Teiserver.Game.Match, type: Ecto.UUID) belongs_to(:event_type, Angen.Telemetry.EventType) field(:inserted_at, :utc_datetime) diff --git a/lib/angen/telemetry/schemas/simple_lobby_event.ex b/lib/angen/telemetry/schemas/simple_lobby_event.ex index ee8997c..246fa5e 100644 --- a/lib/angen/telemetry/schemas/simple_lobby_event.ex +++ b/lib/angen/telemetry/schemas/simple_lobby_event.ex @@ -5,7 +5,7 @@ defmodule Angen.Telemetry.SimpleLobbyEvent do ### Attributes - * `:user_id` - The `Teiserver.Account.User` this event took place for + * `:user_id` - The `Teiserver.Account.User` this event took place for (nullable) * `:match_id` - The match_id of the lobby this took place in * `:event_type_id` - The `Angen.Telemetry.EventType` this event belongs to * `:inserted_at` - The timestamp the event took place @@ -14,7 +14,7 @@ defmodule Angen.Telemetry.SimpleLobbyEvent do schema "telemetry_simple_lobby_events" do belongs_to(:user, Teiserver.Account.User, type: Ecto.UUID) - belongs_to(:match_id, Teiserver.Game.Match) + belongs_to(:match, Teiserver.Game.Match, type: Ecto.UUID) belongs_to(:event_type, Angen.Telemetry.EventType) field(:inserted_at, :utc_datetime) end @@ -34,6 +34,6 @@ defmodule Angen.Telemetry.SimpleLobbyEvent do def changeset(struct, attrs \\ %{}) do struct |> cast(attrs, ~w(user_id match_id event_type_id inserted_at)a) - |> validate_required(~w(user_id match_id event_type_id inserted_at)a) + |> validate_required(~w(match_id event_type_id inserted_at)a) end end diff --git a/lib/angen/telemetry/schemas/simple_match_event.ex b/lib/angen/telemetry/schemas/simple_match_event.ex index 956ec88..e8fd052 100644 --- a/lib/angen/telemetry/schemas/simple_match_event.ex +++ b/lib/angen/telemetry/schemas/simple_match_event.ex @@ -15,7 +15,7 @@ defmodule Angen.Telemetry.SimpleMatchEvent do schema "telemetry_simple_anon_events" do belongs_to(:user, Teiserver.Account.User, type: Ecto.UUID) - belongs_to(:match_id, Teiserver.Game.Match) + belongs_to(:match, Teiserver.Game.Match, type: Ecto.UUID) belongs_to(:event_type, Angen.Telemetry.EventType) field(:inserted_at, :utc_datetime) diff --git a/lib/angen/telemetry/servers/angen_collector_server.ex b/lib/angen/telemetry/servers/angen_collector_server.ex index 8e1c3f4..7486efa 100644 --- a/lib/angen/telemetry/servers/angen_collector_server.ex +++ b/lib/angen/telemetry/servers/angen_collector_server.ex @@ -51,12 +51,12 @@ defmodule Angen.Telemetry.AngenCollectorServer do # end def handle_info({:emit, _event, _measurement, _meta, _opts} = msg, state) do - IO.puts "#{__MODULE__}:#{__ENV__.line}" - IO.inspect "No telemetry handler for event: #{inspect elem(msg, 1)}" - IO.inspect elem(msg, 2), label: "Measurement: " - IO.inspect elem(msg, 3), label: "Meta: " - IO.inspect elem(msg, 4), label: "Opts: " - IO.puts "" + # IO.puts "#{__MODULE__}:#{__ENV__.line}" + # IO.inspect "No telemetry handler for event: #{inspect elem(msg, 1)}" + # IO.inspect elem(msg, 2), label: "Measurement: " + # IO.inspect elem(msg, 3), label: "Meta: " + # IO.inspect elem(msg, 4), label: "Opts: " + # IO.puts "" {:noreply, state} end diff --git a/lib/angen/telemetry/servers/teiserver_collector_server.ex b/lib/angen/telemetry/servers/teiserver_collector_server.ex index 401e8c8..a210e42 100644 --- a/lib/angen/telemetry/servers/teiserver_collector_server.ex +++ b/lib/angen/telemetry/servers/teiserver_collector_server.ex @@ -47,6 +47,7 @@ defmodule Angen.Telemetry.TeiserverCollectorServer do {:noreply, %{state | client_disconnect_counter: new_counter}} end + # Lobby events def handle_info({:emit, [:teiserver, :lobby, :event], %{type: type}, _meta, _opts}, state) do new_count = Map.get(state.lobby_event_counter, type, 0) + 1 new_counter = Map.put(state.lobby_event_counter, type, new_count) @@ -54,6 +55,24 @@ defmodule Angen.Telemetry.TeiserverCollectorServer do {:noreply, %{state | lobby_event_counter: new_counter}} end + def handle_info({:emit, [:teiserver, :lobby, :cycle], data, meta, _opts}, state) do + new_count = Map.get(state.lobby_event_counter, :cycle, 0) + 1 + new_counter = Map.put(state.lobby_event_counter, :cycle, new_count) + + :ok = Telemetry.log_simple_lobby_event("cycle", meta.match_id, meta[:user_id]) + + {:noreply, %{state | lobby_event_counter: new_counter}} + end + + def handle_info({:emit, [:teiserver, :lobby, :start_match], _, meta, _opts}, state) do + new_count = Map.get(state.lobby_event_counter, :start_match, 0) + 1 + new_counter = Map.put(state.lobby_event_counter, :start_match, new_count) + + :ok = Telemetry.log_simple_lobby_event("start_match", meta.match_id, meta[:user_id]) + + {:noreply, %{state | lobby_event_counter: new_counter}} + end + def handle_info({:emit, _event, _measurement, _meta, _opts} = _msg, state) do # IO.puts "#{__MODULE__}:#{__ENV__.line}" # IO.inspect "No telemetry handler for" diff --git a/lib/angen_web/components/logging/server_components.ex b/lib/angen_web/components/logging/server_components.ex index 4e2dd6d..babe308 100644 --- a/lib/angen_web/components/logging/server_components.ex +++ b/lib/angen_web/components/logging/server_components.ex @@ -81,10 +81,6 @@ defmodule AngenWeb.Logging.ServerComponents do

Peaks

- - - - @@ -93,6 +89,22 @@ defmodule AngenWeb.Logging.ServerComponents do + + + + + + + + + + + + + + + +
Total<%= @data["peak_user_counts"]["total"] %>
Player <%= @data["peak_user_counts"]["player"] %>Spectator <%= @data["peak_user_counts"]["spectator"] %>
Lobby<%= @data["peak_user_counts"]["lobby"] %>
Menu<%= @data["peak_user_counts"]["menu"] %>
Bot<%= @data["peak_user_counts"]["bot"] %>
Total (no bots)<%= @data["peak_user_counts"]["total_non_bot"] %>
@@ -103,10 +115,6 @@ defmodule AngenWeb.Logging.ServerComponents do

Time

- - - - @@ -115,6 +123,22 @@ defmodule AngenWeb.Logging.ServerComponents do + + + + + + + + + + + + + + + +
Total<%= represent_minutes(@data["minutes"]["total"]) %>
Player <%= represent_minutes(@data["minutes"]["player"]) %>Spectator <%= represent_minutes(@data["minutes"]["spectator"]) %>
Lobby<%= represent_minutes(@data["minutes"]["lobby"]) %>
Menu<%= represent_minutes(@data["minutes"]["menu"]) %>
Bot<%= represent_minutes(@data["minutes"]["bot"]) %>
Total (no bots)<%= represent_minutes(@data["minutes"]["total_non_bot"]) %>
@@ -124,7 +148,21 @@ defmodule AngenWeb.Logging.ServerComponents do
<.card> -

Simple Clientapp events

+

Server events

+ + +
+ +
+ <.card> +

Anon events

+ + +
+ +
+ <.card> +

Clientapp events

@@ -138,14 +176,21 @@ defmodule AngenWeb.Logging.ServerComponents do
<.card> -

...

- +

Lobby events

+
+ + + + + + +
<%= event %><%= StringHelper.format_number(count) %>
<.card> -

...

+

Match events

diff --git a/lib/angen_web/live/admin/logging/server/now_live.ex b/lib/angen_web/live/admin/logging/server/now_live.ex index ad3bb64..223edcb 100644 --- a/lib/angen_web/live/admin/logging/server/now_live.ex +++ b/lib/angen_web/live/admin/logging/server/now_live.ex @@ -10,13 +10,17 @@ defmodule AngenWeb.Admin.Logging.Server.NowLive do |> assign(:site_menu_active, "logging") |> assign(:resolution, Map.get(params, "resolution", "1") |> String.to_integer()) |> assign(:minutes, Map.get(params, "minutes", "30") |> String.to_integer()) - |> generate_graph_data + |> assign(:mode, "this_minute") + |> get_logs + # |> generate_graph_data {:ok, socket} end def mount(_params, _session, socket) do - {:ok, socket} + {:ok, socket + |> assign(:mode, "this_minute") + } end @impl true @@ -29,20 +33,25 @@ defmodule AngenWeb.Admin.Logging.Server.NowLive do {:noreply, socket} end - defp generate_graph_data(%{assigns: %{resolution: resolution, minutes: minutes}} = socket) do + defp get_logs(%{assigns: %{minutes: _minutes}} = socket) do start_timestamp = nil logs = Logging.list_server_minute_logs( - order: "Oldest first", + order: "Newest first", where: [ # node: "all", after: start_timestamp ], limit: 10 ) - |> Enum.group_by(fn log -> log.node end) + |> Enum.reverse + + socket + |> assign(:logs, logs) + end + defp generate_graph_data(%{assigns: %{logs: logs}} = socket) do socket |> assign(column_clients: GraphMinuteLogsTask.perform_clients(logs, 1)) # |> assign(columns_matches: GraphMinuteLogsTask.perform_matches(logs, 1)) diff --git a/lib/angen_web/live/admin/logging/server/now_live.html.heex b/lib/angen_web/live/admin/logging/server/now_live.html.heex index 7368af9..2ce457e 100644 --- a/lib/angen_web/live/admin/logging/server/now_live.html.heex +++ b/lib/angen_web/live/admin/logging/server/now_live.html.heex @@ -1,6 +1,45 @@ +<% + mode_items = ~w(graphs table this_minute) + |> Enum.map(fn i -> + %{ + click: "set-mode:#{i}", + label: String.capitalize(i) |> String.replace("_", " "), + selected: assigns[:mode] == i, + } + end) +%> + + + <.dropdown + items={mode_items} + label={@mode |> String.replace("_", " ")} + /> +<%= if assigns[:logs] != nil and not Enum.empty?(@logs) do %> + <%= case @mode do %> + <% "this_minute" -> %> + <% first_log = hd(@logs) %> + +
+
+ <.card> + +
+ + + +
+
+ + <% end %> +<% end %> + + + + +<%= if false do %>