diff --git a/lib/towerops_web/live/equipment_live/show.ex b/lib/towerops_web/live/equipment_live/show.ex index 9d41cdd0..fb67e19b 100644 --- a/lib/towerops_web/live/equipment_live/show.ex +++ b/lib/towerops_web/live/equipment_live/show.ex @@ -55,6 +55,7 @@ defmodule ToweropsWeb.EquipmentLive.Show do cpu_chart_data = load_sensor_chart_data(equipment_id, ["cpu_load"]) memory_chart_data = load_sensor_chart_data(equipment_id, ["memory_usage"]) storage_chart_data = load_sensor_chart_data(equipment_id, ["disk_usage"]) + traffic_chart_data = load_overall_traffic_chart_data(equipment_id) # Filter sensors by type for temperature and voltage temperature_sensors = @@ -77,6 +78,7 @@ defmodule ToweropsWeb.EquipmentLive.Show do |> assign(:cpu_chart_data, cpu_chart_data) |> assign(:memory_chart_data, memory_chart_data) |> assign(:storage_chart_data, storage_chart_data) + |> assign(:traffic_chart_data, traffic_chart_data) |> assign(:temperature_sensors, temperature_sensors) |> assign(:voltage_sensors, voltage_sensors) end @@ -260,4 +262,78 @@ defmodule ToweropsWeb.EquipmentLive.Show do end end end + + defp load_overall_traffic_chart_data(equipment_id) do + case Snmp.get_device_with_associations(equipment_id) do + nil -> + nil + + device -> + if Enum.empty?(device.interfaces) do + nil + else + # Get stats for past 24 hours for all interfaces + twenty_four_hours_ago = DateTime.add(DateTime.utc_now(), -24, :hour) + + # Get all stats for all interfaces + all_stats = + device.interfaces + |> Enum.flat_map(fn interface -> + stats = + interface.id + |> Snmp.get_interface_stats(since: twenty_four_hours_ago, limit: 1000) + |> Enum.reverse() + + Enum.map(stats, fn stat -> + {stat.checked_at, stat.if_in_octets, stat.if_out_octets} + end) + end) + |> Enum.group_by(&elem(&1, 0)) + |> Enum.map(fn {timestamp, stats} -> + total_in = Enum.reduce(stats, 0, fn {_, in_octets, _}, acc -> acc + (in_octets || 0) end) + total_out = Enum.reduce(stats, 0, fn {_, _, out_octets}, acc -> acc + (out_octets || 0) end) + {timestamp, total_in, total_out} + end) + |> Enum.sort_by(&elem(&1, 0), DateTime) + + if Enum.empty?(all_stats) do + nil + else + # Calculate bits per second from counter differences + in_data = + all_stats + |> Enum.chunk_every(2, 1, :discard) + |> Enum.map(fn [{t1, in1, _out1}, {t2, in2, _out2}] -> + time_diff = t2 |> DateTime.diff(t1, :second) |> max(1) + bps = ((in2 - in1) * 8 / time_diff) |> max(0) |> Float.round(2) + + %{ + x: DateTime.to_unix(t2, :millisecond), + y: bps + } + end) + + out_data = + all_stats + |> Enum.chunk_every(2, 1, :discard) + |> Enum.map(fn [{t1, _in1, out1}, {t2, _in2, out2}] -> + time_diff = t2 |> DateTime.diff(t1, :second) |> max(1) + bps = ((out2 - out1) * 8 / time_diff) |> max(0) |> Float.round(2) + + %{ + x: DateTime.to_unix(t2, :millisecond), + y: bps + } + end) + + datasets = [ + %{label: "Inbound", data: in_data}, + %{label: "Outbound", data: out_data} + ] + + Jason.encode!(%{datasets: datasets}) + end + end + end + end end diff --git a/lib/towerops_web/live/equipment_live/show.html.heex b/lib/towerops_web/live/equipment_live/show.html.heex index 65eb8c5e..501529aa 100644 --- a/lib/towerops_web/live/equipment_live/show.html.heex +++ b/lib/towerops_web/live/equipment_live/show.html.heex @@ -70,6 +70,29 @@
<%= case @active_tab do %> <% "overview" -> %> + + <%= if @traffic_chart_data do %> +
+
+

+ Overall Traffic (24 Hours) +

+

+ Combined traffic across all interfaces +

+
+
+
+ +
+
+
+ <% end %>