From 67e9cf14a60c09bd69aa51fb1e73d85e54969e8d Mon Sep 17 00:00:00 2001 From: Andrea Leopardi Date: Fri, 18 Aug 2023 11:29:44 +0200 Subject: [PATCH] Re-haul Telemetry documentation Closes #325. --- .formatter.exs | 3 +- .gitignore | 1 + lib/xandra/cluster.ex | 94 +----- lib/xandra/cluster/control_connection.ex | 1 - lib/xandra/connection.ex | 110 ++++--- lib/xandra/telemetry.ex | 138 +-------- mix.exs | 9 +- mix.lock | 6 +- pages/generate_telemetry_events_page.exs | 370 +++++++++++++++++++++++ 9 files changed, 441 insertions(+), 291 deletions(-) create mode 100644 pages/generate_telemetry_events_page.exs diff --git a/.formatter.exs b/.formatter.exs index d002e4da..05c08f60 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,7 +1,8 @@ [ inputs: [ "{mix,.formatter}.exs", - "{config,lib,test,test_clustering}/**/*.{ex,exs}" + "{config,lib,test,test_clustering}/**/*.{ex,exs}", + "pages/*.exs" ], import_deps: [:stream_data] ] diff --git a/.gitignore b/.gitignore index 6be12efe..e165ebe8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /priv/plts erl_crash.dump *.ez +/pages/Telemetry events.md diff --git a/lib/xandra/cluster.ex b/lib/xandra/cluster.ex index 6e2b7441..cd3de39b 100644 --- a/lib/xandra/cluster.ex +++ b/lib/xandra/cluster.ex @@ -92,97 +92,9 @@ defmodule Xandra.Cluster do ## Telemetry - This section describes all the Telemetry events that `Xandra.Cluster` emits. These events - are available since *v0.15.0*. See also `Xandra.Telemetry`. - - * `[:xandra, :cluster, :change_event]` — emitted when there is a change in the - cluster, either as reported by Cassandra itself or as detected by Xandra. - - **Measurements**: *none*. - - **Metadata**: - - * `:event_type` - one of `:host_up` (a host went up), `:host_down` (a host went down), - `:host_added` (a host was added to the cluster topology), or `:host_removed` (a host - was removed from the cluster topology). - * `:source` - one of `:cassandra` or `:xandra`. If the event was reported by - Cassandra itself, the source is `:cassandra`. If the event was detected by - Xandra, the source is `:xandra`. - * `:changed` (`t:boolean/0`) - this is `true` if the node wasn't in the state - reported by the event, and `false` if the node was already in the reported state. - * `:host` (`t:Xandra.Cluster.Host.t/0`) - the host that went up or down. - * `:cluster_pid` (`t:pid/0`) - the PID of the cluster process. - * `:cluster_name` - the name of the cluster executing the event, if provided - through the `:name` option in `start_link/1`. `nil` if no `:name` was provided. - - * `[:xandra, :cluster, :control_connection, :connected]` — emitted when the control - connection for the cluster is established. - - **Measurements**: *none*. - - **Metadata**: - * `:host` (`t:Xandra.Cluster.Host.t/0`) - the host that the control connection is - connected to. - * `:cluster_pid` (`t:pid/0`) - the PID of the cluster process. - * `:cluster_name` - the name of the cluster executing the event, if provided - through the `:name` option in `start_link/1`. `nil` if no `:name` was provided. - - * `[:xandra, :cluster, :control_connection, :disconnected]` — emitted when the control - connection for the cluster is established. - - **Measurements**: *none*. - - **Metadata**: - - * `:host` (`t:Xandra.Cluster.Host.t/0`) - the host that the control connection is - connected to. - * `:reason` - the reason for the disconnection. For example, `:closed` if the connected - node closes the connection peacefully. - * `:cluster_pid` (`t:pid/0`) - the PID of the cluster process. - * `:cluster_name` - the name of the cluster executing the event, if provided - through the `:name` option in `start_link/1`. `nil` if no `:name` was provided. - - * `[:xandra, :cluster, :control_connection, :failed_to_connect]` — (available since v0.17.0) - emitted when the control connection for the cluster fails to connect to the given node. - - **Measurements**: *none*. - - **Metadata**: - - * `:host` (`t:Xandra.Cluster.Host.t/0`) - the host that the control connection failed - to connect to. - * `:reason` - the reason for the failure. - * `:cluster_pid` (`t:pid/0`) - the PID of the cluster process. - * `:cluster_name` - the name of the cluster executing the event, if provided - through the `:name` option in `start_link/1`. `nil` if no `:name` was provided. - - * `[:xandra, :cluster, :pool, :started | :restarted]` — (available since v0.17.0) emitted - when a pool of connection to a node is started or restarted. - - **Measurements**: *none*. - - **Metadata**: - - * `:host` (`t:Xandra.Cluster.Host.t/0`) - the host that the pool connected or reconnected - to. - * `:cluster_pid` (`t:pid/0`) - the PID of the cluster process. - * `:cluster_name` - the name of the cluster executing the event, if provided - through the `:name` option in `start_link/1`. `nil` if no `:name` was provided. - - * `[:xandra, :cluster, :discovered_peers]` - (available since v0.17.0) executed when - the Xandra cluster's control connection discovers peers. The peers might have been - already discovered in the past, so you'll need to keep track of new peers if you need to. - - **Measurements**: - - * `:peers` (list of `t:Xandra.Cluster.Host.t/0`) the discovered peers. - - **Metadata**: - - * `:cluster_pid` (`t:pid/0`) - the PID of the cluster process. - * `:cluster_name` - the name of the cluster executing the event, if provided - through the `:name` option in `start_link/1`. `nil` if no `:name` was provided. - + `Xandra.Cluster` emits several Telemetry events to help you log, instrument, + and debug your application. See the [*Telemetry Events*](telemetry-events.html) + page in the guides for a comprehensive list of the events that Xandra emits. """ alias Xandra.{Batch, ConnectionError, OptionsValidators, Prepared, RetryStrategy} diff --git a/lib/xandra/cluster/control_connection.ex b/lib/xandra/cluster/control_connection.ex index 7b16c24c..d1f2bf2f 100644 --- a/lib/xandra/cluster/control_connection.ex +++ b/lib/xandra/cluster/control_connection.ex @@ -239,7 +239,6 @@ defmodule Xandra.Cluster.ControlConnection do end defp refresh_topology(%__MODULE__{} = state, new_peers) do - :telemetry.execute([:xandra, :cluster, :discovered_peers], %{peers: new_peers}, %{}) send(state.cluster_pid, {:discovered_hosts, new_peers}) state end diff --git a/lib/xandra/connection.ex b/lib/xandra/connection.ex index 5f5bcc53..12303a59 100644 --- a/lib/xandra/connection.ex +++ b/lib/xandra/connection.ex @@ -41,24 +41,25 @@ defmodule Xandra.Connection do |> Keyword.merge(@forced_transport_options) } + state = %__MODULE__{ + transport: transport, + prepared_cache: Keyword.fetch!(options, :prepared_cache), + compressor: compressor, + default_consistency: Keyword.fetch!(options, :default_consistency), + atom_keys?: Keyword.fetch!(options, :atom_keys), + current_keyspace: nil, + address: address, + port: port, + connection_name: connection_name, + cluster_pid: cluster_pid, + pool_index: Keyword.fetch!(options, :pool_index) + } + case Transport.connect(transport, address, port, @default_timeout) do {:ok, transport} -> {:ok, peername} = Transport.address_and_port(transport) - state = %__MODULE__{ - transport: transport, - prepared_cache: Keyword.fetch!(options, :prepared_cache), - compressor: compressor, - default_consistency: Keyword.fetch!(options, :default_consistency), - atom_keys?: Keyword.fetch!(options, :atom_keys), - current_keyspace: nil, - address: address, - port: port, - connection_name: connection_name, - cluster_pid: cluster_pid, - pool_index: Keyword.fetch!(options, :pool_index), - peername: peername - } + state = %__MODULE__{state | transport: transport, peername: peername} with {:ok, supported_options, protocol_module} <- Utils.request_options(transport, enforced_protocol), @@ -71,13 +72,14 @@ defmodule Xandra.Connection do compressor, options ) do - :telemetry.execute([:xandra, :connected], %{}, %{ - connection_name: connection_name, - address: address, - port: port, - protocol_module: protocol_module, - supported_options: supported_options - }) + :telemetry.execute( + [:xandra, :connected], + %{}, + telemetry_meta(state, %{ + protocol_module: protocol_module, + supported_options: supported_options + }) + ) if cluster_pid do send(cluster_pid, {:xandra, :connected, peername, self()}) @@ -93,12 +95,14 @@ defmodule Xandra.Connection do """ {:error, {:use_this_protocol_instead, failed_protocol_version, protocol_version}} -> - :telemetry.execute([:xandra, :debug, :downgrading_protocol], %{}, %{ - failed_version: failed_protocol_version, - new_version: protocol_version, - address: address, - port: port - }) + :telemetry.execute( + [:xandra, :debug, :downgrading_protocol], + %{}, + telemetry_meta(state, %{ + failed_version: failed_protocol_version, + new_version: protocol_version + }) + ) _transport = Transport.close(transport) options = Keyword.put(options, :protocol_version, protocol_version) @@ -119,13 +123,11 @@ defmodule Xandra.Connection do {:error, _reason} -> address end - :telemetry.execute([:xandra, :failed_to_connect], %{}, %{ - connection: self(), - connection_name: connection_name, - address: address, - port: port, - reason: reason - }) + :telemetry.execute( + [:xandra, :failed_to_connect], + %{}, + telemetry_meta(state, %{reason: reason}) + ) if cluster_pid do send(cluster_pid, {:xandra, :failed_to_connect, {ipfied_address, port}, self()}) @@ -193,14 +195,7 @@ defmodule Xandra.Connection do force? = Keyword.fetch!(options, :force) telemetry_metadata = Keyword.fetch!(options, :telemetry_metadata) - - metadata = %{ - query: prepared, - connection_name: state.connection_name, - address: state.address, - port: state.port, - extra_metadata: telemetry_metadata - } + metadata = telemetry_meta(state, %{query: prepared, extra_metadata: telemetry_metadata}) case prepared_cache_lookup(state, prepared, force?) do {:ok, prepared} -> @@ -293,14 +288,7 @@ defmodule Xandra.Connection do assert_valid_compressor(state.compressor, options[:compressor]) telemetry_metadata = Keyword.fetch!(options, :telemetry_metadata) - - metadata = %{ - query: query, - connection_name: state.connection_name, - address: state.address, - port: state.port, - extra_metadata: telemetry_metadata - } + metadata = telemetry_meta(state, %{query: query, extra_metadata: telemetry_metadata}) :telemetry.span( [:xandra, :execute_query], @@ -354,7 +342,7 @@ defmodule Xandra.Connection do if warnings != [] do metadata = state - |> Map.take([:address, :port, :current_keyspace]) + |> telemetry_meta(Map.take(state, [:current_keyspace])) |> Map.put(:query, query) :telemetry.execute([:xandra, :server_warnings], %{warnings: warnings}, metadata) @@ -368,13 +356,7 @@ defmodule Xandra.Connection do @impl true def disconnect(exception, %__MODULE__{} = state) do - :telemetry.execute([:xandra, :disconnected], %{}, %{ - connection: self(), - connection_name: state.connection_name, - address: state.address, - port: state.port, - reason: exception - }) + :telemetry.execute([:xandra, :disconnected], %{}, telemetry_meta(state, %{reason: exception})) if state.cluster_pid do send(state.cluster_pid, {:xandra, :disconnected, state.peername, self()}) @@ -502,4 +484,16 @@ defmodule Xandra.Connection do "module (which uses the #{inspect(initial_algorithm)} algorithm)" end end + + defp telemetry_meta(%__MODULE__{} = state, extra_meta) do + Map.merge( + %{ + connection: self(), + connection_name: state.connection_name, + address: state.address, + port: state.port + }, + extra_meta + ) + end end diff --git a/lib/xandra/telemetry.ex b/lib/xandra/telemetry.ex index 3d999c07..3e8fbc67 100644 --- a/lib/xandra/telemetry.ex +++ b/lib/xandra/telemetry.ex @@ -10,142 +10,10 @@ defmodule Xandra.Telemetry do ## Events - Here is a comprehensive list of the Telemetry events that Xandra emits. - - ### Connection Events - - * `[:xandra, :connected]` — executed when a connection connects to its Cassandra node. - * **Measurements**: *none*. - * **Metadata**: - * `:connection_name` - given name of the connection or `nil` if not set - * `:address` - the address of the node the connection is connected to - * `:port` - the port of the node the connection is connected to - * `:protocol_module` - the protocol module used by the connection - * `:supported_options` - Cassandra supported options as a map (mostly useful for - internal debugging) - - * `[:xandra, :disconnected]` — executed when a connection disconnects from its Cassandra node. - * **Measurements**: *none*. - * **Metadata**: - * `:connection_name` - given name of the connection or `nil` if not set - * `:address` - the address of the node the connection is connected to - * `:port` - the port of the node the connection is connected to - * `:reason` - the reason for the disconnection (usually a `DBConnection.ConnectionError`) - - ### Query Events - - The `[:xandra, :prepare_query, ...]` and `[:xandra, :execute_query, ...]` events are - Telemetry **spans**. See - [`telemetry:span/3`](https://hexdocs.pm/telemetry/telemetry.html#span/3). All the time - measurements are in *native* time unit, so you need to use `System.convert_time_unit/3` - to convert to the desired time unit. - - * `[:xandra, :prepare_query, :start]` — executed before a query is prepared. - * Measurements: - * `:system_time` (in `:native` time units) - * `:monotonic_time` (in `:native` time units) - * Metadata: - * `:query` (`t:Xandra.Prepared.t/0`) - the query being prepared - * `:connection_name` - given name of the connection or `nil` if not set - * `:address` - the address of the node the connection is connected to - * `:port` - the port of the node the connection is connected to - * `:extra_metadata` - extra metadata provided by `:telemetry_metadata` option - - * `[:xandra, :prepare_query, :stop]` — executed after a query was prepared. - * Measurements: - * `:duration` (in `:native` time units) - * `:monotonic_time` (in `:native` time units) - * Metadata: - * `:query` (`t:Xandra.Prepared.t/0`) - the query being prepared - * `:connection_name` - given name of the connection or `nil` if not set - * `:address` - the address of the node the connection is connected to - * `:port` - the port of the node the connection is connected to - * `:reason` - if error, reason - * `:extra_metadata` - extra metadata provided by `:telemetry_metadata` option - - * `[:xandra, :prepare_query, :exception]` — executed if there was an exception - when preparing a query. - * Measurements: - * `:duration` (in `:native` time units) - * `:monotonic_time` (in `:native` time units) - * Metadata: - * `:query` (`t:Xandra.Prepared.t/0`) - the query being prepared - * `:connection_name` - given name of the connection or `nil` if not set - * `:address` - the address of the node the connection is connected to - * `:port` - the port of the node the connection is connected to - * `:reason` - if error, reason - * `:kind` - kind on `:exception` - * `:stacktrace` - stacktrace on `:exception` - * `:extra_metadata` - extra metadata provided by `:telemetry_metadata` option - - * `[:xandra, :execute_query, :start]` — executed before a query is executed. - * Measurements: - * `:system_time` (in `:native` time units) - * `:monotonic_time` (in `:native` time units) - * Metadata: - * `:query` (`t:Xandra.Simple.t/0`, `t:Xandra.Batch.t/0`, or `t:Xandra.Prepared.t/0`) — - the query being executed - * `:connection_name` - given name of the connection or `nil` if not set - * `:address` - the address of the node the connection is connected to - * `:port` - the port of the node the connection is connected to - * `:extra_metadata` - extra metadata provided by `:telemetry_metadata` option - - * `[:xandra, :execute_query, :stop]` — executed after a query was executed. - * Measurements: - * `:duration` (in `:native` time units) - * `:monotonic_time` (in `:native` time units) - * Metadata: - * `:query` (`t:Xandra.Simple.t/0`, `t:Xandra.Batch.t/0`, or `t:Xandra.Prepared.t/0`) — - the query being executed - * `:connection_name` - given name of the connection or `nil` if not set - * `:address` - the address of the node the connection is connected to - * `:port` - the port of the node the connection is connected to - * `:reason` - if error, reason - * `:extra_metadata` - extra metadata provided by `:telemetry_metadata` option - - * `[:xandra, :execute_query, :exception]` — executed if there was an exception - when executing a query. - * Measurements: - * `:duration` (in `:native` time units) - * `:monotonic_time` (in `:native` time units) - * Metadata: - * `:query` (`t:Xandra.Simple.t/0`, `t:Xandra.Batch.t/0`, or `t:Xandra.Prepared.t/0`) — - the query being executed - * `:connection_name` - given name of the connection or `nil` if not set - * `:address` - the address of the node the connection is connected to - * `:port` - the port of the node the connection is connected to - * `:reason` - if error, reason - * `:kind` - kind on `:exception` - * `:stacktrace` - stacktrace on `:exception` - * `:extra_metadata` - extra metadata provided by `:telemetry_metadata` option - - * `[:xandra, :prepared_cache, :hit]` and `[:xandra, :prepared_cache, :miss]` — executed - when a query is executed and the prepared cache is checked. - - * Measurements: - * `:query` (`t:Xandra.Prepared.t/0`) - the query being looked up in the cache - * `:connection_name` - given name of the connection or `nil` if not set - * `:address` - the address of the node the connection is connected to - * `:port` - the port of the node the connection is connected to - * `:extra_metadata` - extra metadata provided by `:telemetry_metadata` option - - ### Warnings - - * `[:xandra, :server_warnings]` - * Measurements: - * `:warnings` - A list of warnings where each warning is a string. It contains at least - one element. - * Metadata: - * `:address` - the address of the node the connection is connected to - * `:port` - the port of the node the connection is connected to - * `:current_keyspace` - the current keyspace of the connection, or `nil` if not set - * `:query` - the query that caused the warning, of type `t:Xandra.Batch.t/0`, - `t:Xandra.Prepared.t/0`, or `t:Xandra.Simple.t/0` - - ### Cluster Events - - See the "Telemetry" section in the documentation for `Xandra.Cluster`. + For a comprehensive list of the events that Xandra emits, see the + [*Telemetry Events*](telemetry-events.html) page in the guides. """ + @moduledoc since: "0.15.0" alias Xandra.Cluster.Host diff --git a/mix.exs b/mix.exs index 6609c5e6..09eb4e64 100644 --- a/mix.exs +++ b/mix.exs @@ -50,7 +50,8 @@ defmodule Xandra.Mixfile do source_url: @repo_url, extras: [ "pages/Data types comparison table.md", - "pages/Compatibility.md" + "pages/Compatibility.md", + "pages/Telemetry events.md" ] ] ] @@ -84,7 +85,11 @@ defmodule Xandra.Mixfile do "test.all": fn args -> Mix.Task.run(:test, args) Mix.Task.run(:"test.scylladb", args) - end + end, + docs: [ + "run pages/generate_telemetry_events_page.exs", + "docs" + ] ] end diff --git a/mix.lock b/mix.lock index a9d1ba18..e4774d22 100644 --- a/mix.lock +++ b/mix.lock @@ -3,14 +3,14 @@ "db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "dialyxir": {:hex, :dialyxir, "1.3.0", "fd1672f0922b7648ff9ce7b1b26fcf0ef56dda964a459892ad15f6b4410b5284", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "00b2a4bcd6aa8db9dcb0b38c1225b7277dca9bc370b6438715667071a304696f"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.32", "fa739a0ecfa34493de19426681b23f6814573faee95dfd4b4aafe15a7b5b32c6", [:mix], [], "hexpm", "b8b0dd77d60373e77a3d7e8afa598f325e49e8663a51bcc2b88ef41838cca755"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.33", "3c3fd9673bb5dcc9edc28dd90f50c87ce506d1f71b70e3de69aa8154bc695d44", [:mix], [], "hexpm", "2d526833729b59b9fdb85785078697c72ac5e5066350663e5be6a1182da61b8f"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"}, + "ex_doc": {:hex, :ex_doc, "0.30.5", "aa6da96a5c23389d7dc7c381eba862710e108cee9cfdc629b7ec021313900e9e", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "88a1e115dcb91cefeef7e22df4a6ebbe4634fbf98b38adcbc25c9607d6d9d8e6"}, "excoveralls": {:hex, :excoveralls, "0.17.0", "279f124dba347903bb654bc40745c493ae265d45040001b4899ea1edf88078c7", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "08b638d114387a888f9cb8d65f2a0021ec04c3e447b793efa7c1e734aba93004"}, "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, - "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.2", "ad87296a092a46e03b7e9b0be7631ddcf64c790fa68a9ef5323b6cbb36affc72", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f3f5a1ca93ce6e092d92b6d9c049bcda58a3b617a8d888f8e7231c85630e8108"}, "mox": {:hex, :mox, "1.0.2", "dc2057289ac478b35760ba74165b4b3f402f68803dd5aecd3bfd19c183815d64", [:mix], [], "hexpm", "f9864921b3aaf763c8741b5b8e6f908f44566f1e427b2630e89e9a73b981fef2"}, "nimble_lz4": {:hex, :nimble_lz4, "0.1.3", "ce2d6594a652489322962f4c037f1b55802f17666c7154c66bab529c542d71be", [:mix], [{:rustler, "~> 0.29.0", [hex: :rustler, repo: "hexpm", optional: false]}, {:rustler_precompiled, "~> 0.6.2", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "eeec9c66d6562155a6c43481f2895828bd3e58287c14bcd65557bd02bbe84993"}, "nimble_options": {:hex, :nimble_options, "1.0.2", "92098a74df0072ff37d0c12ace58574d26880e522c22801437151a159392270e", [:mix], [], "hexpm", "fd12a8db2021036ce12a309f26f564ec367373265b53e25403f0ee697380f1b8"}, diff --git a/pages/generate_telemetry_events_page.exs b/pages/generate_telemetry_events_page.exs new file mode 100644 index 00000000..ad020b65 --- /dev/null +++ b/pages/generate_telemetry_events_page.exs @@ -0,0 +1,370 @@ +defmodule Helpers do + def render_list(items) do + template = """ + <%= for {name, info} <- items do %> + * `<%= inspect(name) %>` (<%= info[:type] %>) - <%= info[:doc] %> + <% end %> + """ + + template + |> EEx.eval_string(items: items) + |> String.replace(~r(\n+), "\n") + end +end + +defmodule Generate do + require EEx + + def go(%{title: title, sections: sections}) do + template = """ + <% import Helpers %> + # <%= title %> + + <%= for section <- sections do %> + + ## <%= section.title %> + + <%= if section[:doc] do %><%= section.doc %><% end %> + + <%= for {event, data} <- section.events do %> + ### `<%= event %>` + + <%= if data[:since] do %> + *Available since v<%= data[:since] %>*. + <% end %> + + <%= if data[:doc] do %><%= data[:doc] %><% end %> + + <%= if (data[:measurements] || []) == [] do %> + **Measurements**: *none* + <% else %> + **Measurements**: + <%= render_list(data[:measurements]) %> + <% end %> + + <%= if (data[:metadata] || []) == [] do %> + **Metadata**: *none* + <% else %> + **Metadata**: + <%= render_list(data[:metadata]) %> + <% end %> + + <% end %> + <% end %> + """ + + EEx.eval_string(template, title: title, sections: sections) + end +end + +span_measurements = [ + system_time: [ + type: "`t:integer/0`", + doc: "in `:native` time units (only for `[..., :start]` events)" + ], + monotonic_time: [ + type: "`t:integer/0`", + doc: "in `:native` time units" + ], + duration: [ + type: "`t:integer/0`", + doc: """ + in `:native` time units (only for `[..., :stop]` and `[..., :exception]` events) + """ + ] +] + +shared_connection_meta = [ + connection: [ + type: "`t:pid/0`", + doc: "the PID of the connection process" + ], + connection_name: [ + type: "`t:String.t/0` or `nil`", + doc: "given name of the connection or `nil` if not set" + ], + address: [ + type: "`t:String.t/0`", + doc: "the address of the node the connection is connected to" + ], + port: [ + type: "`t::inet.port_number/0`", + doc: "the port of the node the connection is connected to" + ] +] + +shared_cluster_meta = [ + cluster_pid: [ + type: "`t:pid/0`", + doc: "the PID of the cluster process" + ], + cluster_name: [ + type: "`t:String.t/0` or `nil`", + doc: """ + the name of the cluster executing the event, if provided + through the `:name` option in `Xandra.Cluster.start_link/1` + """ + ], + host: [ + type: "`t:Xandra.Cluster.Host.t/0`", + doc: "the host the event is related to" + ] +] + +data = %{ + title: "Telemetry Events", + sections: [ + %{ + title: "Connection Events", + events: [ + "[:xandra, :connected]": %{ + doc: "Executed when a connection connects to its Cassandra node.", + metadata: + shared_connection_meta ++ + [ + protocol_module: [ + type: "`t:module/0`", + doc: "the protocol module used for the connection" + ], + supported_options: [ + type: "`t:map/0`", + doc: """ + Cassandra supported options (mostly useful for internal debugging) + """ + ] + ] + }, + "[:xandra, :disconnected]": %{ + doc: "Executed when a connection disconnects from its Cassandra node.", + metadata: + shared_connection_meta ++ + [ + reason: [ + type: "usually a `DBConnection.ConnectionError`", + doc: "the reason for the disconnection" + ] + ] + }, + "[:xandra, :failed_to_connect]": %{ + since: "0.18.0", + doc: "Executed when a connection fails to connect to its Cassandra node.", + metadata: + shared_connection_meta ++ + [ + reason: [ + type: "usually a `DBConnection.ConnectionError`", + doc: "the reason for the disconnection" + ] + ] + } + ] + }, + %{ + title: "Query Events", + doc: """ + The `[:xandra, :prepare_query, ...]` and `[:xandra, :execute_query, ...]` events are + Telemetry **spans**. See + [`telemetry:span/3`](https://hexdocs.pm/telemetry/telemetry.html#span/3). All the time + measurements are in *native* time unit, so you need to use `System.convert_time_unit/3` + to convert to the desired time unit. + """, + events: [ + "[:xandra, :prepare_query, ...]": [ + doc: "Executed before and after a query is prepared (as a Telemetry **span**).", + measurements: span_measurements, + metadata: + shared_connection_meta ++ + [ + query: [ + type: "`t:Xandra.Prepared.t/0`", + doc: "the query being prepared" + ], + extra_metadata: [ + type: "any term", + doc: """ + extra metadata provided by the `:telemetry_metadata` option + """ + ], + reprepared: [ + type: "`t:boolean/0`", + doc: """ + whether the query was reprepared or not (only available for + `[..., :stop]` events) + """ + ], + reason: [ + type: "any term", + doc: """ + if there the result of the query was an error, this is the reason + (only available for `[..., :stop]` events), otherwise it's the error + that was raised (only available for `[..., :exception]` events) + """ + ], + kind: [ + type: "`t:Exception.kind/0`", + doc: "exception kind (only available for `[..., :exception]` events)" + ], + stacktrace: [ + type: "`t:Exception.stacktrace/0`", + doc: "exception stacktrace (only available for `[..., :exception]` events)" + ] + ] + ], + "[:xandra, :execute_query, ...]": [ + doc: "Executed before and after a query is executed (as a Telemetry **span**).", + measurements: span_measurements, + metadata: + shared_connection_meta ++ + [ + query: [ + type: "`t:Xandra.Simple.t/0`, `t:Xandra.Batch.t/0`, or `t:Xandra.Prepared.t/0`", + doc: "the query being executed" + ], + extra_metadata: [ + type: "any term", + doc: """ + extra metadata provided by the `:telemetry_metadata` option + """ + ], + reason: [ + type: "any term", + doc: """ + if there the result of the query was an error, this is the reason + (only available for `[..., :stop]` events), otherwise it's the error + that was raised (only available for `[..., :exception]` events) + """ + ], + kind: [ + type: "`t:Exception.kind/0`", + doc: "exception kind (only available for `[..., :exception]` events)" + ], + stacktrace: [ + type: "`t:Exception.stacktrace/0`", + doc: "exception stacktrace (only available for `[..., :exception]` events)" + ] + ] + ], + "[:xandra, :prepared_cache, :hit | :miss]": [ + doc: "Executed when a query is executed and the prepared cache is checked.", + measurements: [], + metadata: + shared_connection_meta ++ + [ + query: [ + type: "`t:Xandra.Prepared.t/0`", + doc: "the query being prepared" + ], + extra_metadata: [ + type: "any term", + doc: """ + extra metadata provided by the `:telemetry_metadata` option + """ + ] + ] + ] + ] + }, + %{ + title: "Warnings", + events: [ + "[:xandra, :server_warnings]": [ + doc: "Executed when a query returns warnings.", + measurements: [ + warnings: [ + type: "non-empty list of `t:String.t/0`", + doc: "a list of warnings" + ] + ], + metadata: [ + address: [ + type: "`t:String.t/0`", + doc: "the address of the node the connection is connected to" + ], + port: [ + type: "`t::inet.port_number/0`", + doc: "the port of the node the connection is connected to" + ], + current_keyspace: [ + type: "`t:String.t/0` or `nil`", + doc: "the current keyspace of the connection, or `nil` if not set" + ], + query: [ + type: "`t:Xandra.Simple.t/0`, `t:Xandra.Batch.t/0`, or `t:Xandra.Prepared.t/0`", + doc: "the query that caused the warnings" + ] + ] + ] + ] + }, + %{ + title: "Cluster Events", + doc: "Unless specified otherwise, these are available since v0.15.0.", + events: [ + "[:xandra, :cluster, :change_event]": [ + doc: """ + Emitted when there is a change in the cluster, either as reported by Cassandra itself + or as detected by Xandra. + """, + metadata: + shared_cluster_meta ++ + [ + event_type: [ + type: "`t:atom/0`", + doc: """ + one of `:host_up` (a host went up), `:host_down` (a host went down), + `:host_added` (a host was added to the cluster topology), or `:host_removed` + (a host was removed from the cluster topology) + """ + ] + ] + ], + "[:xandra, :cluster, :discovered_peers]": [ + since: "0.17.0", + doc: """ + Executed when the Xandra cluster's control connection discovers peers. The peers might have been + already discovered in the past, so you'll need to keep track of new peers if you need to. + """, + measurements: [ + peers: [ + type: "list of `t:Xandra.Cluster.Host.t/0`", + doc: "the discovered peers" + ] + ], + metadata: Keyword.delete(shared_cluster_meta, :host) + ], + "[:xandra, :cluster, :pool, :started | :restarted | :stopped]": [ + since: "0.17.0", + doc: """ + Executed when a connection pool to a node is started, restarted, or stopped. + """, + metadata: shared_cluster_meta + ], + "[:xandra, :cluster, :control_connection, :connected]": [ + doc: """ + Emitted when the control connection for the cluster is established. + """, + metadata: shared_cluster_meta + ], + "[:xandra, :cluster, :control_connection, :disconnected | :failed_to_connect]": [ + doc: """ + Emitted when the control connection for the cluster disconnects or fails to connect. + """, + metadata: + shared_cluster_meta ++ + [ + reason: [ + type: "any term", + doc: "the reason for the disconnection or failure to connect" + ] + ] + ] + ] + } + ] +} + +path = "pages/Telemetry events.md" +markdown = Generate.go(data) +File.write!(path, markdown) + +IO.puts(IO.ANSI.format([:cyan, "Generated Telemetry docs", :reset, " (at #{inspect(path)})"]))