Skip to content

Commit 147d061

Browse files
committed
Add marina request telemetry events for 0.4.4
marina now emits two telemetry events at the request boundary: [marina, request, sent] - shackle dispatch (query/batch/prepare/execute) [marina, request, error] - pool resolution failed The sent event fires once per shackle:cast / shackle:call -- so a reusable_query with a cache miss fires twice (prepare then execute), giving accurate accounting of outgoing CQL operations rather than API-level intent. Metadata is {operation, pool, async} so handlers can break down by op kind and routing pool. The error event fires at the four pool-resolution sites in marina.erl: async_call/2, call/2, async_reusable_query/2, reusable_query/2. Metadata is {operation, reason}. Per-request shackle lifecycle (queue / send / receive) stays observable via shackle's own telemetry hooks -- marina's events surface the CQL-level intent without duplicating that work. telemetry (1.4.2) promoted to a direct dep (was already transitive via shackle). vsn switched from 'git' to an explicit '0.4.4' string, matching the convention used by the rest of the family. A new eunit subtest attaches a sent handler and asserts the event fires on a real Scylla query. The error path is short and exercised through a single shared helper -- I'm leaving its coverage to manual review rather than wiring an app-stop dance into the parallel integration suite.
1 parent 9e779c8 commit 147d061

7 files changed

Lines changed: 86 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,34 @@
11
# Changelog
22

3+
## 0.4.4
4+
5+
### Added
6+
7+
- Two telemetry events at the request boundary:
8+
9+
| Event | Measurements | Metadata |
10+
|---|---|---|
11+
| `[marina, request, sent]` | `count => 1` | `operation, pool, async` |
12+
| `[marina, request, error]` | `count => 1` | `operation, reason` |
13+
14+
`sent` fires at each shackle dispatch — once per query/batch/prepare/
15+
execute. `reusable_query` with a cache miss fires twice (`prepare`
16+
then `execute`), giving an accurate count of CQL ops. The `error`
17+
event fires when `marina_pool:node/1` returns no pool (e.g.
18+
`marina_pool_not_started`). Attach handlers via `telemetry:attach/4`.
19+
20+
Per-request shackle lifecycle (queue / send / receive) remains
21+
observable via shackle's own telemetry — marina's events surface
22+
the CQL-level intent without duplicating that work.
23+
24+
- `telemetry` (1.4.2) is now a direct dependency (was already
25+
transitively present via shackle).
26+
27+
- `vsn` in `marina.app.src` is now an explicit string (`"0.4.4"`) —
28+
was `git`, which only works when built from a checkout.
29+
30+
No source or API changes beyond the instrumentation.
31+
332
## 0.4.3
433

534
### Changed

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,19 @@ Asynchronous (return a `shackle:request_id()`, consume via `marina:receive_respo
120120
- **Token-aware routing.** On boot, a balanced BST over token intervals is compiled to a runtime-generated `marina_ring_utils:lookup/1`. Routing keys are hashed with Murmur3 and traverse the tree in O(log N).
121121
- **Topology refresh.** `marina_control` holds one long-lived CQL connection subscribed to `TOPOLOGY_CHANGE`, `STATUS_CHANGE`, and `SCHEMA_CHANGE`. Any topology event — or any reconnect — re-queries `system.peers` and posts `{topology_full_sync, Nodes}` to the pool server, which diffs the node list, adds/removes pools, evicts prepared-statement cache for removed pools, and rebuilds the ring.
122122

123+
## Telemetry
124+
125+
marina emits two telemetry events at the request boundary. Attach handlers via `telemetry:attach/4`:
126+
127+
| Event | Measurements | Metadata |
128+
|---|---|---|
129+
| `[marina, request, sent]` | `count => 1` | `operation, pool, async` |
130+
| `[marina, request, error]` | `count => 1` | `operation, reason` |
131+
132+
`sent` fires at each shackle dispatch — once per `query` / `batch` / `prepare` / `execute`. A `reusable_query` with a cache miss fires twice (`prepare` then `execute`), so the sum gives an accurate count of outgoing CQL operations. The `error` event fires when `marina_pool:node/1` returns no pool (e.g. `marina_pool_not_started`).
133+
134+
Per-request shackle lifecycle (queue / send / receive) remains observable via shackle's own telemetry — marina's events surface the CQL-level intent without duplicating that work.
135+
123136
## Development
124137

125138
```sh

rebar.config

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
{foil, "0.1.4"},
99
{lz4_nif, "0.1.1"},
1010
{murmur_nif, "0.1.0"},
11-
{shackle, "0.7.1"}
11+
{shackle, "0.7.1"},
12+
{telemetry, "1.4.2"}
1213
]}.
1314

1415
{dialyzer, [{plt_extra_apps, [public_key]}]}.

rebar.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
{<<"metal">>,{pkg,<<"metal">>,<<"0.1.2">>},1},
66
{<<"murmur_nif">>,{pkg,<<"murmur_nif">>,<<"0.1.0">>},0},
77
{<<"shackle">>,{pkg,<<"shackle">>,<<"0.7.1">>},0},
8-
{<<"telemetry">>,{pkg,<<"telemetry">>,<<"1.4.2">>},1}]}.
8+
{<<"telemetry">>,{pkg,<<"telemetry">>,<<"1.4.2">>},0}]}.
99
[
1010
{pkg_hash,[
1111
{<<"foil">>, <<"1B786A2CC3E81496F98F799DF23AA24065253A94032AB79E5D60AED5423850AE">>},

src/marina.app.src

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{application, marina, [
22
{description, "High-Performance Erlang Cassandra / Scylla CQL Client"},
3-
{vsn, git},
3+
{vsn, "0.4.4"},
44
{registered, []},
55
{applications, [
66
kernel,
@@ -11,7 +11,8 @@
1111
lz4_nif,
1212
metal,
1313
syntax_tools,
14-
compiler
14+
compiler,
15+
telemetry
1516
]},
1617
{mod, {marina_app, []}},
1718
{env, []},

src/marina.erl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ async_reusable_query(Query, QueryOpts) ->
3434
{ok, Pool} ->
3535
async_reusable_query(Pool, Query, QueryOpts);
3636
{error, Reason} ->
37+
telemetry_error(reusable_query, Reason),
3738
{error, Reason}
3839
end.
3940

@@ -72,6 +73,7 @@ reusable_query(Query, QueryOpts) ->
7273
{ok, Pool} ->
7374
reusable_query(Pool, Query, QueryOpts);
7475
{error, Reason} ->
76+
telemetry_error(reusable_query, Reason),
7577
{error, Reason}
7678
end.
7779

@@ -82,13 +84,18 @@ async_call(Msg, QueryOpts) ->
8284
{ok, Pool} ->
8385
async_call(Pool, Msg, QueryOpts);
8486
{error, Reason} ->
87+
telemetry_error(element(1, Msg), Reason),
8588
{error, Reason}
8689
end.
8790

8891

8992
async_call(Pool, Msg, QueryOpts) ->
9093
Pid = marina_utils:query_opts(pid, QueryOpts),
9194
Timeout = marina_utils:query_opts(timeout, QueryOpts),
95+
telemetry:execute([marina, request, sent],
96+
#{count => 1},
97+
#{operation => element(1, Msg), pool => Pool,
98+
async => true}),
9299
shackle:cast(Pool, {Msg, QueryOpts}, Pid, Timeout).
93100

94101
async_reusable_query(Pool, Query, QueryOpts) ->
@@ -111,13 +118,23 @@ call(Msg, QueryOpts) ->
111118
{ok, Pool} ->
112119
call(Pool, Msg, QueryOpts);
113120
{error, Reason} ->
121+
telemetry_error(element(1, Msg), Reason),
114122
{error, Reason}
115123
end.
116124

117125
call(Pool, Msg, QueryOpts) ->
118126
Timeout = marina_utils:query_opts(timeout, QueryOpts),
127+
telemetry:execute([marina, request, sent],
128+
#{count => 1},
129+
#{operation => element(1, Msg), pool => Pool,
130+
async => false}),
119131
response(shackle:call(Pool, {Msg, QueryOpts}, Timeout)).
120132

133+
telemetry_error(Operation, Reason) ->
134+
telemetry:execute([marina, request, error],
135+
#{count => 1},
136+
#{operation => Operation, reason => Reason}).
137+
121138
reusable_query(Pool, Query, QueryOpts) ->
122139
Timeout = marina_utils:query_opts(timeout, QueryOpts),
123140
Timestamp = os:timestamp(),

test/marina_tests.erl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ marina_test_() ->
2020
fun reusable_query/0,
2121
fun reusable_query_invalid/0,
2222
fun schema_change_udt/0,
23+
fun telemetry_sent/0,
2324
fun tuples/0
2425
]).
2526

@@ -226,6 +227,26 @@ reusable_query_invalid() ->
226227
?assertMatch({error, {8704, _}},
227228
marina:reusable_query(<<"SELECT * FROM user LIMIT 1;">>, #{})).
228229

230+
telemetry_sent() ->
231+
Self = self(),
232+
HandlerId = <<"marina-test-sent">>,
233+
ok = telemetry:attach(HandlerId, [marina, request, sent],
234+
fun (Event, Measurements, Metadata, _) ->
235+
Self ! {telemetry, Event, Measurements, Metadata}
236+
end, undefined),
237+
try
238+
?QUERY1_RESULT = q(?QUERY1),
239+
receive
240+
{telemetry, [marina, request, sent],
241+
#{count := 1},
242+
#{operation := query, async := false}} -> ok
243+
after 1000 ->
244+
erlang:error(timeout_waiting_for_sent_event)
245+
end
246+
after
247+
telemetry:detach(HandlerId)
248+
end.
249+
229250
schema_change_udt() ->
230251
q(<<"DROP KEYSPACE IF EXISTS test2;">>),
231252
q(<<"CREATE KEYSPACE test2 WITH REPLICATION ="

0 commit comments

Comments
 (0)