fix: add detailed error logging for ARP upsert failures

Previously just logged a count without any details, making debugging
impossible. Now logs first 3 sample errors with IP, MAC, and validation
errors to help identify root cause.

Sample output:
  290 ARP upsert failures for device X
  sample_errors: [
    %{ip: nil, mac: "00:11:22:33:44:55", errors: %{ip_address: ["can't be blank"]}},
    %{ip: "10.0.0.1", mac: nil, errors: %{mac_address: ["can't be blank"]}},
    ...
  ]
This commit is contained in:
Graham McIntire 2026-03-10 14:46:45 -05:00
parent bbb5f886ec
commit 3e70f0ba48
No known key found for this signature in database

View file

@ -1858,6 +1858,26 @@ defmodule Towerops.Snmp do
end)
end
# Helper to format changeset errors for logging
defp format_changeset_errors(changeset) do
Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end)
end
# Helper to collect error samples (first N errors for debugging)
defp maybe_add_error_sample(error_count, samples, attrs, changeset, max_samples \\ 3) do
if error_count < max_samples do
error_details = %{
ip: Map.get(attrs, :ip_address),
mac: Map.get(attrs, :mac_address),
errors: format_changeset_errors(changeset)
}
[error_details | samples]
else
samples
end
end
@doc """
Bulk upserts ARP entries for a device.
Returns `{success_count, error_count}` tuple.
@ -1866,7 +1886,7 @@ defmodule Towerops.Snmp do
interface_map = Map.new(interfaces, fn i -> {i.if_index, i.id} end)
arp_entries
|> Enum.reduce({0, 0}, fn entry, {s, e} ->
|> Enum.reduce({0, 0, []}, fn entry, {s, e, error_samples} ->
interface_id = Map.get(interface_map, entry.if_index)
attrs =
@ -1875,18 +1895,25 @@ defmodule Towerops.Snmp do
|> Map.put(:interface_id, interface_id)
case upsert_arp_entry(attrs) do
{:ok, _} -> {s + 1, e}
{:error, _} -> {s, e + 1}
{:ok, _} ->
{s + 1, e, error_samples}
{:error, changeset} ->
# Sample first 3 errors for debugging
sample = maybe_add_error_sample(e, error_samples, attrs, changeset)
{s, e + 1, sample}
end
end)
|> tap(fn {_s, errors} ->
|> tap(fn {_s, errors, error_samples} ->
if errors > 0 do
Logger.warning("#{errors} ARP upsert failures for device #{device_id}",
device_id: device_id,
error_count: errors
error_count: errors,
sample_errors: Enum.reverse(error_samples)
)
end
end)
|> then(fn {s, e, _samples} -> {s, e} end)
end
# MAC Address queries