Skip to content

Commit e896c20

Browse files
authored
Telemetry Fishish (#457)
1 parent e922d4a commit e896c20

File tree

7 files changed

+113
-44
lines changed

7 files changed

+113
-44
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
44

55
## Unreleased
66

7+
### Added
8+
- Telemetry Support (#415)
9+
710
### Fixed
811
- Properly override jobs with duplicate name (#392)
912
- Simplify `TaskRegistry` and make tests deterministic

lib/quantum/executor.ex

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,17 @@ defmodule Quantum.Executor do
7575

7676
# Ececute the given function on a given node via the task supervisor
7777
@spec run(Node.t(), Job.t(), GenServer.server(), boolean(), atom()) :: Task.t()
78-
defp run(node, %{name: job_name, task: task}, task_supervisor, debug_logging, scheduler) do
78+
defp run(
79+
node,
80+
%Job{name: job_name, task: task} = job,
81+
task_supervisor,
82+
debug_logging,
83+
scheduler
84+
) do
7985
debug_logging &&
8086
Logger.debug(fn ->
8187
"[#{inspect(Node.self())}][#{__MODULE__}] Task for job #{inspect(job_name)} started on node #{
82-
inspect(node)
88+
node
8389
}"
8490
end)
8591

@@ -93,8 +99,8 @@ defmodule Quantum.Executor do
9399
start_monotonic_time = :erlang.monotonic_time()
94100

95101
:telemetry.execute([:quantum, :job, :start], %{system_time: start_monotonic_time}, %{
96-
job_name: job_name,
97-
node: inspect(node),
102+
job: job,
103+
node: node,
98104
scheduler: scheduler
99105
})
100106

@@ -112,8 +118,8 @@ defmodule Quantum.Executor do
112118
duration = :erlang.monotonic_time() - start_monotonic_time
113119

114120
:telemetry.execute([:quantum, :job, :exception], %{duration: duration}, %{
115-
job_name: job_name,
116-
node: inspect(node),
121+
job: job,
122+
node: node,
117123
reason: value,
118124
stacktrace: __STACKTRACE__,
119125
scheduler: scheduler
@@ -130,9 +136,10 @@ defmodule Quantum.Executor do
130136
duration = :erlang.monotonic_time() - start_monotonic_time
131137

132138
:telemetry.execute([:quantum, :job, :stop], %{duration: duration}, %{
133-
job_name: job_name,
134-
node: inspect(node),
135-
scheduler: scheduler
139+
job: job,
140+
node: node,
141+
scheduler: scheduler,
142+
result: result
136143
})
137144
end
138145

lib/quantum/job_broadcaster.ex

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,10 @@ defmodule Quantum.JobBroadcaster do
6060
"[#{inspect(Node.self())}][#{__MODULE__}] Loading Initial Jobs from Storage, skipping config"
6161
end)
6262

63-
for %Job{state: :active, name: name} = job <- storage_jobs do
63+
for %Job{state: :active} = job <- storage_jobs do
6464
# Send event to telemetry incase the end user wants to monitor events
6565
:telemetry.execute([:quantum, :job, :add], %{}, %{
66-
job_name: name,
6766
job: job,
68-
node: inspect(Node.self()),
6967
scheduler: scheduler
7068
})
7169
end
@@ -111,9 +109,7 @@ defmodule Quantum.JobBroadcaster do
111109

112110
# Send event to telemetry incase the end user wants to monitor events
113111
:telemetry.execute([:quantum, :job, :update], %{}, %{
114-
job_name: job_name,
115112
job: job,
116-
node: inspect(Node.self()),
117113
scheduler: state.scheduler
118114
})
119115

@@ -131,9 +127,7 @@ defmodule Quantum.JobBroadcaster do
131127

132128
# Send event to telemetry incase the end user wants to monitor events
133129
:telemetry.execute([:quantum, :job, :update], %{}, %{
134-
job_name: job_name,
135130
job: job,
136-
node: inspect(Node.self()),
137131
scheduler: state.scheduler
138132
})
139133

@@ -150,9 +144,7 @@ defmodule Quantum.JobBroadcaster do
150144

151145
# Send event to telemetry incase the end user wants to monitor events
152146
:telemetry.execute([:quantum, :job, :add], %{}, %{
153-
job_name: job_name,
154147
job: job,
155-
node: inspect(Node.self()),
156148
scheduler: state.scheduler
157149
})
158150

@@ -180,9 +172,7 @@ defmodule Quantum.JobBroadcaster do
180172

181173
# Send event to telemetry incase the end user wants to monitor events
182174
:telemetry.execute([:quantum, :job, :update], %{}, %{
183-
job_name: job_name,
184175
job: job,
185-
node: inspect(Node.self()),
186176
scheduler: state.scheduler
187177
})
188178

@@ -199,9 +189,7 @@ defmodule Quantum.JobBroadcaster do
199189

200190
# Send event to telemetry incase the end user wants to monitor events
201191
:telemetry.execute([:quantum, :job, :update], %{}, %{
202-
job_name: job_name,
203192
job: job,
204-
node: inspect(Node.self()),
205193
scheduler: state.scheduler
206194
})
207195

@@ -218,9 +206,7 @@ defmodule Quantum.JobBroadcaster do
218206

219207
# Send event to telemetry incase the end user wants to monitor events
220208
:telemetry.execute([:quantum, :job, :add], %{}, %{
221-
job_name: job_name,
222209
job: job,
223-
node: inspect(Node.self()),
224210
scheduler: state.scheduler
225211
})
226212

@@ -248,9 +234,7 @@ defmodule Quantum.JobBroadcaster do
248234
{:ok, %{state: :active, name: name} = job} ->
249235
# Send event to telemetry incase the end user wants to monitor events
250236
:telemetry.execute([:quantum, :job, :delete], %{}, %{
251-
job_name: name,
252237
job: job,
253-
node: inspect(Node.self()),
254238
scheduler: state.scheduler
255239
})
256240

@@ -261,9 +245,7 @@ defmodule Quantum.JobBroadcaster do
261245
{:ok, %{state: :inactive, name: name} = job} ->
262246
# Send event to telemetry incase the end user wants to monitor events
263247
:telemetry.execute([:quantum, :job, :delete], %{}, %{
264-
job_name: name,
265248
job: job,
266-
node: inspect(Node.self()),
267249
scheduler: state.scheduler
268250
})
269251

@@ -300,9 +282,7 @@ defmodule Quantum.JobBroadcaster do
300282
{:ok, job} ->
301283
# Send event to telemetry incase the end user wants to monitor events
302284
:telemetry.execute([:quantum, :job, :update], %{}, %{
303-
job_name: name,
304285
job: job,
305-
node: inspect(Node.self()),
306286
scheduler: state.scheduler
307287
})
308288

@@ -334,12 +314,10 @@ defmodule Quantum.JobBroadcaster do
334314
"[#{inspect(Node.self())}][#{__MODULE__}] Deleting all jobs"
335315
end)
336316

337-
for {name, %Job{} = job} <- jobs do
317+
for {_name, %Job{} = job} <- jobs do
338318
# Send event to telemetry incase the end user wants to monitor events
339319
:telemetry.execute([:quantum, :job, :delete], %{}, %{
340-
job_name: name,
341320
job: job,
342-
node: inspect(Node.self()),
343321
scheduler: state.scheduler
344322
})
345323
end

mix.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ defmodule Quantum.Mixfile do
7474
"pages/configuration.md",
7575
"pages/runtime.md",
7676
"pages/crontab-format.md",
77-
"pages/run-strategies.md"
77+
"pages/run-strategies.md",
78+
"pages/telemetry.md"
7879
],
7980
groups_for_modules: [
8081
"Run Strategy": [

pages/telemetry.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Telemetry
2+
3+
Sice version [`3.2.0`](https://github.com/quantum-elixir/quantum-core/releases/tag/v3.2.0) `quantum` supports [`:telemetry`](https://hexdocs.pm/telemetry) metrics.
4+
5+
<!--
6+
large parts of this docs are copied from https://raw.githubusercontent.com/phoenixframework/phoenix/master/guides/telemetry.md
7+
thanks phoenix :heart:
8+
-->
9+
10+
## Overview
11+
12+
The [`:telemetry`](https://hexdocs.pm/telemetry) library allows you to emit events at various stages of an application's lifecycle. You can then respond to these events by, among other things, aggregating them as metrics and sending the metrics data to a reporting destination.
13+
14+
Telemetry stores events by their name in an ETS table, along with the handler for each event. Then, when a given event is executed, Telemetry looks up its handler and invokes it.
15+
16+
## Telemetry Events
17+
18+
Many Elixir libraries (including Quantum) are already using
19+
the [`:telemetry`](http://hexdocs.pm/telemetry) package as a
20+
way to give users more insight into the behavior of their
21+
applications, by emitting events at key moments in the
22+
application lifecycle.
23+
24+
A Telemetry event is made up of the following:
25+
26+
* `name` - A string (e.g. `"my_app.worker.stop"`) or a
27+
list of atoms that uniquely identifies the event.
28+
29+
* `measurements` - A map of atom keys (e.g. `:duration`)
30+
and numeric values.
31+
32+
* `metadata` - A map of key/value pairs that can be used
33+
for tagging metrics.
34+
35+
### A Quantum Example
36+
37+
Here is an example of an event from your endpoint:
38+
39+
* `[:quantum, :job, :stop]` - dispatched whenever a job
40+
execution is done
41+
42+
* Measurement: `%{duration: native_time}`
43+
44+
* Metadata: `%{job: Quantum.Job.t(), node: Node.t(), scheduler: atom()}`
45+
46+
This means that after each job execution, `Quantum`, via `:telemetry`,
47+
will emit a "stop" event, with a measurement of how long it
48+
took to execute the job:
49+
50+
```elixir
51+
:telemetry.execute([:quantum, :job, :start], %{system_time: system_time}, %{
52+
job: job,
53+
node: node,
54+
scheduler: scheduler
55+
})
56+
```
57+
58+
### Quantum Telemetry Events
59+
60+
The following events are published by Quantum with the following measurements and metadata:
61+
62+
* `[:quantum, :job, :start]` - dispatched on job executiuon start
63+
* Measurement: `%{system_time: system_time}`
64+
* Metadata: `%{job: Quantum.Job.t(), node: Node.t(), scheduler: atom()}`
65+
* `[:quantum, :job, :exception]` - dispatched on job executiuon fail
66+
* Measurement: `%{duration: native_time}`
67+
* Metadata: `%{job: Quantum.Job.t(), node: Node.t(), scheduler: atom(), reason: term(), stacktrace: __STACKTRACE__}`
68+
* `[:quantum, :job, :stop]` - dispatched on job executiuon end
69+
* Measurement: `%{duration: native_time}`
70+
* Metadata: `%{job: Quantum.Job.t(), node: Node.t(), scheduler: atom(), result: term()}`
71+
* `[:quantum, :job, :add]` - dispatched when a job is added
72+
* Measurement: `%{}`
73+
* Metadata: `%{job: Quantum.Job.t(), scheduler: atom()}`
74+
* `[:quantum, :job, :update]` - dispatched when a job is updated
75+
* Measurement: `%{}`
76+
* Metadata: `%{job: Quantum.Job.t(), scheduler: atom()}`
77+
* `[:quantum, :job, :delete]` - dispatched when a job is deleted
78+
* Measurement: `%{}`
79+
* Metadata: `%{job: Quantum.Job.t(), scheduler: atom()}`

test/quantum/executor_test.exs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ defmodule Quantum.ExecutorTest do
1818
end
1919

2020
defmodule TelemetryTestHandler do
21-
require Logger
21+
@moduledoc false
2222

2323
def handle_event(
2424
[:quantum, :job, :start],
2525
%{system_time: _system_time} = _measurements,
26-
%{job_name: job_name, node: _node, scheduler: _scheduler} = _metadata,
26+
%{job: %Job{name: job_name}, node: _node, scheduler: _scheduler} = _metadata,
2727
%{parent_thread: parent_thread, test_id: test_id}
2828
) do
2929
send(parent_thread, %{test_id: test_id, job_name: job_name, type: :start})
@@ -32,7 +32,8 @@ defmodule Quantum.ExecutorTest do
3232
def handle_event(
3333
[:quantum, :job, :stop],
3434
%{duration: _duration} = _measurements,
35-
%{job_name: job_name, node: _node, scheduler: _scheduler} = _metadata,
35+
%{job: %Job{name: job_name}, node: _node, scheduler: _scheduler, result: _result} =
36+
_metadata,
3637
%{parent_thread: parent_thread, test_id: test_id}
3738
) do
3839
send(parent_thread, %{test_id: test_id, job_name: job_name, type: :stop})
@@ -42,11 +43,11 @@ defmodule Quantum.ExecutorTest do
4243
[:quantum, :job, :exception],
4344
%{duration: _duration} = _measurements,
4445
%{
45-
job_name: job_name,
46+
job: %Job{name: job_name},
4647
node: _node,
48+
scheduler: _scheduler,
4749
reason: reason,
48-
stacktrace: stacktrace,
49-
scheduler: _scheduler
50+
stacktrace: stacktrace
5051
} = _metadata,
5152
%{parent_thread: parent_thread, test_id: test_id}
5253
) do

test/quantum/job_broadcaster_test.exs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ defmodule Quantum.JobBroadcasterTest do
2222
end
2323

2424
defmodule TelemetryTestHandler do
25-
require Logger
25+
@moduledoc false
2626

2727
def handle_event(
2828
[:quantum, :job, :add],
2929
_measurements,
30-
%{job_name: job_name, job: _job, node: _node, scheduler: _scheduler} = _metadata,
30+
%{job: %Job{name: job_name}, scheduler: _scheduler} = _metadata,
3131
%{parent_thread: parent_thread, test_id: test_id}
3232
) do
3333
send(parent_thread, %{test_id: test_id, job_name: job_name, type: :add})
@@ -36,7 +36,7 @@ defmodule Quantum.JobBroadcasterTest do
3636
def handle_event(
3737
[:quantum, :job, :delete],
3838
_measurements,
39-
%{job_name: job_name, job: _job, node: _node, scheduler: _scheduler} = _metadata,
39+
%{job: %Job{name: job_name}, scheduler: _scheduler} = _metadata,
4040
%{parent_thread: parent_thread, test_id: test_id}
4141
) do
4242
send(parent_thread, %{test_id: test_id, job_name: job_name, type: :delete})
@@ -45,7 +45,7 @@ defmodule Quantum.JobBroadcasterTest do
4545
def handle_event(
4646
[:quantum, :job, :update],
4747
_measurements,
48-
%{job_name: job_name, job: _job, node: _node, scheduler: _scheduler} = _metadata,
48+
%{job: %Job{name: job_name}, scheduler: _scheduler} = _metadata,
4949
%{parent_thread: parent_thread, test_id: test_id}
5050
) do
5151
send(parent_thread, %{test_id: test_id, job_name: job_name, type: :update})

0 commit comments

Comments
 (0)