diff --git a/README.md b/README.md
index d99b196..e5cdc21 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,3 @@
-> [!IMPORTANT]
-> (2025-02-14) [zakkarry](https://github.com/sponsors/zakkarry), who is a collaborator on [cross-seed](https://github.com/cross-seed/cross-seed) and an extremely helpful community member in general, is facing hard times due to medical debt and family illness. If you're able, please consider [sponsoring him on GitHub](https://github.com/sponsors/zakkarry) or donating via [buymeacoffee](https://tip.ary.dev). Tell him I sent you!
-
[](LICENSE)
-[](https://github.com/kieraneglin/pinchflat/releases)
-[](https://discord.gg/j7T6dCuwU4)
+[](https://github.com/kieraneglin/pinchflat/releases)
[](#)
[](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/kieraneglin/pinchflat)
@@ -37,7 +33,6 @@
- [Portainer](#portainer)
- [Docker](#docker)
- [Environment Variables](#environment-variables)
- - [A note on reverse proxies](#reverse-proxies)
- [Username and Password (authentication)](https://github.com/kieraneglin/pinchflat/wiki/Username-and-Password)
- [Frequently asked questions](https://github.com/kieraneglin/pinchflat/wiki/Frequently-Asked-Questions)
- [Documentation](https://github.com/kieraneglin/pinchflat/wiki)
@@ -129,23 +124,6 @@ docker run \
ghcr.io/kieraneglin/pinchflat:latest
```
-### Podman
-
-The Podman setup is similar to Docker but changes a few flags to run under a User Namespace instead of root. To run Pinchflat under Podman and use the current user's UID/GID for file access run this:
-
-```
-podman run \
- --security-opt label=disable \
- --userns=keep-id --user=$UID \
- -e TZ=America/Los_Angeles \
- -p 8945:8945 \
- -v /host/path/to/config:/config:rw \
- -v /host/path/to/downloads/:/downloads:rw \
- ghcr.io/kieraneglin/pinchflat:latest
-```
-
-Using this setup consider creating a new `pinchflat` user and giving that user ownership to the config and download directory. See [Podman --userns](https://docs.podman.io/en/v4.6.1/markdown/options/userns.container.html) docs.
-
### IMPORTANT: File permissions
You _must_ ensure the host directories you've mounted are writable by the user running the Docker container. If you get a permission error follow the steps it suggests. See [#106](https://github.com/kieraneglin/pinchflat/issues/106) for more.
@@ -164,24 +142,18 @@ If you change this setting and it works well for you, please leave a comment on
### Environment variables
-| Name | Required? | Default | Notes |
-| --------------------------- | --------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
-| `TZ` | No | `UTC` | Must follow IANA TZ format |
-| `LOG_LEVEL` | No | `debug` | Can be set to `info` but `debug` is strongly recommended |
-| `UMASK` | No | `022` | Unraid users may want to set this to `000` |
-| `BASIC_AUTH_USERNAME` | No | | See [authentication docs](https://github.com/kieraneglin/pinchflat/wiki/Username-and-Password) |
-| `BASIC_AUTH_PASSWORD` | No | | See [authentication docs](https://github.com/kieraneglin/pinchflat/wiki/Username-and-Password) |
-| `EXPOSE_FEED_ENDPOINTS` | No | `false` | See [RSS feed docs](https://github.com/kieraneglin/pinchflat/wiki/Podcast-RSS-Feeds) |
-| `ENABLE_IPV6` | No | `false` | Setting to _any_ non-blank value will enable IPv6 |
-| `JOURNAL_MODE` | No | `wal` | Set to `delete` if your config directory is stored on a network share (not recommended) |
-| `TZ_DATA_DIR` | No | `/etc/elixir_tzdata_data` | The container path where the timezone database is stored |
-| `BASE_ROUTE_PATH` | No | `/` | The base path for route generation. Useful when running behind certain reverse proxies - prefixes must be stripped. |
-| `YT_DLP_WORKER_CONCURRENCY` | No | `2` | The number of concurrent workers that use `yt-dlp` _per queue_. Set to 1 if you're getting IP limited, otherwise don't touch it |
-| `ENABLE_PROMETHEUS` | No | `false` | Setting to _any_ non-blank value will enable Prometheus. See [docs](https://github.com/kieraneglin/pinchflat/wiki/Prometheus-and-Grafana) |
-
-### Reverse Proxies
-
-Pinchflat makes heavy use of websockets for real-time updates. If you're running Pinchflat behind a reverse proxy then you'll need to make sure it's configured to support websockets.
+| Name | Required? | Default | Notes |
+| --------------------------- | --------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
+| `TZ` | No | `UTC` | Must follow IANA TZ format |
+| `LOG_LEVEL` | No | `debug` | Can be set to `info` but `debug` is strongly recommended |
+| `BASIC_AUTH_USERNAME` | No | | See [authentication docs](https://github.com/kieraneglin/pinchflat/wiki/Username-and-Password) |
+| `BASIC_AUTH_PASSWORD` | No | | See [authentication docs](https://github.com/kieraneglin/pinchflat/wiki/Username-and-Password) |
+| `EXPOSE_FEED_ENDPOINTS` | No | `false` | See [RSS feed docs](https://github.com/kieraneglin/pinchflat/wiki/Podcast-RSS-Feeds) |
+| `ENABLE_IPV6` | No | `false` | Setting to _any_ non-blank value will enable IPv6 |
+| `JOURNAL_MODE` | No | `wal` | Set to `delete` if your config directory is stored on a network share (not recommended) |
+| `TZ_DATA_DIR` | No | `/etc/elixir_tzdata_data` | The container path where the timezone database is stored |
+| `BASE_ROUTE_PATH` | No | `/` | The base path for route generation. Useful when running behind certain reverse proxies, but prefix must be stripped. |
+| `YT_DLP_WORKER_CONCURRENCY` | No | `2` | The number of concurrent workers that use `yt-dlp` _per queue_. Set to 1 if you're getting IP limited, otherwise don't touch it |
## EFF donations
diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js
index fdb2bc4..49d9b55 100644
--- a/assets/tailwind.config.js
+++ b/assets/tailwind.config.js
@@ -347,38 +347,6 @@ module.exports = {
},
{ values }
)
- }),
- plugin(function ({ matchComponents, theme }) {
- let iconsDir = path.join(__dirname, './vendor/simple-icons')
- let values = {}
-
- fs.readdirSync(iconsDir).forEach((file) => {
- let name = path.basename(file, '.svg')
- values[name] = { name, fullPath: path.join(iconsDir, file) }
- })
-
- matchComponents(
- {
- si: ({ name, fullPath }) => {
- let content = fs
- .readFileSync(fullPath)
- .toString()
- .replace(/\r?\n|\r/g, '')
- return {
- [`--si-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
- '-webkit-mask': `var(--si-${name})`,
- mask: `var(--si-${name})`,
- 'mask-repeat': 'no-repeat',
- 'background-color': 'currentColor',
- 'vertical-align': 'middle',
- display: 'inline-block',
- width: theme('spacing.5'),
- height: theme('spacing.5')
- }
- }
- },
- { values }
- )
})
]
}
diff --git a/assets/vendor/simple-icons/discord.svg b/assets/vendor/simple-icons/discord.svg
deleted file mode 100644
index 9d7796b..0000000
--- a/assets/vendor/simple-icons/discord.svg
+++ /dev/null
@@ -1 +0,0 @@
-Discord
\ No newline at end of file
diff --git a/assets/vendor/simple-icons/github.svg b/assets/vendor/simple-icons/github.svg
deleted file mode 100644
index 2334976..0000000
--- a/assets/vendor/simple-icons/github.svg
+++ /dev/null
@@ -1 +0,0 @@
-GitHub
diff --git a/config/config.exs b/config/config.exs
index f57e0cc..7df3a77 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -10,7 +10,6 @@ import Config
config :pinchflat,
ecto_repos: [Pinchflat.Repo],
generators: [timestamp_type: :utc_datetime],
- env: config_env(),
# Specifying backend data here makes mocking and local testing SUPER easy
yt_dlp_executable: System.find_executable("yt-dlp"),
apprise_executable: System.find_executable("apprise"),
@@ -50,7 +49,16 @@ config :pinchflat, PinchflatWeb.Endpoint,
config :pinchflat, Oban,
engine: Oban.Engines.Lite,
- repo: Pinchflat.Repo
+ repo: Pinchflat.Repo,
+ # Keep old jobs for 30 days for display in the UI
+ plugins: [
+ {Oban.Plugins.Pruner, max_age: 30 * 24 * 60 * 60},
+ {Oban.Plugins.Cron,
+ crontab: [
+ {"0 1 * * *", Pinchflat.Downloading.MediaRetentionWorker},
+ {"0 2 * * *", Pinchflat.Downloading.MediaQualityUpgradeWorker}
+ ]}
+ ]
# Configures the mailer
#
@@ -91,12 +99,6 @@ config :logger, :default_formatter,
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
-config :pinchflat, Pinchflat.PromEx,
- disabled: true,
- manual_metrics_start_delay: :no_delay,
- drop_metrics_groups: [],
- metrics_server: :disabled
-
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{config_env()}.exs"
diff --git a/config/dev.exs b/config/dev.exs
index 8b9b793..771f5c1 100644
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -81,5 +81,3 @@ config :phoenix_live_view, :debug_heex_annotations, true
# Disable swoosh api client as it is only required for production adapters.
config :swoosh, :api_client, false
-
-config :pinchflat, Pinchflat.PromEx, disabled: false
diff --git a/config/runtime.exs b/config/runtime.exs
index 5624bfe..afce572 100644
--- a/config/runtime.exs
+++ b/config/runtime.exs
@@ -43,30 +43,15 @@ config :pinchflat, Pinchflat.Repo,
# Some users may want to increase the number of workers that use yt-dlp to improve speeds
# Others may want to decrease the number of these workers to lessen the chance of an IP ban
{yt_dlp_worker_count, _} = Integer.parse(System.get_env("YT_DLP_WORKER_CONCURRENCY", "2"))
-# Used to set the cron for the yt-dlp update worker. The reason for this is
-# to avoid all instances of PF updating yt-dlp at the same time, which 1)
-# could result in rate limiting and 2) gives me time to react if an update
-# breaks something
-%{hour: current_hour, minute: current_minute} = DateTime.utc_now()
config :pinchflat, Oban,
queues: [
default: 10,
- fast_indexing: yt_dlp_worker_count,
+ fast_indexing: 6,
media_collection_indexing: yt_dlp_worker_count,
media_fetching: yt_dlp_worker_count,
remote_metadata: yt_dlp_worker_count,
local_data: 8
- ],
- plugins: [
- # Keep old jobs for 30 days for display in the UI
- {Oban.Plugins.Pruner, max_age: 30 * 24 * 60 * 60},
- {Oban.Plugins.Cron,
- crontab: [
- {"#{current_minute} #{current_hour} * * *", Pinchflat.YtDlp.UpdateWorker},
- {"0 1 * * *", Pinchflat.Downloading.MediaRetentionWorker},
- {"0 2 * * *", Pinchflat.Downloading.MediaQualityUpgradeWorker}
- ]}
]
if config_env() == :prod do
@@ -87,7 +72,6 @@ if config_env() == :prod do
# For running PF in a subdirectory via a reverse proxy
base_route_path = System.get_env("BASE_ROUTE_PATH", "/")
enable_ipv6 = String.length(System.get_env("ENABLE_IPV6", "")) > 0
- enable_prometheus = String.length(System.get_env("ENABLE_PROMETHEUS", "")) > 0
config :logger, level: String.to_existing_atom(System.get_env("LOG_LEVEL", "debug"))
@@ -111,8 +95,6 @@ if config_env() == :prod do
database: db_path,
journal_mode: journal_mode
- config :pinchflat, Pinchflat.PromEx, disabled: !enable_prometheus
-
# The secret key base is used to sign/encrypt cookies and other secrets.
# A default value is used in config/dev.exs and config/test.exs but you
# want to use a different value for prod and you most likely don't want
diff --git a/docker/dev.Dockerfile b/docker/dev.Dockerfile
index 04a3e13..fe61ee1 100644
--- a/docker/dev.Dockerfile
+++ b/docker/dev.Dockerfile
@@ -1,7 +1,6 @@
-ARG ELIXIR_VERSION=1.18.4
-ARG OTP_VERSION=27.2.4
-ARG DEBIAN_VERSION=bookworm-20250428-slim
-
+ARG ELIXIR_VERSION=1.17.0
+ARG OTP_VERSION=26.2.5
+ARG DEBIAN_VERSION=bookworm-20240612-slim
ARG DEV_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
FROM ${DEV_IMAGE}
@@ -13,7 +12,7 @@ RUN echo "Building for ${TARGETPLATFORM:?}"
RUN apt-get update -qq && \
apt-get install -y inotify-tools curl git openssh-client jq \
python3 python3-setuptools python3-wheel python3-dev pipx \
- python3-mutagen locales procps build-essential graphviz zsh unzip
+ python3-mutagen locales procps build-essential graphviz zsh
# Install ffmpeg
RUN export FFMPEG_DOWNLOAD=$(case ${TARGETPLATFORM:-linux/amd64} in \
@@ -32,14 +31,8 @@ RUN curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh && \
# Install baseline Elixir packages
mix local.hex --force && \
mix local.rebar --force && \
- # Install Deno - required for YouTube downloads (See yt-dlp#14404)
- curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh -s -- -y --no-modify-path && \
# Download and update YT-DLP
- export YT_DLP_DOWNLOAD=$(case ${TARGETPLATFORM:-linux/amd64} in \
- "linux/amd64") echo "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux" ;; \
- "linux/arm64") echo "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux_aarch64" ;; \
- *) echo "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux" ;; esac) && \
- curl -L ${YT_DLP_DOWNLOAD} -o /usr/local/bin/yt-dlp && \
+ curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp && \
chmod a+rx /usr/local/bin/yt-dlp && \
yt-dlp -U && \
# Install Apprise
diff --git a/docker/selfhosted.Dockerfile b/docker/selfhosted.Dockerfile
index 17f7af7..235206a 100644
--- a/docker/selfhosted.Dockerfile
+++ b/docker/selfhosted.Dockerfile
@@ -1,13 +1,13 @@
# Find eligible builder and runner images on Docker Hub. We use Ubuntu/Debian
# instead of Alpine to avoid DNS resolution issues in production.
-ARG ELIXIR_VERSION=1.18.4
-ARG OTP_VERSION=27.2.4
-ARG DEBIAN_VERSION=bookworm-20250428-slim
+ARG ELIXIR_VERSION=1.17.0
+ARG OTP_VERSION=26.2.5
+ARG DEBIAN_VERSION=bookworm-20240612-slim
ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}"
-FROM ${BUILDER_IMAGE} AS builder
+FROM ${BUILDER_IMAGE} as builder
ARG TARGETPLATFORM
RUN echo "Building for ${TARGETPLATFORM:?}"
@@ -73,7 +73,6 @@ RUN mix release
FROM ${RUNNER_IMAGE}
-ARG TARGETPLATFORM
ARG PORT=8945
COPY --from=builder ./usr/local/bin/ffmpeg /usr/bin/ffmpeg
@@ -95,21 +94,13 @@ RUN apt-get update -y && \
python3 \
pipx \
jq \
- # unzip is needed for Deno
- unzip \
procps && \
- # Install Deno - required for YouTube downloads (See yt-dlp#14404)
- curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh -s -- -y --no-modify-path && \
# Apprise
export PIPX_HOME=/opt/pipx && \
export PIPX_BIN_DIR=/usr/local/bin && \
pipx install apprise && \
# yt-dlp
- export YT_DLP_DOWNLOAD=$(case ${TARGETPLATFORM:-linux/amd64} in \
- "linux/amd64") echo "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux" ;; \
- "linux/arm64") echo "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux_aarch64" ;; \
- *) echo "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux" ;; esac) && \
- curl -L ${YT_DLP_DOWNLOAD} -o /usr/local/bin/yt-dlp && \
+ curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp && \
chmod a+rx /usr/local/bin/yt-dlp && \
yt-dlp -U && \
# Set the locale
@@ -119,27 +110,26 @@ RUN apt-get update -y && \
rm -rf /var/lib/apt/lists/*
# More locale setup
-ENV LANG=en_US.UTF-8
-ENV LANGUAGE=en_US:en
-ENV LC_ALL=en_US.UTF-8
+ENV LANG en_US.UTF-8
+ENV LANGUAGE en_US:en
+ENV LC_ALL en_US.UTF-8
WORKDIR "/app"
# Set up data volumes
RUN mkdir -p /config /downloads /etc/elixir_tzdata_data /etc/yt-dlp/plugins && \
- chmod ugo+rw /etc/elixir_tzdata_data /etc/yt-dlp /etc/yt-dlp/plugins /usr/local/bin /usr/local/bin/yt-dlp
+ chmod ugo+rw /etc/elixir_tzdata_data /etc/yt-dlp /etc/yt-dlp/plugins
# set runner ENV
ENV MIX_ENV="prod"
ENV PORT=${PORT}
ENV RUN_CONTEXT="selfhosted"
-ENV UMASK=022
EXPOSE ${PORT}
# Only copy the final release from the build stage
COPY --from=builder /app/_build/${MIX_ENV}/rel/pinchflat ./
-HEALTHCHECK --interval=30s --start-period=15s \
+HEALTHCHECK --interval=120s --start-period=10s \
CMD curl --fail http://localhost:${PORT}/healthcheck || exit 1
# Start the app
diff --git a/lib/pinchflat/application.ex b/lib/pinchflat/application.ex
index 3f823f4..61b2538 100644
--- a/lib/pinchflat/application.ex
+++ b/lib/pinchflat/application.ex
@@ -9,13 +9,8 @@ defmodule Pinchflat.Application do
@impl true
def start(_type, _args) do
check_and_update_timezone()
- attach_oban_telemetry()
- Logger.add_handlers(:pinchflat)
- # See https://hexdocs.pm/elixir/Supervisor.html
- # for other strategies and supported options
- [
- Pinchflat.PromEx,
+ children = [
PinchflatWeb.Telemetry,
Pinchflat.Repo,
# Must be before startup tasks
@@ -28,11 +23,17 @@ defmodule Pinchflat.Application do
{Finch, name: Pinchflat.Finch},
# Start a worker by calling: Pinchflat.Worker.start_link(arg)
# {Pinchflat.Worker, arg},
- # Start to serve requests, typically the last entry (except for the post-boot tasks)
- PinchflatWeb.Endpoint,
- Pinchflat.Boot.PostBootStartupTasks
+ # Start to serve requests, typically the last entry
+ PinchflatWeb.Endpoint
]
- |> Supervisor.start_link(strategy: :one_for_one, name: Pinchflat.Supervisor)
+
+ attach_oban_telemetry()
+ Logger.add_handlers(:pinchflat)
+
+ # See https://hexdocs.pm/elixir/Supervisor.html
+ # for other strategies and supported options
+ opts = [strategy: :one_for_one, name: Pinchflat.Supervisor]
+ Supervisor.start_link(children, opts)
end
# Tell Phoenix to update the endpoint configuration
diff --git a/lib/pinchflat/boot/post_boot_startup_tasks.ex b/lib/pinchflat/boot/post_boot_startup_tasks.ex
deleted file mode 100644
index d6ae6eb..0000000
--- a/lib/pinchflat/boot/post_boot_startup_tasks.ex
+++ /dev/null
@@ -1,46 +0,0 @@
-defmodule Pinchflat.Boot.PostBootStartupTasks do
- @moduledoc """
- This module is responsible for running startup tasks on app boot
- AFTER all other boot steps have taken place and the app is ready to serve requests.
-
- It's a GenServer because that plays REALLY nicely with the existing
- Phoenix supervision tree.
- """
-
- alias Pinchflat.YtDlp.UpdateWorker, as: YtDlpUpdateWorker
-
- # restart: :temporary means that this process will never be restarted (ie: will run once and then die)
- use GenServer, restart: :temporary
- import Ecto.Query, warn: false
-
- def start_link(opts \\ []) do
- GenServer.start_link(__MODULE__, %{env: Application.get_env(:pinchflat, :env)}, opts)
- end
-
- @doc """
- Runs post-boot application startup tasks.
-
- Any code defined here will run every time the application starts. You must
- make sure that the code is idempotent and safe to run multiple times.
-
- This is a good place to set up default settings, create initial records, stuff like that.
- Should be fast - anything with the potential to be slow should be kicked off as a job instead.
- """
- @impl true
- def init(%{env: :test} = state) do
- # Do nothing _as part of the app bootup process_.
- # Since bootup calls `start_link` and that's where the `env` state is injected,
- # you can still call `.init()` manually to run these tasks for testing purposes
- {:ok, state}
- end
-
- def init(state) do
- update_yt_dlp()
-
- {:ok, state}
- end
-
- defp update_yt_dlp do
- YtDlpUpdateWorker.kickoff()
- end
-end
diff --git a/lib/pinchflat/boot/post_job_startup_tasks.ex b/lib/pinchflat/boot/post_job_startup_tasks.ex
index 6eba701..5043a25 100644
--- a/lib/pinchflat/boot/post_job_startup_tasks.ex
+++ b/lib/pinchflat/boot/post_job_startup_tasks.ex
@@ -1,7 +1,7 @@
defmodule Pinchflat.Boot.PostJobStartupTasks do
@moduledoc """
This module is responsible for running startup tasks on app boot
- AFTER the job runner has initialized.
+ AFTER the job runner has initiallized.
It's a GenServer because that plays REALLY nicely with the existing
Phoenix supervision tree.
@@ -12,7 +12,7 @@ defmodule Pinchflat.Boot.PostJobStartupTasks do
import Ecto.Query, warn: false
def start_link(opts \\ []) do
- GenServer.start_link(__MODULE__, %{env: Application.get_env(:pinchflat, :env)}, opts)
+ GenServer.start_link(__MODULE__, %{}, opts)
end
@doc """
@@ -25,13 +25,6 @@ defmodule Pinchflat.Boot.PostJobStartupTasks do
Should be fast - anything with the potential to be slow should be kicked off as a job instead.
"""
@impl true
- def init(%{env: :test} = state) do
- # Do nothing _as part of the app bootup process_.
- # Since bootup calls `start_link` and that's where the `env` state is injected,
- # you can still call `.init()` manually to run these tasks for testing purposes
- {:ok, state}
- end
-
def init(state) do
# Nothing at the moment!
diff --git a/lib/pinchflat/boot/pre_job_startup_tasks.ex b/lib/pinchflat/boot/pre_job_startup_tasks.ex
index 5035e35..2843db9 100644
--- a/lib/pinchflat/boot/pre_job_startup_tasks.ex
+++ b/lib/pinchflat/boot/pre_job_startup_tasks.ex
@@ -19,7 +19,7 @@ defmodule Pinchflat.Boot.PreJobStartupTasks do
alias Pinchflat.Lifecycle.UserScripts.CommandRunner, as: UserScriptRunner
def start_link(opts \\ []) do
- GenServer.start_link(__MODULE__, %{env: Application.get_env(:pinchflat, :env)}, opts)
+ GenServer.start_link(__MODULE__, %{}, opts)
end
@doc """
@@ -32,13 +32,6 @@ defmodule Pinchflat.Boot.PreJobStartupTasks do
Should be fast - anything with the potential to be slow should be kicked off as a job instead.
"""
@impl true
- def init(%{env: :test} = state) do
- # Do nothing _as part of the app bootup process_.
- # Since bootup calls `start_link` and that's where the `env` state is injected,
- # you can still call `.init()` manually to run these tasks for testing purposes
- {:ok, state}
- end
-
def init(state) do
ensure_tmpfile_directory()
reset_executing_jobs()
diff --git a/lib/pinchflat/downloading/downloading_helpers.ex b/lib/pinchflat/downloading/downloading_helpers.ex
index eae187c..5898533 100644
--- a/lib/pinchflat/downloading/downloading_helpers.ex
+++ b/lib/pinchflat/downloading/downloading_helpers.ex
@@ -27,15 +27,13 @@ defmodule Pinchflat.Downloading.DownloadingHelpers do
Returns :ok
"""
- def enqueue_pending_download_tasks(source, job_opts \\ [])
-
- def enqueue_pending_download_tasks(%Source{download_media: true} = source, job_opts) do
+ def enqueue_pending_download_tasks(%Source{download_media: true} = source) do
source
|> Media.list_pending_media_items_for()
- |> Enum.each(&MediaDownloadWorker.kickoff_with_task(&1, %{}, job_opts))
+ |> Enum.each(&MediaDownloadWorker.kickoff_with_task/1)
end
- def enqueue_pending_download_tasks(%Source{download_media: false}, _job_opts) do
+ def enqueue_pending_download_tasks(%Source{download_media: false}) do
:ok
end
@@ -57,13 +55,13 @@ defmodule Pinchflat.Downloading.DownloadingHelpers do
Returns {:ok, %Task{}} | {:error, :should_not_download} | {:error, any()}
"""
- def kickoff_download_if_pending(%MediaItem{} = media_item, job_opts \\ []) do
+ def kickoff_download_if_pending(%MediaItem{} = media_item) do
media_item = Repo.preload(media_item, :source)
if media_item.source.download_media && Media.pending_download?(media_item) do
Logger.info("Kicking off download for media item ##{media_item.id} (#{media_item.media_id})")
- MediaDownloadWorker.kickoff_with_task(media_item, %{}, job_opts)
+ MediaDownloadWorker.kickoff_with_task(media_item)
else
{:error, :should_not_download}
end
diff --git a/lib/pinchflat/downloading/media_download_worker.ex b/lib/pinchflat/downloading/media_download_worker.ex
index a0fbceb..ff1459b 100644
--- a/lib/pinchflat/downloading/media_download_worker.ex
+++ b/lib/pinchflat/downloading/media_download_worker.ex
@@ -3,7 +3,6 @@ defmodule Pinchflat.Downloading.MediaDownloadWorker do
use Oban.Worker,
queue: :media_fetching,
- priority: 5,
unique: [period: :infinity, states: [:available, :scheduled, :retryable, :executing]],
tags: ["media_item", "media_fetching", "show_in_dashboard"]
@@ -50,7 +49,8 @@ defmodule Pinchflat.Downloading.MediaDownloadWorker do
media_item = fetch_and_run_prevent_download_user_script(media_item_id)
- if should_download_media?(media_item, should_force, is_quality_upgrade) do
+ # If the source or media item is set to not download media, perform a no-op unless forced
+ if (media_item.source.download_media && !media_item.prevent_download) || should_force do
download_media_and_schedule_jobs(media_item, is_quality_upgrade, should_force)
else
:ok
@@ -60,20 +60,6 @@ defmodule Pinchflat.Downloading.MediaDownloadWorker do
Ecto.StaleEntryError -> Logger.info("#{__MODULE__} discarded: media item #{media_item_id} stale")
end
- # If this is a quality upgrade, only check if the source is set to download media
- # or that the media item's download hasn't been prevented
- defp should_download_media?(media_item, should_force, true = _is_quality_upgrade) do
- (media_item.source.download_media && !media_item.prevent_download) || should_force
- end
-
- # If it's not a quality upgrade, additionally check if the media item is pending download
- defp should_download_media?(media_item, should_force, _is_quality_upgrade) do
- source = media_item.source
- is_pending = Media.pending_download?(media_item)
-
- (is_pending && source.download_media && !media_item.prevent_download) || should_force
- end
-
# If a user script exists and, when run, returns a non-zero exit code, prevent this and all future downloads
# of the media item.
defp fetch_and_run_prevent_download_user_script(media_item_id) do
@@ -105,13 +91,13 @@ defmodule Pinchflat.Downloading.MediaDownloadWorker do
:ok
- {:recovered, _media_item, _message} ->
+ {:recovered, _} ->
{:error, :retry}
- {:error, :unsuitable_for_download, _message} ->
+ {:error, :unsuitable_for_download} ->
{:ok, :non_retry}
- {:error, _error_atom, message} ->
+ {:error, message} ->
action_on_error(message)
end
end
@@ -129,11 +115,7 @@ defmodule Pinchflat.Downloading.MediaDownloadWorker do
defp action_on_error(message) do
# This will attempt re-download at the next indexing, but it won't be retried
# immediately as part of job failure logic
- non_retryable_errors = [
- "Video unavailable",
- "Sign in to confirm",
- "This video is available to this channel's members"
- ]
+ non_retryable_errors = ["Video unavailable"]
if String.contains?(to_string(message), non_retryable_errors) do
Logger.error("yt-dlp download will not be retried: #{inspect(message)}")
diff --git a/lib/pinchflat/downloading/media_downloader.ex b/lib/pinchflat/downloading/media_downloader.ex
index 1a1ee2f..1103abc 100644
--- a/lib/pinchflat/downloading/media_downloader.ex
+++ b/lib/pinchflat/downloading/media_downloader.ex
@@ -9,9 +9,7 @@ defmodule Pinchflat.Downloading.MediaDownloader do
alias Pinchflat.Repo
alias Pinchflat.Media
- alias Pinchflat.Sources
alias Pinchflat.Media.MediaItem
- alias Pinchflat.Utils.StringUtils
alias Pinchflat.Metadata.NfoBuilder
alias Pinchflat.Metadata.MetadataParser
alias Pinchflat.Metadata.MetadataFileHelpers
@@ -22,57 +20,16 @@ defmodule Pinchflat.Downloading.MediaDownloader do
@doc """
Downloads media for a media item, updating the media item based on the metadata
- returned by yt-dlp. Encountered errors are saved to the Media Item record. Saves
- the entire metadata response to the associated media_metadata record.
+ returned by yt-dlp. Also saves the entire metadata response to the associated
+ media_metadata record.
- NOTE: related methods (like the download worker) won't download if Pthe media item's source
+ NOTE: related methods (like the download worker) won't download if the media item's source
is set to not download media. However, I'm not enforcing that here since I need this for testing.
This may change in the future but I'm not stressed.
- Returns {:ok, %MediaItem{}} | {:error, atom(), String.t()} | {:recovered, %MediaItem{}, String.t()}
+ Returns {:ok, %MediaItem{}} | {:error, any, ...any}
"""
def download_for_media_item(%MediaItem{} = media_item, override_opts \\ []) do
- case attempt_download_and_update_for_media_item(media_item, override_opts) do
- {:ok, media_item} ->
- # Returns {:ok, %MediaItem{}}
- Media.update_media_item(media_item, %{last_error: nil})
-
- {:error, error_atom, message} ->
- Media.update_media_item(media_item, %{last_error: StringUtils.wrap_string(message)})
-
- {:error, error_atom, message}
-
- {:recovered, media_item, message} ->
- {:ok, updated_media_item} = Media.update_media_item(media_item, %{last_error: StringUtils.wrap_string(message)})
-
- {:recovered, updated_media_item, message}
- end
- end
-
- # Looks complicated, but here's the key points:
- # - download_with_options runs a pre-check to see if the media item is suitable for download.
- # - If the media item fails the precheck, it returns {:error, :unsuitable_for_download, message}
- # - However, if the precheck fails in a way that we think can be fixed by using cookies, we retry with cookies
- # and return the result of that
- # - If the precheck passes but the download fails, it normally returns {:error, :download_failed, message}
- # - However, there are some errors we can recover from (eg: failure to communicate with SponsorBlock).
- # In this case, we attempt the download anyway and update the media item with what details we do have.
- # This case returns {:recovered, updated_media_item, message}
- # - If we attempt a retry but it fails, we return {:error, :unrecoverable, message}
- # - If there is an unknown error unrelated to the above, we return {:error, :unknown, message}
- # - Finally, if there is no error, we update the media item with the parsed JSON and return {:ok, updated_media_item}
- #
- # Restated, here are the return values for each case:
- # - On success: {:ok, updated_media_item}
- # - On initial failure but successfully recovered: {:recovered, updated_media_item, message}
- # - On error: {:error, error_atom, message} where error_atom is one of:
- # - `:unsuitable_for_download` if the media item fails the precheck
- # - `:unrecoverable` if there was an initial failure and the recovery attempt failed
- # - `:download_failed` for all other yt-dlp-related downloading errors
- # - `:unknown` for any other errors, including those not related to yt-dlp
- # - If we retry using cookies, all of the above return values apply. The cookie retry
- # logic is handled transparently as far as the caller is concerned
- defp attempt_download_and_update_for_media_item(media_item, override_opts) do
output_filepath = FilesystemUtils.generate_metadata_tmpfile(:json)
media_with_preloads = Repo.preload(media_item, [:metadata, source: :media_profile])
@@ -81,30 +38,31 @@ defmodule Pinchflat.Downloading.MediaDownloader do
update_media_item_from_parsed_json(media_with_preloads, parsed_json)
{:error, :unsuitable_for_download} ->
- message =
+ Logger.warning(
"Media item ##{media_with_preloads.id} isn't suitable for download yet. May be an active or processing live stream"
+ )
- Logger.warning(message)
-
- {:error, :unsuitable_for_download, message}
+ {:error, :unsuitable_for_download}
{:error, message, _exit_code} ->
Logger.error("yt-dlp download error for media item ##{media_with_preloads.id}: #{inspect(message)}")
if String.contains?(to_string(message), recoverable_errors()) do
- attempt_recovery_from_error(media_with_preloads, output_filepath, message)
+ attempt_update_media_item(media_with_preloads, output_filepath)
+
+ {:recovered, message}
else
- {:error, :download_failed, message}
+ {:error, message}
end
err ->
Logger.error("Unknown error downloading media item ##{media_with_preloads.id}: #{inspect(err)}")
- {:error, :unknown, "Unknown error: #{inspect(err)}"}
+ {:error, "Unknown error: #{inspect(err)}"}
end
end
- defp attempt_recovery_from_error(media_with_preloads, output_filepath, error_message) do
+ defp attempt_update_media_item(media_with_preloads, output_filepath) do
with {:ok, contents} <- File.read(output_filepath),
{:ok, parsed_json} <- Phoenix.json_library().decode(contents) do
Logger.info("""
@@ -113,13 +71,12 @@ defmodule Pinchflat.Downloading.MediaDownloader do
anyway
""")
- {:ok, updated_media_item} = update_media_item_from_parsed_json(media_with_preloads, parsed_json)
- {:recovered, updated_media_item, error_message}
+ update_media_item_from_parsed_json(media_with_preloads, parsed_json)
else
err ->
Logger.error("Unable to recover error for media item ##{media_with_preloads.id}: #{inspect(err)}")
- {:error, :unrecoverable, error_message}
+ {:error, :retry_failed}
end
end
@@ -156,48 +113,13 @@ defmodule Pinchflat.Downloading.MediaDownloader do
defp download_with_options(url, item_with_preloads, output_filepath, override_opts) do
{:ok, options} = DownloadOptionBuilder.build(item_with_preloads, override_opts)
- force_use_cookies = Keyword.get(override_opts, :force_use_cookies, false)
- source_uses_cookies = Sources.use_cookies?(item_with_preloads.source, :downloading)
- should_use_cookies = force_use_cookies || source_uses_cookies
+ use_cookies = item_with_preloads.source.use_cookies
+ runner_opts = [output_filepath: output_filepath, use_cookies: use_cookies]
- runner_opts = [output_filepath: output_filepath, use_cookies: should_use_cookies]
-
- case {YtDlpMedia.get_downloadable_status(url, use_cookies: should_use_cookies), should_use_cookies} do
- {{:ok, :downloadable}, _} ->
- YtDlpMedia.download(url, options, runner_opts)
-
- {{:ok, :ignorable}, _} ->
- {:error, :unsuitable_for_download}
-
- {{:error, _message, _exit_code} = err, false} ->
- # If there was an error and we don't have cookies, this method will retry with cookies
- # if doing so would help AND the source allows. Otherwise, it will return the error as-is
- maybe_retry_with_cookies(url, item_with_preloads, output_filepath, override_opts, err)
-
- # This gets hit if cookies are enabled which, importantly, also covers the case where we
- # retry a download with cookies and it fails again
- {{:error, message, exit_code}, true} ->
- {:error, message, exit_code}
-
- {err, _} ->
- err
- end
- end
-
- defp maybe_retry_with_cookies(url, item_with_preloads, output_filepath, override_opts, err) do
- {:error, message, _} = err
- source = item_with_preloads.source
- message_contains_cookie_error = String.contains?(to_string(message), recoverable_cookie_errors())
-
- if Sources.use_cookies?(source, :error_recovery) && message_contains_cookie_error do
- download_with_options(
- url,
- item_with_preloads,
- output_filepath,
- Keyword.put(override_opts, :force_use_cookies, true)
- )
- else
- err
+ case YtDlpMedia.get_downloadable_status(url, use_cookies: use_cookies) do
+ {:ok, :downloadable} -> YtDlpMedia.download(url, options, runner_opts)
+ {:ok, :ignorable} -> {:error, :unsuitable_for_download}
+ err -> err
end
end
@@ -206,11 +128,4 @@ defmodule Pinchflat.Downloading.MediaDownloader do
"Unable to communicate with SponsorBlock"
]
end
-
- defp recoverable_cookie_errors do
- [
- "Sign in to confirm",
- "This video is available to this channel's members"
- ]
- end
end
diff --git a/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex b/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex
index 15a4342..c31388d 100644
--- a/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex
+++ b/lib/pinchflat/fast_indexing/fast_indexing_helpers.ex
@@ -12,7 +12,6 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do
alias Pinchflat.Repo
alias Pinchflat.Media
alias Pinchflat.Tasks
- alias Pinchflat.Sources
alias Pinchflat.Sources.Source
alias Pinchflat.FastIndexing.YoutubeRss
alias Pinchflat.FastIndexing.YoutubeApi
@@ -41,7 +40,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do
Returns [%MediaItem{}] where each item is a new media item that was created _but not necessarily
downloaded_.
"""
- def index_and_kickoff_downloads(%Source{} = source) do
+ def kickoff_download_tasks_from_youtube_rss_feed(%Source{} = source) do
# The media_profile is needed to determine the quality options to _then_ determine a more
# accurate predicted filepath
source = Repo.preload(source, [:media_profile])
@@ -54,7 +53,6 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do
Enum.map(new_media_ids, fn media_id ->
case create_media_item_from_media_id(source, media_id) do
{:ok, media_item} ->
- DownloadingHelpers.kickoff_download_if_pending(media_item, priority: 0)
media_item
err ->
@@ -63,9 +61,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do
end
end)
- # Pick up any stragglers. Intentionally has a lower priority than the per-media item
- # kickoff above
- DownloadingHelpers.enqueue_pending_download_tasks(source, priority: 1)
+ DownloadingHelpers.enqueue_pending_download_tasks(source)
Enum.filter(maybe_new_media_items, & &1)
end
@@ -89,16 +85,12 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpers do
defp create_media_item_from_media_id(source, media_id) do
url = "https://www.youtube.com/watch?v=#{media_id}"
- # This is set to :metadata instead of :indexing since this happens _after_ the
- # actual indexing process. In reality, slow indexing is the only thing that
- # should be using :indexing.
- should_use_cookies = Sources.use_cookies?(source, :metadata)
command_opts =
[output: DownloadOptionBuilder.build_output_path_for(source)] ++
DownloadOptionBuilder.build_quality_options_for(source)
- case YtDlpMedia.get_media_attributes(url, command_opts, use_cookies: should_use_cookies) do
+ case YtDlpMedia.get_media_attributes(url, command_opts, use_cookies: source.use_cookies) do
{:ok, media_attrs} ->
Media.create_media_item_from_backend_attrs(source, media_attrs)
diff --git a/lib/pinchflat/fast_indexing/fast_indexing_worker.ex b/lib/pinchflat/fast_indexing/fast_indexing_worker.ex
index ed83bf3..368da17 100644
--- a/lib/pinchflat/fast_indexing/fast_indexing_worker.ex
+++ b/lib/pinchflat/fast_indexing/fast_indexing_worker.ex
@@ -38,8 +38,8 @@ defmodule Pinchflat.FastIndexing.FastIndexingWorker do
Order of operations:
1. FastIndexingWorker (this module) periodically checks the YouTube RSS feed for new media.
- with `FastIndexingHelpers.index_and_kickoff_downloads`
- 2. If the above `index_and_kickoff_downloads` finds new media items in the RSS feed,
+ with `FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed`
+ 2. If the above `kickoff_download_tasks_from_youtube_rss_feed` finds new media items in the RSS feed,
it indexes them with a yt-dlp call to create the media item records then kicks off downloading
tasks (MediaDownloadWorker) for any new media items _that should be downloaded_.
3. Once downloads are kicked off, this worker sends a notification to the apprise server if applicable
@@ -67,7 +67,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingWorker do
new_media_items =
source
- |> FastIndexingHelpers.index_and_kickoff_downloads()
+ |> FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed()
|> Enum.filter(&Media.pending_download?(&1))
if source.download_media do
diff --git a/lib/pinchflat/fast_indexing/youtube_api.ex b/lib/pinchflat/fast_indexing/youtube_api.ex
index 04c7326..95e6b39 100644
--- a/lib/pinchflat/fast_indexing/youtube_api.ex
+++ b/lib/pinchflat/fast_indexing/youtube_api.ex
@@ -12,8 +12,6 @@ defmodule Pinchflat.FastIndexing.YoutubeApi do
@behaviour YoutubeBehaviour
- @agent_name {:global, __MODULE__.KeyIndex}
-
@doc """
Determines if the YouTube API is enabled for fast indexing by checking
if the user has an API key set
@@ -21,7 +19,7 @@ defmodule Pinchflat.FastIndexing.YoutubeApi do
Returns boolean()
"""
@impl YoutubeBehaviour
- def enabled?, do: Enum.any?(api_keys())
+ def enabled?(), do: is_binary(api_key())
@doc """
Fetches the recent media IDs from the YouTube API for a given source.
@@ -76,45 +74,8 @@ defmodule Pinchflat.FastIndexing.YoutubeApi do
|> FunctionUtils.wrap_ok()
end
- defp api_keys do
- case Settings.get!(:youtube_api_key) do
- nil ->
- []
-
- keys ->
- keys
- |> String.split(",")
- |> Enum.map(&String.trim/1)
- |> Enum.reject(&(&1 == ""))
- end
- end
-
- defp get_or_start_api_key_agent do
- case Agent.start(fn -> 0 end, name: @agent_name) do
- {:ok, pid} -> pid
- {:error, {:already_started, pid}} -> pid
- end
- end
-
- # Gets the next API key in round-robin fashion
- defp next_api_key do
- keys = api_keys()
-
- case keys do
- [] ->
- nil
-
- keys ->
- pid = get_or_start_api_key_agent()
-
- current_index =
- Agent.get_and_update(pid, fn current ->
- {current, rem(current + 1, length(keys))}
- end)
-
- Logger.debug("Using YouTube API key: #{Enum.at(keys, current_index)}")
- Enum.at(keys, current_index)
- end
+ defp api_key do
+ Settings.get!(:youtube_api_key)
end
defp construct_api_endpoint(playlist_id) do
@@ -122,7 +83,7 @@ defmodule Pinchflat.FastIndexing.YoutubeApi do
property_type = "contentDetails"
max_results = 50
- "#{api_base}?part=#{property_type}&maxResults=#{max_results}&playlistId=#{playlist_id}&key=#{next_api_key()}"
+ "#{api_base}?part=#{property_type}&maxResults=#{max_results}&playlistId=#{playlist_id}&key=#{api_key()}"
end
defp http_client do
diff --git a/lib/pinchflat/media/media_item.ex b/lib/pinchflat/media/media_item.ex
index ced8e8c..7a4fb32 100644
--- a/lib/pinchflat/media/media_item.ex
+++ b/lib/pinchflat/media/media_item.ex
@@ -40,7 +40,6 @@ defmodule Pinchflat.Media.MediaItem do
:thumbnail_filepath,
:metadata_filepath,
:nfo_filepath,
- :last_error,
# These are user or system controlled fields
:prevent_download,
:prevent_culling,
@@ -89,7 +88,6 @@ defmodule Pinchflat.Media.MediaItem do
# Will very likely revisit because I can't leave well-enough alone.
field :subtitle_filepaths, {:array, {:array, :string}}, default: []
- field :last_error, :string
field :prevent_download, :boolean, default: false
field :prevent_culling, :boolean, default: false
field :culled_at, :utc_datetime
@@ -114,9 +112,6 @@ defmodule Pinchflat.Media.MediaItem do
|> dynamic_default(:uuid, fn _ -> Ecto.UUID.generate() end)
|> update_upload_date_index()
|> validate_required(@required_fields)
- # Validate that the title does NOT start with "youtube video #" since that indicates a restriction by YouTube.
- # See issue #549 for more information.
- |> validate_format(:title, ~r/^(?!youtube video #)/)
|> unique_constraint([:media_id, :source_id])
end
diff --git a/lib/pinchflat/metadata/metadata_file_helpers.ex b/lib/pinchflat/metadata/metadata_file_helpers.ex
index 842f6ef..7adc632 100644
--- a/lib/pinchflat/metadata/metadata_file_helpers.ex
+++ b/lib/pinchflat/metadata/metadata_file_helpers.ex
@@ -9,7 +9,6 @@ defmodule Pinchflat.Metadata.MetadataFileHelpers do
needed
"""
- alias Pinchflat.Sources
alias Pinchflat.Utils.FilesystemUtils
alias Pinchflat.YtDlp.Media, as: YtDlpMedia
@@ -67,7 +66,7 @@ defmodule Pinchflat.Metadata.MetadataFileHelpers do
yt_dlp_filepath = generate_filepath_for(media_item_with_preloads, "thumbnail.%(ext)s")
real_filepath = generate_filepath_for(media_item_with_preloads, "thumbnail.jpg")
command_opts = [output: yt_dlp_filepath]
- addl_opts = [use_cookies: Sources.use_cookies?(media_item_with_preloads.source, :metadata)]
+ addl_opts = [use_cookies: media_item_with_preloads.source.use_cookies]
case YtDlpMedia.download_thumbnail(media_item_with_preloads.original_url, command_opts, addl_opts) do
{:ok, _} -> real_filepath
diff --git a/lib/pinchflat/metadata/source_metadata_storage_worker.ex b/lib/pinchflat/metadata/source_metadata_storage_worker.ex
index feb793b..adaf0df 100644
--- a/lib/pinchflat/metadata/source_metadata_storage_worker.ex
+++ b/lib/pinchflat/metadata/source_metadata_storage_worker.ex
@@ -93,7 +93,7 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorker do
defp determine_series_directory(source) do
output_path = DownloadOptionBuilder.build_output_path_for(source)
runner_opts = [output: output_path]
- addl_opts = [use_cookies: Sources.use_cookies?(source, :metadata)]
+ addl_opts = [use_cookies: source.use_cookies]
{:ok, %{filepath: filepath}} = MediaCollection.get_source_details(source.original_url, runner_opts, addl_opts)
case MetadataFileHelpers.series_directory_from_media_filepath(filepath) do
@@ -113,7 +113,6 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorker do
defp fetch_metadata_for_source(source) do
tmp_output_path = "#{tmp_directory()}/#{StringUtils.random_string(16)}/source_image.%(ext)S"
base_opts = [convert_thumbnails: "jpg", output: tmp_output_path]
- should_use_cookies = Sources.use_cookies?(source, :metadata)
opts =
if source.collection_type == :channel do
@@ -122,7 +121,7 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorker do
base_opts ++ [:write_thumbnail, playlist_items: 1]
end
- MediaCollection.get_source_metadata(source.original_url, opts, use_cookies: should_use_cookies)
+ MediaCollection.get_source_metadata(source.original_url, opts, use_cookies: source.use_cookies)
end
defp tmp_directory do
diff --git a/lib/pinchflat/profiles/media_profile_deletion_worker.ex b/lib/pinchflat/profiles/media_profile_deletion_worker.ex
index 230a085..529474d 100644
--- a/lib/pinchflat/profiles/media_profile_deletion_worker.ex
+++ b/lib/pinchflat/profiles/media_profile_deletion_worker.ex
@@ -14,7 +14,7 @@ defmodule Pinchflat.Profiles.MediaProfileDeletionWorker do
Starts the profile deletion worker. Does not attach it to a task like `kickoff_with_task/2`
since deletion also cancels all tasks for the profile
- Returns {:ok, %Oban.Job{}} | {:error, %Ecto.Changeset{}}
+ Returns {:ok, %Task{}} | {:error, %Ecto.Changeset{}}
"""
def kickoff(profile, job_args \\ %{}, job_opts \\ []) do
%{id: profile.id}
diff --git a/lib/pinchflat/prom_ex.ex b/lib/pinchflat/prom_ex.ex
deleted file mode 100644
index a46347d..0000000
--- a/lib/pinchflat/prom_ex.ex
+++ /dev/null
@@ -1,40 +0,0 @@
-defmodule Pinchflat.PromEx do
- @moduledoc """
- Configuration for the PromEx library which provides Prometheus metrics
- """
-
- use PromEx, otp_app: :pinchflat
-
- alias PromEx.Plugins
-
- @impl true
- def plugins do
- [
- Plugins.Application,
- Plugins.Beam,
- {Plugins.Phoenix, router: PinchflatWeb.Router, endpoint: PinchflatWeb.Endpoint},
- Plugins.Ecto,
- Plugins.Oban,
- Plugins.PhoenixLiveView
- ]
- end
-
- @impl true
- def dashboard_assigns do
- [
- default_selected_interval: "30s"
- ]
- end
-
- @impl true
- def dashboards do
- [
- {:prom_ex, "application.json"},
- {:prom_ex, "beam.json"},
- {:prom_ex, "phoenix.json"},
- {:prom_ex, "ecto.json"},
- {:prom_ex, "oban.json"},
- {:prom_ex, "phoenix_live_view.json"}
- ]
- end
-end
diff --git a/lib/pinchflat/settings/setting.ex b/lib/pinchflat/settings/setting.ex
index f2a6b0a..8e63fc7 100644
--- a/lib/pinchflat/settings/setting.ex
+++ b/lib/pinchflat/settings/setting.ex
@@ -14,19 +14,15 @@ defmodule Pinchflat.Settings.Setting do
:apprise_server,
:video_codec_preference,
:audio_codec_preference,
- :youtube_api_key,
- :extractor_sleep_interval_seconds,
- :download_throughput_limit,
- :restrict_filenames
+ :youtube_api_key
]
- @required_fields [
- :onboarding,
- :pro_enabled,
- :video_codec_preference,
- :audio_codec_preference,
- :extractor_sleep_interval_seconds
- ]
+ @required_fields ~w(
+ onboarding
+ pro_enabled
+ video_codec_preference
+ audio_codec_preference
+ )a
schema "settings" do
field :onboarding, :boolean, default: true
@@ -36,10 +32,6 @@ defmodule Pinchflat.Settings.Setting do
field :apprise_server, :string
field :youtube_api_key, :string
field :route_token, :string
- field :extractor_sleep_interval_seconds, :integer, default: 0
- # This is a string because it accepts values like "100K" or "4.2M"
- field :download_throughput_limit, :string
- field :restrict_filenames, :boolean, default: false
field :video_codec_preference, :string
field :audio_codec_preference, :string
@@ -50,6 +42,5 @@ defmodule Pinchflat.Settings.Setting do
setting
|> cast(attrs, @allowed_fields)
|> validate_required(@required_fields)
- |> validate_number(:extractor_sleep_interval_seconds, greater_than_or_equal_to: 0)
end
end
diff --git a/lib/pinchflat/slow_indexing/file_follower_server.ex b/lib/pinchflat/slow_indexing/file_follower_server.ex
index 655a6da..91c514d 100644
--- a/lib/pinchflat/slow_indexing/file_follower_server.ex
+++ b/lib/pinchflat/slow_indexing/file_follower_server.ex
@@ -106,7 +106,7 @@ defmodule Pinchflat.SlowIndexing.FileFollowerServer do
{:noreply, %{state | last_activity: DateTime.utc_now()}}
:eof ->
- Logger.debug("Current batch of media processed. Will check again in #{@poll_interval_ms}ms")
+ Logger.debug("EOF reached, waiting before trying to read new lines")
Process.send_after(self(), :read_new_lines, @poll_interval_ms)
{:noreply, state}
diff --git a/lib/pinchflat/slow_indexing/slow_indexing_helpers.ex b/lib/pinchflat/slow_indexing/slow_indexing_helpers.ex
index 8721b21..433af5a 100644
--- a/lib/pinchflat/slow_indexing/slow_indexing_helpers.ex
+++ b/lib/pinchflat/slow_indexing/slow_indexing_helpers.ex
@@ -39,6 +39,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpers do
def kickoff_indexing_task(%Source{} = source, job_args \\ %{}, job_opts \\ []) do
job_offset_seconds = if job_args[:force], do: 0, else: calculate_job_offset_seconds(source)
+ Tasks.delete_pending_tasks_for(source, "FastIndexingWorker")
Tasks.delete_pending_tasks_for(source, "MediaCollectionIndexingWorker", include_executing: true)
MediaCollectionIndexingWorker.kickoff_with_task(source, job_args, job_opts ++ [schedule_in: job_offset_seconds])
@@ -132,14 +133,13 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpers do
{:ok, pid} = FileFollowerServer.start_link()
handler = fn filepath -> setup_file_follower_watcher(pid, filepath, source) end
- should_use_cookies = Sources.use_cookies?(source, :indexing)
command_opts =
[output: DownloadOptionBuilder.build_output_path_for(source)] ++
DownloadOptionBuilder.build_quality_options_for(source) ++
build_download_archive_options(source, was_forced)
- runner_opts = [file_listener_handler: handler, use_cookies: should_use_cookies]
+ runner_opts = [file_listener_handler: handler, use_cookies: source.use_cookies]
result = MediaCollection.get_media_attributes_for_collection(source.original_url, command_opts, runner_opts)
FileFollowerServer.stop(pid)
@@ -231,9 +231,8 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpers do
# The download archive isn't useful for playlists (since those are ordered arbitrarily)
# and we don't want to use it if the indexing was forced by the user. In other words,
# only create an archive for channels that are being indexed as part of their regular
- # indexing schedule. The first indexing pass should also not create an archive.
+ # indexing schedule
defp build_download_archive_options(%Source{collection_type: :playlist}, _was_forced), do: []
- defp build_download_archive_options(%Source{last_indexed_at: nil}, _was_forced), do: []
defp build_download_archive_options(_source, true), do: []
defp build_download_archive_options(source, _was_forced) do
diff --git a/lib/pinchflat/sources/source.ex b/lib/pinchflat/sources/source.ex
index 00b4776..38da139 100644
--- a/lib/pinchflat/sources/source.ex
+++ b/lib/pinchflat/sources/source.ex
@@ -28,7 +28,7 @@ defmodule Pinchflat.Sources.Source do
series_directory
index_frequency_minutes
fast_index
- cookie_behaviour
+ use_cookies
download_media
last_indexed_at
original_url
@@ -78,7 +78,7 @@ defmodule Pinchflat.Sources.Source do
field :collection_type, Ecto.Enum, values: [:channel, :playlist]
field :index_frequency_minutes, :integer, default: 60 * 24
field :fast_index, :boolean, default: false
- field :cookie_behaviour, Ecto.Enum, values: [:disabled, :when_needed, :all_operations], default: :disabled
+ field :use_cookies, :boolean, default: false
field :download_media, :boolean, default: true
field :last_indexed_at, :utc_datetime
# Only download media items that were published after this date
diff --git a/lib/pinchflat/sources/sources.ex b/lib/pinchflat/sources/sources.ex
index edd37f1..ecbe7d4 100644
--- a/lib/pinchflat/sources/sources.ex
+++ b/lib/pinchflat/sources/sources.ex
@@ -32,19 +32,6 @@ defmodule Pinchflat.Sources do
source.output_path_template_override || media_profile.output_path_template
end
- @doc """
- Returns a boolean indicating whether or not cookies should be used for a given operation.
-
- Returns boolean()
- """
- def use_cookies?(source, operation) when operation in [:indexing, :downloading, :metadata, :error_recovery] do
- case source.cookie_behaviour do
- :disabled -> false
- :all_operations -> true
- :when_needed -> operation in [:indexing, :error_recovery]
- end
- end
-
@doc """
Returns the list of sources. Returns [%Source{}, ...]
"""
@@ -193,12 +180,9 @@ defmodule Pinchflat.Sources do
end
defp add_source_details_to_changeset(source, changeset) do
- original_url = changeset.changes.original_url
- should_use_cookies = Ecto.Changeset.get_field(changeset, :cookie_behaviour) == :all_operations
- # Skipping sleep interval since this is UI blocking and we want to keep this as fast as possible
- addl_opts = [use_cookies: should_use_cookies, skip_sleep_interval: true]
+ use_cookies = Ecto.Changeset.get_field(changeset, :use_cookies)
- case MediaCollection.get_source_details(original_url, [], addl_opts) do
+ case MediaCollection.get_source_details(changeset.changes.original_url, [], use_cookies: use_cookies) do
{:ok, source_details} ->
add_source_details_by_collection_type(source, changeset, source_details)
@@ -313,10 +297,6 @@ defmodule Pinchflat.Sources do
%{__meta__: %{state: :built}} ->
SlowIndexingHelpers.kickoff_indexing_task(source)
- if Ecto.Changeset.get_field(changeset, :fast_index) do
- FastIndexingHelpers.kickoff_indexing_task(source)
- end
-
# If the record has been persisted, only run indexing if the
# indexing frequency has been changed and is now greater than 0
%{__meta__: %{state: :loaded}} ->
diff --git a/lib/pinchflat/utils/number_utils.ex b/lib/pinchflat/utils/number_utils.ex
index d86002b..b7128f8 100644
--- a/lib/pinchflat/utils/number_utils.ex
+++ b/lib/pinchflat/utils/number_utils.ex
@@ -36,18 +36,4 @@ defmodule Pinchflat.Utils.NumberUtils do
end
end)
end
-
- @doc """
- Adds jitter to a number based on a percentage. Returns 0 if the number is less than or equal to 0.
-
- Returns integer()
- """
- def add_jitter(num, jitter_percentage \\ 0.5)
- def add_jitter(num, _jitter_percentage) when num <= 0, do: 0
-
- def add_jitter(num, jitter_percentage) do
- jitter = :rand.uniform(round(num * jitter_percentage))
-
- round(num + jitter)
- end
end
diff --git a/lib/pinchflat/utils/string_utils.ex b/lib/pinchflat/utils/string_utils.ex
index 66efc5e..49328b2 100644
--- a/lib/pinchflat/utils/string_utils.ex
+++ b/lib/pinchflat/utils/string_utils.ex
@@ -35,13 +35,4 @@ defmodule Pinchflat.Utils.StringUtils do
def double_brace(string) do
"{{ #{string} }}"
end
-
- @doc """
- Wraps a string in quotes if it's not already a string. Useful for working with
- error messages whose types can vary.
-
- Returns binary()
- """
- def wrap_string(message) when is_binary(message), do: message
- def wrap_string(message), do: "#{inspect(message)}"
end
diff --git a/lib/pinchflat/yt_dlp/command_runner.ex b/lib/pinchflat/yt_dlp/command_runner.ex
index f574d30..8391b5c 100644
--- a/lib/pinchflat/yt_dlp/command_runner.ex
+++ b/lib/pinchflat/yt_dlp/command_runner.ex
@@ -5,9 +5,7 @@ defmodule Pinchflat.YtDlp.CommandRunner do
require Logger
- alias Pinchflat.Settings
alias Pinchflat.Utils.CliUtils
- alias Pinchflat.Utils.NumberUtils
alias Pinchflat.YtDlp.YtDlpCommandRunner
alias Pinchflat.Utils.FilesystemUtils, as: FSUtils
@@ -24,23 +22,23 @@ defmodule Pinchflat.YtDlp.CommandRunner do
for a file watcher.
- :use_cookies - if true, will add a cookie file to the command options. Will not
attach a cookie file if the user hasn't set one up.
- - :skip_sleep_interval - if true, will not add the sleep interval options to the command.
- Usually only used for commands that would be UI-blocking
Returns {:ok, binary()} | {:error, output, status}.
"""
@impl YtDlpCommandRunner
def run(url, action_name, command_opts, output_template, addl_opts \\ []) do
Logger.debug("Running yt-dlp command for action: #{action_name}")
+ # This approach lets us mock the command for testing
+ command = backend_executable()
output_filepath = generate_output_filepath(addl_opts)
print_to_file_opts = [{:print_to_file, output_template}, output_filepath]
- user_configured_opts = cookie_file_options(addl_opts) ++ rate_limit_options(addl_opts) ++ misc_options()
+ user_configured_opts = cookie_file_options(addl_opts)
# These must stay in exactly this order, hence why I'm giving it its own variable.
all_opts = command_opts ++ print_to_file_opts ++ user_configured_opts ++ global_options()
formatted_command_opts = [url] ++ CliUtils.parse_options(all_opts)
- case CliUtils.wrap_cmd(backend_executable(), formatted_command_opts, stderr_to_stdout: true) do
+ case CliUtils.wrap_cmd(command, formatted_command_opts, stderr_to_stdout: true) do
# yt-dlp exit codes:
# 0 = Everything is successful
# 100 = yt-dlp must restart for update to complete
@@ -76,24 +74,6 @@ defmodule Pinchflat.YtDlp.CommandRunner do
end
end
- @doc """
- Updates yt-dlp to the latest version
-
- Returns {:ok, binary()} | {:error, binary()}
- """
- @impl YtDlpCommandRunner
- def update do
- command = backend_executable()
-
- case CliUtils.wrap_cmd(command, ["--update"]) do
- {output, 0} ->
- {:ok, String.trim(output)}
-
- {output, _} ->
- {:error, output}
- end
- end
-
defp generate_output_filepath(addl_opts) do
case Keyword.get(addl_opts, :output_filepath) do
nil -> FSUtils.generate_metadata_tmpfile(:json)
@@ -131,32 +111,6 @@ defmodule Pinchflat.YtDlp.CommandRunner do
end)
end
- defp rate_limit_options(addl_opts) do
- throughput_limit = Settings.get!(:download_throughput_limit)
- sleep_interval_opts = sleep_interval_opts(addl_opts)
- throughput_option = if throughput_limit, do: [limit_rate: throughput_limit], else: []
-
- throughput_option ++ sleep_interval_opts
- end
-
- defp sleep_interval_opts(addl_opts) do
- sleep_interval = Settings.get!(:extractor_sleep_interval_seconds)
-
- if sleep_interval <= 0 || Keyword.get(addl_opts, :skip_sleep_interval) do
- []
- else
- [
- sleep_requests: NumberUtils.add_jitter(sleep_interval),
- sleep_interval: NumberUtils.add_jitter(sleep_interval),
- sleep_subtitles: NumberUtils.add_jitter(sleep_interval)
- ]
- end
- end
-
- defp misc_options do
- if Settings.get!(:restrict_filenames), do: [:restrict_filenames], else: []
- end
-
defp backend_executable do
Application.get_env(:pinchflat, :yt_dlp_executable)
end
diff --git a/lib/pinchflat/yt_dlp/media.ex b/lib/pinchflat/yt_dlp/media.ex
index 9abf8e5..d936041 100644
--- a/lib/pinchflat/yt_dlp/media.ex
+++ b/lib/pinchflat/yt_dlp/media.ex
@@ -151,7 +151,7 @@ defmodule Pinchflat.YtDlp.Media do
#
# These don't fail if duration or aspect_ratio are missing
# due to Elixir's comparison semantics
- response["duration"] <= 180 && response["aspect_ratio"] <= 0.85
+ response["duration"] <= 60 && response["aspect_ratio"] <= 0.85
end
end
diff --git a/lib/pinchflat/yt_dlp/update_worker.ex b/lib/pinchflat/yt_dlp/update_worker.ex
deleted file mode 100644
index 2d9b43f..0000000
--- a/lib/pinchflat/yt_dlp/update_worker.ex
+++ /dev/null
@@ -1,44 +0,0 @@
-defmodule Pinchflat.YtDlp.UpdateWorker do
- @moduledoc false
-
- use Oban.Worker,
- queue: :local_data,
- tags: ["local_data"]
-
- require Logger
-
- alias __MODULE__
- alias Pinchflat.Settings
-
- @doc """
- Starts the yt-dlp update worker. Does not attach it to a task like `kickoff_with_task/2`
-
- Returns {:ok, %Oban.Job{}} | {:error, %Ecto.Changeset{}}
- """
- def kickoff do
- Oban.insert(UpdateWorker.new(%{}))
- end
-
- @doc """
- Updates yt-dlp and saves the version to the settings.
-
- This worker is scheduled to run via the Oban Cron plugin as well as on app boot.
-
- Returns :ok
- """
- @impl Oban.Worker
- def perform(%Oban.Job{}) do
- Logger.info("Updating yt-dlp")
-
- yt_dlp_runner().update()
-
- {:ok, yt_dlp_version} = yt_dlp_runner().version()
- Settings.set(yt_dlp_version: yt_dlp_version)
-
- :ok
- end
-
- defp yt_dlp_runner do
- Application.get_env(:pinchflat, :yt_dlp_runner)
- end
-end
diff --git a/lib/pinchflat/yt_dlp/yt_dlp_command_runner.ex b/lib/pinchflat/yt_dlp/yt_dlp_command_runner.ex
index e5c770e..ff1cbcf 100644
--- a/lib/pinchflat/yt_dlp/yt_dlp_command_runner.ex
+++ b/lib/pinchflat/yt_dlp/yt_dlp_command_runner.ex
@@ -9,5 +9,4 @@ defmodule Pinchflat.YtDlp.YtDlpCommandRunner do
@callback run(binary(), atom(), keyword(), binary()) :: {:ok, binary()} | {:error, binary(), integer()}
@callback run(binary(), atom(), keyword(), binary(), keyword()) :: {:ok, binary()} | {:error, binary(), integer()}
@callback version() :: {:ok, binary()} | {:error, binary()}
- @callback update() :: {:ok, binary()} | {:error, binary()}
end
diff --git a/lib/pinchflat_web.ex b/lib/pinchflat_web.ex
index 9401e3b..28d5807 100644
--- a/lib/pinchflat_web.ex
+++ b/lib/pinchflat_web.ex
@@ -43,7 +43,7 @@ defmodule PinchflatWeb do
layouts: [html: PinchflatWeb.Layouts]
import Plug.Conn
- use Gettext, backend: PinchflatWeb.Gettext
+ import PinchflatWeb.Gettext
alias Pinchflat.Settings
alias PinchflatWeb.Layouts
@@ -94,7 +94,7 @@ defmodule PinchflatWeb do
# HTML escaping functionality
import Phoenix.HTML
# Core UI components and translation
- use Gettext, backend: PinchflatWeb.Gettext
+ import PinchflatWeb.Gettext
import PinchflatWeb.CoreComponents
import PinchflatWeb.CustomComponents.TabComponents
import PinchflatWeb.CustomComponents.TextComponents
diff --git a/lib/pinchflat_web/components/core_components.ex b/lib/pinchflat_web/components/core_components.ex
index 37af104..e66e236 100644
--- a/lib/pinchflat_web/components/core_components.ex
+++ b/lib/pinchflat_web/components/core_components.ex
@@ -15,7 +15,8 @@ defmodule PinchflatWeb.CoreComponents do
Icons are provided by [heroicons](https://heroicons.com). See `icon/1` for usage.
"""
use Phoenix.Component, global_prefixes: ~w(x-)
- use Gettext, backend: PinchflatWeb.Gettext
+
+ import PinchflatWeb.Gettext
alias Phoenix.LiveView.JS
alias PinchflatWeb.CustomComponents.TextComponents
@@ -699,7 +700,7 @@ defmodule PinchflatWeb.CoreComponents do
attr :class, :string, default: nil
attr :rest, :global
- def icon(assigns) do
+ def icon(%{name: "hero-" <> _} = assigns) do
~H"""
"""
diff --git a/lib/pinchflat_web/components/custom_components/button_components.ex b/lib/pinchflat_web/components/custom_components/button_components.ex
index 95f16cf..f1f3470 100644
--- a/lib/pinchflat_web/components/custom_components/button_components.ex
+++ b/lib/pinchflat_web/components/custom_components/button_components.ex
@@ -3,7 +3,6 @@ defmodule PinchflatWeb.CustomComponents.ButtonComponents do
use Phoenix.Component, global_prefixes: ~w(x-)
alias PinchflatWeb.CoreComponents
- alias PinchflatWeb.CustomComponents.TextComponents
@doc """
Render a button
@@ -105,7 +104,7 @@ defmodule PinchflatWeb.CustomComponents.ButtonComponents do
def icon_button(assigns) do
~H"""
-
+
"""
end
end
diff --git a/lib/pinchflat_web/components/custom_components/tab_components.ex b/lib/pinchflat_web/components/custom_components/tab_components.ex
index e566b58..baade53 100644
--- a/lib/pinchflat_web/components/custom_components/tab_components.ex
+++ b/lib/pinchflat_web/components/custom_components/tab_components.ex
@@ -41,7 +41,7 @@ defmodule PinchflatWeb.CustomComponents.TabComponents do
{render_slot(@tab_append)}
-
+
{render_slot(tab)}
diff --git a/lib/pinchflat_web/components/custom_components/text_components.ex b/lib/pinchflat_web/components/custom_components/text_components.ex
index d6762ce..2145bae 100644
--- a/lib/pinchflat_web/components/custom_components/text_components.ex
+++ b/lib/pinchflat_web/components/custom_components/text_components.ex
@@ -71,39 +71,19 @@ defmodule PinchflatWeb.CustomComponents.TextComponents do
formatted_text =
Regex.split(~r{https?://\S+}, assigns.text, include_captures: true)
|> Enum.map(fn
- "http" <> _ = url -> {:url, url}
- text -> Regex.split(~r{\n}, text, include_captures: true, trim: true)
+ "http" <> _ = url ->
+ Phoenix.HTML.Tag.content_tag(:a, url, class: "text-blue-500 hover:text-blue-300", href: url, target: "_blank")
+
+ text ->
+ text
+ |> String.split("\n", trim: false)
+ |> Enum.intersperse(Phoenix.HTML.Tag.tag(:span, class: "inline-block mt-2"))
end)
assigns = Map.put(assigns, :text, formatted_text)
~H"""
-
- <.rendered_description_line :for={line <- @text} content={line} />
-
- """
- end
-
- defp rendered_description_line(%{content: {:url, url}} = assigns) do
- assigns = Map.put(assigns, :url, url)
-
- ~H"""
-
- {@url}
-
- """
- end
-
- defp rendered_description_line(%{content: list_of_content} = assigns) do
- assigns = Map.put(assigns, :list_of_content, list_of_content)
-
- ~H"""
-
- {inner_content}
-
+
{@text}
"""
end
@@ -166,60 +146,4 @@ defmodule PinchflatWeb.CustomComponents.TextComponents do
<.localized_number number={@num} /> {@suffix}
"""
end
-
- @doc """
- Renders a tooltip with the given content
- """
-
- attr :tooltip, :string, required: true
- attr :position, :string, default: ""
- attr :tooltip_class, :any, default: ""
- attr :tooltip_arrow_class, :any, default: ""
- slot :inner_block
-
- def tooltip(%{position: "bottom-right"} = assigns) do
- ~H"""
- <.tooltip tooltip={@tooltip} tooltip_class={@tooltip_class} tooltip_arrow_class={["-top-1", @tooltip_arrow_class]}>
- {render_slot(@inner_block)}
-
- """
- end
-
- def tooltip(%{position: "bottom"} = assigns) do
- ~H"""
- <.tooltip
- tooltip={@tooltip}
- tooltip_class={["left-1/2 -translate-x-1/2", @tooltip_class]}
- tooltip_arrow_class={["-top-1 left-1/2 -translate-x-1/2", @tooltip_arrow_class]}
- >
- {render_slot(@inner_block)}
-
- """
- end
-
- def tooltip(assigns) do
- ~H"""
-
-
- {render_slot(@inner_block)}
-
-
-
- """
- end
end
diff --git a/lib/pinchflat_web/components/layouts.ex b/lib/pinchflat_web/components/layouts.ex
index 7312c30..2dacac2 100644
--- a/lib/pinchflat_web/components/layouts.ex
+++ b/lib/pinchflat_web/components/layouts.ex
@@ -15,12 +15,11 @@ defmodule PinchflatWeb.Layouts do
attr :text, :string, required: true
attr :href, :any, required: true
attr :target, :any, default: "_self"
- attr :icon_class, :string, default: ""
def sidebar_item(assigns) do
~H"""
- <.sidebar_link icon={@icon} text={@text} href={@href} target={@target} icon_class={@icon_class} />
+ <.sidebar_link icon={@icon} text={@text} href={@href} target={@target} />
"""
end
@@ -90,7 +89,6 @@ defmodule PinchflatWeb.Layouts do
attr :href, :any, required: true
attr :target, :any, default: "_self"
attr :class, :string, default: ""
- attr :icon_class, :string, default: ""
def sidebar_link(assigns) do
~H"""
@@ -105,7 +103,7 @@ defmodule PinchflatWeb.Layouts do
@class
]}
>
- <.icon :if={@icon} name={@icon} class={@icon_class} /> {@text}
+ <.icon :if={@icon} name={@icon} /> {@text}
"""
end
diff --git a/lib/pinchflat_web/components/layouts/partials/sidebar.html.heex b/lib/pinchflat_web/components/layouts/partials/sidebar.html.heex
index e7f89a3..e5e5b39 100644
--- a/lib/pinchflat_web/components/layouts/partials/sidebar.html.heex
+++ b/lib/pinchflat_web/components/layouts/partials/sidebar.html.heex
@@ -8,7 +8,7 @@
>
-
+
@@ -47,10 +47,8 @@
text="Docs"
target="_blank"
href="https://github.com/kieraneglin/pinchflat/wiki"
- icon_class="scale-110"
/>
- <.sidebar_item icon="si-github" text="Github" target="_blank" href="https://github.com/kieraneglin/pinchflat" />
- <.sidebar_item icon="si-discord" text="Discord" target="_blank" href="https://discord.gg/j7T6dCuwU4" />
+ <.sidebar_item icon="hero-cog" text="Github" target="_blank" href="https://github.com/kieraneglin/pinchflat" />
- <.icon name="hero-currency-dollar" class="scale-110" /> Donate
+ <.icon name="hero-currency-dollar" /> Donate
diff --git a/lib/pinchflat_web/controllers/media_items/media_item_html/show.html.heex b/lib/pinchflat_web/controllers/media_items/media_item_html/show.html.heex
index f531731..a8b812a 100644
--- a/lib/pinchflat_web/controllers/media_items/media_item_html/show.html.heex
+++ b/lib/pinchflat_web/controllers/media_items/media_item_html/show.html.heex
@@ -16,7 +16,7 @@
-
+
<.tabbed_layout>
<:tab_append>
@@ -24,15 +24,7 @@
<:tab title="Media" id="media">
-
-
-
- <.icon name="hero-exclamation-circle-solid" class="text-red-500" />
-
Last Error
-
- {@media_item.last_error}
-
-
+
<%= if media_file_exists?(@media_item) do %>
@@ -62,21 +54,19 @@
<% end %>
+
Raw Attributes
- Raw Attributes
-
- Source:
- <.subtle_link href={~p"/sources/#{@media_item.source_id}"}>
- {@media_item.source.custom_name}
-
- <.list_items_from_map map={Map.from_struct(@media_item)} />
-
+ Source:
+ <.subtle_link href={~p"/sources/#{@media_item.source_id}"}>
+ {@media_item.source.custom_name}
+
+ <.list_items_from_map map={Map.from_struct(@media_item)} />
<:tab title="Tasks" id="tasks">
<%= if match?([_|_], @media_item.tasks) do %>
- <.table rows={@media_item.tasks} table_class="text-white">
+ <.table rows={@media_item.tasks} table_class="text-black dark:text-white">
<:col :let={task} label="Worker">
{task.job.worker}
diff --git a/lib/pinchflat_web/controllers/media_profiles/media_profile_html/media_profile_form.html.heex b/lib/pinchflat_web/controllers/media_profiles/media_profile_html/media_profile_form.html.heex
index 618cc7a..fb83857 100644
--- a/lib/pinchflat_web/controllers/media_profiles/media_profile_html/media_profile_form.html.heex
+++ b/lib/pinchflat_web/controllers/media_profiles/media_profile_html/media_profile_form.html.heex
@@ -100,7 +100,7 @@
field={f[:embed_subs]}
type="toggle"
label="Embed Subtitles"
- help="Downloads and embeds subtitles in the media file itself, if supported. Unaffected by 'Download Subtitles'"
+ help="Downloads and embeds subtitles in the media file itself, if supported. Uneffected by 'Download Subtitles'"
x-init="$watch('selectedPreset', p => p && (enabled = presets[p]))"
/>
@@ -154,7 +154,7 @@
field={f[:embed_thumbnail]}
type="toggle"
label="Embed Thumbnail"
- help="Downloads and embeds thumbnail in the media file itself, if supported. Unaffected by 'Download Thumbnail' (recommended)"
+ help="Downloads and embeds thumbnail in the media file itself, if supported. Uneffected by 'Download Thumbnail' (recommended)"
x-init="$watch('selectedPreset', p => p && (enabled = presets[p]))"
/>
@@ -178,7 +178,7 @@
field={f[:embed_metadata]}
type="toggle"
label="Embed Metadata"
- help="Downloads and embeds metadata in the media file itself, if supported. Unaffected by 'Download Metadata' (recommended)"
+ help="Downloads and embeds metadata in the media file itself, if supported. Uneffected by 'Download Metadata' (recommended)"
x-init="$watch('selectedPreset', p => p && (enabled = presets[p]))"
/>
diff --git a/lib/pinchflat_web/controllers/media_profiles/media_profile_html/show.html.heex b/lib/pinchflat_web/controllers/media_profiles/media_profile_html/show.html.heex
index 641296e..d08237f 100644
--- a/lib/pinchflat_web/controllers/media_profiles/media_profile_html/show.html.heex
+++ b/lib/pinchflat_web/controllers/media_profiles/media_profile_html/show.html.heex
@@ -25,10 +25,8 @@
<:tab title="Media Profile" id="media-profile">
-
- Raw Attributes
- <.list_items_from_map map={Map.from_struct(@media_profile)} />
-
+
Raw Attributes
+ <.list_items_from_map map={Map.from_struct(@media_profile)} />
<:tab title="Sources" id="sources">
diff --git a/lib/pinchflat_web/controllers/pages/page_html/history_table_live.ex b/lib/pinchflat_web/controllers/pages/page_html/history_table_live.ex
index 6c104aa..d2cab17 100644
--- a/lib/pinchflat_web/controllers/pages/page_html/history_table_live.ex
+++ b/lib/pinchflat_web/controllers/pages/page_html/history_table_live.ex
@@ -28,22 +28,10 @@ defmodule Pinchflat.Pages.HistoryTableLive do
<.table rows={@records} table_class="text-white">
- <:col :let={media_item} label="Title" class="max-w-xs">
-
- <.tooltip
- :if={media_item.last_error}
- tooltip={media_item.last_error}
- position="bottom-right"
- tooltip_class="w-64"
- >
- <.icon name="hero-exclamation-circle-solid" class="text-red-500" />
-
-
- <.subtle_link href={~p"/sources/#{media_item.source_id}/media/#{media_item.id}"}>
- {media_item.title}
-
-
-
+ <:col :let={media_item} label="Title" class="truncate max-w-xs">
+ <.subtle_link href={~p"/sources/#{media_item.source_id}/media/#{media_item}"}>
+ {media_item.title}
+
<:col :let={media_item} label="Upload Date">
{DateTime.to_date(media_item.uploaded_at)}
diff --git a/lib/pinchflat_web/controllers/pages/page_html/home.html.heex b/lib/pinchflat_web/controllers/pages/page_html/home.html.heex
index 6d3b36f..1579c31 100644
--- a/lib/pinchflat_web/controllers/pages/page_html/home.html.heex
+++ b/lib/pinchflat_web/controllers/pages/page_html/home.html.heex
@@ -56,8 +56,12 @@
session: %{"media_state" => "pending"}
)}
- <:tab title="Active Tasks" id="active-tasks">
- {live_render(@conn, Pinchflat.Pages.JobTableLive)}
-
+
+
+ Active Tasks
+
+ {live_render(@conn, Pinchflat.Pages.JobTableLive)}
+
+
diff --git a/lib/pinchflat_web/controllers/settings/setting_html/setting_form.html.heex b/lib/pinchflat_web/controllers/settings/setting_html/setting_form.html.heex
index c59031f..7fe2c94 100644
--- a/lib/pinchflat_web/controllers/settings/setting_html/setting_form.html.heex
+++ b/lib/pinchflat_web/controllers/settings/setting_html/setting_form.html.heex
@@ -29,40 +29,18 @@
- Extractor Settings
+ Indexing Settings
<.input
field={f[:youtube_api_key]}
- placeholder="ABC123,DEF456"
+ placeholder="ABC123"
type="text"
- label="YouTube API Key(s)"
+ label="YouTube API Key"
help={youtube_api_help()}
html_help={true}
inputclass="font-mono text-sm mr-4"
/>
-
- <.input
- field={f[:extractor_sleep_interval_seconds]}
- placeholder="0"
- type="number"
- label="Sleep Interval (seconds)"
- help="Sleep interval in seconds between each extractor request. Must be a positive whole number. Set to 0 to disable"
- />
-
- <.input
- field={f[:download_throughput_limit]}
- placeholder="4.2M"
- label="Download Throughput"
- help="Sets the max bytes-per-second throughput when downloading media. Examples: '50K' or '4.2M'. Leave blank to disable"
- />
-
- <.input
- field={f[:restrict_filenames]}
- type="toggle"
- label="Restrict Filenames"
- help="Restrict filenames to only ASCII characters and avoid ampersands/spaces in filenames"
- />
diff --git a/lib/pinchflat_web/controllers/sources/source_html.ex b/lib/pinchflat_web/controllers/sources/source_html.ex
index 00ab498..57a57b4 100644
--- a/lib/pinchflat_web/controllers/sources/source_html.ex
+++ b/lib/pinchflat_web/controllers/sources/source_html.ex
@@ -27,14 +27,6 @@ defmodule PinchflatWeb.Sources.SourceHTML do
]
end
- def friendly_cookie_behaviours do
- [
- {"Disabled", :disabled},
- {"When Needed", :when_needed},
- {"All Operations", :all_operations}
- ]
- end
-
def cutoff_date_presets do
[
{"7 days", compute_date_offset(7)},
diff --git a/lib/pinchflat_web/controllers/sources/source_html/media_item_table_live.ex b/lib/pinchflat_web/controllers/sources/source_html/media_item_table_live.ex
index de4c7ab..bbcf681 100644
--- a/lib/pinchflat_web/controllers/sources/source_html/media_item_table_live.ex
+++ b/lib/pinchflat_web/controllers/sources/source_html/media_item_table_live.ex
@@ -23,7 +23,7 @@ defmodule PinchflatWeb.Sources.MediaItemTableLive do
<.icon_button icon_name="hero-arrow-path" class="h-10 w-10" phx-click="reload_page" tooltip="Refresh" />
-
+
Showing <.localized_number number={length(@records)} /> of <.localized_number number={@filtered_record_count} />
@@ -46,22 +46,10 @@ defmodule PinchflatWeb.Sources.MediaItemTableLive do
<.table rows={@records} table_class="text-white">
- <:col :let={media_item} label="Title" class="max-w-xs">
-
- <.tooltip
- :if={media_item.last_error}
- tooltip={media_item.last_error}
- position="bottom-right"
- tooltip_class="w-64"
- >
- <.icon name="hero-exclamation-circle-solid" class="text-red-500" />
-
-
- <.subtle_link href={~p"/sources/#{@source.id}/media/#{media_item.id}"}>
- {media_item.title}
-
-
-
+ <:col :let={media_item} label="Title" class="truncate max-w-xs">
+ <.subtle_link href={~p"/sources/#{@source.id}/media/#{media_item.id}"}>
+ {media_item.title}
+
<:col :let={media_item} :if={@media_state == "other"} label="Manually Ignored?">
<.icon name={if media_item.prevent_download, do: "hero-check", else: "hero-x-mark"} />
@@ -217,6 +205,6 @@ defmodule PinchflatWeb.Sources.MediaItemTableLive do
# Selecting only what we need GREATLY speeds up queries on large tables
defp select_fields do
- [:id, :title, :uploaded_at, :prevent_download, :last_error]
+ [:id, :title, :uploaded_at, :prevent_download]
end
end
diff --git a/lib/pinchflat_web/controllers/sources/source_html/show.html.heex b/lib/pinchflat_web/controllers/sources/source_html/show.html.heex
index aefe7fe..855b52e 100644
--- a/lib/pinchflat_web/controllers/sources/source_html/show.html.heex
+++ b/lib/pinchflat_web/controllers/sources/source_html/show.html.heex
@@ -24,18 +24,16 @@
<:tab title="Source" id="source">
-
+
+
Raw Attributes
- Raw Attributes
-
- Media Profile:
- <.subtle_link href={~p"/media_profiles/#{@source.media_profile_id}"}>
- {@source.media_profile.name}
-
-
-
- <.list_items_from_map map={Map.from_struct(@source)} />
+ Media Profile:
+ <.subtle_link href={~p"/media_profiles/#{@source.media_profile_id}"}>
+ {@source.media_profile.name}
+
+
+ <.list_items_from_map map={Map.from_struct(@source)} />
<:tab title="Pending" id="pending">
diff --git a/lib/pinchflat_web/controllers/sources/source_html/source_form.html.heex b/lib/pinchflat_web/controllers/sources/source_html/source_form.html.heex
index 014d597..d4e41f2 100644
--- a/lib/pinchflat_web/controllers/sources/source_html/source_form.html.heex
+++ b/lib/pinchflat_web/controllers/sources/source_html/source_form.html.heex
@@ -87,11 +87,10 @@
/>
<.input
- field={f[:cookie_behaviour]}
- options={friendly_cookie_behaviours()}
- type="select"
- label="Cookie Behaviour"
- help="Uses your YouTube cookies for this source (if configured). 'When Needed' tries to minimize cookie usage except for certain indexing and downloading tasks. See docs"
+ field={f[:use_cookies]}
+ type="toggle"
+ label="Use Cookies for Downloading"
+ help="Uses your YouTube cookies for this source (if configured). Used for downloading private playlists and videos. See docs for important details"
/>
diff --git a/lib/pinchflat_web/controllers/sources/source_live/index_table_live.ex b/lib/pinchflat_web/controllers/sources/source_live/index_table_live.ex
index a9f63c8..5ada1b0 100644
--- a/lib/pinchflat_web/controllers/sources/source_live/index_table_live.ex
+++ b/lib/pinchflat_web/controllers/sources/source_live/index_table_live.ex
@@ -54,8 +54,8 @@ defmodule PinchflatWeb.Sources.SourceLive.IndexTableLive do
defp sort_attr(:pending_count), do: dynamic([s, mp, dl, pe], pe.pending_count)
defp sort_attr(:downloaded_count), do: dynamic([s, mp, dl], dl.downloaded_count)
defp sort_attr(:media_size_bytes), do: dynamic([s, mp, dl], dl.media_size_bytes)
- defp sort_attr(:media_profile_name), do: dynamic([s, mp], fragment("? COLLATE NOCASE", mp.name))
- defp sort_attr(:custom_name), do: dynamic([s], fragment("? COLLATE NOCASE", s.custom_name))
+ defp sort_attr(:media_profile_name), do: dynamic([s, mp], mp.name)
+ defp sort_attr(:custom_name), do: dynamic([s], s.custom_name)
defp sort_attr(:enabled), do: dynamic([s], s.enabled)
defp set_sources(%{assigns: assigns} = socket) do
diff --git a/lib/pinchflat_web/endpoint.ex b/lib/pinchflat_web/endpoint.ex
index bf094ed..66ee1b6 100644
--- a/lib/pinchflat_web/endpoint.ex
+++ b/lib/pinchflat_web/endpoint.ex
@@ -20,7 +20,7 @@ defmodule PinchflatWeb.Endpoint do
plug Plug.Static,
at: "/",
from: :pinchflat,
- gzip: Application.compile_env(:pinchflat, :env) == :prod,
+ gzip: Mix.env() == :prod,
only: PinchflatWeb.static_paths()
# Code reloading can be explicitly enabled under the
@@ -32,17 +32,12 @@ defmodule PinchflatWeb.Endpoint do
plug Phoenix.Ecto.CheckRepoStatus, otp_app: :pinchflat
end
- plug PromEx.Plug, prom_ex_module: Pinchflat.PromEx
-
plug Phoenix.LiveDashboard.RequestLogger,
param_key: "request_logger",
cookie_key: "request_logger"
plug Plug.RequestId
-
- plug Plug.Telemetry,
- event_prefix: [:phoenix, :endpoint],
- log: {__MODULE__, :log_level, []}
+ plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
@@ -58,10 +53,6 @@ defmodule PinchflatWeb.Endpoint do
plug PinchflatWeb.Router
- # Disables logging in Plug.Telemetry for healthcheck requests
- def log_level(%Plug.Conn{path_info: ["healthcheck"]}), do: false
- def log_level(_), do: :info
-
# URLs need to be generated using the host of the current page being accessed
# for things like Podcast RSS feeds to contain links to the right location.
#
diff --git a/lib/pinchflat_web/gettext.ex b/lib/pinchflat_web/gettext.ex
index 6aa0242..9c042a7 100644
--- a/lib/pinchflat_web/gettext.ex
+++ b/lib/pinchflat_web/gettext.ex
@@ -5,7 +5,7 @@ defmodule PinchflatWeb.Gettext do
By using [Gettext](https://hexdocs.pm/gettext),
your module gains a set of macros for translations, for example:
- use Gettext, backend: PinchflatWeb.Gettext
+ import PinchflatWeb.Gettext
# Simple translation
gettext("Here is the string to translate")
@@ -20,5 +20,5 @@ defmodule PinchflatWeb.Gettext do
See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
"""
- use Gettext.Backend, otp_app: :pinchflat
+ use Gettext, otp_app: :pinchflat
end
diff --git a/lib/pinchflat_web/router.ex b/lib/pinchflat_web/router.ex
index 9586f13..bdbb17e 100644
--- a/lib/pinchflat_web/router.ex
+++ b/lib/pinchflat_web/router.ex
@@ -68,7 +68,7 @@ defmodule PinchflatWeb.Router do
scope "/", PinchflatWeb do
pipe_through :api
- get "/healthcheck", HealthController, :check, log: false
+ get "/healthcheck", HealthController, :check
end
scope "/dev" do
diff --git a/mix.exs b/mix.exs
index 27e5f85..bcd8f86 100644
--- a/mix.exs
+++ b/mix.exs
@@ -4,10 +4,9 @@ defmodule Pinchflat.MixProject do
def project do
[
app: :pinchflat,
- version: "2025.9.26",
+ version: "2025.1.3",
elixir: "~> 1.17",
elixirc_paths: elixirc_paths(Mix.env()),
- elixirc_options: [warnings_as_errors: System.get_env("EX_CHECK") == "1"],
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps(),
@@ -47,13 +46,13 @@ defmodule Pinchflat.MixProject do
# Type `mix help deps` for examples and options.
defp deps do
[
- {:phoenix, "~> 1.7.21"},
+ {:phoenix, "~> 1.7.14"},
{:phoenix_ecto, "~> 4.4"},
{:ecto, "~> 3.12.3"},
{:ecto_sql, "~> 3.12"},
{:ecto_sqlite3, ">= 0.0.0"},
{:ecto_sqlite3_extras, "~> 1.2.0"},
- {:phoenix_html, "~> 4.2"},
+ {:phoenix_html, "~> 3.3"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 1.0.0"},
{:floki, ">= 0.36.0", only: :test},
@@ -61,22 +60,20 @@ defmodule Pinchflat.MixProject do
{:esbuild, "~> 0.8", runtime: Mix.env() == :dev},
{:tailwind, "~> 0.2.0", runtime: Mix.env() == :dev},
{:swoosh, "~> 1.3"},
- {:finch, "~> 0.18"},
- {:telemetry_metrics, "~> 1.0"},
- {:telemetry_poller, "~> 1.1"},
+ {:finch, "~> 0.13"},
+ {:telemetry_metrics, "~> 0.6"},
+ {:telemetry_poller, "~> 1.0"},
{:gettext, "~> 0.20"},
{:jason, "~> 1.2"},
- {:dns_cluster, "~> 0.2"},
+ {:dns_cluster, "~> 0.1.1"},
{:plug_cowboy, "~> 2.5"},
{:oban, "~> 2.17"},
{:nimble_parsec, "~> 1.4"},
- # See: https://github.com/bitwalker/timex/issues/778
- {:timex, git: "https://github.com/bitwalker/timex.git", ref: "cc649c7a586f1266b17d57aff3c6eb1a56116ca2"},
- {:prom_ex, "~> 1.11.0"},
+ {:timex, "~> 3.0"},
{:mox, "~> 1.0", only: :test},
{:credo, "~> 1.7.7", only: [:dev, :test], runtime: false},
{:credo_naming, "~> 2.1", only: [:dev, :test], runtime: false},
- {:ex_check, "~> 0.16.0", only: [:dev, :test], runtime: false},
+ {:ex_check, "~> 0.14.0", only: [:dev, :test], runtime: false},
{:faker, "~> 0.17", only: :test},
{:sobelow, "~> 0.13", only: [:dev, :test], runtime: false}
]
diff --git a/mix.lock b/mix.lock
index c316d72..3f6847f 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,73 +1,68 @@
%{
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
- "castore": {:hex, :castore, "1.0.14", "4582dd7d630b48cf5e1ca8d3d42494db51e406b7ba704e81fbd401866366896a", [:mix], [], "hexpm", "7bc1b65249d31701393edaaac18ec8398d8974d52c647b7904d01b964137b9f4"},
+ "castore": {:hex, :castore, "1.0.10", "43bbeeac820f16c89f79721af1b3e092399b3a1ecc8df1a472738fd853574911", [:mix], [], "hexpm", "1b0b7ea14d889d9ea21202c43a4fa015eb913021cb535e8ed91946f4b77a8848"},
"cc_precompiler": {:hex, :cc_precompiler, "0.1.10", "47c9c08d8869cf09b41da36538f62bc1abd3e19e41701c2cea2675b53c704258", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f6e046254e53cd6b41c6bacd70ae728011aa82b2742a80d6e2214855c6e06b22"},
- "certifi": {:hex, :certifi, "2.15.0", "0e6e882fcdaaa0a5a9f2b3db55b1394dba07e8d6d9bcad08318fb604c6839712", [:rebar3], [], "hexpm", "b147ed22ce71d72eafdad94f055165c1c182f61a2ff49df28bcc71d1d5b94a60"},
+ "certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
- "cowboy": {:hex, :cowboy, "2.13.0", "09d770dd5f6a22cc60c071f432cd7cb87776164527f205c5a6b0f24ff6b38990", [:make, :rebar3], [{:cowlib, ">= 2.14.0 and < 3.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, ">= 1.8.0 and < 3.0.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "e724d3a70995025d654c1992c7b11dbfea95205c047d86ff9bf1cda92ddc5614"},
+ "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.15.0", "3c97a318a933962d1c12b96ab7c1d728267d2c523c25a5b57b0f93392b6e9e25", [:make, :rebar3], [], "hexpm", "4f00c879a64b4fe7c8fcb42a4281925e9ffdb928820b03c3ad325a617e857532"},
- "credo": {:hex, :credo, "1.7.12", "9e3c20463de4b5f3f23721527fcaf16722ec815e70ff6c60b86412c695d426c1", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8493d45c656c5427d9c729235b99d498bd133421f3e0a683e5c1b561471291e5"},
+ "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
+ "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"},
"credo_naming": {:hex, :credo_naming, "2.1.0", "d44ad58890d4db552e141ce64756a74ac1573665af766d1ac64931aa90d47744", [:make, :mix], [{:credo, "~> 1.6", [hex: :credo, repo: "hexpm", optional: false]}], "hexpm", "830e23b3fba972e2fccec49c0c089fe78c1e64bc16782a2682d78082351a2909"},
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
- "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"},
- "dns_cluster": {:hex, :dns_cluster, "0.2.0", "aa8eb46e3bd0326bd67b84790c561733b25c5ba2fe3c7e36f28e88f384ebcb33", [:mix], [], "hexpm", "ba6f1893411c69c01b9e8e8f772062535a4cf70f3f35bcc964a324078d8c8240"},
- "ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"},
- "ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"},
- "ecto_sqlite3": {:hex, :ecto_sqlite3, "0.19.0", "00030bbaba150369ff3754bbc0d2c28858e8f528ae406bf6997d1772d3a03203", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.12", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:exqlite, "~> 0.22", [hex: :exqlite, repo: "hexpm", optional: false]}], "hexpm", "297b16750fe229f3056fe32afd3247de308094e8b0298aef0d73a8493ce97c81"},
+ "decimal": {:hex, :decimal, "2.2.0", "df3d06bb9517e302b1bd265c1e7f16cda51547ad9d99892049340841f3e15836", [:mix], [], "hexpm", "af8daf87384b51b7e611fb1a1f2c4d4876b65ef968fa8bd3adf44cff401c7f21"},
+ "dns_cluster": {:hex, :dns_cluster, "0.1.2", "3eb5be824c7888dadf9781018e1a5f1d3d1113b333c50bce90fb1b83df1015f2", [:mix], [], "hexpm", "7494272040f847637bbdb01bcdf4b871e82daf09b813e7d3cb3b84f112c6f2f8"},
+ "ecto": {:hex, :ecto, "3.12.3", "1a9111560731f6c3606924c81c870a68a34c819f6d4f03822f370ea31a582208", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9efd91506ae722f95e48dc49e70d0cb632ede3b7a23896252a60a14ac6d59165"},
+ "ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"},
+ "ecto_sqlite3": {:hex, :ecto_sqlite3, "0.17.2", "200226e057f76c40be55fbac77771eb1a233260ab8ec7283f5da6d9402bde8de", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.12", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:exqlite, "~> 0.22", [hex: :exqlite, repo: "hexpm", optional: false]}], "hexpm", "a3838919c5a34c268c28cafab87b910bcda354a9a4e778658da46c149bb2c1da"},
"ecto_sqlite3_extras": {:hex, :ecto_sqlite3_extras, "1.2.2", "36e60b561a11441d15f26c791817999269fb578b985162207ebb08b04ca71e40", [:mix], [{:exqlite, ">= 0.13.2", [hex: :exqlite, repo: "hexpm", optional: false]}, {:table_rex, "~> 4.0", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "2b66ba7246bb4f7e39e2578acd4a0e4e4be54f60ff52d450a01be95eeb78ff1e"},
- "elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"},
- "esbuild": {:hex, :esbuild, "0.10.0", "b0aa3388a1c23e727c5a3e7427c932d89ee791746b0081bbe56103e9ef3d291f", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "468489cda427b974a7cc9f03ace55368a83e1a7be12fba7e30969af78e5f8c70"},
- "ex_check": {:hex, :ex_check, "0.16.0", "07615bef493c5b8d12d5119de3914274277299c6483989e52b0f6b8358a26b5f", [:mix], [], "hexpm", "4d809b72a18d405514dda4809257d8e665ae7cf37a7aee3be6b74a34dec310f5"},
- "expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"},
- "exqlite": {:hex, :exqlite, "0.31.0", "bdf87c618861147382cee29eb8bd91d8cfb0949f89238b353d24fa331527a33a", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "df352de99ba4ce1bac2ad4943d09dbe9ad59e0e7ace55917b493ae289c78fc75"},
- "faker": {:hex, :faker, "0.18.0", "943e479319a22ea4e8e39e8e076b81c02827d9302f3d32726c5bf82f430e6e14", [:mix], [], "hexpm", "bfbdd83958d78e2788e99ec9317c4816e651ad05e24cfd1196ce5db5b3e81797"},
- "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"},
- "finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"},
- "floki": {:hex, :floki, "0.37.1", "d7aaee758c8a5b4a7495799a4260754fec5530d95b9c383c03b27359dea117cf", [:mix], [], "hexpm", "673d040cb594d31318d514590246b6dd587ed341d3b67e17c1c0eb8ce7ca6f04"},
- "gettext": {:hex, :gettext, "0.26.2", "5978aa7b21fada6deabf1f6341ddba50bc69c999e812211903b169799208f2a8", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "aa978504bcf76511efdc22d580ba08e2279caab1066b76bb9aa81c4a1e0a32a5"},
- "hackney": {:hex, :hackney, "1.24.1", "f5205a125bba6ed4587f9db3cc7c729d11316fa8f215d3e57ed1c067a9703fa9", [:rebar3], [{:certifi, "~> 2.15.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "f4a7392a0b53d8bbc3eb855bdcc919cd677358e65b2afd3840b5b3690c4c8a39"},
- "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"},
+ "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"},
+ "esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
+ "ex_check": {:hex, :ex_check, "0.14.0", "d6fbe0bcc51cf38fea276f5bc2af0c9ae0a2bb059f602f8de88709421dae4f0e", [:mix], [], "hexpm", "8a602e98c66e6a4be3a639321f1f545292042f290f91fa942a285888c6868af0"},
+ "expo": {:hex, :expo, "0.5.1", "249e826a897cac48f591deba863b26c16682b43711dd15ee86b92f25eafd96d9", [:mix], [], "hexpm", "68a4233b0658a3d12ee00d27d37d856b1ba48607e7ce20fd376958d0ba6ce92b"},
+ "exqlite": {:hex, :exqlite, "0.23.0", "6e851c937a033299d0784994c66da24845415072adbc455a337e20087bce9033", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "404341cceec5e6466aaed160cf0b58be2019b60af82588c215e1224ebd3ec831"},
+ "faker": {:hex, :faker, "0.17.0", "671019d0652f63aefd8723b72167ecdb284baf7d47ad3a82a15e9b8a6df5d1fa", [:mix], [], "hexpm", "a7d4ad84a93fd25c5f5303510753789fc2433ff241bf3b4144d3f6f291658a6a"},
+ "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
+ "finch": {:hex, :finch, "0.17.0", "17d06e1d44d891d20dbd437335eebe844e2426a0cd7e3a3e220b461127c73f70", [: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", "8d014a661bb6a437263d4b5abf0bcbd3cf0deb26b1e8596f2a271d22e48934c7"},
+ "floki": {:hex, :floki, "0.36.3", "1102f93b16a55bc5383b85ae3ec470f82dee056eaeff9195e8afdf0ef2a43c30", [:mix], [], "hexpm", "fe0158bff509e407735f6d40b3ee0d7deb47f3f3ee7c6c182ad28599f9f6b27a"},
+ "gettext": {:hex, :gettext, "0.24.0", "6f4d90ac5f3111673cbefc4ebee96fe5f37a114861ab8c7b7d5b30a1108ce6d8", [:mix], [{:expo, "~> 0.5.1", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "bdf75cdfcbe9e4622dd18e034b227d77dd17f0f133853a1c73b97b3d6c770e8b"},
+ "hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
+ "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
- "mime": {:hex, :mime, "2.0.7", "b8d739037be7cd402aee1ba0306edfdef982687ee7e9859bee6198c1e7e2f128", [:mix], [], "hexpm", "6171188e399ee16023ffc5b76ce445eb6d9672e2e241d2df6050f3c771e80ccd"},
- "mimerl": {:hex, :mimerl, "1.4.0", "3882a5ca67fbbe7117ba8947f27643557adec38fa2307490c4c4207624cb213b", [:rebar3], [], "hexpm", "13af15f9f68c65884ecca3a3891d50a7b57d82152792f3e19d88650aa126b144"},
- "mint": {:hex, :mint, "1.7.1", "113fdb2b2f3b59e47c7955971854641c61f378549d73e829e1768de90fc1abf1", [: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", "fceba0a4d0f24301ddee3024ae116df1c3f4bb7a563a731f45fdfeb9d39a231b"},
- "mox": {:hex, :mox, "1.2.0", "a2cd96b4b80a3883e3100a221e8adc1b98e4c3a332a8fc434c39526babafd5b3", [:mix], [{:nimble_ownership, "~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}], "hexpm", "c7b92b3cc69ee24a7eeeaf944cd7be22013c52fcb580c1f33f50845ec821089a"},
- "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"},
- "nimble_ownership": {:hex, :nimble_ownership, "1.0.1", "f69fae0cdd451b1614364013544e66e4f5d25f36a2056a9698b793305c5aa3a6", [:mix], [], "hexpm", "3825e461025464f519f3f3e4a1f9b68c47dc151369611629ad08b636b73bb22d"},
- "nimble_parsec": {:hex, :nimble_parsec, "1.4.2", "8efba0122db06df95bfaa78f791344a89352ba04baedd3849593bfce4d0dc1c6", [:mix], [], "hexpm", "4b21398942dda052b403bbe1da991ccd03a053668d147d53fb8c4e0efe09c973"},
- "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"},
- "oban": {:hex, :oban, "2.19.4", "045adb10db1161dceb75c254782f97cdc6596e7044af456a59decb6d06da73c1", [:mix], [{:ecto_sql, "~> 3.10", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:ecto_sqlite3, "~> 0.9", [hex: :ecto_sqlite3, repo: "hexpm", optional: true]}, {:igniter, "~> 0.5", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5fcc6219e6464525b808d97add17896e724131f498444a292071bf8991c99f97"},
- "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"},
+ "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
+ "mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
+ "mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"},
+ "mox": {:hex, :mox, "1.1.0", "0f5e399649ce9ab7602f72e718305c0f9cdc351190f72844599545e4996af73c", [:mix], [], "hexpm", "d44474c50be02d5b72131070281a5d3895c0e7a95c780e90bc0cfe712f633a13"},
+ "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"},
+ "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
+ "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"},
+ "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"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
- "peep": {:hex, :peep, "3.4.1", "0e5263710fa0b42675bd0a11fdcdd3ee4f484e319105b6ad9a576c91a5d3cb55", [: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", "7a9b8c1f17b8b9475efb27b7048afa4d89ab84ef33a3d1df13696c85c12cd632"},
- "phoenix": {:hex, :phoenix, "1.7.21", "14ca4f1071a5f65121217d6b57ac5712d1857e40a0833aff7a691b7870fc9a3b", [: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", "336dce4f86cba56fed312a7d280bf2282c720abb6074bdb1b61ec8095bdd0bc9"},
- "phoenix_ecto": {:hex, :phoenix_ecto, "4.6.4", "dcf3483ab45bab4c15e3a47c34451392f64e433846b08469f5d16c2a4cd70052", [: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", "f5b8584c36ccc9b903948a696fc9b8b81102c79c7c0c751a9f00cdec55d5f2d7"},
- "phoenix_html": {:hex, :phoenix_html, "4.2.1", "35279e2a39140068fc03f8874408d58eef734e488fc142153f055c5454fd1c08", [:mix], [], "hexpm", "cff108100ae2715dd959ae8f2a8cef8e20b593f8dfd031c9cba92702cf23e053"},
- "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.7", "405880012cb4b706f26dd1c6349125bfc903fb9e44d1ea668adaf4e04d4884b7", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "3a8625cab39ec261d48a13b7468dc619c0ede099601b084e343968309bd4d7d7"},
- "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.6.0", "2791fac0e2776b640192308cc90c0dbcf67843ad51387ed4ecae2038263d708d", [:mix], [{:file_system, "~> 0.2.10 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b3a1fa036d7eb2f956774eda7a7638cf5123f8f2175aca6d6420a7f95e598e1c"},
- "phoenix_live_view": {:hex, :phoenix_live_view, "1.0.17", "beeb16d83a7d3760f7ad463df94e83b087577665d2acc0bf2987cd7d9778068f", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0-rc", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, 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.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a4ca05c1eb6922c4d07a508a75bfa12c45e5f4d8f77ae83283465f02c53741e1"},
+ "phoenix": {:hex, :phoenix, "1.7.17", "2fcdceecc6fb90bec26fab008f96abbd0fd93bc9956ec7985e5892cf545152ca", [: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", "50e8ad537f3f7b0efb1509b2f75b5c918f697be6a45d48e49a30d3b7c0e464c9"},
+ "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.3", "86e9878f833829c3f66da03d75254c155d91d72a201eb56ae83482328dc7ca93", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "d36c401206f3011fefd63d04e8ef626ec8791975d9d107f9a0817d426f61ac07"},
+ "phoenix_html": {:hex, :phoenix_html, "3.3.4", "42a09fc443bbc1da37e372a5c8e6755d046f22b9b11343bf885067357da21cb3", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0249d3abec3714aff3415e7ee3d9786cb325be3151e6c4b3021502c585bf53fb"},
+ "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.3", "7ff51c9b6609470f681fbea20578dede0e548302b0c8bdf338b5a753a4f045bf", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "f9470a0a8bae4f56430a23d42f977b5a6205fdba6559d76f932b876bfaec652d"},
+ "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"},
+ "phoenix_live_view": {:hex, :phoenix_live_view, "1.0.0", "3a10dfce8f87b2ad4dc65de0732fc2a11e670b2779a19e8d3281f4619a85bce4", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, 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.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "254caef0028765965ca6bd104cc7d68dcc7d57cc42912bef92f6b03047251d99"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
- "plug": {:hex, :plug, "1.18.0", "d78df36c41f7e798f2edf1f33e1727eae438e9dd5d809a9997c463a108244042", [: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", "819f9e176d51e44dc38132e132fe0accaf6767eab7f0303431e404da8476cfa2"},
- "plug_cowboy": {:hex, :plug_cowboy, "2.7.3", "1304d36752e8bdde213cea59ef424ca932910a91a07ef9f3874be709c4ddb94b", [: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", "77c95524b2aa5364b247fa17089029e73b951ebc1adeef429361eab0bb55819d"},
- "plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"},
- "prom_ex": {:hex, :prom_ex, "1.11.0", "1f6d67f2dead92224cb4f59beb3e4d319257c5728d9638b4a5e8ceb51a4f9c7e", [: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: true]}, {: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", "76b074bc3730f0802978a7eb5c7091a65473eaaf07e99ec9e933138dcc327805"},
- "ranch": {:hex, :ranch, "2.2.0", "25528f82bc8d7c6152c57666ca99ec716510fe0925cb188172f41ce93117b1b0", [:make, :rebar3], [], "hexpm", "fa0b99a1780c80218a4197a59ea8d3bdae32fbff7e88527d7d8a4787eff4f8e7"},
- "sobelow": {:hex, :sobelow, "0.14.0", "dd82aae8f72503f924fe9dd97ffe4ca694d2f17ec463dcfd365987c9752af6ee", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "7ecf91e298acfd9b24f5d761f19e8f6e6ac585b9387fb6301023f1f2cd5eed5f"},
+ "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"},
+ "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
+ "sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
- "swoosh": {:hex, :swoosh, "1.19.1", "77e839b27fc7af0704788e5854934c77d4dea7b437270c924a717513d598b8a4", [: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.10 or ~> 0.6 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "eab57462d41a3330e82cb93a9d7640f5c79a85951f3457db25c1eb28fda193a6"},
- "table_rex": {:hex, :table_rex, "4.1.0", "fbaa8b1ce154c9772012bf445bfb86b587430fb96f3b12022d3f35ee4a68c918", [:mix], [], "hexpm", "95932701df195d43bc2d1c6531178fc8338aa8f38c80f098504d529c43bc2601"},
+ "swoosh": {:hex, :swoosh, "1.14.4", "94e9dba91f7695a10f49b0172c4a4cb658ef24abef7e8140394521b7f3bbb2d4", [:mix], [{: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]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "081c5a590e4ba85cc89baddf7b2beecf6c13f7f84a958f1cd969290815f0f026"},
+ "table_rex": {:hex, :table_rex, "4.0.0", "3c613a68ebdc6d4d1e731bc973c233500974ec3993c99fcdabb210407b90959b", [:mix], [], "hexpm", "c35c4d5612ca49ebb0344ea10387da4d2afe278387d4019e4d8111e815df8f55"},
"tailwind": {:hex, :tailwind, "0.2.2", "9e27288b568ede1d88517e8c61259bc214a12d7eed271e102db4c93fcca9b2cd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "ccfb5025179ea307f7f899d1bb3905cd0ac9f687ed77feebc8f67bdca78565c4"},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
- "telemetry_metrics": {:hex, :telemetry_metrics, "1.1.0", "5bd5f3b5637e0abea0426b947e3ce5dd304f8b3bc6617039e2b5a008adc02f8f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "e7b79e8ddfde70adb6db8a6623d1778ec66401f366e9a8f5dd0955c56bc8ce67"},
- "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_poller": {:hex, :telemetry_poller, "1.2.0", "ba82e333215aed9dd2096f93bd1d13ae89d249f82760fcada0850ba33bac154b", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7216e21a6c326eb9aa44328028c34e9fd348fb53667ca837be59d0aa2a0156e8"},
- "timex": {:git, "https://github.com/bitwalker/timex.git", "cc649c7a586f1266b17d57aff3c6eb1a56116ca2", [ref: "cc649c7a586f1266b17d57aff3c6eb1a56116ca2"]},
- "tzdata": {:hex, :tzdata, "1.1.3", "b1cef7bb6de1de90d4ddc25d33892b32830f907e7fc2fccd1e7e22778ab7dfbc", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "d4ca85575a064d29d4e94253ee95912edfb165938743dbf002acdf0dcecb0c28"},
- "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.1", "a48703a25c170eedadca83b11e88985af08d35f37c6f664d6dcfb106a97782fc", [:rebar3], [], "hexpm", "b3a917854ce3ae233619744ad1e0102e05673136776fb2fa76234f3e03b23642"},
+ "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_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
+ "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.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"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
"websock_adapter": {:hex, :websock_adapter, "0.5.8", "3b97dc94e407e2d1fc666b2fb9acf6be81a1798a2602294aac000260a7c4a47d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "315b9a1865552212b5f35140ad194e67ce31af45bcee443d4ecb96b5fd3f3782"},
}
diff --git a/priv/grafana/application.json b/priv/grafana/application.json
deleted file mode 100644
index 1cc05d4..0000000
--- a/priv/grafana/application.json
+++ /dev/null
@@ -1,607 +0,0 @@
-{
- "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", "pinchflat", "start"],
- "type": "tags"
- },
- {
- "datasource": "-- Grafana --",
- "enable": true,
- "hide": true,
- "iconColor": "#FF9830",
- "limit": 100,
- "name": "PromEx service stop",
- "showIn": 0,
- "tags": ["prom_ex", "pinchflat", "stop"],
- "type": "tags"
- }
- ]
- },
- "description": "All the data that is presented here is captured by the PromEx Application plugin (https://github.com/akoutmos/prom_ex/blob/master/lib/prom_ex/plugins/application.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": "Application Plugin Docs",
- "tooltip": "",
- "type": "link",
- "url": "https://hexdocs.pm/prom_ex/PromEx.Plugins.Application.html"
- }
- ],
- "panels": [
- {
- "datasource": "prometheus",
- "description": "The amount of time that the application has been running.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "decimals": 1,
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "dtdurationms"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 6,
- "w": 8,
- "x": 0,
- "y": 0
- },
- "id": 6,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_application_uptime_milliseconds_count{job=\"$job\", instance=\"$instance\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Application Uptime",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The data is populated by the PromEx Application plugin and provides information regarding your application's dependencies.",
- "fieldConfig": {
- "defaults": {
- "custom": {
- "align": "left",
- "displayMode": "auto"
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": [
- {
- "matcher": {
- "id": "byName",
- "options": "Status"
- },
- "properties": [
- {
- "id": "custom.displayMode",
- "value": "color-background"
- },
- {
- "id": "mappings",
- "value": [
- {
- "from": "",
- "id": 0,
- "text": "Started",
- "to": "",
- "type": 1,
- "value": "1"
- },
- {
- "from": "",
- "id": 1,
- "text": "Loaded",
- "to": "",
- "type": 1,
- "value": "0"
- }
- ]
- },
- {
- "id": "custom.align",
- "value": "center"
- },
- {
- "id": "custom.width",
- "value": 202
- }
- ]
- },
- {
- "matcher": {
- "id": "byName",
- "options": "Name"
- },
- "properties": [
- {
- "id": "custom.width",
- "value": 349
- }
- ]
- },
- {
- "matcher": {
- "id": "byName",
- "options": "Version"
- },
- "properties": [
- {
- "id": "custom.width",
- "value": 187
- }
- ]
- }
- ]
- },
- "gridPos": {
- "h": 36,
- "w": 16,
- "x": 8,
- "y": 0
- },
- "id": 2,
- "options": {
- "showHeader": true,
- "sortBy": [
- {
- "desc": false,
- "displayName": "Name"
- }
- ]
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_application_dependency_info{job=\"$job\", instance=\"$instance\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Dependency Information",
- "transformations": [
- {
- "id": "organize",
- "options": {
- "excludeByName": {
- "Time": true,
- "__name__": true,
- "instance": true,
- "job": true,
- "Value": true
- },
- "indexByName": {
- "Time": 0,
- "Value": 4,
- "__name__": 1,
- "instance": 2,
- "job": 3,
- "modules": 7,
- "name": 5,
- "version": 6
- },
- "renameByName": {
- "Value": "Status",
- "modules": "Number of Modules Loaded",
- "name": "Name",
- "version": "Version"
- }
- }
- }
- ],
- "type": "table"
- },
- {
- "datasource": "prometheus",
- "description": "The name of the primary application that is running.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 6,
- "w": 8,
- "x": 0,
- "y": 6
- },
- "id": 11,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "/^name$/",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_application_primary_info{job=\"$job\", instance=\"$instance\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Application Name",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The Git SHA of the application.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 6,
- "w": 8,
- "x": 0,
- "y": 12
- },
- "id": 10,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "/^sha$/",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_application_git_sha_info{job=\"$job\", instance=\"$instance\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Application Git SHA",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The author of the application's last Git commit.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 6,
- "w": 8,
- "x": 0,
- "y": 18
- },
- "id": 12,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "/^author$/",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_application_git_author_info{job=\"$job\", instance=\"$instance\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Application Git Author",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The version of the primary application that is running.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 6,
- "w": 8,
- "x": 0,
- "y": 24
- },
- "id": 7,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "/^version$/",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_application_primary_info{job=\"$job\", instance=\"$instance\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Application Version",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The number of modules loaded by the primary application that is running.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 6,
- "w": 8,
- "x": 0,
- "y": 30
- },
- "id": 9,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "/^modules$/",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_application_primary_info{job=\"$job\", instance=\"$instance\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Application Modules Loaded",
- "type": "stat"
- }
- ],
- "refresh": "5s",
- "schemaVersion": 26,
- "style": "dark",
- "tags": ["PromEx", "Application", "pinchflat"],
- "templating": {
- "list": [
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_prom_ex_status_info, job)",
- "hide": 0,
- "includeAll": false,
- "label": "Prometheus Job",
- "multi": false,
- "name": "job",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_prom_ex_status_info, job)",
- "refresh": 2,
- "regex": "",
- "skipUrlSync": false,
- "sort": 6,
- "tagValuesQuery": "",
- "tags": [],
- "tagsQuery": "",
- "type": "query",
- "useTags": false
- },
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_prom_ex_status_info, instance)",
- "hide": 0,
- "includeAll": false,
- "label": "Application Instance",
- "multi": false,
- "name": "instance",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_prom_ex_status_info{job=\"$job\"}, instance)",
- "refresh": 2,
- "regex": "",
- "skipUrlSync": false,
- "sort": 0,
- "tagValuesQuery": "",
- "tags": [],
- "tagsQuery": "",
- "type": "query",
- "useTags": false
- }
- ]
- },
- "time": {
- "from": "now-1h",
- "to": "now"
- },
- "timepicker": {
- "refresh_intervals": ["5s", "10s", "30s", "1m", "5m"]
- },
- "timezone": "",
- "title": "Pinchflat - PromEx Application Dashboard",
- "uid": "7DBBC471C5775585391E8F24D1E62319",
- "version": 1
-}
diff --git a/priv/grafana/beam.json b/priv/grafana/beam.json
deleted file mode 100644
index d35d0f0..0000000
--- a/priv/grafana/beam.json
+++ /dev/null
@@ -1,2328 +0,0 @@
-{
- "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", "pinchflat", "start"],
- "type": "tags"
- },
- {
- "datasource": "-- Grafana --",
- "enable": true,
- "hide": true,
- "iconColor": "#FF9830",
- "limit": 100,
- "name": "PromEx service stop",
- "showIn": 0,
- "tags": ["prom_ex", "pinchflat", "stop"],
- "type": "tags"
- }
- ]
- },
- "description": "All the data that is presented here is captured by the PromEx BEAM plugin (https://github.com/akoutmos/prom_ex/blob/master/lib/prom_ex/plugins/beam.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": "BEAM Plugin Docs",
- "tooltip": "",
- "type": "link",
- "url": "https://hexdocs.pm/prom_ex/PromEx.Plugins.Beam.html"
- }
- ],
- "panels": [
- {
- "collapsed": false,
- "datasource": null,
- "gridPos": {
- "h": 1,
- "w": 24,
- "x": 0,
- "y": 0
- },
- "id": 25,
- "panels": [],
- "title": "Overview",
- "type": "row"
- },
- {
- "datasource": "prometheus",
- "description": "The amount of time that has passed since the system has started.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "decimals": 1,
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "dtdurationms"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 4,
- "w": 6,
- "x": 0,
- "y": 1
- },
- "id": 32,
- "options": {
- "colorMode": "value",
- "graphMode": "none",
- "justifyMode": "center",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_beam_stats_uptime_milliseconds_count{job=\"$job\", instance=\"$instance\"}",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Uptime",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "Shows the various options that OTP was compiled with.",
- "fieldConfig": {
- "defaults": {
- "custom": {
- "align": null
- },
- "mappings": [
- {
- "from": "",
- "id": 0,
- "text": "Enabled",
- "to": "",
- "type": 1,
- "value": "1"
- },
- {
- "from": "",
- "id": 1,
- "text": "Disabled",
- "to": "",
- "type": 1,
- "value": "0"
- }
- ],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "dark-red",
- "value": null
- },
- {
- "color": "dark-green",
- "value": 1
- }
- ]
- }
- },
- "overrides": [
- {
- "matcher": {
- "id": "byName",
- "options": "Status"
- },
- "properties": [
- {
- "id": "custom.align",
- "value": "center"
- },
- {
- "id": "custom.displayMode",
- "value": "color-background"
- }
- ]
- },
- {
- "matcher": {
- "id": "byName",
- "options": "Compiler Option"
- },
- "properties": [
- {
- "id": "mappings",
- "value": [
- {
- "from": "",
- "id": 0,
- "text": "SMP Support",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_smp_support_info"
- },
- {
- "from": "",
- "id": 1,
- "text": "Thread Support",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_thread_support_info"
- },
- {
- "from": "",
- "id": 2,
- "text": "Time Correction Support",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_time_correction_support_info"
- },
- {
- "from": "",
- "id": 3,
- "text": "JIT Support",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_jit_support_info"
- }
- ]
- },
- {
- "id": "custom.width",
- "value": 219
- }
- ]
- }
- ]
- },
- "gridPos": {
- "h": 8,
- "w": 6,
- "x": 6,
- "y": 1
- },
- "id": 10,
- "options": {
- "frameIndex": 0,
- "showHeader": true,
- "sortBy": []
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "{__name__=~\"pinchflat_prom_ex_beam_system_thread_support_info|pinchflat_prom_ex_beam_system_jit_support_info|pinchflat_prom_ex_beam_system_smp_support_info|pinchflat_prom_ex_beam_system_time_correction_support_info\", job=\"$job\", instance=\"$instance\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "OTP Compiler Options",
- "transformations": [
- {
- "id": "organize",
- "options": {
- "excludeByName": {
- "Time": true,
- "instance": true,
- "job": true
- },
- "indexByName": {
- "Time": 0,
- "Value": 4,
- "__name__": 3,
- "instance": 1,
- "job": 2
- },
- "renameByName": {
- "Value": "Status",
- "__name__": "Compiler Option"
- }
- }
- }
- ],
- "type": "table"
- },
- {
- "datasource": "prometheus",
- "description": "The OTP major version running the application.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 5,
- "w": 6,
- "x": 12,
- "y": 1
- },
- "id": 4,
- "options": {
- "colorMode": "value",
- "graphMode": "none",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["lastNotNull"],
- "fields": "",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_beam_system_version_info{job=\"$job\", instance=\"$instance\"}",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "OTP Major Version",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The number of running BEAM processes currently running.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "#EAB839",
- "value": 25000
- },
- {
- "color": "red",
- "value": 75000
- }
- ]
- },
- "unit": "locale"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 5,
- "w": 6,
- "x": 18,
- "y": 1
- },
- "id": 28,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_beam_stats_process_count{job=\"$job\", instance=\"$instance\"}",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Process Count",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "Shows information regarding the schedulers configured for the BEAM instance.",
- "fieldConfig": {
- "defaults": {
- "custom": {
- "align": null
- },
- "mappings": [
- {
- "from": "",
- "id": 0,
- "text": "Enabled",
- "to": "",
- "type": 1,
- "value": "1"
- },
- {
- "from": "",
- "id": 1,
- "text": "Disabled",
- "to": "",
- "type": 1,
- "value": "0"
- }
- ],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": [
- {
- "matcher": {
- "id": "byName",
- "options": "Value"
- },
- "properties": [
- {
- "id": "custom.align",
- "value": "center"
- }
- ]
- },
- {
- "matcher": {
- "id": "byName",
- "options": "Type"
- },
- "properties": [
- {
- "id": "mappings",
- "value": [
- {
- "from": "",
- "id": 0,
- "text": "Dirty CPU Schedulers",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_dirty_cpu_schedulers_info"
- },
- {
- "from": "",
- "id": 1,
- "text": "Dirty CPU Schedulers Online",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_dirty_cpu_schedulers_online_info"
- },
- {
- "from": "",
- "id": 2,
- "text": "Dirty IO Schedulers",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_dirty_io_schedulers_info"
- },
- {
- "from": "",
- "id": 3,
- "text": "System Schedulers",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_schedulers_info"
- },
- {
- "from": "",
- "id": 4,
- "text": "System Schedulers Online",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_schedulers_online_info"
- },
- {
- "from": "",
- "id": 5,
- "text": "Word Size in Bytes",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_word_size_bytes_info"
- },
- {
- "from": "",
- "id": 6,
- "text": "Logical Processors",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_logical_processors_info"
- },
- {
- "from": "",
- "id": 7,
- "text": "Logical Processors Available",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_logical_processors_available_info"
- },
- {
- "from": "",
- "id": 8,
- "text": "Logical Processors Online",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_logical_processors_online_info"
- }
- ]
- }
- ]
- }
- ]
- },
- "gridPos": {
- "h": 11,
- "w": 6,
- "x": 0,
- "y": 5
- },
- "id": 11,
- "options": {
- "frameIndex": 0,
- "showHeader": true
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "{__name__=~\"pinchflat_prom_ex_beam_system_dirty_cpu_schedulers_info|pinchflat_prom_ex_beam_system_dirty_cpu_schedulers_online_info|pinchflat_prom_ex_beam_system_dirty_io_schedulers_info|pinchflat_prom_ex_beam_system_schedulers_info|pinchflat_prom_ex_beam_system_schedulers_online_info|pinchflat_prom_ex_beam_system_word_size_bytes_info|pinchflat_prom_ex_beam_system_logical_processors_info|pinchflat_prom_ex_beam_system_logical_processors_available_info|pinchflat_prom_ex_beam_system_logical_processors_online_info\", job=\"$job\", instance=\"$instance\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "System Information",
- "transformations": [
- {
- "id": "organize",
- "options": {
- "excludeByName": {
- "Time": true,
- "instance": true,
- "job": true
- },
- "indexByName": {
- "Time": 0,
- "Value": 4,
- "__name__": 3,
- "instance": 1,
- "job": 2
- },
- "renameByName": {
- "Value": "Value",
- "__name__": "Type"
- }
- }
- }
- ],
- "type": "table"
- },
- {
- "datasource": "prometheus",
- "description": "The number of currently active ports.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "#EAB839",
- "value": 25000
- },
- {
- "color": "red",
- "value": 75000
- }
- ]
- },
- "unit": "locale"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 5,
- "w": 6,
- "x": 12,
- "y": 6
- },
- "id": 29,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_beam_stats_port_count{job=\"$job\", instance=\"$instance\"}",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Port Count",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The number of currently allocated ETS tables.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "#EAB839",
- "value": 2500
- },
- {
- "color": "red",
- "value": 5000
- }
- ]
- },
- "unit": "locale"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 5,
- "w": 6,
- "x": 18,
- "y": 6
- },
- "id": 31,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_beam_stats_ets_count{job=\"$job\", instance=\"$instance\"}",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "ETS Table Count",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "Shows information regarding the system limits of the BEAM instance.",
- "fieldConfig": {
- "defaults": {
- "custom": {
- "align": null
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": [
- {
- "matcher": {
- "id": "byName",
- "options": "Value"
- },
- "properties": [
- {
- "id": "custom.align",
- "value": "center"
- },
- {
- "id": "unit",
- "value": "locale"
- }
- ]
- },
- {
- "matcher": {
- "id": "byName",
- "options": "Type"
- },
- "properties": [
- {
- "id": "mappings",
- "value": [
- {
- "from": "",
- "id": 0,
- "text": "Atom Limit",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_atom_limit_info"
- },
- {
- "from": "",
- "id": 1,
- "text": "ETS Table Limit",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_ets_limit_info"
- },
- {
- "from": "",
- "id": 2,
- "text": "Port Limit",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_port_limit_info"
- },
- {
- "from": "",
- "id": 3,
- "text": "Process Limit",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_beam_system_process_limit_info"
- },
- {
- "from": "",
- "id": 4,
- "text": "Thread Pool Size",
- "to": "",
- "type": 1,
- "value": "beam_system_thread_pool_size_info"
- }
- ]
- }
- ]
- }
- ]
- },
- "gridPos": {
- "h": 7,
- "w": 6,
- "x": 6,
- "y": 9
- },
- "id": 12,
- "options": {
- "frameIndex": 0,
- "showHeader": true
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "{__name__=~\"pinchflat_prom_ex_beam_system_ets_limit_info|pinchflat_prom_ex_beam_system_port_limit_info|pinchflat_prom_ex_beam_system_process_limit_info|pinchflat_prom_ex_beam_system_atom_limit_info\", job=\"$job\", instance=\"$instance\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "System Limits",
- "transformations": [
- {
- "id": "organize",
- "options": {
- "excludeByName": {
- "Time": true,
- "instance": true,
- "job": true
- },
- "indexByName": {
- "Time": 0,
- "Value": 4,
- "__name__": 3,
- "instance": 1,
- "job": 2
- },
- "renameByName": {
- "Value": "Value",
- "__name__": "Type"
- }
- }
- }
- ],
- "type": "table"
- },
- {
- "datasource": "prometheus",
- "description": "The amount of memory currently allocated by the BEAM.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "#EAB839",
- "value": 500000000
- },
- {
- "color": "red",
- "value": 1000000000
- }
- ]
- },
- "unit": "bytes"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 5,
- "w": 6,
- "x": 12,
- "y": 11
- },
- "id": 27,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_beam_memory_allocated_bytes{job=\"$job\", instance=\"$instance\"}",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Total Memory Usage",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The number of atoms currently in the atom table.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- },
- {
- "color": "#EAB839",
- "value": 150000
- },
- {
- "color": "red",
- "value": 300000
- }
- ]
- },
- "unit": "locale"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 5,
- "w": 6,
- "x": 18,
- "y": 11
- },
- "id": 30,
- "options": {
- "colorMode": "value",
- "graphMode": "area",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_beam_stats_atom_count{job=\"$job\", instance=\"$instance\"}",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Atom Count",
- "type": "stat"
- },
- {
- "collapsed": false,
- "datasource": null,
- "gridPos": {
- "h": 1,
- "w": 24,
- "x": 0,
- "y": 16
- },
- "id": 17,
- "panels": [],
- "title": "Details",
- "type": "row"
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "prometheus",
- "description": "Stats on the current memory usage.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [
- {
- "from": "",
- "id": 0,
- "text": "",
- "to": "",
- "type": 1
- }
- ],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "bytes"
- },
- "overrides": []
- },
- "fill": 1,
- "fillGradient": 0,
- "gridPos": {
- "h": 15,
- "w": 12,
- "x": 0,
- "y": 17
- },
- "hiddenSeries": false,
- "id": 21,
- "legend": {
- "avg": false,
- "current": false,
- "max": false,
- "min": 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": "pinchflat_prom_ex_beam_memory_allocated_bytes{job=\"$job\", instance=\"$instance\"}",
- "interval": "",
- "legendFormat": "Total Usage",
- "refId": "A"
- },
- {
- "expr": "pinchflat_prom_ex_beam_memory_atom_total_bytes{job=\"$job\", instance=\"$instance\"}",
- "interval": "",
- "legendFormat": "Atoms",
- "refId": "B"
- },
- {
- "expr": "pinchflat_prom_ex_beam_memory_binary_total_bytes{job=\"$job\", instance=\"$instance\"}",
- "interval": "",
- "legendFormat": "Binaries",
- "refId": "C"
- },
- {
- "expr": "pinchflat_prom_ex_beam_memory_code_total_bytes{job=\"$job\", instance=\"$instance\"}",
- "interval": "",
- "legendFormat": "Code",
- "refId": "D"
- },
- {
- "expr": "pinchflat_prom_ex_beam_memory_ets_total_bytes{job=\"$job\", instance=\"$instance\"}",
- "interval": "",
- "legendFormat": "ETS",
- "refId": "E"
- },
- {
- "expr": "pinchflat_prom_ex_beam_memory_processes_total_bytes{job=\"$job\", instance=\"$instance\"}",
- "interval": "",
- "legendFormat": "Processes",
- "refId": "F"
- },
- {
- "expr": "pinchflat_prom_ex_beam_memory_persistent_term_total_bytes{job=\"$job\", instance=\"$instance\"}",
- "interval": "",
- "legendFormat": "Persistent Term",
- "refId": "G"
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "Allocated Memory",
- "tooltip": {
- "shared": true,
- "sort": 2,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "bytes",
- "label": null,
- "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
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "prometheus",
- "description": "The number of garbage collection events that are occurring and the number of bytes reclaimed",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [
- {
- "from": "",
- "id": 0,
- "text": "",
- "to": "",
- "type": 1
- }
- ],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "fill": 1,
- "fillGradient": 0,
- "gridPos": {
- "h": 15,
- "w": 12,
- "x": 12,
- "y": 17
- },
- "hiddenSeries": false,
- "id": 34,
- "legend": {
- "avg": false,
- "current": false,
- "hideZero": 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": [
- {
- "alias": "Garbage Collections",
- "yaxis": 1
- },
- {
- "alias": "Bytes Reclaimed",
- "yaxis": 2
- }
- ],
- "spaceLength": 10,
- "stack": false,
- "steppedLine": false,
- "targets": [
- {
- "expr": "irate(pinchflat_prom_ex_beam_stats_gc_count{job=\"$job\", instance=\"$instance\"}[$interval])",
- "interval": "",
- "legendFormat": "Garbage Collections",
- "refId": "A"
- },
- {
- "expr": "irate(pinchflat_prom_ex_beam_stats_gc_reclaimed_bytes{job=\"$job\", instance=\"$instance\"}[$interval])",
- "instant": false,
- "interval": "",
- "legendFormat": "Bytes Reclaimed",
- "refId": "B"
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "Garbage Collection",
- "tooltip": {
- "shared": true,
- "sort": 2,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "locale",
- "label": "Garbage Collections",
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- },
- {
- "format": "bytes",
- "label": "Reclaimed Bytes",
- "logBase": 2,
- "max": null,
- "min": null,
- "show": true
- }
- ],
- "yaxis": {
- "align": false,
- "alignLevel": null
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "prometheus",
- "description": "Statistics regarding the normal scheduler.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [
- {
- "from": "",
- "id": 0,
- "text": "",
- "to": "",
- "type": 1
- }
- ],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "fill": 1,
- "fillGradient": 0,
- "gridPos": {
- "h": 15,
- "w": 12,
- "x": 0,
- "y": 32
- },
- "hiddenSeries": false,
- "id": 36,
- "legend": {
- "avg": false,
- "current": false,
- "hideZero": 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": "pinchflat_prom_ex_beam_stats_active_task_count{job=\"$job\", instance=\"$instance\", type=\"normal\"}",
- "interval": "",
- "legendFormat": "Normal Tasks",
- "refId": "A"
- },
- {
- "expr": "0 - pinchflat_prom_ex_beam_stats_run_queue_count{job=\"$job\", instance=\"$instance\", type=\"normal\"}",
- "instant": false,
- "interval": "",
- "legendFormat": "Normal Run Queue",
- "refId": "B"
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "Normal Scheduler Status",
- "tooltip": {
- "shared": true,
- "sort": 2,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "locale",
- "label": "Normal Run Queue (-) / Normal Tasks (+)",
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- },
- {
- "format": "locale",
- "label": "",
- "logBase": 1,
- "max": null,
- "min": null,
- "show": false
- }
- ],
- "yaxis": {
- "align": true,
- "alignLevel": null
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "prometheus",
- "description": "Statistics regarding the dirty schedulers.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [
- {
- "from": "",
- "id": 0,
- "text": "",
- "to": "",
- "type": 1
- }
- ],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "fill": 1,
- "fillGradient": 0,
- "gridPos": {
- "h": 15,
- "w": 12,
- "x": 12,
- "y": 32
- },
- "hiddenSeries": false,
- "id": 37,
- "legend": {
- "avg": false,
- "current": false,
- "hideZero": 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": "pinchflat_prom_ex_beam_stats_active_task_count{job=\"$job\", instance=\"$instance\", type=\"dirty\"}",
- "interval": "",
- "legendFormat": "Dirty Tasks",
- "refId": "C"
- },
- {
- "expr": "0 - pinchflat_prom_ex_beam_stats_run_queue_count{job=\"$job\", instance=\"$instance\", type=\"dirty\"}",
- "instant": false,
- "interval": "",
- "legendFormat": "Dirty Run Queue",
- "refId": "D"
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "Dirty Scheduler Status",
- "tooltip": {
- "shared": true,
- "sort": 2,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "locale",
- "label": "Dirty Run Queue (-) / Dirty Tasks (+)",
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- },
- {
- "format": "locale",
- "label": "",
- "logBase": 1,
- "max": null,
- "min": null,
- "show": false
- }
- ],
- "yaxis": {
- "align": true,
- "alignLevel": null
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "prometheus",
- "description": "The number of context switches that have occurred along with the number of reductions.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [
- {
- "from": "",
- "id": 0,
- "text": "",
- "to": "",
- "type": 1
- }
- ],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "fill": 1,
- "fillGradient": 0,
- "gridPos": {
- "h": 15,
- "w": 12,
- "x": 0,
- "y": 47
- },
- "hiddenSeries": false,
- "id": 35,
- "legend": {
- "avg": false,
- "current": false,
- "hideZero": 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": [
- {
- "alias": "Reductions",
- "yaxis": 1
- },
- {
- "alias": "Context Switches",
- "yaxis": 2
- }
- ],
- "spaceLength": 10,
- "stack": false,
- "steppedLine": false,
- "targets": [
- {
- "expr": "irate(pinchflat_prom_ex_beam_stats_reduction_count{job=\"$job\", instance=\"$instance\"}[$interval]) / 1000000",
- "interval": "",
- "legendFormat": "Reductions",
- "refId": "A"
- },
- {
- "expr": "irate(pinchflat_prom_ex_beam_stats_context_switch_count{job=\"$job\", instance=\"$instance\"}[$interval])",
- "instant": false,
- "interval": "",
- "legendFormat": "Context Switches",
- "refId": "B"
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "VM Load",
- "tooltip": {
- "shared": true,
- "sort": 2,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "locale",
- "label": "Reduction Count (in Millions)",
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- },
- {
- "format": "locale",
- "label": "Context Switch Count",
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- }
- ],
- "yaxis": {
- "align": false,
- "alignLevel": null
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "prometheus",
- "description": "The number of running BEAM processes.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [
- {
- "from": "",
- "id": 0,
- "text": "",
- "to": "",
- "type": 1
- }
- ],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "fill": 1,
- "fillGradient": 0,
- "gridPos": {
- "h": 15,
- "w": 12,
- "x": 12,
- "y": 47
- },
- "hiddenSeries": false,
- "id": 19,
- "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": "pinchflat_prom_ex_beam_stats_process_count{job=\"$job\", instance=\"$instance\"}",
- "interval": "",
- "legendFormat": "Active Processes",
- "refId": "A"
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "Active BEAM Processes",
- "tooltip": {
- "shared": true,
- "sort": 2,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "short",
- "label": "Processes",
- "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
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "prometheus",
- "description": "The number of atoms currently in the atom table",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [
- {
- "from": "",
- "id": 0,
- "text": "",
- "to": "",
- "type": 1
- }
- ],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "locale"
- },
- "overrides": []
- },
- "fill": 1,
- "fillGradient": 0,
- "gridPos": {
- "h": 15,
- "w": 12,
- "x": 0,
- "y": 62
- },
- "hiddenSeries": false,
- "id": 22,
- "legend": {
- "avg": false,
- "current": false,
- "max": false,
- "min": 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": "pinchflat_prom_ex_beam_stats_atom_count{job=\"$job\", instance=\"$instance\"}",
- "interval": "",
- "legendFormat": "Active ports",
- "refId": "A"
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "Atom Table Size",
- "tooltip": {
- "shared": true,
- "sort": 2,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "locale",
- "label": "Atoms",
- "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
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "prometheus",
- "description": "The number of bytes sent and received through ports.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [
- {
- "from": "",
- "id": 0,
- "text": "",
- "to": "",
- "type": 1
- }
- ],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "Bps"
- },
- "overrides": []
- },
- "fill": 1,
- "fillGradient": 0,
- "gridPos": {
- "h": 15,
- "w": 12,
- "x": 12,
- "y": 62
- },
- "hiddenSeries": false,
- "id": 33,
- "legend": {
- "avg": false,
- "current": false,
- "hideZero": false,
- "max": false,
- "min": 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": "0 - irate(pinchflat_prom_ex_beam_stats_port_io_byte_count{job=\"$job\", instance=\"$instance\", type=\"input\"}[$interval])",
- "interval": "",
- "legendFormat": "Data Received",
- "refId": "A"
- },
- {
- "expr": "irate(pinchflat_prom_ex_beam_stats_port_io_byte_count{job=\"$job\", instance=\"$instance\", type=\"output\"}[$interval])",
- "interval": "",
- "legendFormat": "Data Sent",
- "refId": "B"
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "Port IO",
- "tooltip": {
- "shared": true,
- "sort": 2,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "Bps",
- "label": "Data Received (-) / Data Sent (+)",
- "logBase": 1,
- "max": null,
- "min": null,
- "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": "prometheus",
- "description": "The number of active ETS tables.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [
- {
- "from": "",
- "id": 0,
- "text": "",
- "to": "",
- "type": 1
- }
- ],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "fill": 1,
- "fillGradient": 0,
- "gridPos": {
- "h": 15,
- "w": 12,
- "x": 0,
- "y": 77
- },
- "hiddenSeries": false,
- "id": 23,
- "legend": {
- "avg": false,
- "current": false,
- "max": false,
- "min": 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": "pinchflat_prom_ex_beam_stats_ets_count{job=\"$job\", instance=\"$instance\"}",
- "interval": "",
- "legendFormat": "Active ETS Tables",
- "refId": "A"
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "ETS Tables",
- "tooltip": {
- "shared": true,
- "sort": 2,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "short",
- "label": "Tables",
- "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
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "prometheus",
- "description": "The number of active ports.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [
- {
- "from": "",
- "id": 0,
- "text": "",
- "to": "",
- "type": 1
- }
- ],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "fill": 1,
- "fillGradient": 0,
- "gridPos": {
- "h": 15,
- "w": 12,
- "x": 12,
- "y": 77
- },
- "hiddenSeries": false,
- "id": 20,
- "legend": {
- "avg": false,
- "current": false,
- "max": false,
- "min": 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": "pinchflat_prom_ex_beam_stats_port_count{job=\"$job\", instance=\"$instance\"}",
- "interval": "",
- "legendFormat": "Active Ports",
- "refId": "A"
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "Active Ports",
- "tooltip": {
- "shared": true,
- "sort": 2,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "short",
- "label": "Ports",
- "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
- }
- }
- ],
- "refresh": "5s",
- "schemaVersion": 26,
- "style": "dark",
- "tags": ["PromEx", "BEAM", "pinchflat"],
- "templating": {
- "list": [
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_prom_ex_status_info, job)",
- "hide": 0,
- "includeAll": false,
- "label": "Prometheus Job",
- "multi": false,
- "name": "job",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_prom_ex_status_info, job)",
- "refresh": 2,
- "regex": "",
- "skipUrlSync": false,
- "sort": 6,
- "tagValuesQuery": "",
- "tags": [],
- "tagsQuery": "",
- "type": "query",
- "useTags": false
- },
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_prom_ex_status_info, instance)",
- "hide": 0,
- "includeAll": false,
- "label": "Application Instance",
- "multi": false,
- "name": "instance",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_prom_ex_status_info{job=\"$job\"}, 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": "30s",
- "value": "30s"
- },
- "hide": 0,
- "label": "Interval",
- "name": "interval",
- "options": [
- {
- "selected": false,
- "text": "15s",
- "value": "15s"
- },
- {
- "selected": true,
- "text": "30s",
- "value": "30s"
- },
- {
- "selected": false,
- "text": "1m",
- "value": "1m"
- },
- {
- "selected": false,
- "text": "5m",
- "value": "5m"
- },
- {
- "selected": false,
- "text": "15m",
- "value": "15m"
- },
- {
- "selected": false,
- "text": "30m",
- "value": "30m"
- },
- {
- "selected": false,
- "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": "Pinchflat - PromEx Beam Dashboard",
- "uid": "14B578642B07F5DEA133D4DE6A6AAD0A",
- "version": 1
-}
diff --git a/priv/grafana/ecto.json b/priv/grafana/ecto.json
deleted file mode 100644
index dc60a69..0000000
--- a/priv/grafana/ecto.json
+++ /dev/null
@@ -1,1247 +0,0 @@
-{
- "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", "pinchflat", "start"],
- "type": "tags"
- },
- {
- "datasource": "-- Grafana --",
- "enable": true,
- "hide": true,
- "iconColor": "#FF9830",
- "limit": 100,
- "name": "PromEx service stop",
- "showIn": 0,
- "tags": ["prom_ex", "pinchflat", "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": "prometheus",
- "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": "pinchflat_prom_ex_ecto_repo_query_idle_time_milliseconds_sum{instance=\"$instance\", job=\"$job\", repo=\"$repo\"} / pinchflat_prom_ex_ecto_repo_query_idle_time_milliseconds_count{instance=\"$instance\", job=\"$job\", repo=\"$repo\"}",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Connection Idle Time (Average)",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "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": "pinchflat_prom_ex_ecto_repo_query_queue_time_milliseconds_sum{instance=\"$instance\", job=\"$job\", repo=\"$repo\"} / pinchflat_prom_ex_ecto_repo_query_queue_time_milliseconds_count{instance=\"$instance\", job=\"$job\", repo=\"$repo\"}",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Connection Queue Time (Average)",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "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": "pinchflat_prom_ex_ecto_repo_query_decode_time_milliseconds_sum{instance=\"$instance\", job=\"$job\", repo=\"$repo\"} / pinchflat_prom_ex_ecto_repo_query_decode_time_milliseconds_count{instance=\"$instance\", job=\"$job\", repo=\"$repo\"}",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Connection Decode Time (Average)",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "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(pinchflat_prom_ex_ecto_repo_query_execution_time_milliseconds_sum{instance=\"$instance\", job=\"$job\", repo=\"$repo\"}) / sum(pinchflat_prom_ex_ecto_repo_query_execution_time_milliseconds_count{instance=\"$instance\", job=\"$job\", repo=\"$repo\"})",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Connection Execution Time (Average)",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The name of the Ecto Repo module",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "none"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 4,
- "w": 3,
- "x": 0,
- "y": 9
- },
- "id": 21,
- "options": {
- "colorMode": "value",
- "graphMode": "none",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "/^repo$/",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_ecto_repo_init_status_info{job=\"$job\", instance=\"$instance\", repo=\"$repo\"}",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Ecto Repo",
- "transformations": [
- {
- "id": "labelsToFields",
- "options": {}
- }
- ],
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The host of the database that the Repo is connected to.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "none"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 4,
- "w": 3,
- "x": 3,
- "y": 9
- },
- "id": 26,
- "options": {
- "colorMode": "value",
- "graphMode": "none",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "/^database_host$/",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_ecto_repo_init_status_info{job=\"$job\", instance=\"$instance\", repo=\"$repo\"}",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Database Host",
- "transformations": [
- {
- "id": "labelsToFields",
- "options": {}
- }
- ],
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The name of the database that the Repo is connected to.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "none"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 4,
- "w": 3,
- "x": 6,
- "y": 9
- },
- "id": 25,
- "options": {
- "colorMode": "value",
- "graphMode": "none",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "/^database_name$/",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_ecto_repo_init_status_info{job=\"$job\", instance=\"$instance\", repo=\"$repo\"}",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Database Name",
- "transformations": [
- {
- "id": "labelsToFields",
- "options": {}
- }
- ],
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The pool size that the repo was initialized with.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "none"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 4,
- "w": 3,
- "x": 9,
- "y": 9
- },
- "id": 27,
- "options": {
- "colorMode": "value",
- "graphMode": "none",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "/init_pool_size/",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_ecto_repo_init_pool_size{job=\"$job\", instance=\"$instance\", repo=\"$repo\"}",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Pool Size",
- "transformations": [
- {
- "id": "labelsToFields",
- "options": {}
- }
- ],
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The timeout duration that the Repo was initialized with.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "ms"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 4,
- "w": 3,
- "x": 12,
- "y": 9
- },
- "id": 28,
- "options": {
- "colorMode": "value",
- "graphMode": "none",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "/init_timeout_duration/",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_ecto_repo_init_timeout_duration{job=\"$job\", instance=\"$instance\", repo=\"$repo\"}",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Timeout Duration",
- "transformations": [
- {
- "id": "labelsToFields",
- "options": {}
- }
- ],
- "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": "prometheus",
- "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(pinchflat_prom_ex_ecto_repo_query_total_time_milliseconds_sum{job=\"$job\", instance=\"$instance\", repo=\"$repo\"}[$interval])) by(command) / sum(irate(pinchflat_prom_ex_ecto_repo_query_total_time_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_ecto_repo_query_execution_time_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_ecto_repo_query_execution_time_milliseconds_sum{job=\"$job\", instance=\"$instance\", repo=\"$repo\"}[$interval])) by(command) / sum(irate(pinchflat_prom_ex_ecto_repo_query_execution_time_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_ecto_repo_query_execution_time_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_ecto_repo_query_execution_time_milliseconds_count{instance=\"$instance\", job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_ecto_repo_query_results_returned_bucket{job=\"$job\", 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", "pinchflat"],
- "templating": {
- "list": [
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_prom_ex_status_info, job)",
- "hide": 0,
- "includeAll": false,
- "label": "Prometheus Job",
- "multi": false,
- "name": "job",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_prom_ex_status_info, job)",
- "refresh": 2,
- "regex": "",
- "skipUrlSync": false,
- "sort": 6,
- "tagValuesQuery": "",
- "tags": [],
- "tagsQuery": "",
- "type": "query",
- "useTags": false
- },
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_prom_ex_status_info, instance)",
- "hide": 0,
- "includeAll": false,
- "label": "Application Instance",
- "multi": false,
- "name": "instance",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_prom_ex_status_info{job=\"$job\"}, instance)",
- "refresh": 2,
- "regex": "",
- "skipUrlSync": false,
- "sort": 0,
- "tagValuesQuery": "",
- "tags": [],
- "tagsQuery": "",
- "type": "query",
- "useTags": false
- },
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_ecto_repo_init_status_info, repo)",
- "hide": 0,
- "includeAll": false,
- "label": "Ecto Repo",
- "multi": false,
- "name": "repo",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_ecto_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": "30s",
- "value": "30s"
- },
- "hide": 0,
- "label": "Interval",
- "name": "interval",
- "options": [
- {
- "selected": false,
- "text": "15s",
- "value": "15s"
- },
- {
- "selected": true,
- "text": "30s",
- "value": "30s"
- },
- {
- "selected": false,
- "text": "1m",
- "value": "1m"
- },
- {
- "selected": false,
- "text": "5m",
- "value": "5m"
- },
- {
- "selected": false,
- "text": "15m",
- "value": "15m"
- },
- {
- "selected": false,
- "text": "30m",
- "value": "30m"
- },
- {
- "selected": false,
- "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": "Pinchflat - PromEx Ecto Dashboard",
- "uid": "449823C137E6C016E4480ADDA42E94EE",
- "version": 1
-}
diff --git a/priv/grafana/oban.json b/priv/grafana/oban.json
deleted file mode 100644
index bf6c843..0000000
--- a/priv/grafana/oban.json
+++ /dev/null
@@ -1,2866 +0,0 @@
-{
- "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", "pinchflat", "start"],
- "type": "tags"
- },
- {
- "datasource": "-- Grafana --",
- "enable": true,
- "hide": true,
- "iconColor": "#FF9830",
- "limit": 100,
- "name": "PromEx service stop",
- "showIn": 0,
- "tags": ["prom_ex", "pinchflat", "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": "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": "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": "prometheus",
- "description": "The configuration of the selected Oban instance",
- "fieldConfig": {
- "defaults": {
- "custom": {
- "align": null,
- "displayMode": "auto"
- },
- "decimals": 1,
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "ms"
- },
- "overrides": [
- {
- "matcher": {
- "id": "byName",
- "options": "Config Setting"
- },
- "properties": [
- {
- "id": "mappings",
- "value": [
- {
- "from": "",
- "id": 1,
- "text": "Cooldown",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_oban_init_dispatch_cooldown_milliseconds"
- },
- {
- "from": "",
- "id": 2,
- "text": "Global Poll Interval",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_oban_init_poll_interval_milliseconds"
- },
- {
- "from": "",
- "id": 3,
- "text": "Shutdown Grace Period",
- "to": "",
- "type": 1,
- "value": "pinchflat_prom_ex_oban_init_shutdown_grace_period_milliseconds"
- }
- ]
- }
- ]
- }
- ]
- },
- "gridPos": {
- "h": 6,
- "w": 5,
- "x": 0,
- "y": 1
- },
- "id": 50,
- "options": {
- "showHeader": true
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "{__name__=~\"pinchflat_prom_ex_oban_init_shutdown_grace_period_milliseconds|pinchflat_prom_ex_oban_init_poll_interval_milliseconds|pinchflat_prom_ex_oban_init_dispatch_cooldown_milliseconds\", job=\"$job\", instance=\"$instance\", name=\"$oban\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Oban Time Limit Settings",
- "transformations": [
- {
- "id": "organize",
- "options": {
- "excludeByName": {
- "Time": true,
- "__name__": false,
- "instance": true,
- "job": true,
- "name": true
- },
- "indexByName": {},
- "renameByName": {
- "Value": "Time Value",
- "__name__": "Config Setting"
- }
- }
- }
- ],
- "type": "table"
- },
- {
- "datasource": "prometheus",
- "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": 12,
- "w": 7,
- "x": 5,
- "y": 1
- },
- "id": 60,
- "options": {
- "displayMode": "lcd",
- "orientation": "horizontal",
- "reduceOptions": {
- "calcs": ["lastNotNull"],
- "fields": "",
- "values": false
- },
- "showUnfilled": true
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_oban_queue_length_count{job=\"$job\", instance=\"$instance\", name=\"$oban\", state=\"available\"}",
- "instant": true,
- "interval": "",
- "legendFormat": "{{ queue }}",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Available Jobs in Queue",
- "type": "bargauge"
- },
- {
- "datasource": "prometheus",
- "description": "The configuration of the selected Oban instance",
- "fieldConfig": {
- "defaults": {
- "custom": {
- "align": null,
- "displayMode": "auto"
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 6,
- "w": 12,
- "x": 12,
- "y": 1
- },
- "id": 49,
- "options": {
- "showHeader": true,
- "sortBy": []
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "{__name__=\"pinchflat_prom_ex_oban_init_status_info\", job=\"$job\", instance=\"$instance\", name=\"$oban\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Oban Configuration",
- "transformations": [
- {
- "id": "organize",
- "options": {
- "excludeByName": {
- "Time": true,
- "Value": true,
- "__name__": true,
- "instance": true,
- "job": true
- },
- "indexByName": {},
- "renameByName": {
- "name": "Oban Instance",
- "node": "Node",
- "plugins": "Configured Plugins",
- "prefix": "Postgres Schema",
- "queues": "Configured Queues",
- "repo": "Ecto Repo"
- }
- }
- }
- ],
- "type": "table"
- },
- {
- "datasource": "prometheus",
- "description": "The configured concurrency limits for each of the queues under the Oban supervisor.",
- "fieldConfig": {
- "defaults": {
- "custom": {
- "align": null
- },
- "decimals": 1,
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "locale"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 6,
- "w": 5,
- "x": 0,
- "y": 7
- },
- "id": 36,
- "options": {
- "showHeader": true
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_oban_init_queue_concurrency_limit{instance=\"$instance\", job=\"$job\", name=\"$oban\"}",
- "format": "table",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Queue Concurrency Limits",
- "transformations": [
- {
- "id": "organize",
- "options": {
- "excludeByName": {
- "Time": true,
- "__name__": true,
- "instance": true,
- "job": true,
- "name": true
- },
- "indexByName": {},
- "renameByName": {
- "Value": "Concurrent Workers",
- "queue": "Queue"
- }
- }
- }
- ],
- "type": "table"
- },
- {
- "datasource": "prometheus",
- "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": 12,
- "y": 7
- },
- "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(pinchflat_prom_ex_oban_job_processing_duration_milliseconds_count{instance=\"$instance\", job=\"$job\", name=\"$oban\"}[$interval])))",
- "interval": "",
- "legendFormat": "",
- "refId": "A",
- "format": "table"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Processed Jobs (by $interval interval)",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "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": 16,
- "y": 7
- },
- "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(pinchflat_prom_ex_oban_job_exception_duration_milliseconds_count{instance=\"$instance\", job=\"$job\", name=\"$oban\"}[$interval])))",
- "interval": "",
- "legendFormat": "",
- "refId": "A",
- "format": "table"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Job Errors (by $interval interval)",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "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": 20,
- "y": 7
- },
- "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(pinchflat_prom_ex_oban_producer_dispatched_count_count{instance=\"$instance\", job=\"$job\", name=\"$oban\"}[$interval])))",
- "interval": "",
- "legendFormat": "",
- "refId": "A",
- "format": "table"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Jobs Enqueued (by $interval interval)",
- "type": "stat"
- },
- {
- "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": "prometheus",
- "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(pinchflat_prom_ex_oban_job_processing_duration_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_job_queue_time_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_job_processing_duration_milliseconds_sum{job=\"$job\", instance=\"$instance\", name=\"$oban\"}[$interval]) / irate(pinchflat_prom_ex_oban_job_processing_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_job_queue_time_milliseconds_sum{job=\"$job\", instance=\"$instance\", name=\"$oban\"}[$interval]) / irate(pinchflat_prom_ex_oban_job_queue_time_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_job_complete_attempts_sum{job=\"$job\", instance=\"$instance\", name=\"$oban\"}[$interval]) / irate(pinchflat_prom_ex_oban_job_complete_attempts_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_job_exception_duration_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_job_exception_queue_time_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_job_exception_duration_milliseconds_sum{job=\"$job\", instance=\"$instance\", name=\"$oban\"}[$interval]) / irate(pinchflat_prom_ex_oban_job_exception_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_job_exception_queue_time_milliseconds_sum{job=\"$job\", instance=\"$instance\", name=\"$oban\"}[$interval]) / irate(pinchflat_prom_ex_oban_job_exception_queue_time_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_job_exception_attempts_sum{job=\"$job\", instance=\"$instance\", name=\"$oban\"}[$interval]) / irate(pinchflat_prom_ex_oban_job_exception_attempts_count{job=\"$job\", 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": "prometheus",
- "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": "pinchflat_prom_ex_oban_queue_length_count{job=\"$job\", 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": "prometheus",
- "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": "pinchflat_prom_ex_oban_queue_length_count{job=\"$job\", 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": "prometheus",
- "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": "pinchflat_prom_ex_oban_queue_length_count{job=\"$job\", 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": "prometheus",
- "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": "pinchflat_prom_ex_oban_queue_length_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_producer_duration_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_producer_dispatched_count_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_producer_duration_milliseconds_sum{job=\"$job\", instance=\"$instance\", name=\"$oban\"}[$interval]) / irate(pinchflat_prom_ex_oban_producer_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_producer_dispatched_count_sum{job=\"$job\", instance=\"$instance\", name=\"$oban\"}[$interval]) / irate(pinchflat_prom_ex_oban_producer_dispatched_count_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_producer_exception_duration_milliseconds_sum{job=\"$job\", instance=\"$instance\", name=\"$oban\"}[$interval]) / irate(pinchflat_prom_ex_oban_producer_exception_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_circuit_trip_total{job=\"$job\", instance=\"$instance\", name=\"$oban\"}[1h])",
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Circuit Trip Events (last 1 hour)",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "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": "pinchflat_prom_ex_oban_circuit_trip_total{job=\"$job\", instance=\"$instance\", name=\"$oban\"}",
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Total Circuit Trip Events",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "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(pinchflat_prom_ex_oban_circuit_open_total{job=\"$job\", instance=\"$instance\", name=\"$oban\"}[1h])",
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Circuit Open Events (last 1 hour)",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "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": "pinchflat_prom_ex_oban_circuit_open_total{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_circuit_trip_total{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_oban_circuit_open_total{job=\"$job\", 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", "pinchflat"],
- "templating": {
- "list": [
- {
- "allValue": null,
- "current": {
- "selected": false,
- "text": "elixir_app",
- "value": "elixir_app"
- },
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_prom_ex_status_info, job)",
- "hide": 0,
- "includeAll": false,
- "label": "Prometheus Job",
- "multi": false,
- "name": "job",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_prom_ex_status_info, job)",
- "refresh": 2,
- "regex": "",
- "skipUrlSync": false,
- "sort": 6,
- "tagValuesQuery": "",
- "tags": [],
- "tagsQuery": "",
- "type": "query",
- "useTags": false
- },
- {
- "allValue": null,
- "current": {
- "selected": false,
- "text": "elixir_app_one:4000",
- "value": "elixir_app_one:4000"
- },
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_prom_ex_status_info, instance)",
- "hide": 0,
- "includeAll": false,
- "label": "Application Instance",
- "multi": false,
- "name": "instance",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_prom_ex_status_info{job=\"$job\"}, instance)",
- "refresh": 2,
- "regex": "",
- "skipUrlSync": false,
- "sort": 0,
- "tagValuesQuery": "",
- "tags": [],
- "tagsQuery": "",
- "type": "query",
- "useTags": false
- },
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_oban_init_status_info, name)",
- "hide": 0,
- "includeAll": false,
- "label": "Oban Instance",
- "multi": false,
- "name": "oban",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_oban_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": "30s",
- "value": "30s"
- },
- "hide": 0,
- "label": "Interval",
- "name": "interval",
- "options": [
- {
- "selected": false,
- "text": "15s",
- "value": "15s"
- },
- {
- "selected": true,
- "text": "30s",
- "value": "30s"
- },
- {
- "selected": false,
- "text": "1m",
- "value": "1m"
- },
- {
- "selected": false,
- "text": "5m",
- "value": "5m"
- },
- {
- "selected": false,
- "text": "15m",
- "value": "15m"
- },
- {
- "selected": false,
- "text": "30m",
- "value": "30m"
- },
- {
- "selected": false,
- "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": "Pinchflat - PromEx Oban Dashboard",
- "uid": "AF9058A0496CA7FF8D4FA747EEDC7AF3",
- "version": 1
-}
diff --git a/priv/grafana/phoenix.json b/priv/grafana/phoenix.json
deleted file mode 100644
index 95dfa63..0000000
--- a/priv/grafana/phoenix.json
+++ /dev/null
@@ -1,1978 +0,0 @@
-{
- "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", "pinchflat", "start"],
- "type": "tags"
- },
- {
- "datasource": "-- Grafana --",
- "enable": true,
- "hide": true,
- "iconColor": "#FF9830",
- "limit": 100,
- "name": "PromEx service stop",
- "showIn": 0,
- "tags": ["prom_ex", "pinchflat", "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": "prometheus",
- "description": "The Phoenix Endpoint module currently active for config metrics.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "none"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 4,
- "w": 8,
- "x": 0,
- "y": 1
- },
- "id": 32,
- "options": {
- "colorMode": "value",
- "graphMode": "none",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "/^endpoint$/",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_phoenix_endpoint_port_info{job=\"$job\", instance=\"$instance\", endpoint=\"$endpoint\"}",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Server Endpoint",
- "transformations": [
- {
- "id": "labelsToFields",
- "options": {}
- }
- ],
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The port that the server is listening on.",
- "fieldConfig": {
- "defaults": {
- "custom": {},
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- },
- "unit": "none"
- },
- "overrides": []
- },
- "gridPos": {
- "h": 4,
- "w": 8,
- "x": 8,
- "y": 1
- },
- "id": 30,
- "options": {
- "colorMode": "value",
- "graphMode": "none",
- "justifyMode": "center",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["last"],
- "fields": "/^port$/",
- "values": false
- },
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "expr": "pinchflat_prom_ex_phoenix_endpoint_port_info{job=\"$job\", instance=\"$instance\", endpoint=\"$endpoint\"}",
- "instant": true,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Server Port",
- "transformations": [
- {
- "id": "labelsToFields",
- "options": {}
- }
- ],
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "description": "The URL that the server is configured to be accessed from.",
- "fieldConfig": {
- "defaults": {
- "color": {
- "mode": "thresholds"
- },
- "mappings": [],
- "thresholds": {
- "mode": "absolute",
- "steps": [
- {
- "color": "green",
- "value": null
- }
- ]
- }
- },
- "overrides": []
- },
- "gridPos": {
- "h": 4,
- "w": 8,
- "x": 16,
- "y": 1
- },
- "id": 31,
- "options": {
- "colorMode": "value",
- "graphMode": "none",
- "justifyMode": "auto",
- "orientation": "auto",
- "reduceOptions": {
- "calcs": ["lastNotNull"],
- "fields": "/^url$/",
- "values": false
- },
- "text": {},
- "textMode": "auto"
- },
- "pluginVersion": "7.1.3",
- "targets": [
- {
- "exemplar": true,
- "expr": "pinchflat_prom_ex_phoenix_endpoint_url_info{job=\"$job\", instance=\"$instance\", endpoint=\"$endpoint\"}",
- "format": "table",
- "interval": "",
- "legendFormat": "",
- "queryType": "randomWalk",
- "refId": "A"
- }
- ],
- "title": "Server URL",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_request_duration_milliseconds_bucket{job=\"$job\", instance=\"$instance\", le=\"500\", status=~\"2..\"}[24h])) + \n (sum(increase(pinchflat_prom_ex_phoenix_http_request_duration_milliseconds_bucket{job=\"$job\", instance=\"$instance\", le=\"1000\", status=~\"2..\"}[24h])) - sum(increase(pinchflat_prom_ex_phoenix_http_request_duration_milliseconds_bucket{job=\"$job\", instance=\"$instance\", le=\"500\", status=~\"2..\"}[24h]))) / 2\n ) \n / \n sum(increase(pinchflat_prom_ex_phoenix_http_request_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_requests_total{job=\"$job\", instance=\"$instance\", status=~\"4..|5..\"}[24h])) / sum(increase(pinchflat_prom_ex_phoenix_http_requests_total{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_response_size_bytes_sum{job=\"$job\", instance=\"$instance\"}[24h]))",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Data Transferred (Last 24h)",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_requests_total{job=\"$job\", instance=\"$instance\"}[24h])))",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Total Requests Received (Last 24h)",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_request_duration_milliseconds_bucket{job=\"$job\", instance=\"$instance\", le=\"500\", status=~\"2..\"}[1h])) + \n (sum(increase(pinchflat_prom_ex_phoenix_http_request_duration_milliseconds_bucket{job=\"$job\", instance=\"$instance\", le=\"1000\", status=~\"2..\"}[1h])) - sum(increase(pinchflat_prom_ex_phoenix_http_request_duration_milliseconds_bucket{job=\"$job\", instance=\"$instance\", le=\"500\", status=~\"2..\"}[1h]))) / 2\n ) \n / \n sum(increase(pinchflat_prom_ex_phoenix_http_request_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_requests_total{job=\"$job\", instance=\"$instance\", status=~\"4..|5..\"}[1h])) / sum(increase(pinchflat_prom_ex_phoenix_http_requests_total{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_response_size_bytes_sum{job=\"$job\", instance=\"$instance\"}[1h]))",
- "instant": false,
- "interval": "",
- "legendFormat": "",
- "refId": "A"
- }
- ],
- "timeFrom": null,
- "timeShift": null,
- "title": "Data Transferred (Last 1h)",
- "type": "stat"
- },
- {
- "datasource": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_requests_total{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_request_duration_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_response_size_bytes_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_request_duration_milliseconds_sum{job=\"$job\", instance=\"$instance\"}[$interval])) by(path, status) / sum(irate(pinchflat_prom_ex_phoenix_http_request_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_response_size_bytes_sum{job=\"$job\", instance=\"$instance\"}[$interval])) by(path, status) / sum(irate(pinchflat_prom_ex_phoenix_http_response_size_bytes_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_requests_total{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_http_requests_total{status=~\"2..\", job=\"$job\", instance=\"$instance\"}[$interval]))",
- "interval": "",
- "legendFormat": "2xx",
- "refId": "A"
- },
- {
- "expr": "sum(irate(pinchflat_prom_ex_phoenix_http_requests_total{status=~\"4..\", job=\"$job\", instance=\"$instance\"}[$interval]))",
- "interval": "",
- "legendFormat": "4xx",
- "refId": "B"
- },
- {
- "expr": "sum(irate(pinchflat_prom_ex_phoenix_http_requests_total{status=~\"5..\", job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_channel_joined_total{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_channel_handled_in_duration_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_channel_handled_in_duration_milliseconds_sum{job=\"$job\", instance=\"$instance\", endpoint=\"$endpoint\"}[$interval]) / irate(pinchflat_prom_ex_phoenix_channel_handled_in_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_socket_connected_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_socket_connected_duration_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_socket_connected_duration_milliseconds_sum{job=\"$job\", instance=\"$instance\", endpoint=\"$endpoint\"}[$interval]) / irate(pinchflat_prom_ex_phoenix_socket_connected_duration_milliseconds_count{job=\"$job\", 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", "pinchflat"],
- "templating": {
- "list": [
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_prom_ex_status_info, job)",
- "hide": 0,
- "includeAll": false,
- "label": "Prometheus Job",
- "multi": false,
- "name": "job",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_prom_ex_status_info, job)",
- "refresh": 2,
- "regex": "",
- "skipUrlSync": false,
- "sort": 6,
- "tagValuesQuery": "",
- "tags": [],
- "tagsQuery": "",
- "type": "query",
- "useTags": false
- },
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_prom_ex_status_info, instance)",
- "hide": 0,
- "includeAll": false,
- "label": "Application Instance",
- "multi": false,
- "name": "instance",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_prom_ex_status_info{job=\"$job\"}, instance)",
- "refresh": 2,
- "regex": "",
- "skipUrlSync": false,
- "sort": 0,
- "tagValuesQuery": "",
- "tagsQuery": "",
- "type": "query",
- "useTags": false
- },
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_phoenix_endpoint_port_info, endpoint)",
- "hide": 0,
- "includeAll": false,
- "label": "Phoenix Endpoint",
- "multi": false,
- "name": "endpoint",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_phoenix_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": "30s",
- "value": "30s"
- },
- "hide": 0,
- "label": "Interval",
- "name": "interval",
- "options": [
- {
- "selected": false,
- "text": "15s",
- "value": "15s"
- },
- {
- "selected": true,
- "text": "30s",
- "value": "30s"
- },
- {
- "selected": false,
- "text": "1m",
- "value": "1m"
- },
- {
- "selected": false,
- "text": "5m",
- "value": "5m"
- },
- {
- "selected": false,
- "text": "15m",
- "value": "15m"
- },
- {
- "selected": false,
- "text": "30m",
- "value": "30m"
- },
- {
- "selected": false,
- "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": "Pinchflat - PromEx Phoenix Dashboard",
- "uid": "970297EC2ACFCF6777A4D3444B63C036",
- "version": 1
-}
diff --git a/priv/grafana/phoenix_live_view.json b/priv/grafana/phoenix_live_view.json
deleted file mode 100644
index edef6f7..0000000
--- a/priv/grafana/phoenix_live_view.json
+++ /dev/null
@@ -1,1380 +0,0 @@
-{
- "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", "pinchflat", "start"],
- "type": "tags"
- },
- {
- "datasource": "-- Grafana --",
- "enable": true,
- "hide": true,
- "iconColor": "#FF9830",
- "limit": 100,
- "name": "PromEx service stop",
- "showIn": 0,
- "tags": ["prom_ex", "pinchflat", "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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_mount_duration_milliseconds_count{job=\"$job\", instance=\"$instance\"}[24h])) / \n(\n sum(increase(pinchflat_prom_ex_phoenix_live_view_mount_duration_milliseconds_count{job=\"$job\", instance=\"$instance\"}[24h])) + \n (sum(increase(pinchflat_prom_ex_phoenix_live_view_mount_exception_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_mount_duration_milliseconds_count{job=\"$job\", instance=\"$instance\"}[24h])) or vector(0)) + (sum(increase(pinchflat_prom_ex_phoenix_live_view_mount_exception_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_handle_event_duration_milliseconds_count{job=\"$job\", instance=\"$instance\"}[24h])) / \n(\n sum(increase(pinchflat_prom_ex_phoenix_live_view_handle_event_duration_milliseconds_count{job=\"$job\", instance=\"$instance\"}[24h])) + \n (sum(increase(pinchflat_prom_ex_phoenix_live_view_handle_event_exception_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_handle_event_exception_duration_milliseconds_count{job=\"$job\", instance=\"$instance\"}[24h])) or vector(0)) + (sum(increase(pinchflat_prom_ex_phoenix_live_view_handle_event_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_mount_duration_milliseconds_count{job=\"$job\", instance=\"$instance\"}[1h])) / \n(\n sum(increase(pinchflat_prom_ex_phoenix_live_view_mount_duration_milliseconds_count{job=\"$job\", instance=\"$instance\"}[1h])) + \n (sum(increase(pinchflat_prom_ex_phoenix_live_view_mount_exception_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_mount_duration_milliseconds_count{job=\"$job\", instance=\"$instance\"}[1h])) or vector(0)) + (sum(increase(pinchflat_prom_ex_phoenix_live_view_mount_exception_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_handle_event_duration_milliseconds_count{job=\"$job\", instance=\"$instance\"}[1h])) / \n(\n sum(increase(pinchflat_prom_ex_phoenix_live_view_handle_event_duration_milliseconds_count{job=\"$job\", instance=\"$instance\"}[1h])) + \n (sum(increase(pinchflat_prom_ex_phoenix_live_view_handle_event_exception_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_handle_event_exception_duration_milliseconds_count{job=\"$job\", instance=\"$instance\"}[1h])) or vector(0)) + (sum(increase(pinchflat_prom_ex_phoenix_live_view_handle_event_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_mount_duration_milliseconds_sum{job=\"$job\", instance=\"$instance\"}[$interval])) by(action, module) / sum(irate(pinchflat_prom_ex_phoenix_live_view_mount_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_mount_exception_duration_milliseconds_sum{job=\"$job\", instance=\"$instance\"}[$interval])) by(action, module, kind, reason) / sum(irate(pinchflat_prom_ex_phoenix_live_view_mount_exception_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_mount_duration_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_mount_exception_duration_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_handle_event_duration_milliseconds_sum{job=\"$job\", instance=\"$instance\"}[$interval])) by(action, module, event) / sum(irate(pinchflat_prom_ex_phoenix_live_view_handle_event_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_handle_event_exception_duration_milliseconds_sum{job=\"$job\", instance=\"$instance\"}[$interval])) by(event, action, module, kind, reason) / sum(irate(pinchflat_prom_ex_phoenix_live_view_handle_event_exception_duration_milliseconds_count{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_handle_event_duration_milliseconds_bucket{job=\"$job\", 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": "prometheus",
- "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(pinchflat_prom_ex_phoenix_live_view_handle_event_exception_duration_milliseconds_bucket{job=\"$job\", 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", "pinchflat"],
- "templating": {
- "list": [
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_prom_ex_status_info, job)",
- "hide": 0,
- "includeAll": false,
- "label": "Prometheus Job",
- "multi": false,
- "name": "job",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_prom_ex_status_info, job)",
- "refresh": 2,
- "regex": "",
- "skipUrlSync": false,
- "sort": 6,
- "tagValuesQuery": "",
- "tags": [],
- "tagsQuery": "",
- "type": "query",
- "useTags": false
- },
- {
- "allValue": null,
- "datasource": "prometheus",
- "definition": "label_values(pinchflat_prom_ex_prom_ex_status_info, instance)",
- "hide": 0,
- "includeAll": false,
- "label": "Application Instance",
- "multi": false,
- "name": "instance",
- "options": [],
- "query": "label_values(pinchflat_prom_ex_prom_ex_status_info{job=\"$job\"}, 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": "30s",
- "value": "30s"
- },
- "hide": 0,
- "label": "Interval",
- "name": "interval",
- "options": [
- {
- "selected": false,
- "text": "15s",
- "value": "15s"
- },
- {
- "selected": true,
- "text": "30s",
- "value": "30s"
- },
- {
- "selected": false,
- "text": "1m",
- "value": "1m"
- },
- {
- "selected": false,
- "text": "5m",
- "value": "5m"
- },
- {
- "selected": false,
- "text": "15m",
- "value": "15m"
- },
- {
- "selected": false,
- "text": "30m",
- "value": "30m"
- },
- {
- "selected": false,
- "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": "Pinchflat - PromEx PhoenixLiveView Dashboard",
- "uid": "57C5565313BA3CBE98CC2A2F8C18248F",
- "version": 1
-}
diff --git a/priv/repo/erd.png b/priv/repo/erd.png
index 4f06954..270eca5 100644
Binary files a/priv/repo/erd.png and b/priv/repo/erd.png differ
diff --git a/priv/repo/migrations/20250110231704_add_extractor_sleep_interval_to_settings.exs b/priv/repo/migrations/20250110231704_add_extractor_sleep_interval_to_settings.exs
deleted file mode 100644
index 17dd735..0000000
--- a/priv/repo/migrations/20250110231704_add_extractor_sleep_interval_to_settings.exs
+++ /dev/null
@@ -1,9 +0,0 @@
-defmodule Pinchflat.Repo.Migrations.AddExtractorSleepIntervalToSettings do
- use Ecto.Migration
-
- def change do
- alter table(:settings) do
- add :extractor_sleep_interval_seconds, :number, null: false, default: 0
- end
- end
-end
diff --git a/priv/repo/migrations/20250210201413_add_last_error_to_media_item.exs b/priv/repo/migrations/20250210201413_add_last_error_to_media_item.exs
deleted file mode 100644
index d8723ba..0000000
--- a/priv/repo/migrations/20250210201413_add_last_error_to_media_item.exs
+++ /dev/null
@@ -1,9 +0,0 @@
-defmodule Pinchflat.Repo.Migrations.AddLastErrorToMediaItem do
- use Ecto.Migration
-
- def change do
- alter table(:media_items) do
- add :last_error, :string
- end
- end
-end
diff --git a/priv/repo/migrations/20250304185528_add_cookie_behaviour_to_sources.exs b/priv/repo/migrations/20250304185528_add_cookie_behaviour_to_sources.exs
deleted file mode 100644
index 0eb9eb0..0000000
--- a/priv/repo/migrations/20250304185528_add_cookie_behaviour_to_sources.exs
+++ /dev/null
@@ -1,18 +0,0 @@
-defmodule Pinchflat.Repo.Migrations.AddCookieBehaviourToSources do
- use Ecto.Migration
-
- def change do
- alter table(:sources) do
- add :cookie_behaviour, :string, null: false, default: "disabled"
- end
-
- execute(
- "UPDATE sources SET cookie_behaviour = 'all_operations' WHERE use_cookies = TRUE",
- "UPDATE sources SET use_cookies = TRUE WHERE cookie_behaviour = 'all_operations'"
- )
-
- alter table(:sources) do
- remove :use_cookies, :boolean, null: false, default: false
- end
- end
-end
diff --git a/priv/repo/migrations/20250311222451_add_rate_limit_speed_to_settings.exs b/priv/repo/migrations/20250311222451_add_rate_limit_speed_to_settings.exs
deleted file mode 100644
index fd7cc82..0000000
--- a/priv/repo/migrations/20250311222451_add_rate_limit_speed_to_settings.exs
+++ /dev/null
@@ -1,9 +0,0 @@
-defmodule Pinchflat.Repo.Migrations.AddRateLimitSpeedToSettings do
- use Ecto.Migration
-
- def change do
- alter table(:settings) do
- add :download_throughput_limit, :string
- end
- end
-end
diff --git a/priv/repo/migrations/20250317213740_add_restrict_filenames_to_settings.exs b/priv/repo/migrations/20250317213740_add_restrict_filenames_to_settings.exs
deleted file mode 100644
index 6a6591d..0000000
--- a/priv/repo/migrations/20250317213740_add_restrict_filenames_to_settings.exs
+++ /dev/null
@@ -1,9 +0,0 @@
-defmodule Pinchflat.Repo.Migrations.AddRestrictFilenamesToSettings do
- use Ecto.Migration
-
- def change do
- alter table(:settings) do
- add :restrict_filenames, :boolean, default: false
- end
- end
-end
diff --git a/rel/overlays/bin/docker_start b/rel/overlays/bin/docker_start
index b60c6d3..4f2d132 100755
--- a/rel/overlays/bin/docker_start
+++ b/rel/overlays/bin/docker_start
@@ -6,9 +6,6 @@ if [ $? -ne 0 ]; then
exit 1
fi
-echo "Setting umask to ${UMASK}"
-umask ${UMASK}
-
/app/bin/migrate
cd -P -- "$(dirname -- "$0")"
diff --git a/test/pinchflat/boot/post_boot_startup_tasks_test.exs b/test/pinchflat/boot/post_boot_startup_tasks_test.exs
deleted file mode 100644
index 43a7086..0000000
--- a/test/pinchflat/boot/post_boot_startup_tasks_test.exs
+++ /dev/null
@@ -1,16 +0,0 @@
-defmodule Pinchflat.Boot.PostBootStartupTasksTest do
- use Pinchflat.DataCase
-
- alias Pinchflat.YtDlp.UpdateWorker
- alias Pinchflat.Boot.PostBootStartupTasks
-
- describe "update_yt_dlp" do
- test "enqueues an update job" do
- assert [] = all_enqueued(worker: UpdateWorker)
-
- PostBootStartupTasks.init(%{})
-
- assert [%Oban.Job{}] = all_enqueued(worker: UpdateWorker)
- end
- end
-end
diff --git a/test/pinchflat/downloading/downloading_helpers_test.exs b/test/pinchflat/downloading/downloading_helpers_test.exs
index cc2f62a..5ab4f40 100644
--- a/test/pinchflat/downloading/downloading_helpers_test.exs
+++ b/test/pinchflat/downloading/downloading_helpers_test.exs
@@ -10,7 +10,7 @@ defmodule Pinchflat.Downloading.DownloadingHelpersTest do
alias Pinchflat.Downloading.MediaDownloadWorker
describe "enqueue_pending_download_tasks/1" do
- test "enqueues a job for each pending media item" do
+ test "it enqueues a job for each pending media item" do
source = source_fixture()
media_item = media_item_fixture(source_id: source.id, media_filepath: nil)
@@ -19,7 +19,7 @@ defmodule Pinchflat.Downloading.DownloadingHelpersTest do
assert_enqueued(worker: MediaDownloadWorker, args: %{"id" => media_item.id})
end
- test "does not enqueue a job for media items with a filepath" do
+ test "it does not enqueue a job for media items with a filepath" do
source = source_fixture()
_media_item = media_item_fixture(source_id: source.id, media_filepath: "some/filepath.mp4")
@@ -28,7 +28,7 @@ defmodule Pinchflat.Downloading.DownloadingHelpersTest do
refute_enqueued(worker: MediaDownloadWorker)
end
- test "attaches a task to each enqueued job" do
+ test "it attaches a task to each enqueued job" do
source = source_fixture()
media_item = media_item_fixture(source_id: source.id, media_filepath: nil)
@@ -39,7 +39,7 @@ defmodule Pinchflat.Downloading.DownloadingHelpersTest do
assert [_] = Tasks.list_tasks_for(media_item)
end
- test "does not create a job if the source is set to not download" do
+ test "it does not create a job if the source is set to not download" do
source = source_fixture(download_media: false)
assert :ok = DownloadingHelpers.enqueue_pending_download_tasks(source)
@@ -47,26 +47,17 @@ defmodule Pinchflat.Downloading.DownloadingHelpersTest do
refute_enqueued(worker: MediaDownloadWorker)
end
- test "does not attach tasks if the source is set to not download" do
+ test "it does not attach tasks if the source is set to not download" do
source = source_fixture(download_media: false)
media_item = media_item_fixture(source_id: source.id, media_filepath: nil)
assert :ok = DownloadingHelpers.enqueue_pending_download_tasks(source)
assert [] = Tasks.list_tasks_for(media_item)
end
-
- test "can pass job options" do
- source = source_fixture()
- media_item = media_item_fixture(source_id: source.id, media_filepath: nil)
-
- assert :ok = DownloadingHelpers.enqueue_pending_download_tasks(source, priority: 1)
-
- assert_enqueued(worker: MediaDownloadWorker, args: %{"id" => media_item.id}, priority: 1)
- end
end
describe "dequeue_pending_download_tasks/1" do
- test "deletes all pending tasks for a source's media items" do
+ test "it deletes all pending tasks for a source's media items" do
source = source_fixture()
media_item = media_item_fixture(source_id: source.id, media_filepath: nil)
@@ -118,14 +109,6 @@ defmodule Pinchflat.Downloading.DownloadingHelpersTest do
refute_enqueued(worker: MediaDownloadWorker)
end
-
- test "can pass job options" do
- media_item = media_item_fixture(media_filepath: nil)
-
- assert {:ok, _} = DownloadingHelpers.kickoff_download_if_pending(media_item, priority: 1)
-
- assert_enqueued(worker: MediaDownloadWorker, args: %{"id" => media_item.id}, priority: 1)
- end
end
describe "kickoff_redownload_for_existing_media/1" do
diff --git a/test/pinchflat/downloading/media_download_worker_test.exs b/test/pinchflat/downloading/media_download_worker_test.exs
index 9b2e0f8..6932fcb 100644
--- a/test/pinchflat/downloading/media_download_worker_test.exs
+++ b/test/pinchflat/downloading/media_download_worker_test.exs
@@ -46,20 +46,13 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do
assert_enqueued(worker: MediaDownloadWorker, args: %{"id" => media_item.id, "force" => true})
end
- test "has a priority of 5 by default", %{media_item: media_item} do
- assert {:ok, _} = MediaDownloadWorker.kickoff_with_task(media_item)
+ test "can be called with additional job options", %{media_item: media_item} do
+ job_opts = [max_attempts: 5]
+
+ assert {:ok, _} = MediaDownloadWorker.kickoff_with_task(media_item, %{}, job_opts)
[job] = all_enqueued(worker: MediaDownloadWorker, args: %{"id" => media_item.id})
-
- assert job.priority == 5
- end
-
- test "priority can be set", %{media_item: media_item} do
- assert {:ok, _} = MediaDownloadWorker.kickoff_with_task(media_item, %{}, priority: 0)
-
- [job] = all_enqueued(worker: MediaDownloadWorker, args: %{"id" => media_item.id})
-
- assert job.priority == 0
+ assert job.max_attempts == 5
end
end
@@ -74,7 +67,7 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do
:ok
end
- test "saves attributes to the media_item", %{media_item: media_item} do
+ test "it saves attributes to the media_item", %{media_item: media_item} do
assert media_item.media_filepath == nil
perform_job(MediaDownloadWorker, %{id: media_item.id})
media_item = Repo.reload(media_item)
@@ -82,20 +75,20 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do
assert media_item.media_filepath != nil
end
- test "saves the metadata to the media_item", %{media_item: media_item} do
+ test "it saves the metadata to the media_item", %{media_item: media_item} do
assert media_item.metadata == nil
perform_job(MediaDownloadWorker, %{id: media_item.id})
assert Repo.reload(media_item).metadata != nil
end
- test "won't double-schedule downloading jobs", %{media_item: media_item} do
+ test "it won't double-schedule downloading jobs", %{media_item: media_item} do
Oban.insert(MediaDownloadWorker.new(%{id: media_item.id}))
Oban.insert(MediaDownloadWorker.new(%{id: media_item.id}))
assert [_] = all_enqueued(worker: MediaDownloadWorker)
end
- test "sets the job to retryable if the download fails", %{media_item: media_item} do
+ test "it sets the job to retryable if the download fails", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, 2, fn
_url, :get_downloadable_status, _opts, _ot, _addl -> {:ok, "{}"}
_url, :download, _opts, _ot, _addl -> {:error, "error"}
@@ -134,36 +127,7 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do
end)
end
- test "does not set the job to retryable if youtube thinks you're a bot", %{media_item: media_item} do
- expect(YtDlpRunnerMock, :run, 2, fn
- _url, :get_downloadable_status, _opts, _ot, _addl -> {:ok, "{}"}
- _url, :download, _opts, _ot, _addl -> {:error, "Sign in to confirm you're not a bot", 1}
- end)
-
- Oban.Testing.with_testing_mode(:inline, fn ->
- {:ok, job} = Oban.insert(MediaDownloadWorker.new(%{id: media_item.id, quality_upgrade?: true}))
-
- assert job.state == "completed"
- end)
- end
-
- test "does not set the job to retryable you aren't a member", %{media_item: media_item} do
- expect(YtDlpRunnerMock, :run, 2, fn
- _url, :get_downloadable_status, _opts, _ot, _addl ->
- {:ok, "{}"}
-
- _url, :download, _opts, _ot, _addl ->
- {:error, "This video is available to this channel's members on level: foo", 1}
- end)
-
- Oban.Testing.with_testing_mode(:inline, fn ->
- {:ok, job} = Oban.insert(MediaDownloadWorker.new(%{id: media_item.id, quality_upgrade?: true}))
-
- assert job.state == "completed"
- end)
- end
-
- test "ensures error are returned in a 2-item tuple", %{media_item: media_item} do
+ test "it ensures error are returned in a 2-item tuple", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, 2, fn
_url, :get_downloadable_status, _opts, _ot, _addl -> {:ok, "{}"}
_url, :download, _opts, _ot, _addl -> {:error, "error", 1}
@@ -172,7 +136,7 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do
assert {:error, :download_failed} = perform_job(MediaDownloadWorker, %{id: media_item.id})
end
- test "does not download if the source is set to not download", %{media_item: media_item} do
+ test "it does not download if the source is set to not download", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, 0, fn _url, :download, _opts, _ot, _addl -> :ok end)
Sources.update_source(media_item.source, %{download_media: false})
@@ -188,7 +152,7 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do
perform_job(MediaDownloadWorker, %{id: media_item.id})
end
- test "saves the file's size to the database", %{media_item: media_item} do
+ test "it saves the file's size to the database", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, 3, fn
_url, :get_downloadable_status, _opts, _ot, _addl ->
{:ok, "{}"}
@@ -237,14 +201,6 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do
perform_job(MediaDownloadWorker, %{id: media_item.id})
end
-
- test "does not download if the media item isn't pending download", %{media_item: media_item} do
- expect(YtDlpRunnerMock, :run, 0, fn _url, :download, _opts, _ot, _addl -> :ok end)
-
- Media.update_media_item(media_item, %{media_filepath: "foo.mp4"})
-
- perform_job(MediaDownloadWorker, %{id: media_item.id})
- end
end
describe "perform/1 when testing non-downloadable media" do
@@ -263,30 +219,12 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do
describe "perform/1 when testing forced downloads" do
test "ignores 'prevent_download' if forced", %{media_item: media_item} do
- expect(YtDlpRunnerMock, :run, 3, fn
- _url, :get_downloadable_status, _opts, _ot, _addl -> {:ok, "{}"}
- _url, :download, _opts, _ot, _addl -> {:ok, render_metadata(:media_metadata)}
- _url, :download_thumbnail, _opts, _ot, _addl -> {:ok, ""}
- end)
-
Sources.update_source(media_item.source, %{download_media: false})
Media.update_media_item(media_item, %{prevent_download: true})
perform_job(MediaDownloadWorker, %{id: media_item.id, force: true})
end
- test "ignores whether the media item is pending when forced", %{media_item: media_item} do
- expect(YtDlpRunnerMock, :run, 3, fn
- _url, :get_downloadable_status, _opts, _ot, _addl -> {:ok, "{}"}
- _url, :download, _opts, _ot, _addl -> {:ok, render_metadata(:media_metadata)}
- _url, :download_thumbnail, _opts, _ot, _addl -> {:ok, ""}
- end)
-
- Media.update_media_item(media_item, %{media_filepath: "foo.mp4"})
-
- perform_job(MediaDownloadWorker, %{id: media_item.id, force: true})
- end
-
test "sets force_overwrites runner option", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, 3, fn
_url, :get_downloadable_status, _opts, _ot, _addl ->
@@ -314,34 +252,6 @@ defmodule Pinchflat.Downloading.MediaDownloadWorkerTest do
assert media_item.media_redownloaded_at != nil
end
- test "ignores whether the media item is pending when re-downloaded", %{media_item: media_item} do
- expect(YtDlpRunnerMock, :run, 3, fn
- _url, :get_downloadable_status, _opts, _ot, _addl -> {:ok, "{}"}
- _url, :download, _opts, _ot, _addl -> {:ok, render_metadata(:media_metadata)}
- _url, :download_thumbnail, _opts, _ot, _addl -> {:ok, ""}
- end)
-
- Media.update_media_item(media_item, %{media_filepath: "foo.mp4"})
-
- perform_job(MediaDownloadWorker, %{id: media_item.id, quality_upgrade?: true})
- end
-
- test "doesn't redownload if the source is set to not download", %{media_item: media_item} do
- expect(YtDlpRunnerMock, :run, 0, fn _url, :download, _opts, _ot, _addl -> :ok end)
-
- Sources.update_source(media_item.source, %{download_media: false})
-
- perform_job(MediaDownloadWorker, %{id: media_item.id, quality_upgrade?: true})
- end
-
- test "doesn't redownload if the media item is set to not download", %{media_item: media_item} do
- expect(YtDlpRunnerMock, :run, 0, fn _url, :download, _opts, _ot, _addl -> :ok end)
-
- Media.update_media_item(media_item, %{prevent_download: true})
-
- perform_job(MediaDownloadWorker, %{id: media_item.id, quality_upgrade?: true})
- end
-
test "sets force_overwrites runner option", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, 3, fn
_url, :get_downloadable_status, _opts, _ot, _addl ->
diff --git a/test/pinchflat/downloading/media_downloader_test.exs b/test/pinchflat/downloading/media_downloader_test.exs
index eb66b99..8a60f93 100644
--- a/test/pinchflat/downloading/media_downloader_test.exs
+++ b/test/pinchflat/downloading/media_downloader_test.exs
@@ -60,8 +60,7 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do
{:ok, Phoenix.json_library().encode!(%{"live_status" => "is_live"})}
end)
- assert {:error, :unsuitable_for_download, message} = MediaDownloader.download_for_media_item(media_item)
- assert message =~ "Media item ##{media_item.id} isn't suitable for download yet."
+ assert {:error, :unsuitable_for_download} = MediaDownloader.download_for_media_item(media_item)
end
test "non-recoverable errors are passed through", %{media_item: media_item} do
@@ -70,7 +69,7 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do
_url, :download, _opts, _ot, _addl -> {:error, :some_error, 1}
end)
- assert {:error, :download_failed, :some_error} = MediaDownloader.download_for_media_item(media_item)
+ assert {:error, :some_error} = MediaDownloader.download_for_media_item(media_item)
end
test "unknown errors are passed through", %{media_item: media_item} do
@@ -79,7 +78,7 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do
_url, :download, _opts, _ot, _addl -> {:error, :some_error}
end)
- assert {:error, :unknown, message} = MediaDownloader.download_for_media_item(media_item)
+ assert {:error, message} = MediaDownloader.download_for_media_item(media_item)
assert message == "Unknown error: {:error, :some_error}"
end
end
@@ -108,15 +107,13 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do
expect(YtDlpRunnerMock, :run, 0, fn _url, :download, _opts, _ot, _addl -> {:ok, ""} end)
- assert {:error, :unsuitable_for_download, message} = MediaDownloader.download_for_media_item(media_item)
- assert message =~ "Media item ##{media_item.id} isn't suitable for download yet."
+ assert {:error, :unsuitable_for_download} = MediaDownloader.download_for_media_item(media_item)
end
test "returns unexpected errors from the download status determination method", %{media_item: media_item} do
expect(YtDlpRunnerMock, :run, fn _url, :get_downloadable_status, _opts, _ot, _addl -> {:error, :what_tha} end)
- assert {:error, :unknown, "Unknown error: {:error, :what_tha}"} =
- MediaDownloader.download_for_media_item(media_item)
+ assert {:error, "Unknown error: {:error, :what_tha}"} = MediaDownloader.download_for_media_item(media_item)
end
end
@@ -157,27 +154,7 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do
{:ok, ""}
end)
- source = source_fixture(%{cookie_behaviour: :all_operations})
- media_item = media_item_fixture(%{source_id: source.id})
-
- assert {:ok, _} = MediaDownloader.download_for_media_item(media_item)
- end
-
- test "does not set use_cookies if the source uses cookies when needed" do
- expect(YtDlpRunnerMock, :run, 3, fn
- _url, :get_downloadable_status, _opts, _ot, addl ->
- assert {:use_cookies, false} in addl
- {:ok, "{}"}
-
- _url, :download, _opts, _ot, addl ->
- assert {:use_cookies, false} in addl
- {:ok, render_metadata(:media_metadata)}
-
- _url, :download_thumbnail, _opts, _ot, _addl ->
- {:ok, ""}
- end)
-
- source = source_fixture(%{cookie_behaviour: :when_needed})
+ source = source_fixture(%{use_cookies: true})
media_item = media_item_fixture(%{source_id: source.id})
assert {:ok, _} = MediaDownloader.download_for_media_item(media_item)
@@ -185,8 +162,7 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do
test "does not set use_cookies if the source does not use cookies" do
expect(YtDlpRunnerMock, :run, 3, fn
- _url, :get_downloadable_status, _opts, _ot, addl ->
- assert {:use_cookies, false} in addl
+ _url, :get_downloadable_status, _opts, _ot, _addl ->
{:ok, "{}"}
_url, :download, _opts, _ot, addl ->
@@ -197,32 +173,26 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do
{:ok, ""}
end)
- source = source_fixture(%{cookie_behaviour: :disabled})
+ source = source_fixture(%{use_cookies: false})
media_item = media_item_fixture(%{source_id: source.id})
assert {:ok, _} = MediaDownloader.download_for_media_item(media_item)
end
end
- describe "download_for_media_item/3 when testing non-cookie retries" do
+ describe "download_for_media_item/3 when testing retries" do
test "returns a recovered tuple on recoverable errors", %{media_item: media_item} do
message = "Unable to communicate with SponsorBlock"
- expect(YtDlpRunnerMock, :run, 3, fn
+ expect(YtDlpRunnerMock, :run, 2, fn
_url, :get_downloadable_status, _opts, _ot, _addl ->
{:ok, "{}"}
- _url, :download, _opts, _ot, addl ->
- [{:output_filepath, filepath} | _] = addl
- File.write(filepath, render_metadata(:media_metadata))
-
+ _url, :download, _opts, _ot, _addl ->
{:error, message, 1}
-
- _url, :download_thumbnail, _opts, _ot, _addl ->
- {:ok, ""}
end)
- assert {:recovered, _media_item, ^message} = MediaDownloader.download_for_media_item(media_item)
+ assert {:recovered, ^message} = MediaDownloader.download_for_media_item(media_item)
end
test "attempts to update the media item on recoverable errors", %{media_item: media_item} do
@@ -242,121 +212,11 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do
{:ok, ""}
end)
- assert {:recovered, updated_media_item, ^message} = MediaDownloader.download_for_media_item(media_item)
-
- assert DateTime.diff(DateTime.utc_now(), updated_media_item.media_downloaded_at) < 2
- assert String.ends_with?(updated_media_item.media_filepath, ".mkv")
- end
-
- test "returns an unrecoverable tuple if recovery fails", %{media_item: media_item} do
- message = "Unable to communicate with SponsorBlock"
-
- expect(YtDlpRunnerMock, :run, 2, fn
- _url, :get_downloadable_status, _opts, _ot, _addl ->
- {:ok, "{}"}
-
- _url, :download, _opts, _ot, _addl ->
- # This errors because the metadata is not written to the file so JSON parsing fails
- {:error, message, 1}
- end)
-
- assert {:error, :unrecoverable, ^message} = MediaDownloader.download_for_media_item(media_item)
- end
-
- test "sets the last_error appropriately when recovered", %{media_item: media_item} do
- expect(YtDlpRunnerMock, :run, 3, fn
- _url, :download, _opts, _ot, addl ->
- [{:output_filepath, filepath} | _] = addl
- File.write(filepath, render_metadata(:media_metadata))
-
- {:error, "Unable to communicate with SponsorBlock", 1}
-
- _url, :get_downloadable_status, _opts, _ot, _addl ->
- {:ok, "{}"}
-
- _url, :download_thumbnail, _opts, _ot, _addl ->
- {:ok, ""}
- end)
-
- assert {:recovered, updated_media_item, _message} = MediaDownloader.download_for_media_item(media_item)
- assert updated_media_item.last_error == "Unable to communicate with SponsorBlock"
- end
-
- test "sets the last_error appropriately when unrecoverable", %{media_item: media_item} do
- expect(YtDlpRunnerMock, :run, 2, fn
- _url, :get_downloadable_status, _opts, _ot, _addl ->
- {:ok, "{}"}
-
- _url, :download, _opts, _ot, _addl ->
- {:error, "Unable to communicate with SponsorBlock", 1}
- end)
-
- assert {:error, :unrecoverable, _message} = MediaDownloader.download_for_media_item(media_item)
+ assert {:recovered, ^message} = MediaDownloader.download_for_media_item(media_item)
media_item = Repo.reload(media_item)
- assert media_item.last_error == "Unable to communicate with SponsorBlock"
- end
- end
-
- describe "download_for_media_item/3 when testing cookie retries" do
- test "retries with cookies if we think it would help and the source allows" do
- expect(YtDlpRunnerMock, :run, 4, fn
- _url, :get_downloadable_status, _opts, _ot, [use_cookies: false] ->
- {:error, "Sign in to confirm your age", 1}
-
- _url, :get_downloadable_status, _opts, _ot, [use_cookies: true] ->
- {:ok, "{}"}
-
- _url, :download, _opts, _ot, addl ->
- assert {:use_cookies, true} in addl
- {:ok, render_metadata(:media_metadata)}
-
- _url, :download_thumbnail, _opts, _ot, _addl ->
- {:ok, ""}
- end)
-
- source = source_fixture(%{cookie_behaviour: :when_needed})
- media_item = media_item_fixture(%{source_id: source.id})
-
- assert {:ok, _} = MediaDownloader.download_for_media_item(media_item)
- end
-
- test "does not retry with cookies if we don't think it would help even the source allows" do
- expect(YtDlpRunnerMock, :run, 1, fn
- _url, :get_downloadable_status, _opts, _ot, [use_cookies: false] ->
- {:error, "Some other error", 1}
- end)
-
- source = source_fixture(%{cookie_behaviour: :when_needed})
- media_item = media_item_fixture(%{source_id: source.id})
-
- assert {:error, :download_failed, "Some other error"} = MediaDownloader.download_for_media_item(media_item)
- end
-
- test "does not retry with cookies even if we think it would help but source doesn't allow" do
- expect(YtDlpRunnerMock, :run, 1, fn
- _url, :get_downloadable_status, _opts, _ot, [use_cookies: false] ->
- {:error, "Sign in to confirm your age", 1}
- end)
-
- source = source_fixture(%{cookie_behaviour: :disabled})
- media_item = media_item_fixture(%{source_id: source.id})
-
- assert {:error, :download_failed, "Sign in to confirm your age"} =
- MediaDownloader.download_for_media_item(media_item)
- end
-
- test "does not retry with cookies if cookies were already used" do
- expect(YtDlpRunnerMock, :run, 1, fn
- _url, :get_downloadable_status, _opts, _ot, [use_cookies: true] ->
- {:error, "This video is available to this channel's members", 1}
- end)
-
- source = source_fixture(%{cookie_behaviour: :all_operations})
- media_item = media_item_fixture(%{source_id: source.id})
-
- assert {:error, :download_failed, "This video is available to this channel's members"} =
- MediaDownloader.download_for_media_item(media_item)
+ assert DateTime.diff(DateTime.utc_now(), media_item.media_downloaded_at) < 2
+ assert String.ends_with?(media_item.media_filepath, ".mkv")
end
end
@@ -464,25 +324,6 @@ defmodule Pinchflat.Downloading.MediaDownloaderTest do
File.rm(updated_media_item.metadata_filepath)
end
-
- test "sets the last_error to nil on success" do
- media_item = media_item_fixture(%{last_error: "Some error"})
-
- assert {:ok, updated_media_item} = MediaDownloader.download_for_media_item(media_item)
- assert updated_media_item.last_error == nil
- end
-
- test "sets the last_error to the error message on failure", %{media_item: media_item} do
- expect(YtDlpRunnerMock, :run, 2, fn
- _url, :get_downloadable_status, _opts, _ot, _addl -> {:ok, "{}"}
- _url, :download, _opts, _ot, _addl -> {:error, :some_error}
- end)
-
- assert {:error, :unknown, _message} = MediaDownloader.download_for_media_item(media_item)
- media_item = Repo.reload(media_item)
-
- assert media_item.last_error == "Unknown error: {:error, :some_error}"
- end
end
describe "download_for_media_item/3 when testing NFO generation" do
diff --git a/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs b/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs
index 77be803..8ef98d7 100644
--- a/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs
+++ b/test/pinchflat/fast_indexing/fast_indexing_helpers_test.exs
@@ -38,48 +38,36 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do
end
end
- describe "index_and_kickoff_downloads/1" do
- test "enqueues a worker for each new media_id in the source's RSS feed", %{source: source} do
+ describe "kickoff_download_tasks_from_youtube_rss_feed/1" do
+ test "enqueues a new worker for each new media_id in the source's RSS feed", %{source: source} do
expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1 "} end)
- assert [media_item] = FastIndexingHelpers.index_and_kickoff_downloads(source)
+ assert [media_item] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
assert [worker] = all_enqueued(worker: MediaDownloadWorker)
assert worker.args["id"] == media_item.id
- assert worker.priority == 0
end
test "does not enqueue a new worker for the source's media IDs we already know about", %{source: source} do
expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1 "} end)
media_item_fixture(source_id: source.id, media_id: "test_1")
- assert [] = FastIndexingHelpers.index_and_kickoff_downloads(source)
+ assert [] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
refute_enqueued(worker: MediaDownloadWorker)
end
- test "kicks off a download task for all pending media but at a lower priority", %{source: source} do
- pending_item = media_item_fixture(source_id: source.id, media_filepath: nil)
- expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1 "} end)
-
- assert [%MediaItem{}] = FastIndexingHelpers.index_and_kickoff_downloads(source)
-
- assert [worker_1, _worker_2] = all_enqueued(worker: MediaDownloadWorker)
- assert worker_1.args["id"] == pending_item.id
- assert worker_1.priority == 1
- end
-
test "returns the found media items", %{source: source} do
expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1 "} end)
- assert [%MediaItem{}] = FastIndexingHelpers.index_and_kickoff_downloads(source)
+ assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
end
test "does not enqueue a download job if the source does not allow it" do
expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1 "} end)
source = source_fixture(%{download_media: false})
- assert [%MediaItem{}] = FastIndexingHelpers.index_and_kickoff_downloads(source)
+ assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
refute_enqueued(worker: MediaDownloadWorker)
end
@@ -87,7 +75,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do
test "creates a download task record", %{source: source} do
expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1 "} end)
- assert [media_item] = FastIndexingHelpers.index_and_kickoff_downloads(source)
+ assert [media_item] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
assert [_] = Tasks.list_tasks_for(media_item, "MediaDownloadWorker")
end
@@ -101,7 +89,35 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do
{:ok, media_attributes_return_fixture()}
end)
- FastIndexingHelpers.index_and_kickoff_downloads(source)
+ FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
+ end
+
+ test "sets use_cookies if the source uses cookies" do
+ expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1 "} end)
+
+ stub(YtDlpRunnerMock, :run, fn _url, :get_media_attributes, _opts, _ot, addl ->
+ assert {:use_cookies, true} in addl
+
+ {:ok, media_attributes_return_fixture()}
+ end)
+
+ source = source_fixture(%{use_cookies: true})
+
+ assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
+ end
+
+ test "does not set use_cookies if the source does not use cookies" do
+ expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1 "} end)
+
+ stub(YtDlpRunnerMock, :run, fn _url, :get_media_attributes, _opts, _ot, addl ->
+ assert {:use_cookies, false} in addl
+
+ {:ok, media_attributes_return_fixture()}
+ end)
+
+ source = source_fixture(%{use_cookies: false})
+
+ assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
end
test "does not enqueue a download job if the media item does not match the format rules" do
@@ -126,7 +142,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do
{:ok, output}
end)
- assert [%MediaItem{}] = FastIndexingHelpers.index_and_kickoff_downloads(source)
+ assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
refute_enqueued(worker: MediaDownloadWorker)
end
@@ -138,7 +154,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do
{:ok, "{}"}
end)
- assert [] = FastIndexingHelpers.index_and_kickoff_downloads(source)
+ assert [] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
end
test "does not blow up if a media item causes a yt-dlp error", %{source: source} do
@@ -148,55 +164,11 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do
{:error, "message", 1}
end)
- assert [] = FastIndexingHelpers.index_and_kickoff_downloads(source)
+ assert [] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
end
end
- describe "index_and_kickoff_downloads/1 when testing cookies" do
- test "sets use_cookies if the source uses cookies" do
- expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1 "} end)
-
- stub(YtDlpRunnerMock, :run, fn _url, :get_media_attributes, _opts, _ot, addl ->
- assert {:use_cookies, true} in addl
-
- {:ok, media_attributes_return_fixture()}
- end)
-
- source = source_fixture(%{cookie_behaviour: :all_operations})
-
- assert [%MediaItem{}] = FastIndexingHelpers.index_and_kickoff_downloads(source)
- end
-
- test "does not set use_cookies if the source uses cookies when needed" do
- expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1 "} end)
-
- stub(YtDlpRunnerMock, :run, fn _url, :get_media_attributes, _opts, _ot, addl ->
- assert {:use_cookies, false} in addl
-
- {:ok, media_attributes_return_fixture()}
- end)
-
- source = source_fixture(%{cookie_behaviour: :when_needed})
-
- assert [%MediaItem{}] = FastIndexingHelpers.index_and_kickoff_downloads(source)
- end
-
- test "does not set use_cookies if the source does not use cookies" do
- expect(HTTPClientMock, :get, fn _url -> {:ok, "test_1 "} end)
-
- stub(YtDlpRunnerMock, :run, fn _url, :get_media_attributes, _opts, _ot, addl ->
- assert {:use_cookies, false} in addl
-
- {:ok, media_attributes_return_fixture()}
- end)
-
- source = source_fixture(%{cookie_behaviour: :disabled})
-
- assert [%MediaItem{}] = FastIndexingHelpers.index_and_kickoff_downloads(source)
- end
- end
-
- describe "index_and_kickoff_downloads/1 when testing backends" do
+ describe "kickoff_download_tasks_from_youtube_rss_feed/1 when testing backends" do
test "uses the YouTube API if it is enabled", %{source: source} do
expect(HTTPClientMock, :get, fn url, _headers ->
assert url =~ "https://youtube.googleapis.com/youtube/v3/playlistItems"
@@ -206,7 +178,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do
Settings.set(youtube_api_key: "test_key")
- assert [] = FastIndexingHelpers.index_and_kickoff_downloads(source)
+ assert [] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
end
test "the YouTube API creates records as expected", %{source: source} do
@@ -216,7 +188,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do
Settings.set(youtube_api_key: "test_key")
- assert [%MediaItem{}] = FastIndexingHelpers.index_and_kickoff_downloads(source)
+ assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
end
test "RSS is used as a backup if the API fails", %{source: source} do
@@ -225,7 +197,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do
Settings.set(youtube_api_key: "test_key")
- assert [%MediaItem{}] = FastIndexingHelpers.index_and_kickoff_downloads(source)
+ assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
end
test "RSS is used if the API is not enabled", %{source: source} do
@@ -237,7 +209,7 @@ defmodule Pinchflat.FastIndexing.FastIndexingHelpersTest do
Settings.set(youtube_api_key: nil)
- assert [%MediaItem{}] = FastIndexingHelpers.index_and_kickoff_downloads(source)
+ assert [%MediaItem{}] = FastIndexingHelpers.kickoff_download_tasks_from_youtube_rss_feed(source)
end
end
end
diff --git a/test/pinchflat/fast_indexing/youtube_api_test.exs b/test/pinchflat/fast_indexing/youtube_api_test.exs
index dde4068..cc310d6 100644
--- a/test/pinchflat/fast_indexing/youtube_api_test.exs
+++ b/test/pinchflat/fast_indexing/youtube_api_test.exs
@@ -7,67 +7,31 @@ defmodule Pinchflat.FastIndexing.YoutubeApiTest do
alias Pinchflat.FastIndexing.YoutubeApi
describe "enabled?/0" do
- test "returns true if the user has set YouTube API keys" do
- Settings.set(youtube_api_key: "key1, key2")
- assert YoutubeApi.enabled?()
- end
-
- test "returns true with a single API key" do
+ test "returns true if the user has set a YouTube API key" do
Settings.set(youtube_api_key: "test_key")
assert YoutubeApi.enabled?()
end
- test "returns false if the user has not set any API keys" do
+ test "returns false if the user has not set an API key" do
Settings.set(youtube_api_key: nil)
- refute YoutubeApi.enabled?()
- end
- test "returns false if only empty or whitespace keys are provided" do
- Settings.set(youtube_api_key: " , ,")
refute YoutubeApi.enabled?()
end
end
describe "get_recent_media_ids/1" do
setup do
- case :global.whereis_name(YoutubeApi.KeyIndex) do
- :undefined -> :ok
- pid -> Agent.stop(pid)
- end
-
source = source_fixture()
- Settings.set(youtube_api_key: "key1, key2")
+ Settings.set(youtube_api_key: "test_key")
{:ok, source: source}
end
- test "rotates through API keys", %{source: source} do
- expect(HTTPClientMock, :get, fn url, _headers ->
- assert url =~ "key=key1"
- {:ok, "{}"}
- end)
-
- expect(HTTPClientMock, :get, fn url, _headers ->
- assert url =~ "key=key2"
- {:ok, "{}"}
- end)
-
- expect(HTTPClientMock, :get, fn url, _headers ->
- assert url =~ "key=key1"
- {:ok, "{}"}
- end)
-
- # three calls to verify rotation
- YoutubeApi.get_recent_media_ids(source)
- YoutubeApi.get_recent_media_ids(source)
- YoutubeApi.get_recent_media_ids(source)
- end
-
test "calls the expected URL", %{source: source} do
expect(HTTPClientMock, :get, fn url, headers ->
api_base = "https://youtube.googleapis.com/youtube/v3/playlistItems"
- request_url = "#{api_base}?part=contentDetails&maxResults=50&playlistId=#{source.collection_id}&key=key1"
+ request_url = "#{api_base}?part=contentDetails&maxResults=50&playlistId=#{source.collection_id}&key=test_key"
assert url == request_url
assert headers == [accept: "application/json"]
diff --git a/test/pinchflat/media_test.exs b/test/pinchflat/media_test.exs
index 6becd5b..891502c 100644
--- a/test/pinchflat/media_test.exs
+++ b/test/pinchflat/media_test.exs
@@ -921,14 +921,6 @@ defmodule Pinchflat.MediaTest do
media_item = media_item_fixture()
assert %Ecto.Changeset{} = Media.change_media_item(media_item)
end
-
- test "validates the title doesn't start with 'youtube video #'" do
- # This is to account for youtube restricting indexing. See issue #549 for more
- media_item = media_item_fixture()
-
- assert %Ecto.Changeset{valid?: false} = Media.change_media_item(media_item, %{title: "youtube video #123"})
- assert %Ecto.Changeset{valid?: true} = Media.change_media_item(media_item, %{title: "any other title"})
- end
end
describe "change_media_item/1 when testing upload_date_index and source is a channel" do
diff --git a/test/pinchflat/metadata/metadata_file_helpers_test.exs b/test/pinchflat/metadata/metadata_file_helpers_test.exs
index bacb861..b193d9a 100644
--- a/test/pinchflat/metadata/metadata_file_helpers_test.exs
+++ b/test/pinchflat/metadata/metadata_file_helpers_test.exs
@@ -88,35 +88,13 @@ defmodule Pinchflat.Metadata.MetadataFileHelpersTest do
Helpers.download_and_store_thumbnail_for(media_item)
end
- test "returns nil if yt-dlp fails", %{media_item: media_item} do
- stub(YtDlpRunnerMock, :run, fn _url, :download_thumbnail, _opts, _ot, _addl -> {:error, "error"} end)
-
- filepath = Helpers.download_and_store_thumbnail_for(media_item)
-
- assert filepath == nil
- end
- end
-
- describe "download_and_store_thumbnail_for/2 when testing cookie usage" do
test "sets use_cookies if the source uses cookies" do
expect(YtDlpRunnerMock, :run, fn _url, :download_thumbnail, _opts, _ot, addl ->
assert {:use_cookies, true} in addl
{:ok, ""}
end)
- source = source_fixture(%{cookie_behaviour: :all_operations})
- media_item = Repo.preload(media_item_fixture(%{source_id: source.id}), :source)
-
- Helpers.download_and_store_thumbnail_for(media_item)
- end
-
- test "does not set use_cookies if the source uses cookies when needed" do
- expect(YtDlpRunnerMock, :run, fn _url, :download_thumbnail, _opts, _ot, addl ->
- assert {:use_cookies, false} in addl
- {:ok, ""}
- end)
-
- source = source_fixture(%{cookie_behaviour: :when_needed})
+ source = source_fixture(%{use_cookies: true})
media_item = Repo.preload(media_item_fixture(%{source_id: source.id}), :source)
Helpers.download_and_store_thumbnail_for(media_item)
@@ -128,11 +106,19 @@ defmodule Pinchflat.Metadata.MetadataFileHelpersTest do
{:ok, ""}
end)
- source = source_fixture(%{cookie_behaviour: :disabled})
+ source = source_fixture(%{use_cookies: false})
media_item = Repo.preload(media_item_fixture(%{source_id: source.id}), :source)
Helpers.download_and_store_thumbnail_for(media_item)
end
+
+ test "returns nil if yt-dlp fails", %{media_item: media_item} do
+ stub(YtDlpRunnerMock, :run, fn _url, :download_thumbnail, _opts, _ot, _addl -> {:error, "error"} end)
+
+ filepath = Helpers.download_and_store_thumbnail_for(media_item)
+
+ assert filepath == nil
+ end
end
describe "parse_upload_date/1" do
diff --git a/test/pinchflat/metadata/source_metadata_storage_worker_test.exs b/test/pinchflat/metadata/source_metadata_storage_worker_test.exs
index 4965964..2b08a2f 100644
--- a/test/pinchflat/metadata/source_metadata_storage_worker_test.exs
+++ b/test/pinchflat/metadata/source_metadata_storage_worker_test.exs
@@ -254,23 +254,7 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do
end)
profile = media_profile_fixture(%{download_source_images: true})
- source = source_fixture(media_profile_id: profile.id, cookie_behaviour: :all_operations)
-
- perform_job(SourceMetadataStorageWorker, %{id: source.id})
- end
-
- test "does not set use_cookies if the source uses cookies when needed" do
- expect(YtDlpRunnerMock, :run, 2, fn
- _url, :get_source_details, _opts, _ot, _addl ->
- {:ok, source_details_return_fixture()}
-
- _url, :get_source_metadata, _opts, _ot, addl ->
- assert {:use_cookies, false} in addl
- {:ok, render_metadata(:channel_source_metadata)}
- end)
-
- profile = media_profile_fixture(%{download_source_images: true})
- source = source_fixture(media_profile_id: profile.id, cookie_behaviour: :when_needed)
+ source = source_fixture(media_profile_id: profile.id, use_cookies: true)
perform_job(SourceMetadataStorageWorker, %{id: source.id})
end
@@ -286,7 +270,7 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do
end)
profile = media_profile_fixture(%{download_source_images: true})
- source = source_fixture(media_profile_id: profile.id, cookie_behaviour: :disabled)
+ source = source_fixture(media_profile_id: profile.id, use_cookies: false)
perform_job(SourceMetadataStorageWorker, %{id: source.id})
end
@@ -339,21 +323,7 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do
{:ok, "{}"}
end)
- source = source_fixture(%{series_directory: nil, cookie_behaviour: :all_operations})
- perform_job(SourceMetadataStorageWorker, %{id: source.id})
- end
-
- test "does not set use_cookies if the source uses cookies when needed" do
- expect(YtDlpRunnerMock, :run, 2, fn
- _url, :get_source_details, _opts, _ot, addl ->
- assert {:use_cookies, false} in addl
- {:ok, source_details_return_fixture()}
-
- _url, :get_source_metadata, _opts, _ot, _addl ->
- {:ok, "{}"}
- end)
-
- source = source_fixture(%{series_directory: nil, cookie_behaviour: :when_needed})
+ source = source_fixture(%{series_directory: nil, use_cookies: true})
perform_job(SourceMetadataStorageWorker, %{id: source.id})
end
@@ -367,7 +337,7 @@ defmodule Pinchflat.Metadata.SourceMetadataStorageWorkerTest do
{:ok, "{}"}
end)
- source = source_fixture(%{series_directory: nil, cookie_behaviour: :disabled})
+ source = source_fixture(%{series_directory: nil, use_cookies: false})
perform_job(SourceMetadataStorageWorker, %{id: source.id})
end
end
diff --git a/test/pinchflat/settings_test.exs b/test/pinchflat/settings_test.exs
index 774e274..944eaf1 100644
--- a/test/pinchflat/settings_test.exs
+++ b/test/pinchflat/settings_test.exs
@@ -77,20 +77,5 @@ defmodule Pinchflat.SettingsTest do
assert %Ecto.Changeset{} = Settings.change_setting(setting, %{onboarding: true})
end
-
- test "ensures the extractor sleep interval is positive" do
- setting = Settings.record()
-
- assert %Ecto.Changeset{valid?: true} = Settings.change_setting(setting, %{extractor_sleep_interval_seconds: 1})
- assert %Ecto.Changeset{valid?: true} = Settings.change_setting(setting, %{extractor_sleep_interval_seconds: 0})
- assert %Ecto.Changeset{valid?: false} = Settings.change_setting(setting, %{extractor_sleep_interval_seconds: -1})
- end
-
- test "allows you to reset the extractor sleep interval" do
- setting = Settings.record()
- assert {:ok, setting} = Settings.update_setting(setting, %{extractor_sleep_interval_seconds: 1})
-
- assert %Ecto.Changeset{valid?: true} = Settings.change_setting(setting, %{extractor_sleep_interval_seconds: 0})
- end
end
end
diff --git a/test/pinchflat/slow_indexing/slow_indexing_helpers_test.exs b/test/pinchflat/slow_indexing/slow_indexing_helpers_test.exs
index d37721a..e410b3c 100644
--- a/test/pinchflat/slow_indexing/slow_indexing_helpers_test.exs
+++ b/test/pinchflat/slow_indexing/slow_indexing_helpers_test.exs
@@ -96,6 +96,26 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(task) end
end
+ test "deletes any pending media tasks for the source" do
+ source = source_fixture()
+ {:ok, job} = Oban.insert(FastIndexingWorker.new(%{"id" => source.id}))
+ task = task_fixture(source_id: source.id, job_id: job.id)
+
+ assert {:ok, _} = SlowIndexingHelpers.kickoff_indexing_task(source)
+
+ assert_raise Ecto.NoResultsError, fn -> Repo.reload!(task) end
+ end
+
+ test "deletes any fast indexing tasks for the source" do
+ source = source_fixture()
+ {:ok, job} = Oban.insert(FastIndexingWorker.new(%{"id" => source.id}))
+ task = task_fixture(source_id: source.id, job_id: job.id)
+
+ assert {:ok, _} = SlowIndexingHelpers.kickoff_indexing_task(source)
+
+ assert_raise Ecto.NoResultsError, fn -> Repo.reload!(task) end
+ end
+
test "can be called with additional job arguments" do
source = source_fixture(index_frequency_minutes: 1)
job_args = %{"force" => true}
@@ -270,29 +290,6 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do
assert %Ecto.Changeset{} = changeset
end
- test "doesn't blow up if the media item cannot be saved", %{source: source} do
- stub(YtDlpRunnerMock, :run, fn _url, :get_media_attributes_for_collection, _opts, _ot, _addl_opts ->
- response =
- Phoenix.json_library().encode!(%{
- id: "video1",
- # This is a disallowed title - see MediaItem changeset or issue #549
- title: "youtube video #123",
- original_url: "https://example.com/video1",
- live_status: "not_live",
- description: "desc1",
- aspect_ratio: 1.67,
- duration: 12.34,
- upload_date: "20210101"
- })
-
- {:ok, response}
- end)
-
- assert [changeset] = SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source)
-
- assert %Ecto.Changeset{} = changeset
- end
-
test "passes the source's download options to the yt-dlp runner", %{source: source} do
expect(YtDlpRunnerMock, :run, fn _url, :get_media_attributes_for_collection, opts, _ot, _addl_opts ->
assert {:output, "/tmp/test/media/%(title)S.%(ext)S"} in opts
@@ -302,27 +299,14 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do
SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source)
end
- end
- describe "index_and_enqueue_download_for_media_items/2 when testing cookies" do
test "sets use_cookies if the source uses cookies" do
expect(YtDlpRunnerMock, :run, fn _url, :get_media_attributes_for_collection, _opts, _ot, addl_opts ->
assert {:use_cookies, true} in addl_opts
{:ok, source_attributes_return_fixture()}
end)
- source = source_fixture(%{cookie_behaviour: :all_operations})
-
- SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source)
- end
-
- test "sets use_cookies if the source uses cookies when needed" do
- expect(YtDlpRunnerMock, :run, fn _url, :get_media_attributes_for_collection, _opts, _ot, addl_opts ->
- assert {:use_cookies, true} in addl_opts
- {:ok, source_attributes_return_fixture()}
- end)
-
- source = source_fixture(%{cookie_behaviour: :when_needed})
+ source = source_fixture(%{use_cookies: true})
SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source)
end
@@ -333,7 +317,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do
{:ok, source_attributes_return_fixture()}
end)
- source = source_fixture(%{cookie_behaviour: :disabled})
+ source = source_fixture(%{use_cookies: false})
SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source)
end
@@ -468,9 +452,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do
end
describe "index_and_enqueue_download_for_media_items when testing the download archive" do
- test "a download archive is used if the source is a channel that has been indexed before" do
- source = source_fixture(%{collection_type: :channel, last_indexed_at: now()})
-
+ test "a download archive is used if the source is a channel", %{source: source} do
expect(YtDlpRunnerMock, :run, fn _url, :get_media_attributes_for_collection, opts, _ot, _addl_opts ->
assert :break_on_existing in opts
assert Keyword.has_key?(opts, :download_archive)
@@ -494,19 +476,6 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do
SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source)
end
- test "a download archive is not used if the source has never been indexed before" do
- source = source_fixture(%{collection_type: :channel, last_indexed_at: nil})
-
- expect(YtDlpRunnerMock, :run, fn _url, :get_media_attributes_for_collection, opts, _ot, _addl_opts ->
- refute :break_on_existing in opts
- refute Keyword.has_key?(opts, :download_archive)
-
- {:ok, source_attributes_return_fixture()}
- end)
-
- SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source)
- end
-
test "a download archive is not used if the index has been forced to run" do
source = source_fixture(%{collection_type: :channel})
@@ -520,9 +489,7 @@ defmodule Pinchflat.SlowIndexing.SlowIndexingHelpersTest do
SlowIndexingHelpers.index_and_enqueue_download_for_media_items(source, was_forced: true)
end
- test "the download archive is formatted correctly and contains the right video" do
- source = source_fixture(%{collection_type: :channel, last_indexed_at: now()})
-
+ test "the download archive is formatted correctly and contains the right video", %{source: source} do
media_items =
1..21
|> Enum.map(fn n ->
diff --git a/test/pinchflat/sources_test.exs b/test/pinchflat/sources_test.exs
index 44bae14..e72c05c 100644
--- a/test/pinchflat/sources_test.exs
+++ b/test/pinchflat/sources_test.exs
@@ -60,33 +60,6 @@ defmodule Pinchflat.SourcesTest do
end
end
- describe "use_cookies?/2" do
- test "returns true if the source has been set to use cookies" do
- source = source_fixture(%{cookie_behaviour: :all_operations})
- assert Sources.use_cookies?(source, :downloading)
- end
-
- test "returns false if the source has not been set to use cookies" do
- source = source_fixture(%{cookie_behaviour: :disabled})
- refute Sources.use_cookies?(source, :downloading)
- end
-
- test "returns true if the action is indexing and the source is set to :when_needed" do
- source = source_fixture(%{cookie_behaviour: :when_needed})
- assert Sources.use_cookies?(source, :indexing)
- end
-
- test "returns false if the action is downloading and the source is set to :when_needed" do
- source = source_fixture(%{cookie_behaviour: :when_needed})
- refute Sources.use_cookies?(source, :downloading)
- end
-
- test "returns true if the action is error_recovery and the source is set to :when_needed" do
- source = source_fixture(%{cookie_behaviour: :when_needed})
- assert Sources.use_cookies?(source, :error_recovery)
- end
- end
-
describe "list_sources/0" do
test "it returns all sources" do
source = source_fixture()
@@ -321,34 +294,6 @@ defmodule Pinchflat.SourcesTest do
assert_enqueued(worker: MediaCollectionIndexingWorker, args: %{"id" => source.id})
end
- test "creation will schedule a fast indexing job if the fast_index option is set" do
- expect(YtDlpRunnerMock, :run, &channel_mock/5)
-
- valid_attrs = %{
- media_profile_id: media_profile_fixture().id,
- original_url: "https://www.youtube.com/channel/abc123",
- fast_index: true
- }
-
- assert {:ok, %Source{} = source} = Sources.create_source(valid_attrs)
-
- assert_enqueued(worker: FastIndexingWorker, args: %{"id" => source.id})
- end
-
- test "creation will not schedule a fast indexing job if the fast_index option is not set" do
- expect(YtDlpRunnerMock, :run, &channel_mock/5)
-
- valid_attrs = %{
- media_profile_id: media_profile_fixture().id,
- original_url: "https://www.youtube.com/channel/abc123",
- fast_index: false
- }
-
- assert {:ok, %Source{}} = Sources.create_source(valid_attrs)
-
- refute_enqueued(worker: FastIndexingWorker)
- end
-
test "creation schedules an index test even if the index frequency is 0" do
expect(YtDlpRunnerMock, :run, &channel_mock/5)
@@ -409,72 +354,7 @@ defmodule Pinchflat.SourcesTest do
end
end
- describe "create_source/2 when testing yt-dlp options" do
- test "sets use_cookies to true if the source has been set to use cookies" do
- expect(YtDlpRunnerMock, :run, fn _url, :get_source_details, _opts, _ot, addl ->
- assert Keyword.get(addl, :use_cookies)
-
- {:ok, playlist_return()}
- end)
-
- valid_attrs = %{
- media_profile_id: media_profile_fixture().id,
- original_url: "https://www.youtube.com/channel/abc123",
- cookie_behaviour: :all_operations
- }
-
- assert {:ok, %Source{}} = Sources.create_source(valid_attrs)
- end
-
- test "does not set use_cookies if the source uses cookies when needed" do
- expect(YtDlpRunnerMock, :run, fn _url, :get_source_details, _opts, _ot, addl ->
- refute Keyword.get(addl, :use_cookies)
-
- {:ok, playlist_return()}
- end)
-
- valid_attrs = %{
- media_profile_id: media_profile_fixture().id,
- original_url: "https://www.youtube.com/channel/abc123",
- cookie_behaviour: :when_needed
- }
-
- assert {:ok, %Source{}} = Sources.create_source(valid_attrs)
- end
-
- test "does not set use_cookies if the source has not been set to use cookies" do
- expect(YtDlpRunnerMock, :run, fn _url, :get_source_details, _opts, _ot, addl ->
- refute Keyword.get(addl, :use_cookies)
-
- {:ok, playlist_return()}
- end)
-
- valid_attrs = %{
- media_profile_id: media_profile_fixture().id,
- original_url: "https://www.youtube.com/channel/abc123",
- cookie_behaviour: :disabled
- }
-
- assert {:ok, %Source{}} = Sources.create_source(valid_attrs)
- end
-
- test "skips sleep interval" do
- expect(YtDlpRunnerMock, :run, fn _url, :get_source_details, _opts, _ot, addl ->
- assert Keyword.get(addl, :skip_sleep_interval)
-
- {:ok, playlist_return()}
- end)
-
- valid_attrs = %{
- media_profile_id: media_profile_fixture().id,
- original_url: "https://www.youtube.com/channel/abc123"
- }
-
- assert {:ok, %Source{}} = Sources.create_source(valid_attrs)
- end
- end
-
- describe "create_source/2 when testing its options" do
+ describe "create_source/2 when testing options" do
test "run_post_commit_tasks: false won't enqueue post-commit tasks" do
expect(YtDlpRunnerMock, :run, &channel_mock/5)
@@ -1022,30 +902,28 @@ defmodule Pinchflat.SourcesTest do
end
defp playlist_mock(_url, :get_source_details, _opts, _ot, _addl) do
- {:ok, playlist_return()}
+ {
+ :ok,
+ Phoenix.json_library().encode!(%{
+ channel: nil,
+ channel_id: nil,
+ playlist_id: "some_playlist_id_#{:rand.uniform(1_000_000)}",
+ playlist_title: "some playlist name"
+ })
+ }
end
defp channel_mock(_url, :get_source_details, _opts, _ot, _addl) do
- {:ok, channel_return()}
- end
-
- defp playlist_return do
- Phoenix.json_library().encode!(%{
- channel: nil,
- channel_id: nil,
- playlist_id: "some_playlist_id_#{:rand.uniform(1_000_000)}",
- playlist_title: "some playlist name"
- })
- end
-
- defp channel_return do
channel_id = "some_channel_id_#{:rand.uniform(1_000_000)}"
- Phoenix.json_library().encode!(%{
- channel: "some channel name",
- channel_id: channel_id,
- playlist_id: channel_id,
- playlist_title: "some channel name - videos"
- })
+ {
+ :ok,
+ Phoenix.json_library().encode!(%{
+ channel: "some channel name",
+ channel_id: channel_id,
+ playlist_id: channel_id,
+ playlist_title: "some channel name - videos"
+ })
+ }
end
end
diff --git a/test/pinchflat/utils/number_utils_test.exs b/test/pinchflat/utils/number_utils_test.exs
index 1eae570..db17e1c 100644
--- a/test/pinchflat/utils/number_utils_test.exs
+++ b/test/pinchflat/utils/number_utils_test.exs
@@ -47,21 +47,4 @@ defmodule Pinchflat.Utils.NumberUtilsTest do
assert NumberUtils.human_byte_size(nil) == {0, "B"}
end
end
-
- describe "add_jitter/2" do
- test "returns 0 when the number is less than or equal to 0" do
- assert NumberUtils.add_jitter(0) == 0
- assert NumberUtils.add_jitter(-1) == 0
- end
-
- test "returns the number with jitter added" do
- assert NumberUtils.add_jitter(100) in 100..150
- end
-
- test "optionally takes a jitter percentage" do
- assert NumberUtils.add_jitter(100, 0.1) in 90..110
- assert NumberUtils.add_jitter(100, 0.5) in 50..150
- assert NumberUtils.add_jitter(100, 1) in 0..200
- end
- end
end
diff --git a/test/pinchflat/utils/string_utils_test.exs b/test/pinchflat/utils/string_utils_test.exs
index 767f74b..a9f79ad 100644
--- a/test/pinchflat/utils/string_utils_test.exs
+++ b/test/pinchflat/utils/string_utils_test.exs
@@ -33,14 +33,4 @@ defmodule Pinchflat.Utils.StringUtilsTest do
assert StringUtils.double_brace("hello") == "{{ hello }}"
end
end
-
- describe "wrap_string/1" do
- test "returns strings as-is" do
- assert StringUtils.wrap_string("hello") == "hello"
- end
-
- test "returns other values as inspected strings" do
- assert StringUtils.wrap_string(1) == "1"
- end
- end
end
diff --git a/test/pinchflat/yt_dlp/command_runner_test.exs b/test/pinchflat/yt_dlp/command_runner_test.exs
index 51653e3..898e64b 100644
--- a/test/pinchflat/yt_dlp/command_runner_test.exs
+++ b/test/pinchflat/yt_dlp/command_runner_test.exs
@@ -1,7 +1,6 @@
defmodule Pinchflat.YtDlp.CommandRunnerTest do
use Pinchflat.DataCase
- alias Pinchflat.Settings
alias Pinchflat.Utils.FilesystemUtils
alias Pinchflat.YtDlp.CommandRunner, as: Runner
@@ -96,52 +95,6 @@ defmodule Pinchflat.YtDlp.CommandRunnerTest do
end
end
- describe "run/4 when testing rate limit options" do
- test "includes sleep interval options by default" do
- Settings.set(extractor_sleep_interval_seconds: 5)
-
- assert {:ok, output} = Runner.run(@media_url, :foo, [], "")
-
- assert String.contains?(output, "--sleep-interval")
- assert String.contains?(output, "--sleep-requests")
- assert String.contains?(output, "--sleep-subtitles")
- end
-
- test "doesn't include sleep interval options when skip_sleep_interval is true" do
- assert {:ok, output} = Runner.run(@media_url, :foo, [], "", skip_sleep_interval: true)
-
- refute String.contains?(output, "--sleep-interval")
- refute String.contains?(output, "--sleep-requests")
- refute String.contains?(output, "--sleep-subtitles")
- end
-
- test "doesn't include sleep interval options when extractor_sleep_interval_seconds is 0" do
- Settings.set(extractor_sleep_interval_seconds: 0)
-
- assert {:ok, output} = Runner.run(@media_url, :foo, [], "")
-
- refute String.contains?(output, "--sleep-interval")
- refute String.contains?(output, "--sleep-requests")
- refute String.contains?(output, "--sleep-subtitles")
- end
-
- test "includes limit_rate option when specified" do
- Settings.set(download_throughput_limit: "100K")
-
- assert {:ok, output} = Runner.run(@media_url, :foo, [], "")
-
- assert String.contains?(output, "--limit-rate 100K")
- end
-
- test "doesn't include limit_rate option when download_throughput_limit is nil" do
- Settings.set(download_throughput_limit: nil)
-
- assert {:ok, output} = Runner.run(@media_url, :foo, [], "")
-
- refute String.contains?(output, "--limit-rate")
- end
- end
-
describe "run/4 when testing global options" do
test "creates windows-safe filenames" do
assert {:ok, output} = Runner.run(@media_url, :foo, [], "")
@@ -162,24 +115,6 @@ defmodule Pinchflat.YtDlp.CommandRunnerTest do
end
end
- describe "run/4 when testing misc options" do
- test "includes --restrict-filenames when enabled" do
- Settings.set(restrict_filenames: true)
-
- assert {:ok, output} = Runner.run(@media_url, :foo, [], "")
-
- assert String.contains?(output, "--restrict-filenames")
- end
-
- test "doesn't include --restrict-filenames when disabled" do
- Settings.set(restrict_filenames: false)
-
- assert {:ok, output} = Runner.run(@media_url, :foo, [], "")
-
- refute String.contains?(output, "--restrict-filenames")
- end
- end
-
describe "version/0" do
test "adds the version arg" do
assert {:ok, output} = Runner.version()
@@ -188,14 +123,6 @@ defmodule Pinchflat.YtDlp.CommandRunnerTest do
end
end
- describe "update/0" do
- test "adds the update arg" do
- assert {:ok, output} = Runner.update()
-
- assert String.contains?(output, "--update")
- end
- end
-
defp wrap_executable(new_executable, fun) do
Application.put_env(:pinchflat, :yt_dlp_executable, new_executable)
fun.()
diff --git a/test/pinchflat/yt_dlp/media_test.exs b/test/pinchflat/yt_dlp/media_test.exs
index 4f5025d..70dc26e 100644
--- a/test/pinchflat/yt_dlp/media_test.exs
+++ b/test/pinchflat/yt_dlp/media_test.exs
@@ -269,7 +269,7 @@ defmodule Pinchflat.YtDlp.MediaTest do
response = %{
"original_url" => "https://www.youtube.com/watch?v=TiZPUDkDYbk",
"aspect_ratio" => 0.5,
- "duration" => 150,
+ "duration" => 59,
"upload_date" => "20210101"
}
diff --git a/test/pinchflat/yt_dlp/update_worker_test.exs b/test/pinchflat/yt_dlp/update_worker_test.exs
deleted file mode 100644
index fed0510..0000000
--- a/test/pinchflat/yt_dlp/update_worker_test.exs
+++ /dev/null
@@ -1,24 +0,0 @@
-defmodule Pinchflat.YtDlp.UpdateWorkerTest do
- use Pinchflat.DataCase
-
- alias Pinchflat.Settings
- alias Pinchflat.YtDlp.UpdateWorker
-
- describe "perform/1" do
- test "calls the yt-dlp runner to update yt-dlp" do
- expect(YtDlpRunnerMock, :update, fn -> {:ok, ""} end)
- expect(YtDlpRunnerMock, :version, fn -> {:ok, ""} end)
-
- perform_job(UpdateWorker, %{})
- end
-
- test "saves the new version to the database" do
- expect(YtDlpRunnerMock, :update, fn -> {:ok, ""} end)
- expect(YtDlpRunnerMock, :version, fn -> {:ok, "1.2.3"} end)
-
- perform_job(UpdateWorker, %{})
-
- assert {:ok, "1.2.3"} = Settings.get(:yt_dlp_version)
- end
- end
-end
diff --git a/test/pinchflat_web/controllers/sources/index_table_live_test.exs b/test/pinchflat_web/controllers/sources/index_table_live_test.exs
index c53380d..675e47d 100644
--- a/test/pinchflat_web/controllers/sources/index_table_live_test.exs
+++ b/test/pinchflat_web/controllers/sources/index_table_live_test.exs
@@ -75,16 +75,6 @@ defmodule PinchflatWeb.Sources.SourceLive.IndexTableLiveTest do
assert render_element(view, "tbody tr:first-child") =~ source1.custom_name
assert render_element(view, "tbody tr:last-child") =~ source2.custom_name
end
-
- test "name is sorted without case sensitivity", %{conn: conn} do
- source1 = source_fixture(custom_name: "Source_B")
- source2 = source_fixture(custom_name: "source_a")
-
- {:ok, view, _html} = live_isolated(conn, IndexTableLive, session: create_session())
-
- assert render_element(view, "tbody tr:first-child") =~ source2.custom_name
- assert render_element(view, "tbody tr:last-child") =~ source1.custom_name
- end
end
describe "when testing pagination" do
diff --git a/test/test_helper.exs b/test/test_helper.exs
index 3a05c78..4b8abf0 100644
--- a/test/test_helper.exs
+++ b/test/test_helper.exs
@@ -10,6 +10,8 @@ Application.put_env(:pinchflat, :http_client, HTTPClientMock)
Mox.defmock(UserScriptRunnerMock, for: Pinchflat.Lifecycle.UserScripts.UserScriptCommandRunner)
Application.put_env(:pinchflat, :user_script_runner, UserScriptRunnerMock)
+if System.get_env("EX_CHECK"), do: Code.put_compiler_option(:warnings_as_errors, true)
+
ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(Pinchflat.Repo, :manual)
Faker.start()
diff --git a/tooling/.check.exs b/tooling/.check.exs
index c0d38c3..87b90ff 100644
--- a/tooling/.check.exs
+++ b/tooling/.check.exs
@@ -18,7 +18,6 @@
{:sobelow, "mix sobelow --config"},
{:prettier_formatting, "yarn run lint:check", fix: "yarn run lint:fix"},
{:npm_test, false},
- {:gettext, false},
{:ex_unit, env: %{"MIX_ENV" => "test", "EX_CHECK" => "1"}}
## curated tools may be disabled (e.g. the check for compilation warnings)