Skip to content

Commit 8d89038

Browse files
committed
✨ Log system cpu and memory on a cadence
1 parent b97f4ce commit 8d89038

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

lib/sequin/application.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ defmodule Sequin.Application do
7171
Sequin.Sinks.Nats.ConnectionCache,
7272
Sequin.Sinks.RabbitMq.ConnectionCache,
7373
SequinWeb.Presence,
74+
Sequin.SystemMetricsServer,
7475
# Sequin.Tracer.DynamicSupervisor,
7576
{Cluster.Supervisor, [topologies]},
7677
{Task, fn -> enqueue_workers() end},
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
defmodule Sequin.SystemMetricsServer do
2+
@moduledoc false
3+
use GenServer
4+
5+
require Logger
6+
7+
@interval :timer.seconds(30)
8+
9+
def start_link(_opts) do
10+
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
11+
end
12+
13+
def init(state) do
14+
# Print metrics immediately on start
15+
schedule_log()
16+
log_metrics()
17+
{:ok, state}
18+
end
19+
20+
def handle_info(:log_metrics, state) do
21+
log_metrics()
22+
schedule_log()
23+
{:noreply, state}
24+
end
25+
26+
defp schedule_log do
27+
Process.send_after(self(), :log_metrics, @interval)
28+
end
29+
30+
defp log_metrics do
31+
memory_info = :erlang.memory()
32+
cpu_load = cpu_load()
33+
34+
Logger.info(
35+
"""
36+
[SystemMetricsServer]
37+
CPU Load: #{format_cpu_load(cpu_load)}
38+
Memory Total: #{format_bytes(memory_info[:total])}
39+
Processes: #{format_bytes(memory_info[:processes])}
40+
Atoms: #{format_bytes(memory_info[:atom])}
41+
Binary: #{format_bytes(memory_info[:binary])}
42+
Code: #{format_bytes(memory_info[:code])}
43+
ETS: #{format_bytes(memory_info[:ets])}
44+
""",
45+
cpu_load: cpu_load,
46+
memory_total_bytes: memory_info[:total],
47+
memory_processes_bytes: memory_info[:processes],
48+
memory_atoms_bytes: memory_info[:atom],
49+
memory_binary_bytes: memory_info[:binary],
50+
memory_code_bytes: memory_info[:code],
51+
memory_ets_bytes: memory_info[:ets]
52+
)
53+
end
54+
55+
defp format_bytes(bytes) when is_integer(bytes) do
56+
cond do
57+
bytes >= 1_000_000_000 -> "#{Float.round(bytes / 1_000_000_000, 2)} GB"
58+
bytes >= 1_000_000 -> "#{Float.round(bytes / 1_000_000, 2)} MB"
59+
bytes >= 1_000 -> "#{Float.round(bytes / 1_000, 2)} KB"
60+
true -> "#{bytes} B"
61+
end
62+
end
63+
64+
defp cpu_load do
65+
case :cpu_sup.util() do
66+
{:error, _reason} -> nil
67+
util when is_float(util) -> util
68+
end
69+
end
70+
71+
defp format_cpu_load(nil), do: "Not available"
72+
defp format_cpu_load(util), do: "#{Float.round(util, 2)}%"
73+
end

0 commit comments

Comments
 (0)