Current section
11 Versions
Jump to
Current section
11 Versions
Compare versions
8
files changed
+293
additions
-159
deletions
| @@ -4,6 +4,7 @@ | |
| 4 4 | locals_without_parens: [ |
| 5 5 | assert_dispatched: 3, |
| 6 6 | assert_dispatched: 4, |
| 7 | - assert_dispatch: 4 |
| 7 | + assert_dispatch: 4, |
| 8 | + on_exit: 1 |
| 8 9 | ] |
| 9 10 | ] |
| @@ -0,0 +1,39 @@ | |
| 1 | + # Changelog |
| 2 | + |
| 3 | + All notable changes to this project will be documented in this file. |
| 4 | + |
| 5 | + The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), |
| 6 | + and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). |
| 7 | + |
| 8 | + ## [0.2.0](https://github.com/beam-telemetry/telemetry_poller/tree/v0.2.0) |
| 9 | + |
| 10 | + ### Added |
| 11 | + |
| 12 | + * Added `:total_run_queue_lengths` and `:run_queue_lengths` memory measurements; |
| 13 | + |
| 14 | + ### Changed |
| 15 | + |
| 16 | + * `:total_run_queue_lengths` is now included in the set of default VM measurements; |
| 17 | + * A default Poller process, with a default set of VM measurements, is started when `:telemetry_poller` |
| 18 | + application starts (configurable via `:telemetry.poller, :default` application environment). |
| 19 | + * VM measurements are now provided to Poller's `:vm_measurements` option. Passing atom `:default` |
| 20 | + to this option makes the Poller use a default set of VM measurements; |
| 21 | + * Telemetry has been upgraded to version 0.3, meaning that VM measurements now use this version to |
| 22 | + emit the events. |
| 23 | + |
| 24 | + ### Removed |
| 25 | + |
| 26 | + * `Telemetry.Poller.vm_measurements/0` function has been removed in favor of `:vm_measurements` |
| 27 | + option. |
| 28 | + |
| 29 | + ### Fixed |
| 30 | + |
| 31 | + * Fixed the type definition of `Telemetry.Poller.measurement/0` type - no Dialyzer warnings are |
| 32 | + emitted when running it on the project. |
| 33 | + |
| 34 | + ## [0.1.0](https://github.com/beam-telemetry/telemetry_poller/tree/v0.1.0) |
| 35 | + |
| 36 | + ### Added |
| 37 | + |
| 38 | + * The Poller process periodically invoking registered functions which emit Telemetry events. |
| 39 | + It supports VM memory measurements and custom measurements provided as MFAs. |
| \ No newline at end of file |
| @@ -1,31 +1,38 @@ | |
| 1 1 | # Telemetry.Poller |
| 2 2 | |
| 3 | + [](https://circleci.com/gh/beam-telemetry/telemetry_poller) |
| 4 | + [](https://codecov.io/gh/beam-telemetry/telemetry_poller/branch/master/graphs/badge.svg) |
| 5 | + |
| 3 6 | Allows to periodically collect measurements and dispatch them as Telemetry events. |
| 4 7 | |
| 5 | - Poller provides a convenient API for specifying functions called periodically to dispatch |
| 6 | - measurements as Telemetry events. It also includes helpers for measuring Erlang virtual machine |
| 7 | - metrics: |
| 8 | + `Telemetry.Poller` ships with a default poller for VM measurements: |
| 9 | + |
| 10 | + ```elixir |
| 11 | + config :telemetry_poller, :default, |
| 12 | + vm_measurements: :default # or a list such as [:total_memory, :binary_memory, ...] |
| 13 | + ``` |
| 14 | + |
| 15 | + Poller also provides a convenient API for specifying functions called periodically to dispatch |
| 16 | + measurements as Telemetry events: |
| 8 17 | |
| 9 18 | ```elixir |
| 10 19 | # define custom function dispatching event with value you're interested in |
| 11 20 | defmodule ExampleApp.Measurements do |
| 12 21 | def dispatch_session_count() do |
| 13 | - Telemetry.execute([:example_app, :session_count], ExampleApp.session_count()) |
| 22 | + :telemetry.execute([:example_app, :session_count], ExampleApp.session_count()) |
| 14 23 | end |
| 15 24 | end |
| 16 25 | |
| 17 26 | Telemetry.Poller.start_link( |
| 27 | + # include custom measurement |
| 18 28 | measurements: [ |
| 19 | - # include custom measurement |
| 20 29 | {ExampleApp.Measurements, :dispatch_session_count, []} |
| 21 | - # include default VM measurements |
| 22 | - | Telemetry.Poller.vm_measurements() |
| 23 30 | ], |
| 24 31 | period: 10_000 # configure sampling period |
| 25 32 | ) |
| 26 33 | ``` |
| 27 34 | |
| 28 | - See [documentation](https://hexdocs.pm/telemetry_poller) for more concrete examples and usage |
| 35 | + See [documentation](https://hexdocs.pm/telemetry_poller/0.2.0) for more concrete examples and usage |
| 29 36 | instructions. |
| 30 37 | |
| 31 38 | ## Copyright and License |
| @@ -2,19 +2,20 @@ | |
| 2 2 | {<<"build_tools">>,[<<"mix">>]}. |
| 3 3 | {<<"description">>, |
| 4 4 | <<"Allows to periodically collect measurements and dispatch them as Telemetry events">>}. |
| 5 | - {<<"elixir">>,<<"~> 1.4">>}. |
| 5 | + {<<"elixir">>,<<"~> 1.5">>}. |
| 6 6 | {<<"files">>, |
| 7 7 | [<<"lib">>,<<"lib/telemetry_poller">>,<<"lib/telemetry_poller.ex">>, |
| 8 | - <<"lib/telemetry_poller/vm.ex">>,<<".formatter.exs">>,<<"mix.exs">>, |
| 9 | - <<"README.md">>,<<"LICENSE">>]}. |
| 8 | + <<"lib/telemetry_poller/application.ex">>,<<"lib/telemetry_poller/vm.ex">>, |
| 9 | + <<".formatter.exs">>,<<"mix.exs">>,<<"README.md">>,<<"LICENSE">>, |
| 10 | + <<"CHANGELOG.md">>]}. |
| 10 11 | {<<"licenses">>,[<<"Apache 2.0">>]}. |
| 11 12 | {<<"links">>, |
| 12 | - [{<<"GitHub">>,<<"https://github.com/elixir-telemetry/telemetry_poller">>}]}. |
| 13 | + [{<<"GitHub">>,<<"https://github.com/beam-telemetry/telemetry_poller">>}]}. |
| 13 14 | {<<"name">>,<<"telemetry_poller">>}. |
| 14 15 | {<<"requirements">>, |
| 15 16 | [[{<<"app">>,<<"telemetry">>}, |
| 16 17 | {<<"name">>,<<"telemetry">>}, |
| 17 18 | {<<"optional">>,false}, |
| 18 19 | {<<"repository">>,<<"hexpm">>}, |
| 19 | - {<<"requirement">>,<<"~> 0.2.0">>}]]}. |
| 20 | - {<<"version">>,<<"0.1.0">>}. |
| 20 | + {<<"requirement">>,<<"~> 0.3">>}]]}. |
| 21 | + {<<"version">>,<<"0.2.0">>}. |
| @@ -1,43 +1,130 @@ | |
| 1 1 | defmodule Telemetry.Poller do |
| 2 | - @moduledoc """ |
| 2 | + @moduledoc ~S""" |
| 3 3 | A time-based poller to periodically dispatch Telemetry events. |
| 4 4 | |
| 5 | - Measurements are MFAs called periodically by the Poller process. These MFAs should collect |
| 6 | - a value (if possible) and dispatch an event using `Telemetry.execute/3` function. |
| 5 | + By default a single poller is started under `Telemetry.Poller` application. |
| 6 | + It is started with name `Telemetry.Poller.Default` and a default set of VM |
| 7 | + measurements. It polls all default VM measurements, which is equivalent to: |
| 7 8 | |
| 8 | - If the invokation of the MFA fails, the measurement is removed from the Poller. |
| 9 | + config :telemetry_poller, :default, |
| 10 | + vm_measurements: :default # this is the default |
| 9 11 | |
| 10 | - See the "Example - (...)" sections for more concrete examples. |
| 12 | + But you may specify all VM measurements you want: |
| 11 13 | |
| 12 | - ## Starting and stopping |
| 14 | + config :telemetry_poller, :default, |
| 15 | + vm_measurements: [:total_memory, :binary_memory, :total_run_queue_lengths] |
| 13 16 | |
| 14 | - You can start the Poller using the `start_link/1` function. Poller can be alaso started as a |
| 15 | - part of your supervision tree, using both the old-style and the new-style child specifications: |
| 17 | + Measurements are MFAs called periodically by the poller process. |
| 18 | + You can disable the default poller by setting it to `false`: |
| 16 19 | |
| 17 | - # pre Elixir 1.5.0 |
| 18 | - children = [Supervisor.Spec.worker(Telemetry.Poller, [[period: 5000]])] |
| 20 | + config :telemetry_poller, :default, false |
| 19 21 | |
| 20 | - # post Elixir 1.5.0 |
| 21 | - children = [{Telemetry.Poller, [period: 5000]}] |
| 22 | + Telemetry poller also allows you perform custom measurements by spawning |
| 23 | + your own poller process: |
| 22 24 | |
| 23 | - Supervisor.start_link(children, [strategy: :one_for_one]) |
| 25 | + children = [ |
| 26 | + {Telemetry.Poller, |
| 27 | + measurements: [{MyApp.Example, :measure, []}]} |
| 28 | + ] |
| 24 29 | |
| 25 | - You can start as many Pollers as you wish, but generally you shouldn't need to do it, unless |
| 26 | - you know that it's not keeping up with collecting all specified measurements. |
| 30 | + For custom pollers, the measurements are given as MFAs. Those MFAs should |
| 31 | + collect a value (if possible) and dispatch an event using `:telemetry.execute/3` |
| 32 | + function. If the invokation of the MFA fails, the measurement is removed |
| 33 | + from the Poller. |
| 27 34 | |
| 28 | - Measurements need to be provided via `:measurements` option. |
| 35 | + For all options, see `start_link/1`. The options listed there can be given |
| 36 | + to the default poller as well as to custom pollers. |
| 37 | + |
| 38 | + Over the next sections, we will describe all built-in VM measurements and |
| 39 | + explore some concrete examples. |
| 29 40 | |
| 30 41 | ## VM measurements |
| 31 42 | |
| 32 | - The `vm_measurements/1` function returns common measurements related to Erlang virtual machine |
| 33 | - metrics. See its documentation for more information. |
| 43 | + VM measurements need to be provided via `:vm_measurements` option. Below you |
| 44 | + can find a list of available measurements per category. |
| 45 | + |
| 46 | + ### Memory |
| 47 | + |
| 48 | + See documentation for `:erlang.memory/0` function for more information about |
| 49 | + each type of memory measured. |
| 50 | + |
| 51 | + * `:total_memory` - dispatches an event with total amount of currently allocated memory, in bytes. |
| 52 | + Event name is `[:vm, :memory, :total]` and event metadata is empty; |
| 53 | + * `:processes_memory` - dispatches an event with amount of memory cyrrently allocated for |
| 54 | + processes, in bytes. Event name is `[:vm, :memory, :processes]` and event metadata is empty; |
| 55 | + * `:processes_used_memory` - dispatches an event with amount of memory currently used for |
| 56 | + processes, in bytes. Event name is `[:vm, :memory, :processes_used]` and event metadata is empty. |
| 57 | + Memory measured is a fraction of value collected by `:processes_memory` measurement; |
| 58 | + * `:binary_memory` - dispatches an event with amount of memory currently allocated for binaries. |
| 59 | + Event name is `[:vm, :memory, :binary]` and event metadata is empty; |
| 60 | + * `:ets_memory` - dispatches an event with amount of memory currently allocated for ETS tables. |
| 61 | + Event name is `[:vm, :memory, :ets]` and event metadata is empty; |
| 62 | + * `:system_memory` - dispatches an event with amount of currently allocated memory not directly |
| 63 | + related to any process running in the VM, in bytes. Event name is `[:vm, :memory, :system]` and |
| 64 | + event metadata is empty; |
| 65 | + * `:atom_memory` - dispatches an event with amount of memory currently allocated for atoms. Event |
| 66 | + name is `[:vm, :memory, :atom]` and event metadata is empty; |
| 67 | + * `:atom_used_memory` - dispatches an event with amount of memory currently used for atoms. Event |
| 68 | + name is `[:vm, :memory, :atom_used]` and event metadata is empty; |
| 69 | + * `:code_memory` - dispatches an event with amount of memory currently allocated for code. Event |
| 70 | + name is `[:vm, :memory, :code]` and event metadata is empty; |
| 71 | + |
| 72 | + ### Run queue lengths |
| 73 | + |
| 74 | + On startup, the Erlang VM starts many schedulers to do both IO and CPU work. If a process |
| 75 | + needs to do some work or wait on IO, it is allocated to the appropriate scheduler. The run |
| 76 | + queue is a queue of tasks to be scheduled. A length of a run queue corresponds to the amount |
| 77 | + of work accumulated in the system. If a run queue length is constantly growing, it means that |
| 78 | + the BEAM is not keeping up with executing all the tasks. |
| 79 | + |
| 80 | + There are several run queue types in the Erlang VMe. Each CPU scheduler (usually one per core) |
| 81 | + has its own run queue, and since Erlang 20.0 there is one dirty CPU run queue, and one dirty |
| 82 | + IO run queue. |
| 83 | + |
| 84 | + The following VM measurements related to run queue lengths are available: |
| 85 | + |
| 86 | + * `:total_run_queue_lengths` - dispatches an event with a sum of normal schedulers' run queue lengths |
| 87 | + and a dirty CPU run queue length (if dirty schedulers are available). Event name is |
| 88 | + `[:vm, run_queue_lengths, :total]` and event metadata is empty. |
| 89 | + |
| 90 | + Note that the method of making this measurement varies between different Erlang versions: for |
| 91 | + Erlang 18 and 19, the implementation is less efficient than for version 20 and up. |
| 92 | + |
| 93 | + The length of all queues is not gathered atomically, so the event value does not represent |
| 94 | + a consistent snapshot of the run queues' state. However, the value is accurate enough to help |
| 95 | + to indentify issues in a running system. |
| 96 | + |
| 97 | + * `:run_queue_lengths` - dispatches events with individual normal run queue lengths and a dirty |
| 98 | + CPU run queue length (if dirty schedulers are available). |
| 99 | + |
| 100 | + For normal run queues, event name is `[:vm, run_queue_lengths, :normal]` and event metadata |
| 101 | + includes a single key, `:scheduler_id`, with the scheduler ID of the queue. Note that number |
| 102 | + of schedulers is fixed at virtual machine boot time, so the number of events emitted on each |
| 103 | + measurement is constant. |
| 104 | + |
| 105 | + For dirty CPU run queue, the event name is `[:vm, :run_queue_lengths, :dirty_cpu]` and the |
| 106 | + event metadata is empty. |
| 107 | + |
| 108 | + The length of all queues is not gathered atomically, so the event values do not represent |
| 109 | + a consistent snapshot of the run queues' state. However, the value is accurate enough to help |
| 110 | + to indentify issues in a running system. |
| 111 | + |
| 112 | + If you do not need the individual run queue lengths, it is more efficient to use |
| 113 | + `:total_run_queue_lengths` measurement. |
| 114 | + |
| 115 | + ### Default measurements |
| 116 | + |
| 117 | + When `:default` is provided as the value of `:vm_measurement` options, Poller uses |
| 118 | + `:total_memory`, `:processes_memory`, `:processes_used_memory`, `:binary_memory`, |
| 119 | + `:ets_memory` and `:total_run_queue_lengths` VM measurements. |
| 34 120 | |
| 35 121 | ## Example - measuring message queue length of the process |
| 36 122 | |
| 37 | - Measuring process' message queue length is a good way to find out if and when the process becomes |
| 38 | - the bottleneck. If the length of the queue is growing, it means that the process is not keeping |
| 39 | - up with the work it's been assigned and other processes asking it to do the work will get |
| 40 | - timeouts. Let's try to simulate that situation using the following GenServer: |
| 123 | + Measuring process' message queue length is a good way to find out if and when the |
| 124 | + process becomes the bottleneck. If the length of the queue is growing, it means that |
| 125 | + the process is not keeping up with the work it's been assigned and other processes |
| 126 | + asking it to do the work will get timeouts. Let's try to simulate that situation |
| 127 | + using the following GenServer: |
| 41 128 | |
| 42 129 | defmodule Worker do |
| 43 130 | use GenServer |
| @@ -60,8 +147,8 @@ defmodule Telemetry.Poller do | |
| 60 147 | end |
| 61 148 | end |
| 62 149 | |
| 63 | - When assigned with work (`handle_call/3`), the worker will sleep for 1 second to imitate long |
| 64 | - running task. |
| 150 | + When assigned with work (`handle_call/3`), the worker will sleep for 1 second to |
| 151 | + imitate long running task. |
| 65 152 | |
| 66 153 | Now we need a measurement dispatching the message queue length of the worker: |
| 67 154 | |
| @@ -69,7 +156,7 @@ defmodule Telemetry.Poller do | |
| 69 156 | def message_queue_length(name) do |
| 70 157 | with pid when is_pid(pid) <- Process.whereis(name), |
| 71 158 | {:message_queue_len, length} <- Process.info(pid, :message_queue_len) do |
| 72 | - Telemetry.execute([:example_app, :message_queue_length], length, %{name: name}) |
| 159 | + :telemetry.execute([:example_app, :message_queue_length], length, %{name: name}) |
| 73 160 | end |
| 74 161 | end |
| 75 162 | end |
| @@ -89,10 +176,10 @@ defmodule Telemetry.Poller do | |
| 89 176 | |
| 90 177 | iex> defmodule Handler do |
| 91 178 | ...> def handle([:example_app, :message_queue_length], length, %{name: name}, _) do |
| 92 | - ...> IO.puts("Process #\{inspect(name)} message queue length: #\{length}") |
| 179 | + ...> IO.puts("Process #{inspect(name)} message queue length: #{length}") |
| 93 180 | ...> end |
| 94 181 | ...> end |
| 95 | - iex> Telemetry.attach(:handler, [:example_app, :message_queue_length], Handler, :handle) |
| 182 | + iex> :telemetry.attach(:handler, [:example_app, :message_queue_length], &Handler.handle/4, nil) |
| 96 183 | :ok |
| 97 184 | |
| 98 185 | Now let's start assigning work to the worker: |
| @@ -144,7 +231,7 @@ defmodule Telemetry.Poller do | |
| 144 231 | |
| 145 232 | defmodule ExampleApp.Measurements do |
| 146 233 | def dispatch_session_count() do |
| 147 | - Telemetry.execute([:example_app, :session_count], ExampleApp.session_count()) |
| 234 | + :telemetry.execute([:example_app, :session_count], ExampleApp.session_count()) |
| 148 235 | end |
| 149 236 | end |
| 150 237 | |
| @@ -161,8 +248,8 @@ defmodule Telemetry.Poller do | |
| 161 248 | def dispatch_session_count() do |
| 162 249 | regulars = ExampleApp.regular_users_session_count() |
| 163 250 | admins = ExampleApp.admin_users_session_count() |
| 164 | - Telemetry.execute([:example_app, :session_count], regulars, %{role: :regular}) |
| 165 | - Telemetry.execute([:example_app, :session_count], admins, %{role: :admin}) |
| 251 | + :telemetry.execute([:example_app, :session_count], regulars, %{role: :regular}) |
| 252 | + :telemetry.execute([:example_app, :session_count], admins, %{role: :admin}) |
| 166 253 | end |
| 167 254 | end |
| 168 255 | |
| @@ -189,9 +276,10 @@ defmodule Telemetry.Poller do | |
| 189 276 | :processes_memory, |
| 190 277 | :processes_used_memory, |
| 191 278 | :binary_memory, |
| 192 | - :ets_memory |
| 279 | + :ets_memory, |
| 280 | + :total_run_queue_lengths |
| 193 281 | ] |
| 194 | - @vm_memory_measurements [ |
| 282 | + @vm_measurements [ |
| 195 283 | :total_memory, |
| 196 284 | :processes_memory, |
| 197 285 | :processes_used_memory, |
| @@ -200,7 +288,9 @@ defmodule Telemetry.Poller do | |
| 200 288 | :atom_used_memory, |
| 201 289 | :binary_memory, |
| 202 290 | :code_memory, |
| 203 | - :ets_memory |
| 291 | + :ets_memory, |
| 292 | + :total_run_queue_lengths, |
| 293 | + :run_queue_lengths |
| 204 294 | ] |
| 205 295 | |
| 206 296 | @type t :: GenServer.server() |
| @@ -209,8 +299,9 @@ defmodule Telemetry.Poller do | |
| 209 299 | {:name, GenServer.name()} |
| 210 300 | | {:period, period()} |
| 211 301 | | {:measurements, [measurement()]} |
| 302 | + | {:vm_measurements, :default | [vm_measurement()]} |
| 212 303 | @type period :: pos_integer() |
| 213 | - @type measurement() :: mfa() |
| 304 | + @type measurement() :: {module(), function :: atom(), args :: list()} |
| 214 305 | @type vm_measurement() :: |
| 215 306 | :total_memory |
| 216 307 | | :processes_memory |
| @@ -221,47 +312,28 @@ defmodule Telemetry.Poller do | |
| 221 312 | | :binary_memory |
| 222 313 | | :code_memory |
| 223 314 | | :ets_memory |
| 315 | + | :total_run_queue_lengths |
| 316 | + | :run_queue_lengths |
| 224 317 | |
| 225 318 | ## API |
| 226 319 | |
| 227 | - @doc """ |
| 228 | - Returns a child specifiction for Poller. |
| 229 | - |
| 230 | - It accepts `t:options/0` as an argument, meaning that it's valid to start it under the supervisor |
| 231 | - as follows: |
| 232 | - |
| 233 | - alias Telemetry.Poller |
| 234 | - # use default options |
| 235 | - Supervisor.start_link([Poller], supervisor_opts) # use default options |
| 236 | - # customize options |
| 237 | - Supervisor.start_link([{Poller, period: 10_000}], supervisor_opts) |
| 238 | - # modify the child spec |
| 239 | - Supervisor.start_link(Supervisor.child_spec(Poller, id: MyPoller), supervisor_opts) |
| 240 | - """ |
| 241 | - # Uncomment when dropping support for 1.4.x releases. |
| 242 | - # @spec child_spec(term()) :: Supervisor.child_spec() |
| 243 | - def child_spec(term) |
| 244 | - |
| 245 | - def child_spec(options) do |
| 246 | - %{ |
| 247 | - id: __MODULE__, |
| 248 | - start: {__MODULE__, :start_link, [options]} |
| 249 | - } |
| 250 | - end |
| 251 | - |
| 252 320 | @doc """ |
| 253 321 | Starts a Poller linked to the calling process. |
| 254 322 | |
| 255 323 | Useful for starting Pollers as a part of a supervision tree. |
| 256 324 | |
| 257 | - ### Options |
| 325 | + ## Options |
| 258 326 | |
| 259 327 | * `:measurements` - a list of measurements used by Poller. For description of possible values |
| 260 328 | see `Telemetry.Poller` module documentation; |
| 329 | + * `:vm_measurements` - a list of atoms describing measurements related to the Erlang VM, or an |
| 330 | + atom `:default`, in which case default VM measurements are used. See "VM measurements" section in |
| 331 | + the module documentation for more information. Default value is `[]`; |
| 261 332 | * `:period` - time period before performing the same measurement again, in milliseconds. Default |
| 262 333 | value is #{@default_period} ms; |
| 263 334 | * `:name` - the name of the Poller process. See "Name Registragion" section of `GenServer` |
| 264 335 | documentation for information about allowed values. |
| 336 | + |
| 265 337 | """ |
| 266 338 | @spec start_link(options()) :: GenServer.on_start() |
| 267 339 | def start_link(options \\ []) when is_list(options) do |
| @@ -287,65 +359,6 @@ defmodule Telemetry.Poller do | |
| 287 359 | GenServer.call(poller, :get_measurements) |
| 288 360 | end |
| 289 361 | |
| 290 | - @doc """ |
| 291 | - Returns measurements dispatching events with Erlang virtual machine metrics |
| 292 | - |
| 293 | - It accepts a list `t:vm_measurement/0`s and returns a list of `t:measurement/0`s which can |
| 294 | - be provided to `start_link/1`'s `:measurements` option. |
| 295 | - |
| 296 | - Do not rely on the exact values returned by this function - the only guarantee is that they |
| 297 | - are of type `t:measurement/0` and their modification will not be considered a breaking change, |
| 298 | - unless the shape of events dispatched by returned measurements changes. |
| 299 | - |
| 300 | - Returned measurements are unique. |
| 301 | - |
| 302 | - ## Available measurements |
| 303 | - |
| 304 | - ### Memory |
| 305 | - |
| 306 | - See documentation for `:erlang.memory/0` function for more information about each type of memory |
| 307 | - measured. |
| 308 | - |
| 309 | - * `:total_memory` - dispatches an event with total amount of currently allocated memory, in bytes. |
| 310 | - Event name is `[:vm, :memory, :total]` and event metadata is empty; |
| 311 | - * `:processes_memory` - dispatches an event with amount of memory cyrrently allocated for |
| 312 | - processes, in bytes. Event name is `[:vm, :memory, :processes]` and event metadata is empty; |
| 313 | - * `:processes_used_memory` - dispatches an event with amount of memory currently used for |
| 314 | - processes, in bytes. Event name is `[:vm, :memory, :processes_used]` and event metadata is empty. |
| 315 | - Memory measured is a fraction of value collected by `:processes_memory` measurement; |
| 316 | - * `:binary_memory` - dispatches an event with amount of memory currently allocated for binaries. |
| 317 | - Event name is `[:vm, :memory, :binary]` and event metadata is empty; |
| 318 | - * `:ets_memory` - dispatches an event with amount of memory currently allocated for ETS tables. |
| 319 | - Event name is `[:vm, :memory, :ets]` and event metadata is empty; |
| 320 | - * `:system_memory` - dispatches an event with amount of currently allocated memory not directly |
| 321 | - related to any process running in the VM, in bytes. Event name is `[:vm, :memory, :system]` and |
| 322 | - event metadata is empty; |
| 323 | - * `:atom_memory` - dispatches an event with amount of memory currently allocated for atoms. Event |
| 324 | - name is `[:vm, :memory, :atom]` and event metadata is empty; |
| 325 | - * `:atom_used_memory` - dispatches an event with amount of memory currently used for atoms. Event |
| 326 | - name is `[:vm, :memory, :atom_used]` and event metadata is empty; |
| 327 | - * `:code_memory` - dispatches an event with amount of memory currently allocated for code. Event |
| 328 | - name is `[:vm, :memory, :code]` and event metadata is empty; |
| 329 | - |
| 330 | - ## Default measurements |
| 331 | - |
| 332 | - The 0-arity version of this function includes `:total_memory`, `:processes_memory`, |
| 333 | - `:processes_used_memory`, `:binary_memory` and `:ets_memory` measurements by default. |
| 334 | - |
| 335 | - ## Examples |
| 336 | - |
| 337 | - alias Telemetry.Poller |
| 338 | - Poller.start_link( |
| 339 | - measurements: Poller.vm_measurements() ++ Poller.vm_measurements(:atom_memory) |
| 340 | - ) |
| 341 | - """ |
| 342 | - @spec vm_measurements([vm_measurement()]) :: [measurement()] |
| 343 | - def vm_measurements(vm_measurements \\ @default_vm_measurements) |
| 344 | - when is_list(vm_measurements) do |
| 345 | - measurements = parse_vm_measurements!(vm_measurements) |
| 346 | - Enum.uniq(measurements) |
| 347 | - end |
| 348 | - |
| 349 362 | ## GenServer callbacks |
| 350 363 | |
| 351 364 | @impl true |
| @@ -379,9 +392,16 @@ defmodule Telemetry.Poller do | |
| 379 392 | gen_server_opts = Keyword.take(options, [:name]) |
| 380 393 | measurements = Keyword.get(options, :measurements, []) |
| 381 394 | validate_measurements!(measurements) |
| 395 | + |
| 396 | + vm_measurements = |
| 397 | + options |
| 398 | + |> Keyword.get(:vm_measurements, []) |
| 399 | + |> parse_vm_measurements!() |
| 400 | + |> Enum.uniq() |
| 401 | + |
| 382 402 | period = Keyword.get(options, :period, @default_period) |
| 383 403 | validate_period!(period) |
| 384 | - {[measurements: measurements, period: period], gen_server_opts} |
| 404 | + {[measurements: measurements ++ vm_measurements, period: period], gen_server_opts} |
| 385 405 | end |
| 386 406 | |
| 387 407 | @spec validate_measurements!(term()) :: :ok | no_return() |
| @@ -391,7 +411,7 @@ defmodule Telemetry.Poller do | |
| 391 411 | end |
| 392 412 | |
| 393 413 | defp validate_measurements!(other) do |
| 394 | - raise ArgumentError, "Expected :measurements to be a list, got #{inspect(other)}" |
| 414 | + raise ArgumentError, "expected :measurements to be a list, got #{inspect(other)}" |
| 395 415 | end |
| 396 416 | |
| 397 417 | @spec validate_measurement!(term()) :: :ok | no_return() |
| @@ -402,14 +422,14 @@ defmodule Telemetry.Poller do | |
| 402 422 | |
| 403 423 | defp validate_measurement!(invalid_measurement) do |
| 404 424 | raise ArgumentError, |
| 405 | - "Expected measurement, got #{inspect(invalid_measurement)}" |
| 425 | + "expected measurement, got #{inspect(invalid_measurement)}" |
| 406 426 | end |
| 407 427 | |
| 408 428 | @spec validate_period!(term()) :: :ok | no_return() |
| 409 429 | defp validate_period!(period) when is_integer(period) and period > 0, do: :ok |
| 410 430 | |
| 411 431 | defp validate_period!(other), |
| 412 | - do: raise(ArgumentError, "Expected :period to be a postivie integer, got #{inspect(other)}") |
| 432 | + do: raise(ArgumentError, "expected :period to be a postivie integer, got #{inspect(other)}") |
| 413 433 | |
| 414 434 | @spec schedule_measurement(collect_in_millis :: non_neg_integer()) :: :ok |
| 415 435 | defp schedule_measurement(collect_in_millis) do |
| @@ -440,18 +460,22 @@ defmodule Telemetry.Poller do | |
| 440 460 | :error |
| 441 461 | end |
| 442 462 | |
| 443 | - @spec parse_vm_measurements!([term()]) :: [measurement()] | no_return() |
| 463 | + @spec parse_vm_measurements!(term()) :: [measurement()] | no_return() |
| 464 | + defp parse_vm_measurements!(:default) do |
| 465 | + parse_vm_measurements!(@default_vm_measurements) |
| 466 | + end |
| 467 | + |
| 444 468 | defp parse_vm_measurements!(vm_measurements) do |
| 445 469 | Enum.map(vm_measurements, &parse_vm_measurement!/1) |
| 446 470 | end |
| 447 471 | |
| 448 472 | @spec parse_vm_measurement!(term()) :: measurement() | no_return() |
| 449 | - defp parse_vm_measurement!(memory) when memory in @vm_memory_measurements do |
| 450 | - vm_measurement(memory) |
| 473 | + defp parse_vm_measurement!(measurement) when measurement in @vm_measurements do |
| 474 | + vm_measurement(measurement) |
| 451 475 | end |
| 452 476 | |
| 453 477 | defp parse_vm_measurement!(other) do |
| 454 | - raise ArgumentError, "Expected VM measurement, got #{inspect(other)}" |
| 478 | + raise ArgumentError, "unknown VM measurement #{inspect(other)}" |
| 455 479 | end |
| 456 480 | |
| 457 481 | @spec vm_measurement(function :: atom()) :: measurement() |
Loading more files…