diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fcdd03b..6927b83 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -45,6 +45,8 @@ jobs: elixir: 1.14.5 - otp: 26.0 elixir: 1.15.4 + - otp: 26.2 + elixir: 1.16.3 steps: - uses: actions/checkout@v2 - uses: erlef/setup-beam@v1 diff --git a/lib/telemetry_metrics_statsd.ex b/lib/telemetry_metrics_statsd.ex index 9ca8821..948b2f1 100644 --- a/lib/telemetry_metrics_statsd.ex +++ b/lib/telemetry_metrics_statsd.ex @@ -410,6 +410,10 @@ defmodule TelemetryMetricsStatsd do @doc false @spec udp_error(pid(), UDP.t(), reason :: term) :: :ok + def udp_error(_reporter, _udp, :eagain) do + :ok + end + def udp_error(reporter, udp, reason) do GenServer.cast(reporter, {:udp_error, udp, reason}) end diff --git a/lib/telemetry_metrics_statsd/udp.ex b/lib/telemetry_metrics_statsd/udp.ex index 31198f8..7413e91 100644 --- a/lib/telemetry_metrics_statsd/udp.ex +++ b/lib/telemetry_metrics_statsd/udp.ex @@ -1,12 +1,10 @@ defmodule TelemetryMetricsStatsd.UDP do @moduledoc false - defstruct [:host, :port, :socket] + defstruct [:socket] @opaque t :: %__MODULE__{ - host: :inet.hostname() | :inet.ip_address() | :inet.local_address(), - port: :inet.port_number(), - socket: :gen_udp.socket() + socket: :socket.socket() } @type config :: %{ @@ -18,43 +16,53 @@ defmodule TelemetryMetricsStatsd.UDP do @spec open(config()) :: {:ok, t()} | {:error, reason :: term()} def open(config) do - opts = [{:active, false}] - - opts = - Enum.reduce(config, opts, fn - {:host, {:local, _}}, opts -> [:local | opts] - {:inet_address_family, value}, opts -> [value | opts] - {_key, _value}, opts -> opts - end) - - case :gen_udp.open(0, opts) do - {:ok, socket} -> - udp = struct(__MODULE__, Map.put(config, :socket, socket)) - {:ok, udp} - - {:error, _} = err -> - err + {domain, address} = + case config.host do + {:local, path} -> + {:local, %{family: :local, path: path}} + + ip when tuple_size(ip) == 4 -> + {:inet, %{family: :inet, port: config.port, addr: ip}} + + ip when tuple_size(ip) == 8 -> + {:inet, %{family: :inet6, port: config.port, addr: ip}} + end + + with {:ok, socket} <- :socket.open(domain, :dgram), + :ok <- :socket.connect(socket, address) do + udp = struct(__MODULE__, Map.put(config, :socket, socket)) + {:ok, udp} end end @spec send(t(), iodata()) :: :ok | {:error, reason :: term()} - def send(%__MODULE__{host: host, port: port, socket: socket}, data) do - case host do - {:local, _} -> - :gen_udp.send(socket, host, 0, data) - - _ -> - :gen_udp.send(socket, host, port, data) - end + def send(%__MODULE__{socket: socket}, data) do + :socket.send(socket, data) + |> handle_send_result() end @spec update(t(), :inet.hostname() | :inet.ip_address(), :inet.port_number()) :: t() - def update(%__MODULE__{} = udp, new_host, new_port) do - %__MODULE__{udp | host: new_host, port: new_port} + def update(%__MODULE__{} = udp, _new_host, _new_port) do + #%__MODULE__{udp | host: new_host, port: new_port} + udp end @spec close(t()) :: :ok def close(%__MODULE__{socket: socket}) do - :gen_udp.close(socket) + :socket.close(socket) + end + + defp handle_send_result({:error, :eagain}) do + # TODO: report packed drop? + :ok + end + + defp handle_send_result({:error, :econnrefused}) do + # TODO: report packed drop? + :ok + end + + defp handle_send_result(result) do + result end end diff --git a/test/telemetry_metrics_statsd_test.exs b/test/telemetry_metrics_statsd_test.exs index ca80d08..24146d4 100644 --- a/test/telemetry_metrics_statsd_test.exs +++ b/test/telemetry_metrics_statsd_test.exs @@ -431,7 +431,7 @@ defmodule TelemetryMetricsStatsdTest do new_udp != udp end) - assert :gen_udp.recv(udp.socket, 0) == {:error, :closed} + assert :socket.recv(udp.socket, 0) == {:error, :closed} end end