From 9d4afc77de9f37a5154bfc6cbd37d9001a98cfb6 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Fri, 13 Sep 2024 16:25:45 +1200 Subject: [PATCH 01/16] Support Grafana via `prom_ex` --- config/runtime.exs | 12 +++++++++ lib/nerves_hub/application.ex | 5 +++- lib/nerves_hub/prom_ex.ex | 38 +++++++++++++++++++++++++++ lib/nerves_hub_web/device_endpoint.ex | 2 ++ lib/nerves_hub_web/endpoint.ex | 2 ++ mix.exs | 5 ++-- mix.lock | 32 +++++++++++++--------- 7 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 lib/nerves_hub/prom_ex.ex diff --git a/config/runtime.exs b/config/runtime.exs index e6125ccc8..dd1f52c56 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -358,6 +358,18 @@ if System.get_env("SENTRY_DSN_URL") do before_send: {NervesHubWeb.SentryEventFilter, :filter_non_500} end +if System.get_env("GRAFANA_HOST") do + config :nerves_hub, NervesHub.PromEx, + manual_metrics_start_delay: :no_delay, + grafana: [ + host: System.get_env("GRAFANA_HOST"), + auth_token: System.get_env("GRAFANA_TOKEN") || raise("GRAFANA_TOKEN is required"), + upload_dashboards_on_start: true, + folder_name: "NervesHub App Dashboards", + annotate_app_lifecycle: true + ] +end + config :nerves_hub, :statsd, host: System.get_env("STATSD_HOST", "localhost"), port: String.to_integer(System.get_env("STATSD_PORT", "8125")) diff --git a/lib/nerves_hub/application.ex b/lib/nerves_hub/application.ex index 7907b75be..587ce2882 100644 --- a/lib/nerves_hub/application.ex +++ b/lib/nerves_hub/application.ex @@ -39,7 +39,10 @@ defmodule NervesHub.Application do {Oban, Application.fetch_env!(:nerves_hub, Oban)} ] ++ deployments_supervisor(deploy_env()) ++ - endpoints(deploy_env()) + endpoints(deploy_env()) ++ + [ + NervesHub.PromEx + ] opts = [strategy: :one_for_one, name: NervesHub.Supervisor] Supervisor.start_link(children, opts) diff --git a/lib/nerves_hub/prom_ex.ex b/lib/nerves_hub/prom_ex.ex new file mode 100644 index 000000000..48e72eaca --- /dev/null +++ b/lib/nerves_hub/prom_ex.ex @@ -0,0 +1,38 @@ +defmodule NervesHub.PromEx do + use PromEx, otp_app: :nerves_hub + + alias PromEx.Plugins + + @impl true + def plugins do + [ + # PromEx built in plugins + Plugins.Application, + Plugins.Beam, + {Plugins.Phoenix, router: NervesHubWeb.Router}, + Plugins.PhoenixLiveView, + Plugins.Ecto, + Plugins.Oban + ] + end + + @impl true + def dashboard_assigns do + [ + datasource_id: "prometheus" + ] + end + + @impl true + def dashboards do + [ + # PromEx built in Grafana dashboards + {:prom_ex, "application.json"}, + {:prom_ex, "beam.json"}, + {:prom_ex, "phoenix.json"}, + {:prom_ex, "phoenix_live_view.json"}, + {:prom_ex, "ecto.json"}, + {:prom_ex, "oban.json"} + ] + end +end diff --git a/lib/nerves_hub_web/device_endpoint.ex b/lib/nerves_hub_web/device_endpoint.ex index b20f63b0a..360d20682 100644 --- a/lib/nerves_hub_web/device_endpoint.ex +++ b/lib/nerves_hub_web/device_endpoint.ex @@ -33,6 +33,8 @@ defmodule NervesHubWeb.DeviceEndpoint do plug(NervesHubWeb.Plugs.ImAlive) + plug(PromEx.Plug, prom_ex_module: NervesHub.PromEx) + plug(Sentry.PlugContext) plug(NervesHubWeb.Plugs.Logger) diff --git a/lib/nerves_hub_web/endpoint.ex b/lib/nerves_hub_web/endpoint.ex index af64b48d0..d70ec7f7f 100644 --- a/lib/nerves_hub_web/endpoint.ex +++ b/lib/nerves_hub_web/endpoint.ex @@ -60,6 +60,8 @@ defmodule NervesHubWeb.Endpoint do cookie_key: "request_logger" ) + plug(PromEx.Plug, prom_ex_module: NervesHub.PromEx) + plug(Plug.RequestId) plug(Plug.Telemetry, event_prefix: [:phoenix, :endpoint]) plug(NervesHubWeb.Plugs.Logger) diff --git a/mix.exs b/mix.exs index 2469e4944..b6ffdd7f7 100644 --- a/mix.exs +++ b/mix.exs @@ -95,16 +95,17 @@ defmodule NervesHub.MixProject do {:phoenix_pubsub, "~> 2.0"}, {:phoenix_swoosh, "~> 1.0"}, {:phoenix_view, "~> 2.0"}, - {:phoenix_test, "~> 0.3.0", only: :test, runtime: false}, + {:phoenix_test, "0.3.1", only: :test, runtime: false}, {:plug, "~> 1.7"}, {:postgrex, "~> 0.14"}, + {:prom_ex, "~> 1.10"}, {:scrivener_ecto, "~> 2.7"}, {:scrivener_html, git: "https://github.com/nerves-hub/scrivener_html", branch: "phx-1.5"}, {:sentry, "~> 10.0"}, {:slipstream, "~> 1.0", only: [:test, :dev]}, {:sweet_xml, "~> 0.6"}, {:swoosh, "~> 1.12"}, - {:telemetry_metrics, "~> 0.4"}, + {:telemetry_metrics, "~> 1.0"}, {:telemetry_metrics_statsd, "~> 0.7.0"}, {:telemetry_poller, "~> 1.0"}, {:timex, "~> 3.1"}, diff --git a/mix.lock b/mix.lock index 6d8fbc725..aba22df44 100644 --- a/mix.lock +++ b/mix.lock @@ -9,6 +9,9 @@ "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"}, "contex": {:hex, :contex, "0.5.0", "5d8a6defbeb41f54adfcb0f85c4756d4f2b84aa5b0d809d45a5d2e90d91d0392", [:mix], [{:nimble_strftime, "~> 0.1.0", [hex: :nimble_strftime, repo: "hexpm", optional: false]}], "hexpm", "b7497a1790324d84247859df44ba4bcf2489d9bba1812a5375b2f2046b9e6fd7"}, + "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"}, + "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, + "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, "crontab": {:hex, :crontab, "1.1.13", "3bad04f050b9f7f1c237809e42223999c150656a6b2afbbfef597d56df2144c5", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "d67441bec989640e3afb94e123f45a2bc42d76e02988c9613885dc3d01cf7085"}, "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, @@ -22,10 +25,10 @@ "elixir_make": {:hex, :elixir_make, "0.8.4", "4960a03ce79081dee8fe119d80ad372c4e7badb84c493cc75983f9d3bc8bde0f", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.0", [hex: :certifi, repo: "hexpm", optional: true]}], "hexpm", "6e7f1d619b5f61dfabd0a20aa268e575572b542ac31723293a4c1a567d5ef040"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "eternal": {:hex, :eternal, "1.2.2", "d1641c86368de99375b98d183042dd6c2b234262b8d08dfd72b9eeaafc2a1abd", [:mix], [], "hexpm", "2c9fe32b9c3726703ba5e1d43a1d255a4f3f2d8f8f9bc19f094c7cb1a7a9e782"}, - "ex_aws": {:hex, :ex_aws, "2.5.4", "86c5bb870a49e0ab6f5aa5dd58cf505f09d2624ebe17530db3c1b61c88a673af", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e82bd0091bb9a5bb190139599f922ff3fc7aebcca4374d65c99c4e23aa6d1625"}, - "ex_aws_s3": {:hex, :ex_aws_s3, "2.5.3", "422468e5c3e1a4da5298e66c3468b465cfd354b842e512cb1f6fbbe4e2f5bdaf", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "4f09dd372cc386550e484808c5ac5027766c8d0cd8271ccc578b82ee6ef4f3b8"}, + "ex_aws": {:hex, :ex_aws, "2.5.5", "5dc378eff99c3c46c917b7a96a75ad0d4c300ab7250df668d0819bcd18c0213d", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:req, "~> 0.3", [hex: :req, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ed7ee39c56012c56600e021953c6487ecce9c49320ec3b4655a15d785f221ca6"}, + "ex_aws_s3": {:hex, :ex_aws_s3, "2.5.4", "87aaf4a2f24a48f516d7f5aaced9d128dd5d0f655c4431f9037a11a85c71109c", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "c06e7f68b33f7c0acba1361dbd951c79661a28f85aa2e0582990fccca4425355"}, "expo": {:hex, :expo, "0.5.2", "beba786aab8e3c5431813d7a44b828e7b922bfa431d6bfbada0904535342efe2", [:mix], [], "hexpm", "8c9bfa06ca017c9cb4020fabe980bc7fdb1aaec059fd004c2ab3bff03b1c599c"}, - "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, + "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"}, "floki": {:hex, :floki, "0.36.2", "a7da0193538c93f937714a6704369711998a51a6164a222d710ebd54020aa7a3", [:mix], [], "hexpm", "a8766c0bc92f074e5cb36c4f9961982eda84c5d2b8e979ca67f5c268ec8ed580"}, "gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"}, @@ -45,14 +48,16 @@ "mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"}, "mint_web_socket": {:hex, :mint_web_socket, "1.0.4", "0b539116dbb3d3f861cdf5e15e269a933cb501c113a14db7001a3157d96ffafd", [:mix], [{:mint, ">= 1.4.1 and < 2.0.0-0", [hex: :mint, repo: "hexpm", optional: false]}], "hexpm", "027d4c5529c45a4ba0ce27a01c0f35f284a5468519c045ca15f43decb360a991"}, "mix_test_watch": {:hex, :mix_test_watch, "1.2.0", "1f9acd9e1104f62f280e30fc2243ae5e6d8ddc2f7f4dc9bceb454b9a41c82b42", [:mix], [{:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "278dc955c20b3fb9a3168b5c2493c2e5cffad133548d307e0a50c7f2cfbf34f6"}, - "mox": {:hex, :mox, "1.1.0", "0f5e399649ce9ab7602f72e718305c0f9cdc351190f72844599545e4996af73c", [:mix], [], "hexpm", "d44474c50be02d5b72131070281a5d3895c0e7a95c780e90bc0cfe712f633a13"}, + "mox": {:hex, :mox, "1.2.0", "a2cd96b4b80a3883e3100a221e8adc1b98e4c3a332a8fc434c39526babafd5b3", [:mix], [{:nimble_ownership, "~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}], "hexpm", "c7b92b3cc69ee24a7eeeaf944cd7be22013c52fcb580c1f33f50845ec821089a"}, "nimble_csv": {:hex, :nimble_csv, "1.2.0", "4e26385d260c61eba9d4412c71cea34421f296d5353f914afe3f2e71cce97722", [:mix], [], "hexpm", "d0628117fcc2148178b034044c55359b26966c6eaa8e2ce15777be3bbc91b12a"}, "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_ownership": {:hex, :nimble_ownership, "1.0.0", "3f87744d42c21b2042a0aa1d48c83c77e6dd9dd357e425a038dd4b49ba8b79a1", [:mix], [], "hexpm", "7c16cc74f4e952464220a73055b557a273e8b1b7ace8489ec9d86e9ad56cb2cc"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "nimble_strftime": {:hex, :nimble_strftime, "0.1.1", "b988184d1bd945bc139b2c27dd00a6c0774ec94f6b0b580083abd62d5d07818b", [:mix], [], "hexpm", "89e599c9b8b4d1203b7bb5c79eb51ef7c6a28fbc6228230b312f8b796310d755"}, - "oban": {:hex, :oban, "2.17.12", "33fb0cbfb92b910d48dd91a908590fe3698bb85eacec8cd0d9bc6aa13dddd6d6", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7a647d6cd6bb300073db17faabce22d80ae135da3baf3180a064fa7c4fa046e3"}, + "oban": {:hex, :oban, "2.18.3", "1608c04f8856c108555c379f2f56bc0759149d35fa9d3b825cb8a6769f8ae926", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "36ca6ca84ef6518f9c2c759ea88efd438a3c81d667ba23b02b062a0aa785475e"}, + "octo_fetch": {:hex, :octo_fetch, "0.4.0", "074b5ecbc08be10b05b27e9db08bc20a3060142769436242702931c418695b19", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "cf8be6f40cd519d7000bb4e84adcf661c32e59369ca2827c4e20042eda7a7fc6"}, "parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, + "peep": {:hex, :peep, "3.2.0", "569d7b1f1a8c8f3e72327b42c0b9d4284db9d4ca53514bcf9c8358ee70f45ff8", [:mix], [{:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:plug, "~> 1.16", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry_metrics, "~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "267ffde5b7261b132f4e6a0b602d789be176fe8160fad788af9ca0de2c9a9180"}, "phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.6.2", "3b83b24ab5a2eb071a20372f740d7118767c272db386831b2e77638c4dcc606d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "3f94d025f59de86be00f5f8c5dd7b5965a3298458d21ab1c328488be3b5fcd59"}, "phoenix_html": {:hex, :phoenix_html, "3.3.4", "42a09fc443bbc1da37e372a5c8e6755d046f22b9b11343bf885067357da21cb3", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0249d3abec3714aff3415e7ee3d9786cb325be3151e6c4b3021502c585bf53fb"}, @@ -65,27 +70,30 @@ "phoenix_test": {:hex, :phoenix_test, "0.3.1", "adf5d67cb152fa1e0220527a9827db7f865a20817c7c0161315ba6fe86a8946c", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:floki, ">= 0.30.0", [hex: :floki, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.7.10", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.20.1", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "03f24332a966673ff40d35c45f427c7671537ea508b5777141dd60e60cdae22a"}, "phoenix_view": {:hex, :phoenix_view, "2.0.4", "b45c9d9cf15b3a1af5fb555c674b525391b6a1fe975f040fb4d913397b31abf4", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "4e992022ce14f31fe57335db27a28154afcc94e9983266835bb3040243eb620b"}, "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, + "plug_cowboy": {:hex, :plug_cowboy, "2.7.2", "fdadb973799ae691bf9ecad99125b16625b1c6039999da5fe544d99218e662e4", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "245d8a11ee2306094840c000e8816f0cbed69a23fc0ac2bcf8d7835ae019bb2f"}, "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, "postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"}, - "ranch": {:hex, :ranch, "2.1.0", "2261f9ed9574dcfcc444106b9f6da155e6e540b2f82ba3d42b339b93673b72a3", [:make, :rebar3], [], "hexpm", "244ee3fa2a6175270d8e1fc59024fd9dbc76294a321057de8f803b1479e76916"}, - "recon": {:hex, :recon, "2.5.5", "c108a4c406fa301a529151a3bb53158cadc4064ec0c5f99b03ddb8c0e4281bdf", [:mix, :rebar3], [], "hexpm", "632a6f447df7ccc1a4a10bdcfce71514412b16660fe59deca0fcf0aa3c054404"}, + "prom_ex": {:hex, :prom_ex, "1.10.0", "2fe14cd0b2f7f8688280b02861c58da9624571f82a878b203825fb2bec206195", [:mix], [{:absinthe, ">= 1.7.0", [hex: :absinthe, repo: "hexpm", optional: true]}, {:broadway, ">= 1.1.0", [hex: :broadway, repo: "hexpm", optional: true]}, {:ecto, ">= 3.11.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:finch, "~> 0.18", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:oban, ">= 2.10.0", [hex: :oban, repo: "hexpm", optional: true]}, {:octo_fetch, "~> 0.4", [hex: :octo_fetch, repo: "hexpm", optional: false]}, {:peep, "~> 3.0", [hex: :peep, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.7.0", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, ">= 0.20.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, ">= 1.16.0", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 2.6.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:telemetry, ">= 1.0.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}, {:telemetry_metrics_prometheus_core, "~> 1.2", [hex: :telemetry_metrics_prometheus_core, repo: "hexpm", optional: false]}, {:telemetry_poller, "~> 1.1", [hex: :telemetry_poller, repo: "hexpm", optional: false]}], "hexpm", "55d6ca87519b14202570dda5f29bf3f52e14b940eaf2ddcd89ad41347fa5781a"}, + "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "recon": {:hex, :recon, "2.5.6", "9052588e83bfedfd9b72e1034532aee2a5369d9d9343b61aeb7fbce761010741", [:mix, :rebar3], [], "hexpm", "96c6799792d735cc0f0fd0f86267e9d351e63339cbe03df9d162010cefc26bb0"}, "scrivener": {:hex, :scrivener, "2.7.2", "1d913c965ec352650a7f864ad7fd8d80462f76a32f33d57d1e48bc5e9d40aba2", [:mix], [], "hexpm", "7866a0ec4d40274efbee1db8bead13a995ea4926ecd8203345af8f90d2b620d9"}, - "scrivener_ecto": {:hex, :scrivener_ecto, "2.7.0", "cf64b8cb8a96cd131cdbcecf64e7fd395e21aaa1cb0236c42a7c2e34b0dca580", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:scrivener, "~> 2.4", [hex: :scrivener, repo: "hexpm", optional: false]}], "hexpm", "e809f171687806b0031129034352f5ae44849720c48dd839200adeaf0ac3e260"}, + "scrivener_ecto": {:hex, :scrivener_ecto, "2.7.1", "b8ca910c11429748d3c2d86f0e095abc6d0c49779c7fc5ac5db195e121c46a91", [:mix], [{:ecto, ">= 3.3.0 and < 3.12.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:scrivener, "~> 2.4", [hex: :scrivener, repo: "hexpm", optional: false]}], "hexpm", "f5c2f7db1fdcdfe9583ba378689c6ac20fd2af2c476378a017c03c950ac82c3e"}, "scrivener_html": {:git, "https://github.com/nerves-hub/scrivener_html", "e7d2ffcf241cebc8490da44b5d09ac297b57a91b", [branch: "phx-1.5"]}, "sentry": {:hex, :sentry, "10.7.1", "33392222d80ccff99c503f972998d2858b4c1e5aca2219a34269b68dacba8e7d", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_ownership, "~> 0.3.0 or ~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.20", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "56291312397bf2b6afab6cf4f7aa1f27413b0eb2ceeb63b8aab2d7658aaea882"}, "sleeplocks": {:hex, :sleeplocks, "1.1.3", "96a86460cc33b435c7310dbd27ec82ca2c1f24ae38e34f8edde97f756503441a", [:rebar3], [], "hexpm", "d3b3958552e6eb16f463921e70ae7c767519ef8f5be46d7696cc1ed649421321"}, "slipstream": {:hex, :slipstream, "1.1.1", "7e56f62f1a9ee81351e3c36f57b9b187e00dc2f470e70ba46ea7ad16e80b061f", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mint_web_socket, "~> 0.2 or ~> 1.0", [hex: :mint_web_socket, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.1 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c20e420cde1654329d38ec3aa1c0e4debbd4c91ca421491e7984ad4644e638a6"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"}, - "swoosh": {:hex, :swoosh, "1.16.9", "20c6a32ea49136a4c19f538e27739bb5070558c0fa76b8a95f4d5d5ca7d319a1", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.0", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "878b1a7a6c10ebbf725a3349363f48f79c5e3d792eb621643b0d276a38acc0a6"}, + "swoosh": {:hex, :swoosh, "1.17.0", "4a082a6ce4d60b1f48ffa725c8da0e2304504569ff550f4ed2d088c923039cb0", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "659b8bc25f7483b872d051a7f0731fb8d5312165be0d0302a3c783b566b0a290"}, "table_rex": {:hex, :table_rex, "4.0.0", "3c613a68ebdc6d4d1e731bc973c233500974ec3993c99fcdabb210407b90959b", [:mix], [], "hexpm", "c35c4d5612ca49ebb0344ea10387da4d2afe278387d4019e4d8111e815df8f55"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, - "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"}, - "telemetry_metrics_statsd": {:hex, :telemetry_metrics_statsd, "0.7.0", "92732fae63db31ef2508df6faee7d81401883e33f2976715a82f296a33a45cee", [:mix], [{:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "797e34a856376dfd4e96347da0f747fcff4e0cadf6e6f0f989598f563cad05ff"}, + "telemetry_metrics": {:hex, :telemetry_metrics, "1.0.0", "29f5f84991ca98b8eb02fc208b2e6de7c95f8bb2294ef244a176675adc7775df", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f23713b3847286a534e005126d4c959ebcca68ae9582118ce436b521d1d47d5d"}, + "telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.2.1", "c9755987d7b959b557084e6990990cb96a50d6482c683fb9622a63837f3cd3d8", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "5e2c599da4983c4f88a33e9571f1458bf98b0cf6ba930f1dc3a6e8cf45d5afb6"}, + "telemetry_metrics_statsd": {:hex, :telemetry_metrics_statsd, "0.7.1", "3502235bb5b35ce50d608bf0f34369ef76eb92a4dbc8708c7e8780ca0da2d53e", [:mix], [{:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "06338d9dc3b4a202f11a6e706fd3feba4c46100d0aca23688dea0b8f801c361f"}, "telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"}, "thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"}, "timex": {:hex, :timex, "3.7.11", "bb95cb4eb1d06e27346325de506bcc6c30f9c6dea40d1ebe390b262fad1862d1", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.20", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.1", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "8b9024f7efbabaf9bd7aa04f65cf8dcd7c9818ca5737677c7b76acbc6a94d1aa"}, - "tzdata": {:hex, :tzdata, "1.1.1", "20c8043476dfda8504952d00adac41c6eda23912278add38edc140ae0c5bcc46", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a69cec8352eafcd2e198dea28a34113b60fdc6cb57eb5ad65c10292a6ba89787"}, + "tzdata": {:hex, :tzdata, "1.1.2", "45e5f1fcf8729525ec27c65e163be5b3d247ab1702581a94674e008413eef50b", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "cec7b286e608371602318c414f344941d5eb0375e14cfdab605cca2fe66cba8b"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "unsafe": {:hex, :unsafe, "1.0.2", "23c6be12f6c1605364801f4b47007c0c159497d0446ad378b5cf05f1855c0581", [:mix], [], "hexpm", "b485231683c3ab01a9cd44cb4a79f152c6f3bb87358439c6f68791b85c2df675"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, From dc240bde01841cd24365709644cef49495a471d0 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Fri, 13 Sep 2024 21:30:16 +1200 Subject: [PATCH 02/16] Fetch the correct request ip (Logger plug) --- lib/nerves_hub_web/plugs/api/logger.ex | 16 +++++++++++++--- lib/nerves_hub_web/plugs/logger.ex | 16 +++++++++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/lib/nerves_hub_web/plugs/api/logger.ex b/lib/nerves_hub_web/plugs/api/logger.ex index e9f630309..ed69f8dbe 100644 --- a/lib/nerves_hub_web/plugs/api/logger.ex +++ b/lib/nerves_hub_web/plugs/api/logger.ex @@ -18,7 +18,7 @@ defmodule NervesHubWeb.API.Plugs.Logger do method: conn.method, path: request_path(conn), status: conn.status, - remote_ip: formatted_ip(conn.remote_ip) + remote_ip: formatted_ip(conn) ) end) @@ -33,7 +33,17 @@ defmodule NervesHubWeb.API.Plugs.Logger do def request_path(%{request_path: request_path}), do: request_path def request_path(_), do: nil - defp formatted_ip(ip) do - to_string(:inet_parse.ntoa(ip)) + defp formatted_ip(conn) do + case Plug.Conn.get_req_header(conn, "x-forwarded-for") do + [ips] -> + ips + |> String.split(",") + |> List.first() + |> String.trim() + _ -> + conn.remote_ip + |> :inet_parse.ntoa + |> to_string() + end end end diff --git a/lib/nerves_hub_web/plugs/logger.ex b/lib/nerves_hub_web/plugs/logger.ex index a478a3aea..5d5722751 100644 --- a/lib/nerves_hub_web/plugs/logger.ex +++ b/lib/nerves_hub_web/plugs/logger.ex @@ -18,7 +18,7 @@ defmodule NervesHubWeb.Plugs.Logger do method: conn.method, path: request_path(conn), status: conn.status, - remote_ip: formatted_ip(conn.remote_ip) + remote_ip: formatted_ip(conn) ) end) @@ -33,7 +33,17 @@ defmodule NervesHubWeb.Plugs.Logger do def request_path(%{request_path: request_path}), do: request_path def request_path(_), do: nil - defp formatted_ip(ip) do - to_string(:inet_parse.ntoa(ip)) + defp formatted_ip(conn) do + case Plug.Conn.get_req_header(conn, "x-forwarded-for") do + [ips] -> + ips + |> String.split(",") + |> List.first() + |> String.trim() + _ -> + conn.remote_ip + |> :inet_parse.ntoa + |> to_string() + end end end From 388d6e12eb9f6cbeaf770e4971e1b655843f743a Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Fri, 13 Sep 2024 21:30:57 +1200 Subject: [PATCH 03/16] Move the PromEx plug above the SSL enforcement --- config/prod.exs | 4 ++-- lib/nerves_hub_web/endpoint.ex | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/config/prod.exs b/config/prod.exs index d4439564c..09a8aa8b9 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -9,8 +9,8 @@ config :phoenix, logger: false # NervesHub Web # config :nerves_hub, NervesHubWeb.Endpoint, - server: true, - force_ssl: [rewrite_on: [:x_forwarded_proto]] + server: true + # force_ssl: [rewrite_on: [:x_forwarded_proto]] ## # NervesHub Device diff --git a/lib/nerves_hub_web/endpoint.ex b/lib/nerves_hub_web/endpoint.ex index d70ec7f7f..aa65dfdf4 100644 --- a/lib/nerves_hub_web/endpoint.ex +++ b/lib/nerves_hub_web/endpoint.ex @@ -10,6 +10,10 @@ defmodule NervesHubWeb.Endpoint do signing_salt: "1CPjriVa" ] + plug(PromEx.Plug, prom_ex_module: NervesHub.PromEx) + + plug(Plug.SSL, rewrite_on: [:x_forwarded_proto]) + socket("/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]]) socket("/socket", NervesHubWeb.UserSocket, @@ -60,14 +64,13 @@ defmodule NervesHubWeb.Endpoint do cookie_key: "request_logger" ) - plug(PromEx.Plug, prom_ex_module: NervesHub.PromEx) + # We don't need to see these in the logs, thus this is defined by telemetry + plug(NervesHubWeb.Plugs.ImAlive) plug(Plug.RequestId) plug(Plug.Telemetry, event_prefix: [:phoenix, :endpoint]) plug(NervesHubWeb.Plugs.Logger) - plug(NervesHubWeb.Plugs.ImAlive) - plug( Plug.Parsers, parsers: [:urlencoded, :multipart, :json], From 7800774a96050142cf6e872edf885a7c1593b337 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Fri, 13 Sep 2024 21:31:12 +1200 Subject: [PATCH 04/16] Disable custom metrics (temp) --- lib/nerves_hub/application.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/nerves_hub/application.ex b/lib/nerves_hub/application.ex index 587ce2882..6a5355394 100644 --- a/lib/nerves_hub/application.ex +++ b/lib/nerves_hub/application.ex @@ -56,7 +56,8 @@ defmodule NervesHub.Application do defp metrics("test"), do: [] defp metrics(_env) do - [NervesHub.Metrics] + # [NervesHub.Metrics] + [] end defp deployments_supervisor("test"), do: [] From 1d6f8333c40f2a9a7b9a1ca141ed446a4e4ec5d8 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sat, 14 Sep 2024 22:26:01 +1200 Subject: [PATCH 05/16] Remove some commented out code --- config/prod.exs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/config/prod.exs b/config/prod.exs index 09a8aa8b9..997e52f59 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -8,9 +8,7 @@ config :phoenix, logger: false ## # NervesHub Web # -config :nerves_hub, NervesHubWeb.Endpoint, - server: true - # force_ssl: [rewrite_on: [:x_forwarded_proto]] +config :nerves_hub, NervesHubWeb.Endpoint, server: true ## # NervesHub Device From 1508edd7cb4cd0e272d41ee133975aa81a16ccd9 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sat, 14 Sep 2024 22:26:36 +1200 Subject: [PATCH 06/16] Formatting --- lib/nerves_hub_web/plugs/api/logger.ex | 3 ++- lib/nerves_hub_web/plugs/logger.ex | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/nerves_hub_web/plugs/api/logger.ex b/lib/nerves_hub_web/plugs/api/logger.ex index ed69f8dbe..51e030095 100644 --- a/lib/nerves_hub_web/plugs/api/logger.ex +++ b/lib/nerves_hub_web/plugs/api/logger.ex @@ -40,9 +40,10 @@ defmodule NervesHubWeb.API.Plugs.Logger do |> String.split(",") |> List.first() |> String.trim() + _ -> conn.remote_ip - |> :inet_parse.ntoa + |> :inet_parse.ntoa() |> to_string() end end diff --git a/lib/nerves_hub_web/plugs/logger.ex b/lib/nerves_hub_web/plugs/logger.ex index 5d5722751..c68997659 100644 --- a/lib/nerves_hub_web/plugs/logger.ex +++ b/lib/nerves_hub_web/plugs/logger.ex @@ -40,9 +40,10 @@ defmodule NervesHubWeb.Plugs.Logger do |> String.split(",") |> List.first() |> String.trim() + _ -> conn.remote_ip - |> :inet_parse.ntoa + |> :inet_parse.ntoa() |> to_string() end end From 09cfc2940863f9d7a7eabe887808a2fbfef74473 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sat, 14 Sep 2024 22:27:13 +1200 Subject: [PATCH 07/16] Pass in the endpoint to the Phoenix Grafana plugin --- lib/nerves_hub/prom_ex.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nerves_hub/prom_ex.ex b/lib/nerves_hub/prom_ex.ex index 48e72eaca..332e02423 100644 --- a/lib/nerves_hub/prom_ex.ex +++ b/lib/nerves_hub/prom_ex.ex @@ -9,7 +9,7 @@ defmodule NervesHub.PromEx do # PromEx built in plugins Plugins.Application, Plugins.Beam, - {Plugins.Phoenix, router: NervesHubWeb.Router}, + {Plugins.Phoenix, endpoint: NervesHubWeb.Endpoint, router: NervesHubWeb.Router}, Plugins.PhoenixLiveView, Plugins.Ecto, Plugins.Oban From 3558b59f4c2a6aca31f1a4730138ff4390bdfdef Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sat, 14 Sep 2024 22:28:07 +1200 Subject: [PATCH 08/16] Move `PromEx` setup to be easier in the supervision tree --- lib/nerves_hub/application.ex | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/nerves_hub/application.ex b/lib/nerves_hub/application.ex index 6a5355394..30ecdfa58 100644 --- a/lib/nerves_hub/application.ex +++ b/lib/nerves_hub/application.ex @@ -31,6 +31,8 @@ defmodule NervesHub.Application do [ {Cachex, name: :geo_ip}, NervesHub.RateLimit, + # PromEx needs to be started before Repo and Endpoint so it can capture some of their early events + NervesHub.PromEx, NervesHub.Repo, NervesHub.ObanRepo, {Phoenix.PubSub, name: NervesHub.PubSub}, @@ -39,10 +41,7 @@ defmodule NervesHub.Application do {Oban, Application.fetch_env!(:nerves_hub, Oban)} ] ++ deployments_supervisor(deploy_env()) ++ - endpoints(deploy_env()) ++ - [ - NervesHub.PromEx - ] + endpoints(deploy_env()) opts = [strategy: :one_for_one, name: NervesHub.Supervisor] Supervisor.start_link(children, opts) From 4964f6eb3905a996334fe1c328afa5976bc637e3 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sat, 14 Sep 2024 22:31:15 +1200 Subject: [PATCH 09/16] Copy and customize the PromEx supplied dashboards --- lib/nerves_hub/prom_ex.ex | 8 +- priv/grafana/ecto.json.eex | 948 +++++++++ priv/grafana/oban.json.eex | 2606 +++++++++++++++++++++++ priv/grafana/phoenix.json.eex | 1811 ++++++++++++++++ priv/grafana/phoenix_live_view.json.eex | 1389 ++++++++++++ 5 files changed, 6758 insertions(+), 4 deletions(-) create mode 100644 priv/grafana/ecto.json.eex create mode 100644 priv/grafana/oban.json.eex create mode 100644 priv/grafana/phoenix.json.eex create mode 100644 priv/grafana/phoenix_live_view.json.eex diff --git a/lib/nerves_hub/prom_ex.ex b/lib/nerves_hub/prom_ex.ex index 332e02423..8f79ea47a 100644 --- a/lib/nerves_hub/prom_ex.ex +++ b/lib/nerves_hub/prom_ex.ex @@ -29,10 +29,10 @@ defmodule NervesHub.PromEx do # PromEx built in Grafana dashboards {:prom_ex, "application.json"}, {:prom_ex, "beam.json"}, - {:prom_ex, "phoenix.json"}, - {:prom_ex, "phoenix_live_view.json"}, - {:prom_ex, "ecto.json"}, - {:prom_ex, "oban.json"} + {:nerves_hub, "grafana/phoenix.json"}, + {:nerves_hub, "grafana/phoenix_live_view.json"}, + {:nerves_hub, "grafana/ecto.json"}, + {:nerves_hub, "grafana/oban.json"} ] end end diff --git a/priv/grafana/ecto.json.eex b/priv/grafana/ecto.json.eex new file mode 100644 index 000000000..4159a5496 --- /dev/null +++ b/priv/grafana/ecto.json.eex @@ -0,0 +1,948 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + }, + { + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "#73BF69", + "limit": 100, + "name": "PromEx service start", + "showIn": 0, + "tags": [ + "prom_ex", + "<%= @otp_app %>", + "start" + ], + "type": "tags" + }, + { + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "#FF9830", + "limit": 100, + "name": "PromEx service stop", + "showIn": 0, + "tags": [ + "prom_ex", + "<%= @otp_app %>", + "stop" + ], + "type": "tags" + } + ] + }, + "description": "All the data that is presented here is captured by the PromEx Ecto plugin (https://github.com/akoutmos/prom_ex/blob/master/lib/prom_ex/plugins/ecto.ex)", + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Sponsor PromEx", + "tooltip": "", + "type": "link", + "url": "https://github.com/sponsors/akoutmos" + }, + { + "asDropdown": false, + "icon": "doc", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Ecto Plugin Docs", + "tooltip": "", + "type": "link", + "url": "https://hexdocs.pm/prom_ex/PromEx.Plugins.Ecto.html" + } + ], + "panels": [ + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 19, + "panels": [], + "title": "Overview", + "type": "row" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The time the connection spent waiting before being checked out for the query.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 1 + }, + "id": 24, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "avg(<%= @ecto_metric_prefix %>_repo_query_idle_time_milliseconds_sum{instance=~\"$instance\", repo=\"$repo\"}) / avg(<%= @ecto_metric_prefix %>_repo_query_idle_time_milliseconds_count{instance=~\"$instance\", repo=\"$repo\"})", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Connection Idle Time (Average)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The time spent waiting to check out a database connection.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 1 + }, + "id": 29, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "avg(<%= @ecto_metric_prefix %>_repo_query_queue_time_milliseconds_sum{instance=~\"$instance\", repo=\"$repo\"}) / avg(<%= @ecto_metric_prefix %>_repo_query_queue_time_milliseconds_count{instance=~\"$instance\", repo=\"$repo\"})", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Connection Queue Time (Average)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The time spent decoding the data received from the database.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 1 + }, + "id": 30, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "avg(<%= @ecto_metric_prefix %>_repo_query_decode_time_milliseconds_sum{instance=~\"$instance\", repo=\"$repo\"}) / avg(<%= @ecto_metric_prefix %>_repo_query_decode_time_milliseconds_count{instance=~\"$instance\", repo=\"$repo\"})", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Connection Decode Time (Average)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The time spent executing the query. This value is the average time across all query types (SELECT, DELETE, etc).", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ms" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 1 + }, + "id": 31, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "sum(<%= @ecto_metric_prefix %>_repo_query_execution_time_milliseconds_sum{instance=~\"$instance\", repo=\"$repo\"}) / sum(<%= @ecto_metric_prefix %>_repo_query_execution_time_milliseconds_count{instance=~\"$instance\", repo=\"$repo\"})", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Connection Execution Time (Average)", + "type": "stat" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 2, + "panels": [], + "title": "Query Details", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average total time to execute and decode a database query.", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 14 + }, + "hiddenSeries": false, + "id": 32, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(<%= @ecto_metric_prefix %>_repo_query_total_time_milliseconds_sum{instance=~\"$instance\", repo=\"$repo\"}[$interval])) by(command) / sum(irate(<%= @ecto_metric_prefix %>_repo_query_total_time_milliseconds_count{instance=~\"$instance\", repo=\"$repo\"}[$interval])) by(command)", + "interval": "", + "legendFormat": "{{ command }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Total Execution Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "Response Time", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the total time spread across all Repo query executions (regardless of query type).", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 14 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 6, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @ecto_metric_prefix %>_repo_query_execution_time_milliseconds_bucket{instance=~\"$instance\", repo=\"$repo\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total Execution Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average query execution time per Ecto command.", + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 27 + }, + "hiddenSeries": false, + "id": 11, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(<%= @ecto_metric_prefix %>_repo_query_execution_time_milliseconds_sum{instance=~\"$instance\", repo=\"$repo\"}[$interval])) by(command) / sum(irate(<%= @ecto_metric_prefix %>_repo_query_execution_time_milliseconds_count{instance=~\"$instance\", repo=\"$repo\"}[$interval])) by(command)", + "interval": "", + "legendFormat": "{{ command }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Query Execution Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "Response Time", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the request time spread across all Repo query executions (regardless of query type).", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 27 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 33, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @ecto_metric_prefix %>_repo_query_execution_time_milliseconds_bucket{instance=~\"$instance\", repo=\"$repo\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Query Execution Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The number of operations taking place on each data source.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 40 + }, + "hiddenSeries": false, + "id": 13, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(increase(<%= @ecto_metric_prefix %>_repo_query_execution_time_milliseconds_count{instance=~\"$instance\", repo=\"$repo\"}[$interval])) by(source)", + "interval": "", + "legendFormat": "{{ source }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Operations Per Source", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "transformations": [], + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "locale", + "label": "Source Operations", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the number of results returned from the database (summed up across all operations and sources).", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 40 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 12, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @ecto_metric_prefix %>_repo_query_results_returned_bucket{instance=~\"$instance\", repo=\"$repo\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Results Returned", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "locale", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": ["PromEx", "Ecto", "<%= @otp_app %>"], + "templating": { + "list": [ + { + "allValue": ".*", + "datasource": "<%= @datasource_id %>", + "definition": "label_values(<%= @prom_ex_metric_prefix %>_status_info, instance)", + "hide": 0, + "includeAll": true, + "label": "Application Instance", + "multi": false, + "name": "instance", + "options": [], + "query": "label_values(<%= @prom_ex_metric_prefix %>_status_info, instance)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "datasource": "<%= @datasource_id %>", + "definition": "label_values(<%= @ecto_metric_prefix %>_repo_init_status_info, repo)", + "hide": 0, + "includeAll": false, + "label": "Ecto Repo", + "multi": false, + "name": "repo", + "options": [], + "query": "label_values(<%= @ecto_metric_prefix %>_repo_init_status_info, repo)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "selected": false, + "text": "<%= @default_selected_interval %>", + "value": "<%= @default_selected_interval %>" + }, + "hide": 0, + "label": "Interval", + "name": "interval", + "options": [ + { + "selected": <%= @default_selected_interval == "15s" %>, + "text": "15s", + "value": "15s" + }, + { + "selected": <%= @default_selected_interval == "30s" %>, + "text": "30s", + "value": "30s" + }, + { + "selected": <%= @default_selected_interval == "1m" %>, + "text": "1m", + "value": "1m" + }, + { + "selected": <%= @default_selected_interval == "5m" %>, + "text": "5m", + "value": "5m" + }, + { + "selected": <%= @default_selected_interval == "15m" %>, + "text": "15m", + "value": "15m" + }, + { + "selected": <%= @default_selected_interval == "30m" %>, + "text": "30m", + "value": "30m" + }, + { + "selected": <%= @default_selected_interval == "1h" %>, + "text": "1h", + "value": "1h" + } + ], + "query": "15s, 30s, 1m, 5m, 15m, 30m, 1h", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m" + ] + }, + "timezone": "", + "title": "<%= @title %>", + "uid": "<%= @uid %>", + "version": 1 +} diff --git a/priv/grafana/oban.json.eex b/priv/grafana/oban.json.eex new file mode 100644 index 000000000..b90c0292d --- /dev/null +++ b/priv/grafana/oban.json.eex @@ -0,0 +1,2606 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + }, + { + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "#73BF69", + "limit": 100, + "name": "PromEx service start", + "showIn": 0, + "tags": [ + "prom_ex", + "<%= @otp_app %>", + "start" + ], + "type": "tags" + }, + { + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "#FF9830", + "limit": 100, + "name": "PromEx service stop", + "showIn": 0, + "tags": [ + "prom_ex", + "<%= @otp_app %>", + "stop" + ], + "type": "tags" + } + ] + }, + "description": "All the data that is presented here is captured by the PromEx Oban plugin (https://github.com/akoutmos/prom_ex/blob/master/lib/prom_ex/plugins/oban.ex)", + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "links": [ + { + "asDropdown": false, + "icon": "doc", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Oban Plugin Docs", + "tooltip": "", + "type": "link", + "url": "https://hexdocs.pm/prom_ex/PromEx.Plugins.Oban.html" + } + ], + "panels": [ + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 19, + "panels": [], + "title": "Overview", + "type": "row" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The number of jobs processed across all queues and states.", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 1 + }, + "id": 45, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "round(sum(increase(<%= @oban_metric_prefix %>_job_processing_duration_milliseconds_count{instance=~\"$instance\", name=\"$oban\"}[$interval])))", + "interval": "", + "legendFormat": "", + "refId": "A", + "format": "table" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Processed Jobs (by $interval interval)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The number of jobs that have been enqueued.", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 4, + "y": 1 + }, + "id": 47, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "round(sum(increase(<%= @oban_metric_prefix %>_producer_dispatched_count_count{instance=~\"$instance\", name=\"$oban\"}[$interval])))", + "interval": "", + "legendFormat": "", + "refId": "A", + "format": "table" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Jobs Enqueued (by $interval interval)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The number of jobs that resulted in an error across all queues.", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 8, + "y": 1 + }, + "id": 46, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "round(sum(increase(<%= @oban_metric_prefix %>_job_exception_duration_milliseconds_count{instance=~\"$instance\", name=\"$oban\"}[$interval])))", + "interval": "", + "legendFormat": "", + "refId": "A", + "format": "table" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Job Errors (by $interval interval)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The number of jobs in each queue that are in the available state.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "max": 500, + "noValue": "NA", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 400 + }, + { + "color": "red", + "value": 500 + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 60, + "options": { + "displayMode": "lcd", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "<%= @oban_metric_prefix %>_queue_length_count{instance=~\"$instance\", name=\"$oban\", state=\"available\"}", + "instant": true, + "interval": "", + "legendFormat": "{{ queue }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Available Jobs in Queue", + "type": "bargauge" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 13 + }, + "id": 2, + "panels": [], + "title": "Successful Job Processing Details", + "type": "row" + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the time it took to process jobs across all queues.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 14 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 6, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @oban_metric_prefix %>_job_processing_duration_milliseconds_bucket{instance=~\"$instance\", name=\"$oban\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Job Execution Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing how long jobs are waiting in queue for processing.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 14 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 12, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @oban_metric_prefix %>_job_queue_time_milliseconds_bucket{instance=~\"$instance\", name=\"$oban\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Job Queue Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average time it took to process jobs per queue. This will include jobs that ended with a successful, snoozed, or discarded state.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 27 + }, + "hiddenSeries": false, + "id": 11, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @oban_metric_prefix %>_job_processing_duration_milliseconds_sum{instance=~\"$instance\", name=\"$oban\"}[$interval]) / irate(<%= @oban_metric_prefix %>_job_processing_duration_milliseconds_count{instance=~\"$instance\", name=\"$oban\"}[$interval])", + "interval": "", + "legendFormat": "({{ state }}) {{ name }} :: {{ worker }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Job Execution Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "Execution Time", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average time a job waited in queue for processing.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 27 + }, + "hiddenSeries": false, + "id": 44, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @oban_metric_prefix %>_job_queue_time_milliseconds_sum{instance=~\"$instance\", name=\"$oban\"}[$interval]) / irate(<%= @oban_metric_prefix %>_job_queue_time_milliseconds_count{instance=~\"$instance\", name=\"$oban\"}[$interval])", + "interval": "", + "legendFormat": "({{ state }}) {{ name }} :: {{ worker }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Job Queue Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "In Queue Time", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average time it took to process jobs per queue. This will include jobs that ended with a successful, snoozed, or discarded state.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 40 + }, + "hiddenSeries": false, + "id": 51, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @oban_metric_prefix %>_job_complete_attempts_sum{instance=~\"$instance\", name=\"$oban\"}[$interval]) / irate(<%= @oban_metric_prefix %>_job_complete_attempts_count{instance=~\"$instance\", name=\"$oban\"}[$interval])", + "interval": "", + "legendFormat": "({{ state }}) {{ name }} :: {{ worker }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Job Attempts", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "locale", + "label": "Job Attempts", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 53 + }, + "id": 54, + "panels": [], + "title": "Job Error Details", + "type": "row" + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the time it took to process jobs across all queues that resulted in an error.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 54 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 55, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @oban_metric_prefix %>_job_exception_duration_milliseconds_bucket{instance=~\"$instance\", name=\"$oban\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Job Execution Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing how long jobs are waiting in queue for processing that resulted in an error.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 54 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 56, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @oban_metric_prefix %>_job_exception_queue_time_milliseconds_bucket{instance=~\"$instance\", name=\"$oban\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Job Queue Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average time it took to process jobs per queue that resulted in an error.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 67 + }, + "hiddenSeries": false, + "id": 57, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @oban_metric_prefix %>_job_exception_duration_milliseconds_sum{instance=~\"$instance\", name=\"$oban\"}[$interval]) / irate(<%= @oban_metric_prefix %>_job_exception_duration_milliseconds_count{instance=~\"$instance\", name=\"$oban\"}[$interval])", + "interval": "", + "legendFormat": "({{ error }}) {{ name }} :: {{ worker }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Job Execution Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "Execution Time", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average time a job waited in queue for processing prior to resulting in an error.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 67 + }, + "hiddenSeries": false, + "id": 58, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @oban_metric_prefix %>_job_exception_queue_time_milliseconds_sum{instance=~\"$instance\", name=\"$oban\"}[$interval]) / irate(<%= @oban_metric_prefix %>_job_exception_queue_time_milliseconds_count{instance=~\"$instance\", name=\"$oban\"}[$interval])", + "interval": "", + "legendFormat": "({{ error }}) {{ name }} :: {{ worker }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Job Queue Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "In Queue Time", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average time it took to process jobs per queue that resulted in an error.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 80 + }, + "hiddenSeries": false, + "id": 52, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "hideEmpty": false, + "hideZero": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @oban_metric_prefix %>_job_exception_attempts_sum{instance=~\"$instance\", name=\"$oban\"}[$interval]) / irate(<%= @oban_metric_prefix %>_job_exception_attempts_count{instance=~\"$instance\", name=\"$oban\"}[$interval])", + "interval": "", + "legendFormat": "({{ state }}) {{ name }} :: {{ worker }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Job Failure Attempts", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "locale", + "label": "Job Attempts", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 93 + }, + "id": 4, + "panels": [], + "title": "Queue Details", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The number of jobs marked as available in each queue.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 94 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "<%= @oban_metric_prefix %>_queue_length_count{instance=~\"$instance\", name=\"$oban\", state=\"available\"}", + "interval": "", + "legendFormat": "{{ queue }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Available Jobs per Queue", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Number of Jobs", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The number of jobs marked as completed in each queue.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 94 + }, + "hiddenSeries": false, + "id": 63, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "<%= @oban_metric_prefix %>_queue_length_count{instance=~\"$instance\", name=\"$oban\", state=\"completed\"}", + "interval": "", + "legendFormat": "{{ queue }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Completed Jobs per Queue", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Number of Jobs", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The number of jobs marked as executing in each queue.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 107 + }, + "hiddenSeries": false, + "id": 62, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "<%= @oban_metric_prefix %>_queue_length_count{instance=~\"$instance\", name=\"$oban\", state=\"executing\"}", + "interval": "", + "legendFormat": "{{ queue }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Executing Jobs per Queue", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Number of Jobs", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The number of jobs marked as retryable in each queue.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 107 + }, + "hiddenSeries": false, + "id": 61, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "<%= @oban_metric_prefix %>_queue_length_count{instance=~\"$instance\", name=\"$oban\", state=\"retryable\"}", + "interval": "", + "legendFormat": "{{ queue }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Retryable Jobs per Queue", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Number of Jobs", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 120 + }, + "id": 30, + "panels": [], + "title": "Producer Details", + "type": "row" + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing how long jobs to be dispatched.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 121 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 73, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @oban_metric_prefix %>_producer_duration_milliseconds_bucket{instance=~\"$instance\", name=\"$oban\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Producer Dispatch Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the number of jobs that were dispatched.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 121 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 74, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @oban_metric_prefix %>_producer_dispatched_count_bucket{instance=~\"$instance\", name=\"$oban\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Producer Dispatch Count", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "locale", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average amount of time it took to dispatch jobs to each queue.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 134 + }, + "hiddenSeries": false, + "id": 67, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @oban_metric_prefix %>_producer_duration_milliseconds_sum{instance=~\"$instance\", name=\"$oban\"}[$interval]) / irate(<%= @oban_metric_prefix %>_producer_duration_milliseconds_count{instance=~\"$instance\", name=\"$oban\"}[$interval])", + "interval": "", + "legendFormat": "{{ queue }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Dispatch Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "Number of Jobs", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average number of jobs dispatched to each queue.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 134 + }, + "hiddenSeries": false, + "id": 75, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @oban_metric_prefix %>_producer_dispatched_count_sum{instance=~\"$instance\", name=\"$oban\"}[$interval]) / irate(<%= @oban_metric_prefix %>_producer_dispatched_count_count{instance=~\"$instance\", name=\"$oban\"}[$interval])", + "interval": "", + "legendFormat": "{{ queue }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Dispatch Count", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Number of Jobs", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average amount of time it took to encounter an encounter an error.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 147 + }, + "hiddenSeries": false, + "id": 76, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @oban_metric_prefix %>_producer_exception_duration_milliseconds_sum{instance=~\"$instance\", name=\"$oban\"}[$interval]) / irate(<%= @oban_metric_prefix %>_producer_exception_duration_milliseconds_count{instance=~\"$instance\", name=\"$oban\"}[$interval])", + "interval": "", + "legendFormat": "{{ queue }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Exception Duration", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "Number of Jobs", + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 160 + }, + "id": 65, + "panels": [], + "title": "Circuit Breaker Details", + "type": "row" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "This is the total number of trip events that have been encountered by the selected application and Oban instances.", + "fieldConfig": { + "defaults": { + "custom": {}, + "noValue": "0", + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 161 + }, + "id": 78, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "increase(<%= @oban_metric_prefix %>_circuit_trip_total{instance=~\"$instance\", name=\"$oban\"}[1h])", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Circuit Trip Events (last 1 hour)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "This is the total number of trip events that have been encountered by the selected application and Oban instances.", + "fieldConfig": { + "defaults": { + "custom": {}, + "noValue": "0", + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 161 + }, + "id": 80, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "<%= @oban_metric_prefix %>_circuit_trip_total{instance=~\"$instance\", name=\"$oban\"}", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total Circuit Trip Events", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "This is the total number of open events that have been encountered by the selected application and Oban instances.", + "fieldConfig": { + "defaults": { + "custom": {}, + "noValue": "0", + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 161 + }, + "id": 81, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "increase(<%= @oban_metric_prefix %>_circuit_open_total{instance=~\"$instance\", name=\"$oban\"}[1h])", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Circuit Open Events (last 1 hour)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "This is the total number of open events that have been encountered by the selected application and Oban instances.", + "fieldConfig": { + "defaults": { + "custom": {}, + "noValue": "0", + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 161 + }, + "id": 79, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "<%= @oban_metric_prefix %>_circuit_open_total{instance=~\"$instance\", name=\"$oban\"}", + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total Circuit Open Events", + "type": "stat" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The number of circuit breaker trip events that occurred along with what component tripped the breaker.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 166 + }, + "hiddenSeries": false, + "id": 70, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "increase(<%= @oban_metric_prefix %>_circuit_trip_total{instance=~\"$instance\", name=\"$oban\"}[$interval])", + "interval": "", + "legendFormat": "{{ circuit_breaker }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Circuit Breaker Trip Events", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Number of Circuit Trips", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The number of circuit breaker open events that occurred along with what component tripped the breaker.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 166 + }, + "hiddenSeries": false, + "id": 72, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "increase(<%= @oban_metric_prefix %>_circuit_open_total{instance=~\"$instance\", name=\"$oban\"}[$interval])", + "interval": "", + "legendFormat": "{{ circuit_breaker }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Circuit Breaker Open Events", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Number of Circuit Opens", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": ["PromEx", "Oban", "<%= @otp_app %>"], + "templating": { + "list": [ + { + "allValue": ".*", + "datasource": "<%= @datasource_id %>", + "definition": "label_values(<%= @prom_ex_metric_prefix %>_status_info, instance)", + "hide": 0, + "includeAll": true, + "label": "Application Instance", + "multi": false, + "name": "instance", + "options": [], + "query": "label_values(<%= @prom_ex_metric_prefix %>_status_info, instance)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "datasource": "<%= @datasource_id %>", + "definition": "label_values(<%= @oban_metric_prefix %>_init_status_info, name)", + "hide": 0, + "includeAll": false, + "label": "Oban Instance", + "multi": false, + "name": "oban", + "options": [], + "query": "label_values(<%= @oban_metric_prefix %>_init_status_info, name)", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "selected": true, + "text": "<%= @default_selected_interval %>", + "value": "<%= @default_selected_interval %>" + }, + "hide": 0, + "label": "Interval", + "name": "interval", + "options": [ + { + "selected": <%= @default_selected_interval == "15s" %>, + "text": "15s", + "value": "15s" + }, + { + "selected": <%= @default_selected_interval == "30s" %>, + "text": "30s", + "value": "30s" + }, + { + "selected": <%= @default_selected_interval == "1m" %>, + "text": "1m", + "value": "1m" + }, + { + "selected": <%= @default_selected_interval == "5m" %>, + "text": "5m", + "value": "5m" + }, + { + "selected": <%= @default_selected_interval == "15m" %>, + "text": "15m", + "value": "15m" + }, + { + "selected": <%= @default_selected_interval == "30m" %>, + "text": "30m", + "value": "30m" + }, + { + "selected": <%= @default_selected_interval == "1h" %>, + "text": "1h", + "value": "1h" + } + ], + "query": "15s, 30s, 1m, 5m, 15m, 30m, 1h", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m" + ] + }, + "timezone": "", + "title": "<%= @title %>", + "uid": "<%= @uid %>", + "version": 1 +} diff --git a/priv/grafana/phoenix.json.eex b/priv/grafana/phoenix.json.eex new file mode 100644 index 000000000..af5106973 --- /dev/null +++ b/priv/grafana/phoenix.json.eex @@ -0,0 +1,1811 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + }, + { + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "#73BF69", + "limit": 100, + "name": "PromEx service start", + "showIn": 0, + "tags": [ + "prom_ex", + "<%= @otp_app %>", + "start" + ], + "type": "tags" + }, + { + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "#FF9830", + "limit": 100, + "name": "PromEx service stop", + "showIn": 0, + "tags": [ + "prom_ex", + "<%= @otp_app %>", + "stop" + ], + "type": "tags" + } + ] + }, + "description": "All the data that is presented here is captured by the PromEx Phoenix plugin (https://github.com/akoutmos/prom_ex/blob/master/lib/prom_ex/plugins/phoenix.ex)", + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Sponsor PromEx", + "tooltip": "", + "type": "link", + "url": "https://github.com/sponsors/akoutmos" + }, + { + "asDropdown": false, + "icon": "doc", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Phoenix Plugin Docs", + "tooltip": "", + "type": "link", + "url": "https://hexdocs.pm/prom_ex/PromEx.Plugins.Phoenix.html" + } + ], + "panels": [ + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 19, + "panels": [], + "title": "Overview", + "type": "row" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The Apdex score of the app based on a satisfactory response time of 500ms and a tolerable response time of 1000ms. This only takes into account how long Phoenix has been handling the request and only requests that resulted in a 2xx status code. The score is based on the last 24 hours of requests.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "noValue": "No data", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 70 + }, + { + "color": "green", + "value": 90 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 5 + }, + "id": 21, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "(\n (\n sum(increase(<%= @phoenix_metric_prefix %>_http_request_duration_milliseconds_bucket{instance=~\"$instance\", le=\"500\", status=~\"2..\"}[24h])) + \n (sum(increase(<%= @phoenix_metric_prefix %>_http_request_duration_milliseconds_bucket{instance=~\"$instance\", le=\"1000\", status=~\"2..\"}[24h])) - sum(increase(<%= @phoenix_metric_prefix %>_http_request_duration_milliseconds_bucket{instance=~\"$instance\", le=\"500\", status=~\"2..\"}[24h]))) / 2\n ) \n / \n sum(increase(<%= @phoenix_metric_prefix %>_http_request_duration_milliseconds_count{instance=~\"$instance\", status=~\"2..\"}[24h]))\n) * 100", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Apdex Score (Last 24h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "A percentage of responses that resulted in 400s or 500s over the past 24 hours.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 1 + }, + { + "color": "red", + "value": 5 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 5 + }, + "id": 22, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "sum(increase(<%= @phoenix_metric_prefix %>_http_requests_total{instance=~\"$instance\", status=~\"4..|5..\"}[24h])) / sum(increase(<%= @phoenix_metric_prefix %>_http_requests_total{instance=~\"$instance\"}[24h])) OR on() vector(0)", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Error Percentage (Last 24h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The amount of data transferred by Phoenix in a 24 hour rolling window.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 5 + }, + "id": 24, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "sum(increase(<%= @phoenix_metric_prefix %>_http_response_size_bytes_sum{instance=~\"$instance\"}[24h]))", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Data Transferred (Last 24h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The amount of requests received by Phoenix in a 24 hour rolling window.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 5 + }, + "id": 23, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "round(sum(increase(<%= @phoenix_metric_prefix %>_http_requests_total{instance=~\"$instance\"}[24h])))", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total Requests Received (Last 24h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The Apdex score of the app based on a satisfactory response time of 500ms and a tolerable response time of 1000ms. This only takes into account how long Phoenix has been handling the request and only requests that resulted in a 2xx status code. The score is based on the previous hour of requests.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "noValue": "No data", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 70 + }, + { + "color": "green", + "value": 90 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 25, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "(\n (\n sum(increase(<%= @phoenix_metric_prefix %>_http_request_duration_milliseconds_bucket{instance=~\"$instance\", le=\"500\", status=~\"2..\"}[1h])) + \n (sum(increase(<%= @phoenix_metric_prefix %>_http_request_duration_milliseconds_bucket{instance=~\"$instance\", le=\"1000\", status=~\"2..\"}[1h])) - sum(increase(<%= @phoenix_metric_prefix %>_http_request_duration_milliseconds_bucket{instance=~\"$instance\", le=\"500\", status=~\"2..\"}[1h]))) / 2\n ) \n / \n sum(increase(<%= @phoenix_metric_prefix %>_http_request_duration_milliseconds_count{instance=~\"$instance\", status=~\"2..\"}[1h]))\n) * 100", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Apdex Score (Last 1h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "A percentage of responses that resulted in 400s or 500s over the past hour.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "noValue": "No data", + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 1 + }, + { + "color": "red", + "value": 5 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 26, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "sum(increase(<%= @phoenix_metric_prefix %>_http_requests_total{instance=~\"$instance\", status=~\"4..|5..\"}[1h])) / sum(increase(<%= @phoenix_metric_prefix %>_http_requests_total{instance=~\"$instance\"}[1h])) OR on() vector(0)", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Error Percentage (Last 1h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The amount of data transferred by Phoenix in the past hour.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "decbytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 11 + }, + "id": 27, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "sum(increase(<%= @phoenix_metric_prefix %>_http_response_size_bytes_sum{instance=~\"$instance\"}[1h]))", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Data Transferred (Last 1h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The amount of requests received by Phoenix in the past hour.", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 11 + }, + "id": 28, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "round(sum(increase(<%= @phoenix_metric_prefix %>_http_requests_total{instance=~\"$instance\"}[1h])))", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total Requests Received (Last 1h)", + "type": "stat" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 2, + "panels": [], + "title": "HTTP Details", + "type": "row" + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the request time spread across all requests (regardless of path).", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 18 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 6, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_metric_prefix %>_http_request_duration_milliseconds_bucket{instance=~\"$instance\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Request Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the response payload size spread across all requests (regardless of path).", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 18 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 12, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_metric_prefix %>_http_response_size_bytes_bucket{instance=~\"$instance\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Response Payload Size", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "decbytes", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average request time per path per status code per HTTP method.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 31 + }, + "hiddenSeries": false, + "id": 11, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_metric_prefix %>_http_request_duration_milliseconds_sum{instance=~\"$instance\"}[$interval])) by(path, status) / sum(irate(<%= @phoenix_metric_prefix %>_http_request_duration_milliseconds_count{instance=~\"$instance\"}[$interval])) by(path, status)", + "interval": "", + "legendFormat": "{{ method }} {{ path }} :: {{ status }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average HTTP Request Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "Response Time", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average response size per path per status code per HTTP method.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 31 + }, + "hiddenSeries": false, + "id": 13, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_metric_prefix %>_http_response_size_bytes_sum{instance=~\"$instance\"}[$interval])) by(path, status) / sum(irate(<%= @phoenix_metric_prefix %>_http_response_size_bytes_count{instance=~\"$instance\"}[$interval])) by(path, status)", + "interval": "", + "legendFormat": "{{ method }} {{ path }} :: {{ status }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average HTTP Response Size", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "decbytes", + "label": "Response Size", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "Shows the number of requests coming into certain paths and the resulting response codes.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 44 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @phoenix_metric_prefix %>_http_requests_total{instance=~\"$instance\"}[$interval])", + "interval": "", + "legendFormat": "{{ method }} {{ path }} :: {{ status }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Path Requests", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "locale", + "label": "Requests", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The aggregate response status of all the requests.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 44 + }, + "hiddenSeries": false, + "id": 10, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_metric_prefix %>_http_requests_total{status=~\"2..\", instance=~\"$instance\"}[$interval]))", + "interval": "", + "legendFormat": "2xx", + "refId": "A" + }, + { + "expr": "sum(irate(<%= @phoenix_metric_prefix %>_http_requests_total{status=~\"4..\", instance=~\"$instance\"}[$interval]))", + "interval": "", + "legendFormat": "4xx", + "refId": "B" + }, + { + "expr": "sum(irate(<%= @phoenix_metric_prefix %>_http_requests_total{status=~\"5..\", instance=~\"$instance\"}[$interval]))", + "interval": "", + "legendFormat": "5xx", + "refId": "C" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Response Status Codes", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Requests", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 57 + }, + "id": 4, + "panels": [], + "title": "Channel Details", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "How many channel joins have occurred over time.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 58 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @phoenix_metric_prefix %>_channel_joined_total{instance=~\"$instance\", endpoint=\"$endpoint\"}[$interval])", + "interval": "", + "legendFormat": "{{ transport }} :: {{ result }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Channel Join Events", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Channel joins", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the request time spread across all channel events.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 58 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 16, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_metric_prefix %>_channel_handled_in_duration_milliseconds_bucket{instance=~\"$instance\", endpoint=\"$endpoint\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Channel Message Handle Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average response time for a channel message.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 71 + }, + "hiddenSeries": false, + "id": 17, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @phoenix_metric_prefix %>_channel_handled_in_duration_milliseconds_sum{instance=~\"$instance\", endpoint=\"$endpoint\"}[$interval]) / irate(<%= @phoenix_metric_prefix %>_channel_handled_in_duration_milliseconds_count{instance=~\"$instance\", endpoint=\"$endpoint\"}[$interval])", + "interval": "", + "legendFormat": "{{ transport }} :: {{ result }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Channel Response Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "Response Time", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 84 + }, + "id": 34, + "panels": [], + "title": "Socket Details", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "How many socket connections have occurred over time.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 85 + }, + "hiddenSeries": false, + "id": 35, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @phoenix_metric_prefix %>_socket_connected_duration_milliseconds_count{instance=~\"$instance\", endpoint=\"$endpoint\"}[$interval])", + "interval": "", + "legendFormat": "{{ transport }} :: {{ result }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Socket Connection Events", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": "Channel joins", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the request time spread across all socket connections.", + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 85 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 36, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "exemplar": true, + "expr": "sum(irate(<%= @phoenix_metric_prefix %>_socket_connected_duration_milliseconds_bucket{instance=~\"$instance\", endpoint=\"$endpoint\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Socket Connection Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average time it connects to establish a socket connection.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 98 + }, + "hiddenSeries": false, + "id": 37, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "irate(<%= @phoenix_metric_prefix %>_socket_connected_duration_milliseconds_sum{instance=~\"$instance\", endpoint=\"$endpoint\"}[$interval]) / irate(<%= @phoenix_metric_prefix %>_socket_connected_duration_milliseconds_count{instance=~\"$instance\", endpoint=\"$endpoint\"}[$interval])", + "interval": "", + "legendFormat": "{{ transport }} :: {{ result }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Socket Connection Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "Response Time", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": ["PromEx", "Phoenix", "<%= @otp_app %>"], + "templating": { + "list": [ + { + "allValue": ".*", + "datasource": "<%= @datasource_id %>", + "definition": "label_values(<%= @prom_ex_metric_prefix %>_status_info, instance)", + "hide": 0, + "includeAll": true, + "label": "Application Instance", + "multi": false, + "name": "instance", + "options": [], + "query": "label_values(<%= @prom_ex_metric_prefix %>_status_info, instance)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": null, + "datasource": "<%= @datasource_id %>", + "definition": "label_values(<%= @phoenix_metric_prefix %>_endpoint_port_info, endpoint)", + "hide": 0, + "includeAll": false, + "label": "Phoenix Endpoint", + "multi": false, + "name": "endpoint", + "options": [], + "query": "label_values(<%= @phoenix_metric_prefix %>_endpoint_port_info, endpoint)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "selected": false, + "text": "<%= @default_selected_interval %>", + "value": "<%= @default_selected_interval %>" + }, + "hide": 0, + "label": "Interval", + "name": "interval", + "options": [ + { + "selected": <%= @default_selected_interval == "15s" %>, + "text": "15s", + "value": "15s" + }, + { + "selected": <%= @default_selected_interval == "30s" %>, + "text": "30s", + "value": "30s" + }, + { + "selected": <%= @default_selected_interval == "1m" %>, + "text": "1m", + "value": "1m" + }, + { + "selected": <%= @default_selected_interval == "5m" %>, + "text": "5m", + "value": "5m" + }, + { + "selected": <%= @default_selected_interval == "15m" %>, + "text": "15m", + "value": "15m" + }, + { + "selected": <%= @default_selected_interval == "30m" %>, + "text": "30m", + "value": "30m" + }, + { + "selected": <%= @default_selected_interval == "1h" %>, + "text": "1h", + "value": "1h" + } + ], + "query": "15s, 30s, 1m, 5m, 15m, 30m, 1h", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m" + ] + }, + "timezone": "", + "title": "<%= @title %>", + "uid": "<%= @uid %>", + "version": 1 +} diff --git a/priv/grafana/phoenix_live_view.json.eex b/priv/grafana/phoenix_live_view.json.eex new file mode 100644 index 000000000..f4e4bf2e4 --- /dev/null +++ b/priv/grafana/phoenix_live_view.json.eex @@ -0,0 +1,1389 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + }, + { + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "#73BF69", + "limit": 100, + "name": "PromEx service start", + "showIn": 0, + "tags": [ + "prom_ex", + "<%= @otp_app %>", + "start" + ], + "type": "tags" + }, + { + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "#FF9830", + "limit": 100, + "name": "PromEx service stop", + "showIn": 0, + "tags": [ + "prom_ex", + "<%= @otp_app %>", + "stop" + ], + "type": "tags" + } + ] + }, + "description": "All the data that is presented here is captured by the PromEx Phoenix LiveView plugin (https://github.com/akoutmos/prom_ex/blob/master/lib/prom_ex/plugins/phoenix_live_view.ex)", + "editable": false, + "gnetId": null, + "graphTooltip": 1, + "id": null, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "Sponsor PromEx", + "tooltip": "", + "type": "link", + "url": "https://github.com/sponsors/akoutmos" + }, + { + "asDropdown": false, + "icon": "doc", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": true, + "title": "PhoenixLiveView Plugin Docs", + "tooltip": "", + "type": "link", + "url": "https://hexdocs.pm/prom_ex/PromEx.Plugins.PhoenixLiveView.html" + } + ], + "panels": [ + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 19, + "panels": [], + "title": "Overview", + "type": "row" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "A percentage of mount callbacks that successfully executed.", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "green", + "value": 95 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 1 + }, + "id": 22, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "sum(increase(<%= @phoenix_live_view_metric_prefix %>_mount_duration_milliseconds_count{instance=~\"$instance\"}[24h])) / \n(\n sum(increase(<%= @phoenix_live_view_metric_prefix %>_mount_duration_milliseconds_count{instance=~\"$instance\"}[24h])) + \n (sum(increase(<%= @phoenix_live_view_metric_prefix %>_mount_exception_duration_milliseconds_count{instance=~\"$instance\"}[24h])) or vector(0))\n)", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Mount Callback Success Rate (last 24h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The amount of LiveView mounts that have occurred in the last 24 hours.", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 1 + }, + "id": 23, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "(sum(increase(<%= @phoenix_live_view_metric_prefix %>_mount_duration_milliseconds_count{instance=~\"$instance\"}[24h])) or vector(0)) + (sum(increase(<%= @phoenix_live_view_metric_prefix %>_mount_exception_duration_milliseconds_count{instance=~\"$instance\"}[24h])) or vector(0))", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total LiveView Mounts (Last 24h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "A percentage of handle_event callbacks that successfully executed.", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "green", + "value": 95 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 1 + }, + "id": 35, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "sum(increase(<%= @phoenix_live_view_metric_prefix %>_handle_event_duration_milliseconds_count{instance=~\"$instance\"}[24h])) / \n(\n sum(increase(<%= @phoenix_live_view_metric_prefix %>_handle_event_duration_milliseconds_count{instance=~\"$instance\"}[24h])) + \n (sum(increase(<%= @phoenix_live_view_metric_prefix %>_handle_event_exception_duration_milliseconds_count{instance=~\"$instance\"}[24h])) or vector(0))\n)", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Handle Event Callback Success Rate (last 24h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The amount of LiveView handle_events that have occurred in the last 24 hours.", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 1 + }, + "id": 33, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^Value$/", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "(sum(increase(<%= @phoenix_live_view_metric_prefix %>_handle_event_exception_duration_milliseconds_count{instance=~\"$instance\"}[24h])) or vector(0)) + (sum(increase(<%= @phoenix_live_view_metric_prefix %>_handle_event_duration_milliseconds_count{instance=~\"$instance\"}[24h])) or vector(0))", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total LiveView Handle Events (Last 24h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "A percentage of mount callbacks that successfully executed.", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "green", + "value": 95 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 6 + }, + "id": 31, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "sum(increase(<%= @phoenix_live_view_metric_prefix %>_mount_duration_milliseconds_count{instance=~\"$instance\"}[1h])) / \n(\n sum(increase(<%= @phoenix_live_view_metric_prefix %>_mount_duration_milliseconds_count{instance=~\"$instance\"}[1h])) + \n (sum(increase(<%= @phoenix_live_view_metric_prefix %>_mount_exception_duration_milliseconds_count{instance=~\"$instance\"}[1h])) or vector(0))\n)", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Mount Callback Success Rate (last 1h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The amount of LiveView mounts that have occurred in the last hour.", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 6 + }, + "id": 32, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "(sum(increase(<%= @phoenix_live_view_metric_prefix %>_mount_duration_milliseconds_count{instance=~\"$instance\"}[1h])) or vector(0)) + (sum(increase(<%= @phoenix_live_view_metric_prefix %>_mount_exception_duration_milliseconds_count{instance=~\"$instance\"}[1h])) or vector(0))", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total LiveView Mounts (Last 1h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "A percentage of handle event callbacks that successfully executed.", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "green", + "value": 95 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 6 + }, + "id": 36, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "sum(increase(<%= @phoenix_live_view_metric_prefix %>_handle_event_duration_milliseconds_count{instance=~\"$instance\"}[1h])) / \n(\n sum(increase(<%= @phoenix_live_view_metric_prefix %>_handle_event_duration_milliseconds_count{instance=~\"$instance\"}[1h])) + \n (sum(increase(<%= @phoenix_live_view_metric_prefix %>_handle_event_exception_duration_milliseconds_count{instance=~\"$instance\"}[1h])) or vector(0))\n)", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Handle Event Callback Success Rate (last 1h)", + "type": "stat" + }, + { + "datasource": "<%= @datasource_id %>", + "description": "The amount of LiveView handle_events that have occurred in the last hour.", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "locale" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 6 + }, + "id": 34, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^Value$/", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "(sum(increase(<%= @phoenix_live_view_metric_prefix %>_handle_event_exception_duration_milliseconds_count{instance=~\"$instance\"}[1h])) or vector(0)) + (sum(increase(<%= @phoenix_live_view_metric_prefix %>_handle_event_duration_milliseconds_count{instance=~\"$instance\"}[1h])) or vector(0))", + "instant": false, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Total LiveView Handle Events (Last 1h)", + "type": "stat" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 2, + "panels": [], + "title": "Mount Callback Details", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average time it took to complete the mount callback function.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 12 + }, + "hiddenSeries": false, + "id": 11, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_live_view_metric_prefix %>_mount_duration_milliseconds_sum{instance=~\"$instance\"}[$interval])) by(action, module) / sum(irate(<%= @phoenix_live_view_metric_prefix %>_mount_duration_milliseconds_count{instance=~\"$instance\"}[$interval])) by(action, module)", + "instant": false, + "interval": "", + "legendFormat": "({{ action }}) {{ module }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Execution Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average time it took to get through the mount callback function when an error was encountered.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 12 + }, + "hiddenSeries": false, + "id": 29, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_live_view_metric_prefix %>_mount_exception_duration_milliseconds_sum{instance=~\"$instance\"}[$interval])) by(action, module, kind, reason) / sum(irate(<%= @phoenix_live_view_metric_prefix %>_mount_exception_duration_milliseconds_count{instance=~\"$instance\"}[$interval])) by(action, module, kind, reason)", + "instant": false, + "interval": "", + "legendFormat": "({{ action }}) {{ module }} :: ({{kind}} -> {{reason}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Exception Execution Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the time it took to get through the mount callback.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 25 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 6, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_live_view_metric_prefix %>_mount_duration_milliseconds_bucket{instance=~\"$instance\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Execution Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the time it took to get through the mount callback when an exception was encountered.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 25 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 30, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_live_view_metric_prefix %>_mount_exception_duration_milliseconds_bucket{instance=~\"$instance\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Exception Execution Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 38 + }, + "id": 38, + "panels": [], + "title": "Handle Event Callback Details", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average time it took to complete the handle_event callback function.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 39 + }, + "hiddenSeries": false, + "id": 39, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_live_view_metric_prefix %>_handle_event_duration_milliseconds_sum{instance=~\"$instance\"}[$interval])) by(action, module, event) / sum(irate(<%= @phoenix_live_view_metric_prefix %>_handle_event_duration_milliseconds_count{instance=~\"$instance\"}[$interval])) by(action, module, event)", + "instant": false, + "interval": "", + "legendFormat": "({{ action }}) {{ module }} :: {{ event }}", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Execution Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "<%= @datasource_id %>", + "description": "The average time it took to get through the handle_event callback function.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 39 + }, + "hiddenSeries": false, + "id": 40, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "hideEmpty": false, + "hideZero": false, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null as zero", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_live_view_metric_prefix %>_handle_event_exception_duration_milliseconds_sum{instance=~\"$instance\"}[$interval])) by(event, action, module, kind, reason) / sum(irate(<%= @phoenix_live_view_metric_prefix %>_handle_event_exception_duration_milliseconds_count{instance=~\"$instance\"}[$interval])) by(event, action, module, kind, reason)", + "instant": false, + "interval": "", + "legendFormat": "({{ action }}) {{ module }} :: {{event}} ({{kind}} -> {{reason}})", + "refId": "A" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Average Exception Execution Time", + "tooltip": { + "shared": true, + "sort": 2, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ms", + "label": "", + "logBase": 1, + "max": null, + "min": "0", + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the time it took to get through the mount callback.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 0, + "y": 52 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 41, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_live_view_metric_prefix %>_handle_event_duration_milliseconds_bucket{instance=~\"$instance\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Execution Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + }, + { + "cards": { + "cardPadding": null, + "cardRound": null + }, + "color": { + "cardColor": "#b4ff00", + "colorScale": "sqrt", + "colorScheme": "interpolateOranges", + "exponent": 0.5, + "mode": "spectrum" + }, + "dataFormat": "tsbuckets", + "datasource": "<%= @datasource_id %>", + "description": "A heatmap showing the time it took to get through the handle_event callback when an exception was encountered.", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 12, + "x": 12, + "y": 52 + }, + "heatmap": {}, + "hideZeroBuckets": true, + "highlightCards": true, + "id": 42, + "legend": { + "show": true + }, + "pluginVersion": "7.1.3", + "reverseYBuckets": false, + "targets": [ + { + "expr": "sum(irate(<%= @phoenix_live_view_metric_prefix %>_handle_event_exception_duration_milliseconds_bucket{instance=~\"$instance\"}[$interval])) by (le)", + "format": "heatmap", + "hide": false, + "interval": "", + "legendFormat": "{{ le }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Exception Execution Time", + "tooltip": { + "show": true, + "showHistogram": true + }, + "type": "heatmap", + "xAxis": { + "show": true + }, + "xBucketNumber": null, + "xBucketSize": null, + "yAxis": { + "decimals": null, + "format": "ms", + "logBase": 1, + "max": null, + "min": null, + "show": true, + "splitFactor": null + }, + "yBucketBound": "auto", + "yBucketNumber": null, + "yBucketSize": null + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": ["PromEx", "Phoenix LiveView", "<%= @otp_app %>"], + "templating": { + "list": [ + { + "allValue": ".*", + "datasource": "<%= @datasource_id %>", + "definition": "label_values(<%= @prom_ex_metric_prefix %>_status_info, instance)", + "hide": 0, + "includeAll": true, + "label": "Application Instance", + "multi": false, + "name": "instance", + "options": [], + "query": "label_values(<%= @prom_ex_metric_prefix %>_status_info, instance)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "selected": false, + "text": "<%= @default_selected_interval %>", + "value": "<%= @default_selected_interval %>" + }, + "hide": 0, + "label": "Interval", + "name": "interval", + "options": [ + { + "selected": <%= @default_selected_interval == "15s" %>, + "text": "15s", + "value": "15s" + }, + { + "selected": <%= @default_selected_interval == "30s" %>, + "text": "30s", + "value": "30s" + }, + { + "selected": <%= @default_selected_interval == "1m" %>, + "text": "1m", + "value": "1m" + }, + { + "selected": <%= @default_selected_interval == "5m" %>, + "text": "5m", + "value": "5m" + }, + { + "selected": <%= @default_selected_interval == "15m" %>, + "text": "15m", + "value": "15m" + }, + { + "selected": <%= @default_selected_interval == "30m" %>, + "text": "30m", + "value": "30m" + }, + { + "selected": <%= @default_selected_interval == "1h" %>, + "text": "1h", + "value": "1h" + } + ], + "query": "15s, 30s, 1m, 5m, 15m, 30m, 1h", + "queryValue": "", + "refresh": 2, + "skipUrlSync": false, + "type": "interval" + } + ] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m" + ] + }, + "timezone": "", + "title": "<%= @title %>", + "uid": "<%= @uid %>", + "version": 1 +} From 9272ce88d081d25cef65098cd9b6462763c81222 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sat, 14 Sep 2024 22:31:57 +1200 Subject: [PATCH 10/16] Use a PromEx fork which doesn't require `plug_cowboy` --- mix.exs | 3 ++- mix.lock | 10 +++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/mix.exs b/mix.exs index b6ffdd7f7..220c4bab2 100644 --- a/mix.exs +++ b/mix.exs @@ -98,7 +98,8 @@ defmodule NervesHub.MixProject do {:phoenix_test, "0.3.1", only: :test, runtime: false}, {:plug, "~> 1.7"}, {:postgrex, "~> 0.14"}, - {:prom_ex, "~> 1.10"}, + {:prom_ex, "~> 1.10", + git: "https://github.com/joshk/prom_ex", ref: "plug_cowboy-should-be-optional"}, {:scrivener_ecto, "~> 2.7"}, {:scrivener_html, git: "https://github.com/nerves-hub/scrivener_html", branch: "phx-1.5"}, {:sentry, "~> 10.0"}, diff --git a/mix.lock b/mix.lock index aba22df44..75b2025fd 100644 --- a/mix.lock +++ b/mix.lock @@ -9,9 +9,6 @@ "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"}, "comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"}, "contex": {:hex, :contex, "0.5.0", "5d8a6defbeb41f54adfcb0f85c4756d4f2b84aa5b0d809d45a5d2e90d91d0392", [:mix], [{:nimble_strftime, "~> 0.1.0", [hex: :nimble_strftime, repo: "hexpm", optional: false]}], "hexpm", "b7497a1790324d84247859df44ba4bcf2489d9bba1812a5375b2f2046b9e6fd7"}, - "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"}, - "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, - "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, "crontab": {:hex, :crontab, "1.1.13", "3bad04f050b9f7f1c237809e42223999c150656a6b2afbbfef597d56df2144c5", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "d67441bec989640e3afb94e123f45a2bc42d76e02988c9613885dc3d01cf7085"}, "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"}, "db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, @@ -70,11 +67,10 @@ "phoenix_test": {:hex, :phoenix_test, "0.3.1", "adf5d67cb152fa1e0220527a9827db7f865a20817c7c0161315ba6fe86a8946c", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:floki, ">= 0.30.0", [hex: :floki, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.7.10", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.20.1", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "03f24332a966673ff40d35c45f427c7671537ea508b5777141dd60e60cdae22a"}, "phoenix_view": {:hex, :phoenix_view, "2.0.4", "b45c9d9cf15b3a1af5fb555c674b525391b6a1fe975f040fb4d913397b31abf4", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "4e992022ce14f31fe57335db27a28154afcc94e9983266835bb3040243eb620b"}, "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.7.2", "fdadb973799ae691bf9ecad99125b16625b1c6039999da5fe544d99218e662e4", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "245d8a11ee2306094840c000e8816f0cbed69a23fc0ac2bcf8d7835ae019bb2f"}, "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, "postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"}, - "prom_ex": {:hex, :prom_ex, "1.10.0", "2fe14cd0b2f7f8688280b02861c58da9624571f82a878b203825fb2bec206195", [:mix], [{:absinthe, ">= 1.7.0", [hex: :absinthe, repo: "hexpm", optional: true]}, {:broadway, ">= 1.1.0", [hex: :broadway, repo: "hexpm", optional: true]}, {:ecto, ">= 3.11.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:finch, "~> 0.18", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:oban, ">= 2.10.0", [hex: :oban, repo: "hexpm", optional: true]}, {:octo_fetch, "~> 0.4", [hex: :octo_fetch, repo: "hexpm", optional: false]}, {:peep, "~> 3.0", [hex: :peep, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.7.0", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, ">= 0.20.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, ">= 1.16.0", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 2.6.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:telemetry, ">= 1.0.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}, {:telemetry_metrics_prometheus_core, "~> 1.2", [hex: :telemetry_metrics_prometheus_core, repo: "hexpm", optional: false]}, {:telemetry_poller, "~> 1.1", [hex: :telemetry_poller, repo: "hexpm", optional: false]}], "hexpm", "55d6ca87519b14202570dda5f29bf3f52e14b940eaf2ddcd89ad41347fa5781a"}, - "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, + "prom_ex": {:git, "https://github.com/joshk/prom_ex", "e53b32d136568d3a34f5b2cc4370072b2d96da49", [ref: "plug_cowboy-should-be-optional"]}, + "ranch": {:hex, :ranch, "2.1.0", "2261f9ed9574dcfcc444106b9f6da155e6e540b2f82ba3d42b339b93673b72a3", [:make, :rebar3], [], "hexpm", "244ee3fa2a6175270d8e1fc59024fd9dbc76294a321057de8f803b1479e76916"}, "recon": {:hex, :recon, "2.5.6", "9052588e83bfedfd9b72e1034532aee2a5369d9d9343b61aeb7fbce761010741", [:mix, :rebar3], [], "hexpm", "96c6799792d735cc0f0fd0f86267e9d351e63339cbe03df9d162010cefc26bb0"}, "scrivener": {:hex, :scrivener, "2.7.2", "1d913c965ec352650a7f864ad7fd8d80462f76a32f33d57d1e48bc5e9d40aba2", [:mix], [], "hexpm", "7866a0ec4d40274efbee1db8bead13a995ea4926ecd8203345af8f90d2b620d9"}, "scrivener_ecto": {:hex, :scrivener_ecto, "2.7.1", "b8ca910c11429748d3c2d86f0e095abc6d0c49779c7fc5ac5db195e121c46a91", [:mix], [{:ecto, ">= 3.3.0 and < 3.12.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:scrivener, "~> 2.4", [hex: :scrivener, repo: "hexpm", optional: false]}], "hexpm", "f5c2f7db1fdcdfe9583ba378689c6ac20fd2af2c476378a017c03c950ac82c3e"}, @@ -84,7 +80,7 @@ "slipstream": {:hex, :slipstream, "1.1.1", "7e56f62f1a9ee81351e3c36f57b9b187e00dc2f470e70ba46ea7ad16e80b061f", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mint_web_socket, "~> 0.2 or ~> 1.0", [hex: :mint_web_socket, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.1 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c20e420cde1654329d38ec3aa1c0e4debbd4c91ca421491e7984ad4644e638a6"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"}, - "swoosh": {:hex, :swoosh, "1.17.0", "4a082a6ce4d60b1f48ffa725c8da0e2304504569ff550f4ed2d088c923039cb0", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "659b8bc25f7483b872d051a7f0731fb8d5312165be0d0302a3c783b566b0a290"}, + "swoosh": {:hex, :swoosh, "1.17.1", "01295a82bddd2c6cac1e65856e29444d7c23c4501e0ebc69cea8a82018227e25", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3b20d25e580cb79af631335a1bdcfbffd835c08ebcdc16e98577223a241a18a1"}, "table_rex": {:hex, :table_rex, "4.0.0", "3c613a68ebdc6d4d1e731bc973c233500974ec3993c99fcdabb210407b90959b", [:mix], [], "hexpm", "c35c4d5612ca49ebb0344ea10387da4d2afe278387d4019e4d8111e815df8f55"}, "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "telemetry_metrics": {:hex, :telemetry_metrics, "1.0.0", "29f5f84991ca98b8eb02fc208b2e6de7c95f8bb2294ef244a176675adc7775df", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f23713b3847286a534e005126d4c959ebcca68ae9582118ce436b521d1d47d5d"}, From 515d5c388210cd6fa7c5b735328d46188d77dffe Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sat, 14 Sep 2024 22:36:21 +1200 Subject: [PATCH 11/16] Fix a comment --- lib/nerves_hub_web/endpoint.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/nerves_hub_web/endpoint.ex b/lib/nerves_hub_web/endpoint.ex index aa65dfdf4..59b948977 100644 --- a/lib/nerves_hub_web/endpoint.ex +++ b/lib/nerves_hub_web/endpoint.ex @@ -64,7 +64,7 @@ defmodule NervesHubWeb.Endpoint do cookie_key: "request_logger" ) - # We don't need to see these in the logs, thus this is defined by telemetry + # We don't need to see these in the logs, thus this is defined before telemetry plug(NervesHubWeb.Plugs.ImAlive) plug(Plug.RequestId) From ec9238fb6e1fb1f2b3ad31f31ea61df6feea97cd Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sat, 14 Sep 2024 23:50:25 +1200 Subject: [PATCH 12/16] Reinstate `NervesHub.Metrics` --- lib/nerves_hub/application.ex | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/nerves_hub/application.ex b/lib/nerves_hub/application.ex index 30ecdfa58..02a819b15 100644 --- a/lib/nerves_hub/application.ex +++ b/lib/nerves_hub/application.ex @@ -55,8 +55,7 @@ defmodule NervesHub.Application do defp metrics("test"), do: [] defp metrics(_env) do - # [NervesHub.Metrics] - [] + [NervesHub.Metrics] end defp deployments_supervisor("test"), do: [] From 78ee29bcfcede53169f12a51db4f5c6e16ace7a8 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sat, 14 Sep 2024 23:50:53 +1200 Subject: [PATCH 13/16] Remove the Grafana dashboard sponsoring links --- priv/grafana/ecto.json.eex | 12 ------------ priv/grafana/phoenix.json.eex | 12 ------------ priv/grafana/phoenix_live_view.json.eex | 12 ------------ 3 files changed, 36 deletions(-) diff --git a/priv/grafana/ecto.json.eex b/priv/grafana/ecto.json.eex index 4159a5496..e55cd693b 100644 --- a/priv/grafana/ecto.json.eex +++ b/priv/grafana/ecto.json.eex @@ -48,18 +48,6 @@ "graphTooltip": 1, "id": null, "links": [ - { - "asDropdown": false, - "icon": "bolt", - "includeVars": false, - "keepTime": false, - "tags": [], - "targetBlank": true, - "title": "Sponsor PromEx", - "tooltip": "", - "type": "link", - "url": "https://github.com/sponsors/akoutmos" - }, { "asDropdown": false, "icon": "doc", diff --git a/priv/grafana/phoenix.json.eex b/priv/grafana/phoenix.json.eex index af5106973..897295f09 100644 --- a/priv/grafana/phoenix.json.eex +++ b/priv/grafana/phoenix.json.eex @@ -48,18 +48,6 @@ "graphTooltip": 1, "id": null, "links": [ - { - "asDropdown": false, - "icon": "bolt", - "includeVars": false, - "keepTime": false, - "tags": [], - "targetBlank": true, - "title": "Sponsor PromEx", - "tooltip": "", - "type": "link", - "url": "https://github.com/sponsors/akoutmos" - }, { "asDropdown": false, "icon": "doc", diff --git a/priv/grafana/phoenix_live_view.json.eex b/priv/grafana/phoenix_live_view.json.eex index f4e4bf2e4..5205a5565 100644 --- a/priv/grafana/phoenix_live_view.json.eex +++ b/priv/grafana/phoenix_live_view.json.eex @@ -48,18 +48,6 @@ "graphTooltip": 1, "id": null, "links": [ - { - "asDropdown": false, - "icon": "bolt", - "includeVars": false, - "keepTime": false, - "tags": [], - "targetBlank": true, - "title": "Sponsor PromEx", - "tooltip": "", - "type": "link", - "url": "https://github.com/sponsors/akoutmos" - }, { "asDropdown": false, "icon": "doc", From 37946038860a889997e6a694c8d3e9d597a8a0ac Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sat, 14 Sep 2024 23:51:14 +1200 Subject: [PATCH 14/16] Fix a LiveView graph --- priv/grafana/phoenix_live_view.json.eex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/priv/grafana/phoenix_live_view.json.eex b/priv/grafana/phoenix_live_view.json.eex index 5205a5565..2c8ef01cd 100644 --- a/priv/grafana/phoenix_live_view.json.eex +++ b/priv/grafana/phoenix_live_view.json.eex @@ -300,7 +300,7 @@ "calcs": [ "lastNotNull" ], - "fields": "/^Value$/", + "fields": "", "values": false }, "textMode": "auto" @@ -544,7 +544,7 @@ "calcs": [ "lastNotNull" ], - "fields": "/^Value$/", + "fields": "", "values": false }, "textMode": "auto" From c317bd5d28aa8907734440d8d29acae9df2eebfa Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sun, 15 Sep 2024 19:46:32 +1200 Subject: [PATCH 15/16] Create a `MetricsEndpoint` This fixes a bunch of `force_ssl` issues since this one endpoint can be http only, plus its easy not to expose it to the world --- config/config.exs | 5 +++++ config/dev.exs | 5 +++++ config/prod.exs | 13 +++++++++++-- config/runtime.exs | 12 ++++++++++++ lib/nerves_hub/application.ex | 5 ++++- lib/nerves_hub_web/device_endpoint.ex | 2 -- lib/nerves_hub_web/endpoint.ex | 4 ---- lib/nerves_hub_web/metrics_endpoint.ex | 7 +++++++ 8 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 lib/nerves_hub_web/metrics_endpoint.ex diff --git a/config/config.exs b/config/config.exs index a9385c453..b6c552faa 100644 --- a/config/config.exs +++ b/config/config.exs @@ -48,6 +48,11 @@ config :nerves_hub, NervesHubWeb.Endpoint, ], pubsub_server: NervesHub.PubSub +## +# NervesHub Metrics +# +config :nerves_hub, NervesHubWeb.MetricsEndpoint, adapter: Bandit.PhoenixAdapter + ## # Database and Oban # diff --git a/config/dev.exs b/config/dev.exs index 02e39b98d..0611aebf3 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -66,6 +66,11 @@ config :nerves_hub, NervesHubWeb.DeviceEndpoint, ] ] +## +# NervesHub Metrics +# +config :nerves_hub, NervesHubWeb.MetricsEndpoint, http: [ip: {0, 0, 0, 0}, port: 4002] + ## # Database and Oban # diff --git a/config/prod.exs b/config/prod.exs index 997e52f59..1d7a5d498 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -8,12 +8,21 @@ config :phoenix, logger: false ## # NervesHub Web # -config :nerves_hub, NervesHubWeb.Endpoint, server: true +config :nerves_hub, NervesHubWeb.Endpoint, + force_ssl: [rewrite_on: [:x_forwarded_proto]], + server: true ## # NervesHub Device # -config :nerves_hub, NervesHubWeb.DeviceEndpoint, server: true +config :nerves_hub, NervesHubWeb.DeviceEndpoint, + force_ssl: [rewrite_on: [:x_forwarded_proto]], + server: true + +## +# NervesHub Metrics +# +config :nerves_hub, NervesHubWeb.MetricsEndpoint, server: true ## # Database and Oban diff --git a/config/runtime.exs b/config/runtime.exs index dd1f52c56..833cfec09 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -168,6 +168,18 @@ if config_env() == :prod do ] end + web_port = System.get_env("HTTP_PORT") || System.get_env("PORT") || "4000" + + metrics_port = + case System.get_env("METRICS_PORT") do + nil -> String.to_integer(web_port) + 40 + port -> String.to_integer(port) + end + + config :nerves_hub, NervesHubWeb.MetricsEndpoint, + http: [port: metrics_port], + server: true + config :nerves_hub, NervesHubWeb.DeviceSocket, shared_secrets: [ enabled: System.get_env("DEVICE_SHARED_SECRETS_ENABLED", "false") == "true" diff --git a/lib/nerves_hub/application.ex b/lib/nerves_hub/application.ex index 02a819b15..e6785b67d 100644 --- a/lib/nerves_hub/application.ex +++ b/lib/nerves_hub/application.ex @@ -41,7 +41,10 @@ defmodule NervesHub.Application do {Oban, Application.fetch_env!(:nerves_hub, Oban)} ] ++ deployments_supervisor(deploy_env()) ++ - endpoints(deploy_env()) + endpoints(deploy_env()) ++ + [ + NervesHubWeb.MetricsEndpoint + ] opts = [strategy: :one_for_one, name: NervesHub.Supervisor] Supervisor.start_link(children, opts) diff --git a/lib/nerves_hub_web/device_endpoint.ex b/lib/nerves_hub_web/device_endpoint.ex index 360d20682..b20f63b0a 100644 --- a/lib/nerves_hub_web/device_endpoint.ex +++ b/lib/nerves_hub_web/device_endpoint.ex @@ -33,8 +33,6 @@ defmodule NervesHubWeb.DeviceEndpoint do plug(NervesHubWeb.Plugs.ImAlive) - plug(PromEx.Plug, prom_ex_module: NervesHub.PromEx) - plug(Sentry.PlugContext) plug(NervesHubWeb.Plugs.Logger) diff --git a/lib/nerves_hub_web/endpoint.ex b/lib/nerves_hub_web/endpoint.ex index 59b948977..35570e75f 100644 --- a/lib/nerves_hub_web/endpoint.ex +++ b/lib/nerves_hub_web/endpoint.ex @@ -10,10 +10,6 @@ defmodule NervesHubWeb.Endpoint do signing_salt: "1CPjriVa" ] - plug(PromEx.Plug, prom_ex_module: NervesHub.PromEx) - - plug(Plug.SSL, rewrite_on: [:x_forwarded_proto]) - socket("/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]]) socket("/socket", NervesHubWeb.UserSocket, diff --git a/lib/nerves_hub_web/metrics_endpoint.ex b/lib/nerves_hub_web/metrics_endpoint.ex new file mode 100644 index 000000000..87f85e2b9 --- /dev/null +++ b/lib/nerves_hub_web/metrics_endpoint.ex @@ -0,0 +1,7 @@ +defmodule NervesHubWeb.MetricsEndpoint do + use Phoenix.Endpoint, otp_app: :nerves_hub + + plug(PromEx.Plug, prom_ex_module: NervesHub.PromEx) + + plug(NervesHubWeb.Plugs.DeviceEndpointRedirect) +end From 2eb30825f32dd9cc4356e541550b7c28c37e8399 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Tue, 17 Sep 2024 10:36:26 +1200 Subject: [PATCH 16/16] Support the `DevicesEndpoint` --- lib/nerves_hub/prom_ex.ex | 10 ++++++++-- mix.exs | 3 +-- mix.lock | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/nerves_hub/prom_ex.ex b/lib/nerves_hub/prom_ex.ex index 8f79ea47a..d34a5ba9a 100644 --- a/lib/nerves_hub/prom_ex.ex +++ b/lib/nerves_hub/prom_ex.ex @@ -9,7 +9,14 @@ defmodule NervesHub.PromEx do # PromEx built in plugins Plugins.Application, Plugins.Beam, - {Plugins.Phoenix, endpoint: NervesHubWeb.Endpoint, router: NervesHubWeb.Router}, + { + PromEx.Plugins.Phoenix, + endpoints: [ + {NervesHubWeb.Endpoint, routers: [NervesHubWeb.Router]}, + # DeviceEndpoint doesn't use a Router, but we need to pass to PromEx + {NervesHubWeb.DeviceEndpoint, routers: [NervesHubWeb.Router]} + ] + }, Plugins.PhoenixLiveView, Plugins.Ecto, Plugins.Oban @@ -27,7 +34,6 @@ defmodule NervesHub.PromEx do def dashboards do [ # PromEx built in Grafana dashboards - {:prom_ex, "application.json"}, {:prom_ex, "beam.json"}, {:nerves_hub, "grafana/phoenix.json"}, {:nerves_hub, "grafana/phoenix_live_view.json"}, diff --git a/mix.exs b/mix.exs index 220c4bab2..529f11d31 100644 --- a/mix.exs +++ b/mix.exs @@ -98,8 +98,7 @@ defmodule NervesHub.MixProject do {:phoenix_test, "0.3.1", only: :test, runtime: false}, {:plug, "~> 1.7"}, {:postgrex, "~> 0.14"}, - {:prom_ex, "~> 1.10", - git: "https://github.com/joshk/prom_ex", ref: "plug_cowboy-should-be-optional"}, + {:prom_ex, "~> 1.10", git: "https://github.com/joshk/prom_ex", ref: "updated-with-prs"}, {:scrivener_ecto, "~> 2.7"}, {:scrivener_html, git: "https://github.com/nerves-hub/scrivener_html", branch: "phx-1.5"}, {:sentry, "~> 10.0"}, diff --git a/mix.lock b/mix.lock index 75b2025fd..4d56747b6 100644 --- a/mix.lock +++ b/mix.lock @@ -69,7 +69,7 @@ "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, "postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"}, - "prom_ex": {:git, "https://github.com/joshk/prom_ex", "e53b32d136568d3a34f5b2cc4370072b2d96da49", [ref: "plug_cowboy-should-be-optional"]}, + "prom_ex": {:git, "https://github.com/joshk/prom_ex", "6d11c1e8ad66d5851197e97e2b36287fabaa50e4", [ref: "updated-with-prs"]}, "ranch": {:hex, :ranch, "2.1.0", "2261f9ed9574dcfcc444106b9f6da155e6e540b2f82ba3d42b339b93673b72a3", [:make, :rebar3], [], "hexpm", "244ee3fa2a6175270d8e1fc59024fd9dbc76294a321057de8f803b1479e76916"}, "recon": {:hex, :recon, "2.5.6", "9052588e83bfedfd9b72e1034532aee2a5369d9d9343b61aeb7fbce761010741", [:mix, :rebar3], [], "hexpm", "96c6799792d735cc0f0fd0f86267e9d351e63339cbe03df9d162010cefc26bb0"}, "scrivener": {:hex, :scrivener, "2.7.2", "1d913c965ec352650a7f864ad7fd8d80462f76a32f33d57d1e48bc5e9d40aba2", [:mix], [], "hexpm", "7866a0ec4d40274efbee1db8bead13a995ea4926ecd8203345af8f90d2b620d9"},