Skip to content

[Experimental] Use :socket API #103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions lib/telemetry_metrics_statsd.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 39 additions & 31 deletions lib/telemetry_metrics_statsd/udp.ex
Original file line number Diff line number Diff line change
@@ -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 :: %{
Expand All @@ -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}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Figure out how to do updates for a connected socket. I suppose the only option is to reconnect?

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
2 changes: 1 addition & 1 deletion test/telemetry_metrics_statsd_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@
new_udp != udp
end)

assert :gen_udp.recv(udp.socket, 0) == {:error, :closed}
assert :socket.recv(udp.socket, 0) == {:error, :closed}
end
end

Expand Down Expand Up @@ -647,7 +647,7 @@
assert_reported(socket, "http.requests:1|c")
end

test "IPv6 end-to-end test" do

Check failure on line 650 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.12.0 (OTP 24)

test IPv6 end-to-end test (TelemetryMetricsStatsdTest)

Check failure on line 650 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.13.4 (OTP 24.3)

test IPv6 end-to-end test (TelemetryMetricsStatsdTest)

Check failure on line 650 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.14.5 (OTP 25.3)

test IPv6 end-to-end test (TelemetryMetricsStatsdTest)

Check failure on line 650 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.15.4 (OTP 26)

test IPv6 end-to-end test (TelemetryMetricsStatsdTest)

Check failure on line 650 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.16.3 (OTP 26.2)

test IPv6 end-to-end test (TelemetryMetricsStatsdTest)
{socket, port} = given_udp_port_opened(:inet6)
counter = given_counter("http.requests", event_name: "http.request")

Expand All @@ -659,7 +659,7 @@
end

describe "hostname resolution" do
test "is performed on start by default" do

Check failure on line 662 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.12.0 (OTP 24)

test hostname resolution is performed on start by default (TelemetryMetricsStatsdTest)

Check failure on line 662 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.13.4 (OTP 24.3)

test hostname resolution is performed on start by default (TelemetryMetricsStatsdTest)

Check failure on line 662 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.14.5 (OTP 25.3)

test hostname resolution is performed on start by default (TelemetryMetricsStatsdTest)

Check failure on line 662 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.15.4 (OTP 26)

test hostname resolution is performed on start by default (TelemetryMetricsStatsdTest)

Check failure on line 662 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.16.3 (OTP 26.2)

test hostname resolution is performed on start by default (TelemetryMetricsStatsdTest)
counter = given_counter("http.request.count")

reporter =
Expand All @@ -674,7 +674,7 @@
assert udp.host == {127, 0, 0, 1}
end

test "Supports IPv6" do

Check failure on line 677 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.12.0 (OTP 24)

test hostname resolution Supports IPv6 (TelemetryMetricsStatsdTest)

Check failure on line 677 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.13.4 (OTP 24.3)

test hostname resolution Supports IPv6 (TelemetryMetricsStatsdTest)

Check failure on line 677 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.14.5 (OTP 25.3)

test hostname resolution Supports IPv6 (TelemetryMetricsStatsdTest)

Check failure on line 677 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.15.4 (OTP 26)

test hostname resolution Supports IPv6 (TelemetryMetricsStatsdTest)

Check failure on line 677 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.16.3 (OTP 26.2)

test hostname resolution Supports IPv6 (TelemetryMetricsStatsdTest)
counter = given_counter("http.request.count")

reporter =
Expand All @@ -690,7 +690,7 @@
assert udp.host == {0, 0, 0, 0, 0, 0, 0, 1}
end

test "is not periodically repeated by default" do

Check failure on line 693 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.12.0 (OTP 24)

test hostname resolution is not periodically repeated by default (TelemetryMetricsStatsdTest)

Check failure on line 693 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.13.4 (OTP 24.3)

test hostname resolution is not periodically repeated by default (TelemetryMetricsStatsdTest)

Check failure on line 693 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.14.5 (OTP 25.3)

test hostname resolution is not periodically repeated by default (TelemetryMetricsStatsdTest)

Check failure on line 693 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.15.4 (OTP 26)

test hostname resolution is not periodically repeated by default (TelemetryMetricsStatsdTest)

Check failure on line 693 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.16.3 (OTP 26.2)

test hostname resolution is not periodically repeated by default (TelemetryMetricsStatsdTest)
counter = given_counter("http.request.count")

reporter =
Expand All @@ -714,7 +714,7 @@
end
end

test "is periodically repeated if configured" do

Check failure on line 717 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.12.0 (OTP 24)

test hostname resolution is periodically repeated if configured (TelemetryMetricsStatsdTest)

Check failure on line 717 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.13.4 (OTP 24.3)

test hostname resolution is periodically repeated if configured (TelemetryMetricsStatsdTest)

Check failure on line 717 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.14.5 (OTP 25.3)

test hostname resolution is periodically repeated if configured (TelemetryMetricsStatsdTest)

Check failure on line 717 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.15.4 (OTP 26)

test hostname resolution is periodically repeated if configured (TelemetryMetricsStatsdTest)

Check failure on line 717 in test/telemetry_metrics_statsd_test.exs

View workflow job for this annotation

GitHub Actions / Test on Elixir 1.16.3 (OTP 26.2)

test hostname resolution is periodically repeated if configured (TelemetryMetricsStatsdTest)
counter = given_counter("http.request.count")

reporter =
Expand Down
Loading