Skip to content

Commit

Permalink
Add telemetry events
Browse files Browse the repository at this point in the history
  • Loading branch information
svsool committed Sep 11, 2024
1 parent 3f1afbd commit ba5e575
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 2 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
- Remove calls to deprecated `Logger.warn/2`
- Correct misspell of 'Empd' -> 'Epmd' in `Cluster.Strategy.LocalEpmd` moduledoc

## 3.4.0

### Added

- Telemetry events added for tracking node connects and disconnects

### 3.3.0

### Changed
Expand Down
46 changes: 46 additions & 0 deletions lib/strategy/strategy.ex
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,36 @@ defmodule Cluster.Strategy do
fargs = connect_args ++ [n]
ensure_exported!(connect_mod, connect_fun, length(fargs))

start = System.monotonic_time()

case apply(connect_mod, connect_fun, fargs) do
true ->
:telemetry.execute(
[:libcluster, :connect_node, :ok],
%{duration: System.monotonic_time() - start},
%{node: n, topology: topology}
)

Cluster.Logger.info(topology, "connected to #{inspect(n)}")
acc

false ->
:telemetry.execute(
[:libcluster, :connect_node, :error],
%{},
%{node: n, topology: topology, reason: :unreachable}
)

Cluster.Logger.warn(topology, "unable to connect to #{inspect(n)}")
[{n, false} | acc]

:ignored ->
:telemetry.execute(
[:libcluster, :connect_node, :error],
%{},
%{node: n, topology: topology, reason: :not_part_of_network}
)

Cluster.Logger.warn(
topology,
"unable to connect to #{inspect(n)}: not part of network"
Expand Down Expand Up @@ -100,12 +120,26 @@ defmodule Cluster.Strategy do
fargs = disconnect_args ++ [n]
ensure_exported!(disconnect_mod, disconnect_fun, length(fargs))

start = System.monotonic_time()

case apply(disconnect_mod, disconnect_fun, fargs) do
true ->
:telemetry.execute(
[:libcluster, :disconnect_node, :ok],
%{duration: System.monotonic_time() - start},
%{node: n, topology: topology}
)

Cluster.Logger.info(topology, "disconnected from #{inspect(n)}")
acc

false ->
:telemetry.execute(
[:libcluster, :disconnect_node, :error],
%{},
%{node: n, topology: topology, reason: :already_disconnected}
)

Cluster.Logger.warn(
topology,
"disconnect from #{inspect(n)} failed because we're already disconnected"
Expand All @@ -114,6 +148,12 @@ defmodule Cluster.Strategy do
acc

:ignored ->
:telemetry.execute(
[:libcluster, :disconnect_node, :error],
%{},
%{node: n, topology: topology, reason: :not_part_of_network}
)

Cluster.Logger.warn(
topology,
"disconnect from #{inspect(n)} failed because it is not part of the network"
Expand All @@ -122,6 +162,12 @@ defmodule Cluster.Strategy do
acc

reason ->
:telemetry.execute(
[:libcluster, :disconnect_node, :error],
%{},
%{node: n, topology: topology, reason: inspect(reason)}
)

Cluster.Logger.warn(
topology,
"disconnect from #{inspect(n)} failed with: #{inspect(reason)}"
Expand Down
5 changes: 3 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Cluster.Mixfile do
use Mix.Project

@version "3.3.3"
@version "3.4.0"
@source_url "https://github.com/bitwalker/libcluster"

def project do
Expand Down Expand Up @@ -40,7 +40,8 @@ defmodule Cluster.Mixfile do
{:ex_doc, ">= 0.0.0", only: :dev, runtime: false},
{:dialyxir, "~> 1.0", only: :dev, runtime: false},
{:exvcr, "~> 0.11", only: :test, runtime: false},
{:jason, "~> 1.1"}
{:jason, "~> 1.1"},
{:telemetry, "~> 1.3"}
]
end

Expand Down
1 change: 1 addition & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
"makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"},
"meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
"nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
}
31 changes: 31 additions & 0 deletions test/strategy_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ defmodule Cluster.StrategyTest do

alias Cluster.Strategy
alias Cluster.Nodes
alias Cluster.Telemetry

require Cluster.Nodes

Expand All @@ -24,36 +25,54 @@ defmodule Cluster.StrategyTest do
connect = {Nodes, :connect, [self()]}
list_nodes = {Nodes, :list_nodes, [[Node.self()]]}

Telemetry.setup_telemetry([:libcluster, :connect_node, :ok])

assert capture_log(fn ->
assert :ok =
Strategy.connect_nodes(__MODULE__, connect, list_nodes, [:"foo@some.host"])
end) =~ "connected to :\"foo@some.host\""

assert_receive {:connect, :"foo@some.host"}

assert_receive {:telemetry_event,
{[:libcluster, :connect_node, :ok], %{duration: _},
%{node: :"foo@some.host", topology: _}, _}}
end

test "handles connect failure" do
connect = {Nodes, :connect, [self(), false]}
list_nodes = {Nodes, :list_nodes, [[Node.self()]]}

Telemetry.setup_telemetry([:libcluster, :connect_node, :error])

assert capture_log(fn ->
assert {:error, ["foo@some.host": false]} =
Strategy.connect_nodes(__MODULE__, connect, list_nodes, [:"foo@some.host"])
end) =~ "unable to connect to :\"foo@some.host\""

assert_receive {:connect, :"foo@some.host"}

assert_receive {:telemetry_event,
{[:libcluster, :connect_node, :error], %{},
%{node: :"foo@some.host", topology: _, reason: :unreachable}, _}}
end

test "handles connect ignore" do
connect = {Nodes, :connect, [self(), :ignored]}
list_nodes = {Nodes, :list_nodes, [[Node.self()]]}

Telemetry.setup_telemetry([:libcluster, :connect_node, :error])

assert capture_log(fn ->
assert {:error, ["foo@some.host": :ignored]} =
Strategy.connect_nodes(__MODULE__, connect, list_nodes, [:"foo@some.host"])
end) =~ "unable to connect to :\"foo@some.host\""

assert_receive {:connect, :"foo@some.host"}

assert_receive {:telemetry_event,
{[:libcluster, :connect_node, :error], %{},
%{node: :"foo@some.host", topology: _, reason: :not_part_of_network,}, _}}
end
end

Expand All @@ -71,6 +90,8 @@ defmodule Cluster.StrategyTest do
disconnect = {Nodes, :disconnect, [self()]}
list_nodes = {Nodes, :list_nodes, [[:"foo@some.host"]]}

Telemetry.setup_telemetry([:libcluster, :disconnect_node, :ok])

assert capture_log(fn ->
assert :ok =
Strategy.disconnect_nodes(__MODULE__, disconnect, list_nodes, [
Expand All @@ -79,12 +100,18 @@ defmodule Cluster.StrategyTest do
end) =~ "disconnected from :\"foo@some.host\""

assert_receive {:disconnect, :"foo@some.host"}

assert_receive {:telemetry_event,
{[:libcluster, :disconnect_node, :ok], %{duration: _},
%{node: :"foo@some.host", topology: _}, _}}
end

test "handles disconnect error" do
disconnect = {Nodes, :disconnect, [self(), :failed]}
list_nodes = {Nodes, :list_nodes, [[:"foo@some.host"]]}

Telemetry.setup_telemetry([:libcluster, :disconnect_node, :error])

assert capture_log(fn ->
assert {:error, ["foo@some.host": :failed]} =
Strategy.disconnect_nodes(__MODULE__, disconnect, list_nodes, [
Expand All @@ -94,6 +121,10 @@ defmodule Cluster.StrategyTest do
"disconnect from :\"foo@some.host\" failed with: :failed"

assert_receive {:disconnect, :"foo@some.host"}

assert_receive {:telemetry_event,
{[:libcluster, :disconnect_node, :error], %{},
%{node: :"foo@some.host", topology: _, reason: ":failed"}, _}}
end
end
end
26 changes: 26 additions & 0 deletions test/support/telemetry.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule Cluster.Telemetry do
@moduledoc false

use ExUnit.Case

def setup_telemetry(event) do
telemetry_handle_id = "test-telemetry-handler-#{inspect(self())}"

:ok = :telemetry.attach_many(
telemetry_handle_id,
[
event,
],
&send_to_pid/4,
nil
)

:ok = on_exit(fn -> :telemetry.detach(telemetry_handle_id) end)
end

defp send_to_pid(event, measurements, metadata, config) do
pid = config[:pid] || self()

send(pid, {:telemetry_event, {event, measurements, metadata, config}})
end
end

0 comments on commit ba5e575

Please sign in to comment.