Current section

Files

Jump to
slipstream lib slipstream telemetry_helper.ex
Raw

lib/slipstream/telemetry_helper.ex

defmodule Slipstream.TelemetryHelper do
@moduledoc false
@moduledoc since: "0.4.0"
alias Slipstream.{Socket, Events}
@doc since: "0.4.0"
def id(length \\ 16) do
length
|> :crypto.strong_rand_bytes()
|> Base.encode16()
|> binary_part(0, length)
|> String.downcase()
end
@doc since: "0.4.0"
def trace_id, do: id(32)
@doc """
Emits a start event for an attempt to connect
Emitted in cases of a client using `Slipstream.connect/2`,
`Slipstream.connect!/2` or `Slipstream.reconnect/1`.
"""
@doc since: "0.4.0"
@spec begin_connect(Socket.t(), Slipstream.Configuration.t()) :: Socket.t()
def begin_connect(socket, config) do
metadata = %{
start_time: DateTime.utc_now(),
start_time_monotonic: :erlang.monotonic_time(),
configuration: config,
socket: socket
}
:telemetry.execute(
[:slipstream, :client, :connect, :start],
%{system_time: :erlang.system_time()},
Map.delete(metadata, :start_time_monotonic)
)
put_in(socket, [Access.key(:metadata), :connect], metadata)
end
@doc """
Emits a stop event for an attempt to connect
Emitted when the connection process tells the client that it has successfully
connected with a `Slipstream.Events.ChannelConnected` event.
"""
@doc since: "0.4.0"
@spec conclude_connect(Socket.t(), %Events.ChannelConnected{}) :: Socket.t()
def conclude_connect(%{metadata: %{connect: start_metadata}} = socket, event)
when is_map(start_metadata) and map_size(start_metadata) > 0 do
metadata =
start_metadata
|> Map.merge(%{
response_headers: event.response_headers,
socket: socket
})
|> Map.delete(:start_time_monotonic)
duration = :erlang.monotonic_time() - start_metadata.start_time_monotonic
:telemetry.execute(
[:slipstream, :client, :connect, :stop],
%{duration: duration},
metadata
)
%Socket{socket | metadata: Map.delete(socket.metadata, :connect)}
end
# technically speaking this case doesn't make any sense... you need to connect
# in order to conclude connecting, but /shrug just putting it here to not
# crash over some spilled telemetry
# coveralls-ignore-start
def conclude_connect(socket, _event), do: socket
# coveralls-ignore-stop
# YARD emit exception event for failure to connect and another when failed to
# join?
@doc """
Emits a start event for an attempt to join
Emitted in cases of a client using `Slipstream.join/3` or
`Slipstream.rejoin/3`.
"""
@doc since: "0.4.0"
@spec begin_join(
Socket.t(),
topic :: String.t(),
params :: Slipstream.json_serializable()
) :: Socket.t()
def begin_join(socket, topic, params) do
metadata = %{
start_time: DateTime.utc_now(),
start_time_monotonic: :erlang.monotonic_time(),
socket: socket,
topic: topic,
params: params
}
:telemetry.execute(
[:slipstream, :client, :join, :start],
%{system_time: :erlang.system_time()},
Map.delete(metadata, :start_time_monotonic)
)
put_in(socket, [Access.key(:metadata), :joins, topic], metadata)
end
@doc """
Emits a stop event for an attempt to join
Emitted when the connection process tells the client that it has successfully
connected with a `Slipstream.Events.TopicJoinSucceeded` event.
"""
@doc since: "0.4.0"
@spec conclude_join(Socket.t(), %Events.TopicJoinSucceeded{}) :: Socket.t()
def conclude_join(socket, event) do
case Map.fetch(socket.metadata.joins, event.topic) do
{:ok, start_metadata} ->
metadata =
start_metadata
|> Map.merge(%{
socket: socket,
response: event.response
})
|> Map.delete(:start_time_monotonic)
duration =
:erlang.monotonic_time() - start_metadata.start_time_monotonic
:telemetry.execute(
[:slipstream, :client, :join, :stop],
%{duration: duration},
metadata
)
update_in(
socket,
[Access.key(:metadata), :joins],
&Map.delete(&1, event.topic)
)
:error ->
# again, this doesn't make sense, but I'd rather not crash if I'm wrong
# coveralls-ignore-start
socket
# coveralls-ignore-stop
end
end
@doc """
Wraps a callback dispatch to a Slipstream client module
"""
@doc since: "0.4.0"
def wrap_dispatch(module, function, args, func) do
metadata = %{
client: module,
callback: function,
arguments: args,
socket: List.last(args),
start_time: DateTime.utc_now()
}
return_value =
:telemetry.span(
[:slipstream, :client, function],
metadata,
fn ->
return = func.()
metadata =
Map.merge(metadata, %{
return: return
})
{return, metadata}
end
)
return_value
end
end