Skip to content
Merged
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
46 changes: 2 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,50 +212,8 @@ shackle_pool:start(pool_name(), client(), client_options(), pool_options())
{ok, <<"bar">>}
```

## Environment variables

<table width="100%">
<theader>
<th>Name</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</theader>
<tr>
<td>hooks</td>
<td>[{atom(), {module(), atom()}}]</td>
<td>[]</td>
<td>used to receive events/metrics about your client</td>
</tr>
</table>

## Hooks
Hooks allow you to receive events and metrics about your client. To do so you need to implement the `shackle_hooks` behaviour and then use the `hooks` environment variable.

```erlang
-module(my_client_hooks).

-behaviour(shackle_hooks).
-export([
metrics/4
]).

metrics(Client, counter, Key, Value) ->
statsderl:increment(key(Client, Key), Value, 0.005);
metrics(Client, timing, Key, Value) ->
statsderl:timing(key(Client, Key), Value, 0.005).

key(Client, Key) ->
[<<"shackle.">>, atom_to_binary(Client, latin1), <<".">>, Key].
```

```erlang
{shackle, [
{hooks, [
{metrics {my_client_hooks, metrics}}
]}
]}
```
## Telemetry
Shackle integrates with the backend-agnostic [telemetry](https://hexdocs.pm/telemetry/) library. See `shackle_telemetry` for the list of telemetry events that shackle can emit.

## Tests

Expand Down
2 changes: 0 additions & 2 deletions include/shackle_internal.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
-define(GET_ENV(Key, Default), application:get_env(?APP, Key, Default)).
-define(LOOKUP(Key, List), ?LOOKUP(Key, List, undefined)).
-define(LOOKUP(Key, List, Default), shackle_utils:lookup(Key, List, Default)).
-define(METRICS(Client, Type, Key), shackle_hooks:metrics(Client, Type, Key, 1)).
-define(METRICS(Client, Type, Key, Value), shackle_hooks:metrics(Client, Type, Key, Value)).
-define(MSG_CONNECT, connect).
-define(SERVER, shackle_server).
-define(SUPERVISOR, shackle_sup).
Expand Down
3 changes: 2 additions & 1 deletion rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
{deps, [
{foil, "0.1.3"},
{granderl, {git, "https://github.com/tokenrove/granderl.git", {ref, "baafd1bc825cb1fc022760eae913f774fa6af91b"}}},
{metal, "0.1.1"}
{metal, "0.1.1"},
{telemetry, "1.2.1"}
]}.

{dialyzer, [{plt_extra_apps, [public_key]}]}.
Expand Down
9 changes: 6 additions & 3 deletions rebar.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
{git,"https://github.com/tokenrove/granderl.git",
{ref,"baafd1bc825cb1fc022760eae913f774fa6af91b"}},
0},
{<<"metal">>,{pkg,<<"metal">>,<<"0.1.1">>},0}]}.
{<<"metal">>,{pkg,<<"metal">>,<<"0.1.1">>},0},
{<<"telemetry">>,{pkg,<<"telemetry">>,<<"1.2.1">>},0}]}.
[
{pkg_hash,[
{<<"foil">>, <<"415835CA94A8D0A55AB3D334FE2D1A1DCF36E7A0F69789050765770B6BF5E6E9">>},
{<<"metal">>, <<"5D3D1322DA7BCD34B94FED5486F577973685298883954F7A3E517EF5EF6953F5">>}]},
{<<"metal">>, <<"5D3D1322DA7BCD34B94FED5486F577973685298883954F7A3E517EF5EF6953F5">>},
{<<"telemetry">>, <<"68FDFE8D8F05A8428483A97D7AAB2F268AAFF24B49E0F599FAA091F1D4E7F61C">>}]},
{pkg_hash_ext,[
{<<"foil">>, <<"3A1CC0939075D7E26F8ED9983839E2E9CE4B2AE301110F7DF5A6EDA544FCD125">>},
{<<"metal">>, <<"88B82B634998A1A768DEDCD372C2F7E657B19445325C0AF5CCBAC62C77210F1D">>}]}
{<<"metal">>, <<"88B82B634998A1A768DEDCD372C2F7E657B19445325C0AF5CCBAC62C77210F1D">>},
{<<"telemetry">>, <<"DAD9CE9D8EFFC621708F99EAC538EF1CBE05D6A874DD741DE2E689C47FEAFED5">>}]}
].
2 changes: 1 addition & 1 deletion src/shackle.app.src
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{application, shackle, [
{applications, [kernel, stdlib, granderl, metal, foil, ssl]},
{applications, [kernel, stdlib, granderl, metal, foil, ssl, telemetry]},
{description, "High-Performance Erlang Network Client Framework"},
{env, []},
{licenses, ["MIT"]},
Expand Down
44 changes: 0 additions & 44 deletions src/shackle_hooks.erl

This file was deleted.

6 changes: 3 additions & 3 deletions src/shackle_pool.erl
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ server(_Name, #pool_options {
client = Client
}, 0) ->

?METRICS(Client, counter, <<"no_server">>),
shackle_telemetry:no_server(Client),
{error, no_server};
server(Name, #pool_options {
backlog_size = BacklogSize,
Expand All @@ -157,11 +157,11 @@ server(Name, #pool_options {
true ->
{ok, Client, ServerName};
false ->
?METRICS(Client, counter, <<"backlog_full">>),
shackle_telemetry:backlog_full(Client),
server(Name, Options, N - 1)
end;
false ->
?METRICS(Client, counter, <<"disabled">>),
shackle_telemetry:disabled(Client),
server(Name, Options, N - 1)
end.

Expand Down
16 changes: 8 additions & 8 deletions src/shackle_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ handle_msg({Request, #cast {
{ok, ExtRequestId, Data, ClientState2} ->
case Protocol:send(Socket, Data) of
ok ->
?METRICS(Client, counter, <<"send">>),
shackle_telemetry:send(Client, size(Data)),
case ExtRequestId of
undefined ->
reply(ok, Cast, State);
Expand Down Expand Up @@ -184,7 +184,7 @@ handle_msg({timeout, ExtRequestId}, {#state {
true ->
try Client:handle_timeout(ExtRequestId, ClientState) of
{ok, Reply, ClientState2} ->
?METRICS(Client, counter, <<"handle_timeout">>),
shackle_telemetry:handle_timeout(Client),
process_responses([Reply], State),
{ok, {State, ClientState2}};
{error, Reason, ClientState2} ->
Expand All @@ -201,7 +201,7 @@ handle_msg({timeout, ExtRequestId}, {#state {
false ->
case shackle_queue:remove(Queue, Id, ExtRequestId) of
{ok, Cast, _TimerRef} ->
?METRICS(Client, counter, <<"timeout">>),
shackle_telemetry:timeout(Client),
reply({error, timeout}, Cast, State);
{error, not_found} ->
ok
Expand Down Expand Up @@ -325,7 +325,7 @@ handle_msg_data(Socket, Data, #state {
socket = Socket
} = State, ClientState) ->

?METRICS(Client, counter, <<"recv">>),
shackle_telemetry:recv(Client, size(Data)),
try Client:handle_data(Data, ClientState) of
{ok, Replies, ClientState2} ->
process_responses(Replies, State),
Expand Down Expand Up @@ -364,16 +364,16 @@ process_responses([{ExtRequestId, Reply} | T], #state {
queue = Queue
} = State) ->

?METRICS(Client, counter, <<"replies">>),
shackle_telemetry:replies(Client),
case shackle_queue:remove(Queue, Id, ExtRequestId) of
{ok, #cast {timestamp = Timestamp} = Cast, TimerRef} ->
?METRICS(Client, counter, <<"found">>),
shackle_telemetry:found(Client),
Diff = timer:now_diff(os:timestamp(), Timestamp),
?METRICS(Client, timing, <<"reply">>, Diff),
shackle_telemetry:reply(Client, Diff),
erlang:cancel_timer(TimerRef),
reply(Reply, Cast, State);
{error, not_found} ->
?METRICS(Client, counter, <<"not_found">>, 1),
shackle_telemetry:not_found(Client),
ok
end,
process_responses(T, State).
Expand Down
1 change: 0 additions & 1 deletion src/shackle_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ start_link() ->
{ok, {{one_for_one, 5, 10}, [supervisor:child_spec()]}}.

init([]) ->
shackle_hooks:init(),
shackle_pool:init(),
shackle_status:init(),

Expand Down
85 changes: 85 additions & 0 deletions src/shackle_telemetry.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
-module(shackle_telemetry).
-include("shackle_internal.hrl").

-compile(inline).
-compile({inline_size, 512}).

-export([
backlog_full/1,
disabled/1,
found/1,
handle_timeout/1,
no_server/1,
not_found/1,
recv/2,
replies/1,
reply/2,
send/2,
timeout/1
]).

-spec backlog_full(client()) -> ok.
backlog_full(Client) ->
Measurements = #{count => 1},
Metadata = #{client => Client},
telemetry:execute([shackle, backlog_full], Measurements, Metadata).

-spec disabled(client()) -> ok.
disabled(Client) ->
Measurements = #{count => 1},
Metadata = #{client => Client},
telemetry:execute([shackle, disabled], Measurements, Metadata).

-spec found(client()) -> ok.
found(Client) ->
Measurements = #{count => 1},
Metadata = #{client => Client},
telemetry:execute([shackle, found], Measurements, Metadata).

-spec handle_timeout(client()) -> ok.
handle_timeout(Client) ->
Measurements = #{count => 1},
Metadata = #{client => Client},
telemetry:execute([shackle, handle_timeout], Measurements, Metadata).

-spec no_server(client()) -> ok.
no_server(Client) ->
Measurements = #{count => 1},
Metadata = #{client => Client},
telemetry:execute([shackle, no_server], Measurements, Metadata).

-spec not_found(client()) -> ok.
not_found(Client) ->
Measurements = #{count => 1},
Metadata = #{client => Client},
telemetry:execute([shackle, not_found], Measurements, Metadata).

-spec recv(client(), non_neg_integer()) -> ok.
recv(Client, NBytes) ->
Measurements = #{count => 1, bytes => NBytes},
Metadata = #{client => Client},
telemetry:execute([shackle, recv], Measurements, Metadata).

-spec replies(client()) -> ok.
replies(Client) ->
Measurements = #{count => 1},
Metadata = #{client => Client},
telemetry:execute([shackle, replies], Measurements, Metadata).

-spec reply(client(), non_neg_integer()) -> ok.
reply(Client, Microseconds) ->
Measurements = #{duration => Microseconds},
Metadata = #{client => Client},
telemetry:execute([shackle, reply], Measurements, Metadata).

-spec send(client(), non_neg_integer()) -> ok.
send(Client, NBytes) ->
Measurements = #{count => 1, bytes => NBytes},
Metadata = #{client => Client},
telemetry:execute([shackle, send], Measurements, Metadata).

-spec timeout(client()) -> ok.
timeout(Client) ->
Measurements = #{count => 1},
Metadata = #{client => Client},
telemetry:execute([shackle, timeout], Measurements, Metadata).