{ "apiVersion": "dashboard.grafana.app/v2", "kind": "Dashboard", "metadata": { "name": "plex-exporter" }, "spec": { "annotations": [ { "kind": "AnnotationQuery", "spec": { "query": { "kind": "DataQuery", "group": "grafana", "version": "v0", "datasource": { "name": "-- Grafana --" }, "spec": {} }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", "builtIn": true, "legacyOptions": { "type": "dashboard" } } } ], "cursorSync": "Crosshair", "description": "What plex-exporter reads from your Plex Media Server: what needs your attention, who is streaming and how, and what Plex is working on. The Libraries, Storage cleanup, Streaming history and Transcoding tabs go deeper, and Exporter health shows what plex-exporter could read.", "editable": true, "elements": { "panel-10": { "kind": "Panel", "spec": { "id": 10, "title": "Library sizes", "description": "Each library with its item count, disk space, total running time and share of all storage. Average size and length are per item, so per episode in a show library, and Size per hour shows how much disk an hour of video takes. A dash means that figure has not been read yet.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"}), \"row\", \"/\", \"server_id\", \"library_id\"))", "format": "table", "instant": true, "legendFormat": "" } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row, name) (label_join((label_join(label_replace(label_join((label_replace(label_join(sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"})) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library) label_replace((label_replace(label_join(sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"})), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library) label_replace(label_replace(label_join(sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}), \"name\", \"$1\", \"library\", \"(.*)\"), \"row\", \"/\", \"server_id\", \"library_id\"))", "format": "table", "instant": true, "legendFormat": "" } }, "refId": "B", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(sum by (server, server_id, library_id, library) (plex_library_duration_milliseconds{server=~\"$server\", library_id=~\"$library_id\"}), \"row\", \"/\", \"server_id\", \"library_id\"))", "format": "table", "instant": true, "legendFormat": "" } }, "refId": "C", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) / scalar(sum(plex_library_storage_bytes{server=~\"$server\"}) > 0), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "D", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) / (sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"}) > 0), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "E", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(sum by (server, server_id, library_id, library) (plex_library_duration_milliseconds{server=~\"$server\", library_id=~\"$library_id\"}) / (sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"}) > 0), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "F", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) / (sum by (server, server_id, library_id, library) (plex_library_duration_milliseconds{server=~\"$server\", library_id=~\"$library_id\"}) / 3600000 > 0), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "G", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "joinByField", "spec": { "options": { "byField": "row", "mode": "outer" } } }, { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Time": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time 1": true, "Time 2": true, "Time #D": true, "Time #E": true, "Time #F": true, "Time #G": true, "Time #H": true, "Time #I": true, "Time #J": true, "Time #K": true, "Time #L": true, "Time #N": true, "row": true }, "indexByName": { "Value #A": 1, "Value #B": 2, "Value #C": 3, "Value #D": 4, "Value #E": 5, "Value #F": 6, "Value #G": 7, "name": 0 }, "renameByName": { "Value #A": "Items", "Value #B": "Storage", "Value #C": "Duration", "Value #D": "Share of storage", "Value #E": "Average size", "Value #F": "Average length", "Value #G": "Size per hour", "name": "Library" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "footer": { "countRows": false, "fields": [ "Items", "Storage", "Duration" ], "reducer": [ "sum" ], "show": true }, "showHeader": true, "sortBy": [ { "desc": true, "displayName": "Storage" } ], "cellHeight": "sm", "frozenColumns": { "left": 1 } }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "noValue": "No libraries yet" }, "overrides": [ { "matcher": { "id": "byName", "options": "Items" }, "properties": [ { "id": "unit", "value": "none" }, { "id": "decimals", "value": 0 } ] }, { "matcher": { "id": "byName", "options": "Storage" }, "properties": [ { "id": "unit", "value": "decbytes" } ] }, { "matcher": { "id": "byName", "options": "Duration" }, "properties": [ { "id": "unit", "value": "ms" } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] }, { "matcher": { "id": "byName", "options": "Share of storage" }, "properties": [ { "id": "unit", "value": "percentunit" } ] }, { "matcher": { "id": "byName", "options": "Average size" }, "properties": [ { "id": "unit", "value": "decbytes" } ] }, { "matcher": { "id": "byName", "options": "Average length" }, "properties": [ { "id": "unit", "value": "ms" } ] }, { "matcher": { "id": "byName", "options": "Size per hour" }, "properties": [ { "id": "unit", "value": "decbytes" } ] }, { "matcher": { "id": "byName", "options": "Library" }, "properties": [ { "id": "custom.wrapText", "value": true } ] } ] } } } } }, "panel-20": { "kind": "Panel", "spec": { "id": 20, "title": "Active sessions", "description": "One row per stream that is playing, paused or stopped in the last minute, longest first. Stream shows how Plex delivers it: direct play sends the file as it is, direct stream repackages it and transcode converts it, which costs the most CPU. Video transcoder shows a video transcode on the GPU as Hardware, on the CPU as Software or half on each, Unknown when Plex sends no usable hardware fields, and a dash otherwise. Resolution is what the player receives, followed by the file's own resolution when Plex converts it, and Location shows whether the player connects from your network or over the internet.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "label_join(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_join(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_join(plex_play_seconds_total{server=~\"$server\"}, \"ep\", \"|\", \"media_type\", \"child_title\", \"grandchild_index\"), \"episode\", \"$1, episode $2\", \"ep\", \"episode[|](.+)[|](.+)\"), \"episode\", \"S$1 E$2\", \"ep\", \"episode[|]Season ([0-9]+)[|](.+)\"), \"ep\", \"\", \"\", \"\"), \"dres\", \"$1\", \"stream_resolution\", \"(.*)\"), \"dres\", \"4K\", \"dres\", \"(?i)(4k|2160)\"), \"dres\", \"${1}p\", \"dres\", \"(480|576|720|1080)\"), \"dres\", \"SD\", \"dres\", \"(?i)sd\"), \"dres\", \"Other\", \"dres\", \"other\"), \"fres\", \"$1\", \"stream_file_resolution\", \"(.*)\"), \"fres\", \"4K\", \"fres\", \"(?i)(4k|2160)\"), \"fres\", \"${1}p\", \"fres\", \"(480|576|720|1080)\"), \"fres\", \"SD\", \"fres\", \"(?i)sd\"), \"fres\", \"Other\", \"fres\", \"other\"), \"res\", \"|\", \"dres\", \"fres\"), \"resolution\", \"$1 from $2\", \"res\", \"(.+)[|](.+)\"), \"resolution\", \"$1\", \"res\", \"(.+)[|]\"), \"resolution\", \"SD\", \"res\", \"SD[|]SD\"), \"resolution\", \"480p\", \"res\", \"480p[|]480p\"), \"resolution\", \"576p\", \"res\", \"576p[|]576p\"), \"resolution\", \"720p\", \"res\", \"720p[|]720p\"), \"resolution\", \"1080p\", \"res\", \"1080p[|]1080p\"), \"resolution\", \"4K\", \"res\", \"4K[|]4K\"), \"resolution\", \"Other\", \"res\", \"Other[|]Other\"), \"dres\", \"\", \"\", \"\"), \"fres\", \"\", \"\", \"\"), \"res\", \"\", \"\", \"\"), \"row\", \"/\", \"server_id\", \"session\")", "format": "table", "instant": true, "legendFormat": "" } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row, pipeline) (label_join(label_join(plex_session_video_transcode{server=~\"$server\"}, \"pipeline\", \"/\", \"decode\", \"encode\"), \"row\", \"/\", \"server_id\", \"session\")) or on (row) label_replace(max by (row) (label_join(plex_play_seconds_total{server=~\"$server\"}, \"row\", \"/\", \"server_id\", \"session\")), \"pipeline\", \"none\", \"\", \"\")", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "B", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "joinByField", "spec": { "options": { "byField": "row", "mode": "outer" } } }, { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "__name__": true, "__tenant_id__": true, "device": true, "grandchild_title": true, "hostname": true, "instance": true, "job": true, "library_id": true, "library_type": true, "media_type": true, "server": true, "server_id": true, "session": true, "local": true, "Time": true, "Time 1": true, "Time 2": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time #D": true, "Time #E": true, "Time #F": true, "Time #G": true, "Time #H": true, "Time #I": true, "Time #J": true, "Time #K": true, "Time #L": true, "Time #N": true, "Value #B": true, "row": true, "child_title": true, "grandchild_index": true, "stream_resolution": true, "stream_file_resolution": true }, "indexByName": { "user": 0, "title": 1, "episode": 2, "Value #A": 3, "location": 4, "device_type": 5, "stream_type": 6, "transcode_type": 7, "pipeline": 8, "resolution": 9, "library": 10, "subtitle_action": 11 }, "renameByName": { "device_type": "Client", "library": "Library", "location": "Location", "stream_type": "Stream", "subtitle_action": "Subtitles", "title": "Title", "transcode_type": "Transcode", "user": "User", "Value #A": "Play time", "pipeline": "Video transcoder", "episode": "Episode", "resolution": "Resolution" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "sortBy": [ { "desc": true, "displayName": "Play time" } ], "cellHeight": "sm", "frozenColumns": { "left": 1 } }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "noValue": "Nobody is streaming", "custom": { "wrapHeaderText": true } }, "overrides": [ { "matcher": { "id": "byName", "options": "Play time" }, "properties": [ { "id": "unit", "value": "s" }, { "id": "custom.width", "value": 96 } ] }, { "matcher": { "id": "byName", "options": "User" }, "properties": [ { "id": "custom.width", "value": 128 }, { "id": "custom.wrapText", "value": true } ] }, { "matcher": { "id": "byName", "options": "Client" }, "properties": [ { "id": "custom.width", "value": 152 } ] }, { "matcher": { "id": "byName", "options": "Title" }, "properties": [ { "id": "custom.minWidth", "value": 150 }, { "id": "custom.wrapText", "value": true } ] }, { "matcher": { "id": "byName", "options": "Episode" }, "properties": [ { "id": "custom.width", "value": 88 } ] }, { "matcher": { "id": "byName", "options": "Library" }, "properties": [ { "id": "custom.width", "value": 112 } ] }, { "matcher": { "id": "byName", "options": "Stream" }, "properties": [ { "id": "mappings", "value": [ { "options": { "copy": { "index": 1, "text": "Direct stream" }, "directplay": { "index": 0, "text": "Direct play" }, "other": { "index": 4, "text": "Other" }, "transcode": { "index": 2, "text": "Transcode" }, "unknown": { "index": 3, "text": "Unknown" } }, "type": "value" } ] }, { "id": "custom.width", "value": 112 } ] }, { "matcher": { "id": "byName", "options": "Resolution" }, "properties": [ { "id": "custom.width", "value": 136 } ] }, { "matcher": { "id": "byName", "options": "Transcode" }, "properties": [ { "id": "mappings", "value": [ { "options": { "audio": { "index": 2, "text": "Audio" }, "both": { "index": 3, "text": "Video and audio" }, "none": { "index": 0, "text": "No" }, "video": { "index": 1, "text": "Video" } }, "type": "value" } ] }, { "id": "custom.width", "value": 128 } ] }, { "matcher": { "id": "byName", "options": "Subtitles" }, "properties": [ { "id": "mappings", "value": [ { "options": { "burn": { "index": 1, "text": "Burned in" }, "copy": { "index": 2, "text": "Copied" }, "none": { "index": 0, "text": "None" }, "other": { "index": 4, "text": "Other" }, "transcode": { "index": 3, "text": "Converted" } }, "type": "value" } ] }, { "id": "custom.width", "value": 96 } ] }, { "matcher": { "id": "byName", "options": "Location" }, "properties": [ { "id": "mappings", "value": [ { "options": { "lan": { "index": 0, "text": "Your network" }, "other": { "index": 3, "text": "Other" }, "unknown": { "index": 2, "text": "Unknown" }, "wan": { "index": 1, "text": "Internet" } }, "type": "value" } ] }, { "id": "custom.width", "value": 120 } ] }, { "matcher": { "id": "byName", "options": "Video transcoder" }, "properties": [ { "id": "mappings", "value": [ { "type": "value", "options": { "hardware/hardware": { "index": 0, "text": "Hardware" }, "hardware/software": { "index": 1, "text": "Hardware decode" }, "software/hardware": { "index": 2, "text": "Hardware encode" }, "software/software": { "index": 3, "text": "Software" }, "none": { "index": 5, "text": "-" } } }, { "type": "regex", "options": { "pattern": ".*unknown.*", "result": { "index": 4, "text": "Unknown" } } } ] }, { "id": "custom.width", "value": 136 } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] } ] } } } } }, "panel-21": { "kind": "Panel", "spec": { "id": 21, "title": "Session bandwidth and bitrate", "description": "Network bandwidth Plex reports for all streams together, per server, as a solid line, with the bitrate of the media they play as a dashed line. Bandwidth well above the bitrate is players buffering ahead, and a high bitrate points to large files such as 4K remuxes. When remote streams buffer, Bandwidth by network on Streaming history splits the bandwidth into home and remote to compare with your upload speed. Both lines read 0 when nobody is streaming, and a gap means plex-exporter was not scraped.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "label_replace(label_join((sum by (server, server_id) (plex_session_bandwidth_kbps{server=~\"$server\"}) or (0 * group by (server, server_id) (plex_server_info{server=~\"$server\"}))) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id) label_replace((sum by (server, server_id) (plex_session_bandwidth_kbps{server=~\"$server\"}) or (0 * group by (server, server_id) (plex_server_info{server=~\"$server\"}))), \"name\", \"$1\", \"server\", \"(.*)\")", "legendFormat": "{{name}} bandwidth" } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "label_replace(label_join((sum by (server, server_id) (plex_session_bitrate_kbps{server=~\"$server\"}) or (0 * group by (server, server_id) (plex_server_info{server=~\"$server\"}))) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id) label_replace((sum by (server, server_id) (plex_session_bitrate_kbps{server=~\"$server\"}) or (0 * group by (server, server_id) (plex_server_info{server=~\"$server\"}))), \"name\", \"$1\", \"server\", \"(.*)\")", "legendFormat": "{{name}} media bitrate" } }, "refId": "B", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "timeseries", "version": "", "spec": { "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi", "sort": "desc" } }, "fieldConfig": { "defaults": { "unit": "Kbits", "min": 0, "color": { "mode": "palette-classic" }, "custom": { "fillOpacity": 20, "lineWidth": 2 }, "noValue": "plex-exporter was not scraped in this range" }, "overrides": [ { "matcher": { "id": "byRegexp", "options": ".* media bitrate" }, "properties": [ { "id": "custom.lineStyle", "value": { "fill": "dash", "dash": [ 10, 10 ] } }, { "id": "custom.fillOpacity", "value": 0 } ] } ] } } } } }, "panel-3": { "kind": "Panel", "spec": { "id": 3, "title": "Transcodes", "description": "Streams Plex is converting right now on the selected servers, because the player cannot play the file as it is. Transcoding uses the most CPU, so a high count explains a slow server. The tile turns yellow at 1 transcode and orange at 3, and zero is normal when your players support your files. Unknown means plex-exporter has not identified the server yet.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(plex_active_transcode_sessions{server=~\"$server\"})", "instant": true, "legendFormat": "{{ server }}", "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "short", "decimals": 0, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" }, { "value": 1, "color": "yellow" }, { "value": 3, "color": "orange" } ] }, "color": { "mode": "thresholds" }, "noValue": "Unknown" }, "overrides": [] } } } } }, "panel-30": { "kind": "Panel", "spec": { "id": 30, "title": "Host CPU", "description": "CPU use of the whole machine Plex runs on, from Plex's own statistics. A yellow dashed line marks 80% and a red one marks 90%. Sustained use above 80% slows transcodes and library scans, and above 90% streams can stutter. An empty panel means Plex reported no host statistics for the selected servers.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "label_replace(label_join((plex_host_cpu_utilization_ratio{server=~\"$server\"}) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id) label_replace((plex_host_cpu_utilization_ratio{server=~\"$server\"}), \"name\", \"$1\", \"server\", \"(.*)\")", "legendFormat": "{{name}}" } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "timeseries", "version": "", "spec": { "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } }, "fieldConfig": { "defaults": { "unit": "percentunit", "min": 0, "max": 1, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "green" }, { "value": 0.8, "color": "yellow" }, { "value": 0.9, "color": "red" } ] }, "color": { "mode": "palette-classic" }, "custom": { "fillOpacity": 20, "lineWidth": 2, "thresholdsStyle": { "mode": "dashed" } }, "noValue": "No host CPU reading, which needs Plex Pass" }, "overrides": [] } } } } }, "panel-31": { "kind": "Panel", "spec": { "id": 31, "title": "Host memory", "description": "Memory use of the whole machine Plex runs on, from Plex's own statistics. A yellow dashed line marks 80% and a red one marks 90%. Use above 80% leaves little room for new streams, and sustained use above 90% risks slowdowns and failed transcodes. An empty panel means Plex reported no host statistics for the selected servers.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "label_replace(label_join((plex_host_memory_utilization_ratio{server=~\"$server\"}) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id) label_replace((plex_host_memory_utilization_ratio{server=~\"$server\"}), \"name\", \"$1\", \"server\", \"(.*)\")", "legendFormat": "{{name}}" } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "timeseries", "version": "", "spec": { "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi" } }, "fieldConfig": { "defaults": { "unit": "percentunit", "min": 0, "max": 1, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "green" }, { "value": 0.8, "color": "yellow" }, { "value": 0.9, "color": "red" } ] }, "color": { "mode": "palette-classic" }, "custom": { "fillOpacity": 20, "lineWidth": 2, "thresholdsStyle": { "mode": "dashed" } }, "noValue": "No host memory reading, which needs Plex Pass" }, "overrides": [] } } } } }, "panel-4": { "kind": "Panel", "spec": { "id": 4, "title": "Plex version", "description": "The Plex Media Server version running now. Use it to confirm that an update went through. Unknown means plex-exporter has not identified the server yet, which happens for a few seconds after it starts, while Plex is unreachable and while plex-exporter is not scraped.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "label_replace(plex_server_info{server=~\"$server\"}, \"version\", \"$1\", \"version\", \"([^-]+)-.*\") or on () label_replace(vector(1), \"version\", \"Unknown\", \"\", \"\")", "instant": true, "legendFormat": "{{ version }}", "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "none", "graphMode": "none", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "textMode": "name", "text": { "titleSize": 14, "valueSize": 24 } }, "fieldConfig": { "defaults": { "noValue": "Unknown" }, "overrides": [] } } } } }, "panel-40": { "kind": "Panel", "spec": { "id": 40, "title": "Streams", "description": "Streams playing or paused right now on the selected servers, with the trend over the time range. A stream drops out about a minute after it stops. The figure is blue when idle and turns yellow at 1 stream, orange at 3 and red at 5, because each stream uses upload bandwidth and server time. Unknown means plex-exporter has not identified the server yet.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "count(plex_play_seconds_total{server=~\"$server\"}) or (0 * count(plex_server_info{server=~\"$server\"}))", "legendFormat": "" } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": { "maxDataPoints": 6285 } } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "area", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "short", "decimals": 0, "min": 0, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" }, { "value": 1, "color": "yellow" }, { "value": 3, "color": "orange" }, { "value": 5, "color": "red" } ] }, "color": { "mode": "thresholds" }, "noValue": "Unknown" }, "overrides": [] } } } } }, "panel-42": { "kind": "Panel", "spec": { "id": 42, "title": "Total items", "description": "Movies, episodes, tracks and photos across the selected libraries, added together. plex-exporter counts them every 15 minutes, so the number can lag after a large scan. Not counted yet means the first count since plex-exporter started has not finished, or plex-exporter is not being scraped.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(plex_library_items{server=~\"$server\", library_id=~\"$library_id\"})", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "short", "min": 0, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "purple" } ] }, "color": { "mode": "thresholds" }, "noValue": "Not counted yet" }, "overrides": [] } } } } }, "panel-43": { "kind": "Panel", "spec": { "id": 43, "title": "Total storage", "description": "Disk space the selected libraries use, as Plex reports it. Compare it with the free space on your media drives. Unknown means plex-exporter has not read the library list yet.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"})", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "decbytes", "min": 0, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "purple" } ] }, "color": { "mode": "thresholds" }, "noValue": "Unknown" }, "overrides": [] } } } } }, "panel-44": { "kind": "Panel", "spec": { "id": 44, "title": "Total duration", "description": "How long it would take to play everything in the selected libraries back to back. It grows when you add media and drops when you remove it. Unknown means plex-exporter has not read the library list yet.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(plex_library_duration_milliseconds{server=~\"$server\", library_id=~\"$library_id\"})", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "ms", "min": 0, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "purple" } ] }, "color": { "mode": "thresholds" }, "noValue": "Unknown" }, "overrides": [] } } } } }, "panel-50": { "kind": "Panel", "spec": { "id": 50, "title": "Items per library", "description": "Item count of each library over time, stacked so the top edge is the total for the selected servers. A show library counts episodes and a music library counts tracks, read every 15 minutes, so a large scan shows up as a step. On a large library a small change barely shows, so Growth in this range and Change per library show it. History reaches back as far as your Prometheus keeps metrics.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "(label_join(label_replace(label_join((label_replace(label_join(sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"})) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library) label_replace((label_replace(label_join(sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"})), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library) label_replace(label_replace(label_join(sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"}), \"name\", \"$1\", \"library\", \"(.*)\")", "legendFormat": "{{name}}" } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "timeseries", "version": "", "spec": { "options": { "legend": { "calcs": [ "lastNotNull" ], "displayMode": "table", "placement": "right", "sortBy": "Last *", "sortDesc": true }, "tooltip": { "mode": "multi", "sort": "desc" } }, "fieldConfig": { "defaults": { "unit": "short", "color": { "mode": "palette-classic" }, "custom": { "drawStyle": "line", "lineWidth": 1, "fillOpacity": 30, "spanNulls": true, "showPoints": "never", "stacking": { "mode": "normal", "group": "A" } }, "min": 0, "noValue": "No item count yet", "decimals": 0 }, "overrides": [] } } } } }, "panel-60": { "kind": "Panel", "spec": { "id": 60, "title": "Items by type", "description": "Movies, episodes, music tracks and photos across the selected servers, counted from every library of that type. A show library counts its episodes, not its shows. A type you have no library for is left out, and No libraries yet means plex-exporter has not counted the items.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(plex_library_items{server=~\"$server\", library_id=~\"$library_id\", content_type=\"movies\"})", "legendFormat": "Movies", "instant": true, "range": false } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(plex_library_items{server=~\"$server\", library_id=~\"$library_id\", content_type=\"episodes\"})", "legendFormat": "Episodes", "instant": true, "range": false } }, "refId": "B", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(plex_library_items{server=~\"$server\", library_id=~\"$library_id\", content_type=\"tracks\"})", "legendFormat": "Tracks", "instant": true, "range": false } }, "refId": "C", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(plex_library_items{server=~\"$server\", library_id=~\"$library_id\", content_type=\"photos\"})", "legendFormat": "Photos", "instant": true, "range": false } }, "refId": "D", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "none", "justifyMode": "center", "orientation": "vertical", "textMode": "value_and_name", "wideLayout": true, "reduceOptions": { "calcs": [ "lastNotNull" ], "fields": "", "values": false }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "short", "noValue": "No libraries yet", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "purple" } ] } }, "overrides": [] } } } } }, "panel-63": { "kind": "Panel", "spec": { "id": 63, "title": "Storage per library", "description": "Disk space of each library over time, stacked so the top edge is the total for the selected servers. A band that thickens is a library growing, a step down means files were removed or replaced by smaller ones, and the legend shows each library's current size. On a large library a small change barely shows, so Growth in this range and Change per library show it. History reaches back as far as your Prometheus keeps metrics.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "(label_join(label_replace(label_join((label_replace(label_join(sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"})) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library) label_replace((label_replace(label_join(sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"})), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library) label_replace(label_replace(label_join(sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}), \"name\", \"$1\", \"library\", \"(.*)\")", "legendFormat": "{{name}}" } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "timeseries", "version": "", "spec": { "options": { "legend": { "calcs": [ "lastNotNull" ], "displayMode": "table", "placement": "right", "sortBy": "Last *", "sortDesc": true }, "tooltip": { "mode": "multi", "sort": "desc" } }, "fieldConfig": { "defaults": { "unit": "decbytes", "color": { "mode": "palette-classic" }, "custom": { "drawStyle": "line", "lineWidth": 1, "fillOpacity": 30, "spanNulls": true, "showPoints": "never", "stacking": { "mode": "normal", "group": "A" } }, "min": 0, "noValue": "No storage reading yet" }, "overrides": [] } } } } }, "panel-70": { "kind": "Panel", "spec": { "id": 70, "title": "Watch time by delivery", "description": "Hours watched, stacked by delivery: direct play sends the file as it is, direct stream repackages it, and transcode re-encodes it. A growing orange transcode band means a device or a file format forces conversions, so check the Transcoding tab for which players. Each bar covers an equal slice of the range, an hour at 24 hours and a day at 30 days, and the newest bar grows until its slice ends. The legend total adds up the bars, which start at the first whole slice inside the range, and a missing bar means nothing played or plex-exporter was not scraped.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(increase(plex_play_seconds_total{server=~\"$server\", stream_type=\"directplay\"}[$__interval] offset -$__interval)) / 3600 and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Direct play" } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(increase(plex_play_seconds_total{server=~\"$server\", stream_type=\"copy\"}[$__interval] offset -$__interval)) / 3600 and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Direct stream" } }, "refId": "B", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(increase(plex_play_seconds_total{server=~\"$server\", stream_type=\"transcode\"}[$__interval] offset -$__interval)) / 3600 and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Transcode" } }, "refId": "C", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(increase(plex_play_seconds_total{server=~\"$server\", stream_type=~\"unknown|other\"}[$__interval] offset -$__interval)) / 3600 and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Unknown" } }, "refId": "D", "hidden": false } } ], "transformations": [], "queryOptions": { "maxDataPoints": 25, "interval": "1h" } } }, "vizConfig": { "kind": "VizConfig", "group": "timeseries", "version": "", "spec": { "options": { "legend": { "calcs": [ "sum" ], "displayMode": "table", "placement": "right" }, "tooltip": { "mode": "multi", "sort": "desc" } }, "fieldConfig": { "defaults": { "unit": "suffix:h", "min": 0, "noValue": "No watch time in this range", "color": { "mode": "palette-classic" }, "custom": { "drawStyle": "bars", "fillOpacity": 80, "lineWidth": 1, "showPoints": "never", "stacking": { "mode": "normal", "group": "A" }, "barAlignment": 1 } }, "overrides": [ { "matcher": { "id": "byName", "options": "Direct play" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "green" } } ] }, { "matcher": { "id": "byName", "options": "Direct stream" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "blue" } } ] }, { "matcher": { "id": "byName", "options": "Transcode" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "orange" } } ] }, { "matcher": { "id": "byName", "options": "Unknown" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "#8e8e8e" } } ] } ] } } } } }, "panel-71": { "kind": "Panel", "spec": { "id": 71, "title": "Watch time by network", "description": "Hours watched, stacked by home network, remote, and Unknown for streams with no network location. Remote watching uses your upload bandwidth, so a growing yellow remote band explains slow remote streams. Each bar covers an equal slice of the range, an hour at 24 hours and a day at 30 days, and the newest bar grows until its slice ends. The legend total adds up the bars, which start at the first whole slice inside the range, and a missing bar means nothing played or plex-exporter was not scraped.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(increase(plex_play_seconds_total{server=~\"$server\", location=\"lan\"}[$__interval] offset -$__interval)) / 3600 and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Home network" } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(increase(plex_play_seconds_total{server=~\"$server\", location=\"wan\"}[$__interval] offset -$__interval)) / 3600 and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Remote" } }, "refId": "B", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(increase(plex_play_seconds_total{server=~\"$server\", location=~\"unknown|other\"}[$__interval] offset -$__interval)) / 3600 and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Unknown" } }, "refId": "C", "hidden": false } } ], "transformations": [], "queryOptions": { "maxDataPoints": 25, "interval": "1h" } } }, "vizConfig": { "kind": "VizConfig", "group": "timeseries", "version": "", "spec": { "options": { "legend": { "calcs": [ "sum" ], "displayMode": "table", "placement": "right" }, "tooltip": { "mode": "multi", "sort": "desc" } }, "fieldConfig": { "defaults": { "unit": "suffix:h", "min": 0, "noValue": "No watch time in this range", "color": { "mode": "palette-classic" }, "custom": { "drawStyle": "bars", "fillOpacity": 80, "lineWidth": 1, "showPoints": "never", "stacking": { "mode": "normal", "group": "A" }, "barAlignment": 1 } }, "overrides": [ { "matcher": { "id": "byName", "options": "Home network" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "green" } } ] }, { "matcher": { "id": "byName", "options": "Remote" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "yellow" } } ] }, { "matcher": { "id": "byName", "options": "Unknown" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "#8e8e8e" } } ] } ] } } } } }, "panel-72": { "kind": "Panel", "spec": { "id": 72, "title": "Watch time by user", "description": "Time each user spent playing in the selected range, longest first. Times are estimates from plex-exporter's 5-second session check, and history reaches back only as far as your Prometheus keeps metrics. Each stream can lose up to one scrape interval, so short streams count low or are missed. No watch time in this range means nothing played, or plex-exporter was not scraped.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sort_desc((sum by (user) (increase(plex_play_seconds_total{server=~\"$server\"}[$__range]))) / 3600)", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "__name__": true, "__tenant_id__": true, "instance": true, "job": true, "hostname": true, "Time": true, "Time 1": true, "Time 2": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time #D": true, "Time #E": true, "Time #F": true, "Time #G": true, "Time #H": true, "Time #I": true, "Time #J": true, "Time #K": true, "Time #L": true, "Time #N": true, "server": true, "server_id": true, "library_id": true, "library": true, "library_type": true, "activity_type": true, "name": true }, "indexByName": { "user": 0, "Value": 1 }, "renameByName": { "user": "User", "Value": "Watch time" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "cellHeight": "sm", "sortBy": [ { "displayName": "Watch time", "desc": true } ] }, "fieldConfig": { "defaults": { "unit": "suffix:h", "min": 0, "noValue": "No watch time in this range", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "fixed", "fixedColor": "blue" }, "custom": { "align": "auto", "cellOptions": { "type": "auto" } } }, "overrides": [ { "matcher": { "id": "byName", "options": "Watch time" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "gauge", "mode": "basic", "valueDisplayMode": "text" } } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] } ] } } } } }, "panel-73": { "kind": "Panel", "spec": { "id": 73, "title": "Watch time by library", "description": "Time spent playing from each library in the selected range, longest first, estimated from plex-exporter's 5-second session check, so short streams count low or are missed. Unknown library covers streams whose library plex-exporter could not resolve. History reaches back only as far as your Prometheus keeps metrics. No watch time in this range means nothing played, or plex-exporter was not scraped.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sort_desc(((label_join(label_replace(label_join((label_replace(label_join(label_replace(sum by (server, server_id, library_id, library) (increase(plex_play_seconds_total{server=~\"$server\"}[$__range])), \"library\", \"Unknown library\", \"library\", \"unknown\") and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) label_replace(sum by (server, server_id, library_id, library) (increase(plex_play_seconds_total{server=~\"$server\"}[$__range])), \"library\", \"Unknown library\", \"library\", \"unknown\")) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library) label_replace((label_replace(label_join(label_replace(sum by (server, server_id, library_id, library) (increase(plex_play_seconds_total{server=~\"$server\"}[$__range])), \"library\", \"Unknown library\", \"library\", \"unknown\") and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) label_replace(sum by (server, server_id, library_id, library) (increase(plex_play_seconds_total{server=~\"$server\"}[$__range])), \"library\", \"Unknown library\", \"library\", \"unknown\")), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library) label_replace(label_replace(label_join(label_replace(sum by (server, server_id, library_id, library) (increase(plex_play_seconds_total{server=~\"$server\"}[$__range])), \"library\", \"Unknown library\", \"library\", \"unknown\") and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) label_replace(sum by (server, server_id, library_id, library) (increase(plex_play_seconds_total{server=~\"$server\"}[$__range])), \"library\", \"Unknown library\", \"library\", \"unknown\"), \"name\", \"$1\", \"library\", \"(.*)\")) / 3600)", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "__name__": true, "__tenant_id__": true, "instance": true, "job": true, "hostname": true, "Time": true, "Time 1": true, "Time 2": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time #D": true, "Time #E": true, "Time #F": true, "Time #G": true, "Time #H": true, "Time #I": true, "Time #J": true, "Time #K": true, "Time #L": true, "Time #N": true, "server": true, "server_id": true, "library_id": true, "library": true, "library_type": true, "activity_type": true, "user": true }, "indexByName": { "name": 0, "Value": 1 }, "renameByName": { "name": "Library", "Value": "Watch time" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "cellHeight": "sm", "sortBy": [ { "displayName": "Watch time", "desc": true } ] }, "fieldConfig": { "defaults": { "unit": "suffix:h", "min": 0, "noValue": "No watch time in this range", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "fixed", "fixedColor": "blue" }, "custom": { "align": "auto", "cellOptions": { "type": "auto" } } }, "overrides": [ { "matcher": { "id": "byName", "options": "Watch time" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "gauge", "mode": "basic", "valueDisplayMode": "text" } } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] } ] } } } } }, "panel-74": { "kind": "Panel", "spec": { "id": 74, "title": "Most watched titles", "description": "The 20 shows, films and music tracks played longest in the selected range, each show counted whole, its watch time the sum of its episodes. A music row names the artist as its title, with the album and track beside it. Times are estimates from plex-exporter's 5-second session check that reach back only as far as your Prometheus keeps metrics, so short streams count low or are missed. No plays in this range means nothing played, or plex-exporter was not scraped.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "(topk(20, (sum by (media_type, title) (increase(plex_play_seconds_total{server=~\"$server\", media_type=\"episode\"}[$__range])) or sum by (media_type, title, child_title, grandchild_title) (increase(plex_play_seconds_total{server=~\"$server\", media_type!=\"episode\"}[$__range]))) > 0)) / 3600", "legendFormat": "", "format": "table", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Time": true }, "indexByName": { "title": 0, "media_type": 1, "child_title": 2, "grandchild_title": 3, "Value": 4 }, "renameByName": { "title": "Title", "media_type": "Type", "child_title": "Album", "grandchild_title": "Track", "Value": "Watched" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "sortBy": [ { "desc": true, "displayName": "Watched" } ], "cellHeight": "sm" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "noValue": "No plays in this range", "custom": { "minWidth": 80, "wrapText": true, "wrapHeaderText": true } }, "overrides": [ { "matcher": { "id": "byName", "options": "Watched" }, "properties": [ { "id": "min", "value": 0 }, { "id": "custom.width", "value": 112 }, { "id": "unit", "value": "suffix:h" } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] }, { "matcher": { "id": "byName", "options": "Type" }, "properties": [ { "id": "custom.width", "value": 88 }, { "id": "mappings", "value": [ { "type": "value", "options": { "episode": { "index": 0, "text": "Show" }, "movie": { "index": 1, "text": "Film" }, "track": { "index": 2, "text": "Track" }, "clip": { "index": 3, "text": "Clip" }, "photo": { "index": 4, "text": "Photo" }, "other": { "index": 5, "text": "Other" } } } ] } ] } ] } } } } }, "panel-75": { "kind": "Panel", "spec": { "id": 75, "title": "Bandwidth by network", "description": "Bandwidth Plex reports for the streams playing at each moment, split by home network and remote players. When remote streams buffer, compare the Remote band with your upload speed. Unknown covers streams with no network location or one this exporter does not recognise, so the stack adds up to all streams. The lines sit at 0 while nobody is streaming, and a gap means plex-exporter was not scraped.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(plex_session_bandwidth_kbps{server=~\"$server\", location=\"lan\"}) or (0 * sum(plex_server_info{server=~\"$server\"}))", "legendFormat": "Home network" } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(plex_session_bandwidth_kbps{server=~\"$server\", location=\"wan\"}) or (0 * sum(plex_server_info{server=~\"$server\"}))", "legendFormat": "Remote" } }, "refId": "B", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(plex_session_bandwidth_kbps{server=~\"$server\", location=~\"unknown|other\"}) or (0 * sum(plex_server_info{server=~\"$server\"}))", "legendFormat": "Unknown" } }, "refId": "C", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "timeseries", "version": "", "spec": { "options": { "legend": { "displayMode": "list", "placement": "bottom" }, "tooltip": { "mode": "multi", "sort": "desc" } }, "fieldConfig": { "defaults": { "unit": "Kbits", "min": 0, "color": { "mode": "palette-classic" }, "custom": { "drawStyle": "line", "lineWidth": 1, "fillOpacity": 30, "stacking": { "mode": "normal" } } }, "overrides": [] } } } } }, "panel-100": { "kind": "Panel", "spec": { "id": 100, "title": "Plex update", "description": "Shows only when Plex reports a release newer than the version this server runs. It counts only a check Plex made in the last week, so an old answer from a server that has stopped checking for updates does not show. On Docker, pull a newer image to update, and Plex version shows when it went through. No alert rule covers this.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max(plex_server_update_available{server=~\"$server\"} and on (server, server_id) (time() - plex_server_update_checked_timestamp_seconds < 604800)) == 1", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "background", "graphMode": "none", "justifyMode": "center", "reduceOptions": { "calcs": [ "lastNotNull" ], "values": false }, "textMode": "auto", "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "none", "decimals": 0, "noValue": "Nothing to report", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "mappings": [ { "type": "value", "options": { "1": { "index": 0, "text": "Available", "color": "blue" } } } ] }, "overrides": [] } } } } }, "panel-102": { "kind": "Panel", "spec": { "id": 102, "title": "Plex tasks", "description": "Background tasks Plex is running now: scans, media analysis and metadata refreshes in each library, and server-wide tasks such as database maintenance, each listed in Current library work below. A task that runs for hours points at a stuck scan or a busy server. Zero is the normal idle state, and also what the tile reads when plex-exporter cannot read the task list, which then shows as Failed reads. Unknown means plex-exporter has not reached Plex.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "count(plex_server_activity_progress_ratio{server=~\"$server\", activity_type!=\"streaming\"}) or (0 * count(plex_server_info{server=~\"$server\"}))", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "short", "noValue": "Unknown", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "thresholds" }, "decimals": 0 }, "overrides": [] } } } } }, "panel-103": { "kind": "Panel", "spec": { "id": 103, "title": "Oldest scan", "description": "How long ago Plex last scanned the library that has gone longest without a scan. A library that stops scanning usually means its media folder went missing, so check the mount. No value means Plex reports no scan time for any library.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max(time() - plex_library_last_scan_timestamp_seconds{server=~\"$server\"})", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "s", "noValue": "No scan time reported", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "thresholds" }, "decimals": 0 }, "overrides": [] } } } } }, "panel-104": { "kind": "Panel", "spec": { "id": 104, "title": "Items added", "description": "Items the selected servers' libraries gained in the selected time range: movies, episodes, tracks and photos added, minus any removed, so a negative figure means more were removed. Zero over a week on a server that usually grows means your downloads or imports have stopped, and Growth in this range on the Libraries tab shows which library. Unknown means there is no item count from the start of the range, as when plex-exporter was set up since or your Prometheus keeps no metrics that old. A library added during the range is not counted, as in Growth in this range.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\"}) - sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\"} offset $__range))", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "none", "noValue": "Unknown", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "thresholds" }, "decimals": 0 }, "overrides": [] } } } } }, "panel-105": { "kind": "Panel", "spec": { "id": 105, "title": "Current library work", "description": "Each scan, analysis or metadata task Plex is running now, by library, with server-wide tasks listed as Server-wide. The Progress bar shows how far the task has got, and Working means Plex gives no estimate. A task whose progress does not move for an hour points at a stuck task.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "((label_join(label_replace(label_join((label_replace(label_join(max by (server, server_id, library_id, library, activity_type) (plex_server_activity_progress_ratio{server=~\"$server\", library_id!=\"\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, activity_type) max by (server, server_id, library_id, library, activity_type) (plex_server_activity_progress_ratio{server=~\"$server\", library_id!=\"\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1))) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library, activity_type) label_replace((label_replace(label_join(max by (server, server_id, library_id, library, activity_type) (plex_server_activity_progress_ratio{server=~\"$server\", library_id!=\"\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, activity_type) max by (server, server_id, library_id, library, activity_type) (plex_server_activity_progress_ratio{server=~\"$server\", library_id!=\"\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1))), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library, activity_type) label_replace(label_replace(label_join(max by (server, server_id, library_id, library, activity_type) (plex_server_activity_progress_ratio{server=~\"$server\", library_id!=\"\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, activity_type) max by (server, server_id, library_id, library, activity_type) (plex_server_activity_progress_ratio{server=~\"$server\", library_id!=\"\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)), \"name\", \"$1\", \"library\", \"(.*)\")) or ((label_join(label_replace(label_join((max by (server, server_id, library, activity_type) (label_replace(plex_server_activity_progress_ratio{server=~\"$server\", library_id=\"\"}, \"library\", \"Server-wide\", \"\", \"\"))) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library, activity_type) label_replace((max by (server, server_id, library, activity_type) (label_replace(plex_server_activity_progress_ratio{server=~\"$server\", library_id=\"\"}, \"library\", \"Server-wide\", \"\", \"\"))), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library, activity_type) label_replace(max by (server, server_id, library, activity_type) (label_replace(plex_server_activity_progress_ratio{server=~\"$server\", library_id=\"\"}, \"library\", \"Server-wide\", \"\", \"\")), \"name\", \"$1\", \"library\", \"(.*)\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "__name__": true, "__tenant_id__": true, "instance": true, "job": true, "hostname": true, "Time": true, "Time 1": true, "Time 2": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time #D": true, "Time #E": true, "Time #F": true, "Time #G": true, "Time #H": true, "Time #I": true, "Time #J": true, "Time #K": true, "Time #L": true, "Time #N": true, "server": true, "server_id": true, "library_id": true, "library": true, "library_type": true, "user": true }, "indexByName": { "name": 0, "activity_type": 1, "Value": 2 }, "renameByName": { "name": "Library", "activity_type": "Task", "Value": "Progress" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "cellHeight": "sm", "sortBy": [ { "displayName": "Progress", "desc": true } ] }, "fieldConfig": { "defaults": { "unit": "percentunit", "noValue": "Nothing running", "min": 0, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "fixed", "fixedColor": "blue" }, "mappings": [ { "type": "value", "options": { "-1": { "index": 0, "text": "Working" } } } ], "max": 1, "decimals": 0, "custom": { "align": "auto", "cellOptions": { "type": "auto" } } }, "overrides": [ { "matcher": { "id": "byName", "options": "Progress" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "gauge", "mode": "basic", "valueDisplayMode": "text" } } ] }, { "matcher": { "id": "byName", "options": "Library" }, "properties": [ { "id": "custom.minWidth", "value": 100 } ] }, { "matcher": { "id": "byName", "options": "Task" }, "properties": [ { "id": "custom.width", "value": 104 }, { "id": "mappings", "value": [ { "type": "value", "options": { "scan": { "index": 0, "text": "Scan" }, "analysis": { "index": 1, "text": "Analysis" }, "metadata": { "index": 2, "text": "Metadata" }, "maintenance": { "index": 3, "text": "Maintenance" }, "streaming": { "index": 4, "text": "Streaming" }, "other": { "index": 5, "text": "Other" } } } ] } ] }, { "matcher": { "id": "byName", "options": "Progress" }, "properties": [ { "id": "custom.minWidth", "value": 112 } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] } ] } } } } }, "panel-117": { "kind": "Panel", "spec": { "id": 117, "title": "Library activity", "description": "How long ago each library's newest item arrived, how long ago Plex scanned it, and how long ago plex-exporter last read it item by item, the hourly read behind the Storage cleanup figures. Growth in this range below shows what each library added in the selected range. A dash means that figure has not been read yet, and music and photo libraries have no catalog read.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row, name) (label_join((label_join(label_replace(label_join((label_replace(label_join(max by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"})) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library) label_replace((label_replace(label_join(max by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"})), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library) label_replace(label_replace(label_join(max by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}), \"name\", \"$1\", \"library\", \"(.*)\"), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "N", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(min by (server, server_id, library_id, library) ((time() - plex_library_newest_item_added_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"}) * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "C", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(min by (server, server_id, library_id, library) ((time() - plex_library_last_scan_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"}) * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "D", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(max by (server, server_id, library_id, library) ((time() - plex_library_walk_last_success_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"}) * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "E", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "joinByField", "spec": { "options": { "byField": "row", "mode": "outer" } } }, { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Time": true, "Time 1": true, "Time 2": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time #D": true, "Time #E": true, "Time #F": true, "Time #G": true, "Time #H": true, "Time #I": true, "Time #J": true, "Time #K": true, "Time #L": true, "Time #N": true, "row": true, "Value #N": true }, "indexByName": { "name": 0, "Value #C": 1, "Value #D": 2, "Value #E": 3 }, "renameByName": { "name": "Library", "Value #C": "Newest item", "Value #D": "Last Plex scan", "Value #E": "Last catalog read" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "sortBy": [ { "displayName": "Newest item", "desc": true } ], "cellHeight": "sm", "frozenColumns": { "left": 1 } }, "fieldConfig": { "defaults": { "noValue": "No library has been read yet", "custom": { "minWidth": 140 } }, "overrides": [ { "matcher": { "id": "byName", "options": "Newest item" }, "properties": [ { "id": "unit", "value": "s" }, { "id": "decimals", "value": 0 } ] }, { "matcher": { "id": "byName", "options": "Last Plex scan" }, "properties": [ { "id": "unit", "value": "s" }, { "id": "decimals", "value": 0 } ] }, { "matcher": { "id": "byName", "options": "Last catalog read" }, "properties": [ { "id": "unit", "value": "s" }, { "id": "decimals", "value": 0 } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] }, { "matcher": { "id": "byName", "options": "Library" }, "properties": [ { "id": "custom.wrapText", "value": true } ] } ] } } } } }, "panel-107": { "kind": "Panel", "spec": { "id": 107, "title": "Storage by resolution", "description": "Disk space in each library by video resolution, one bar per library. A large SD or 480 share is old, low-quality video you may want to replace, and a large 4K share explains a library that fills disks quickly. Items whose file size Plex does not report are left out, see Exporter health.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (server_id, library_id, name, video_resolution) ((label_join(label_replace(label_join((label_replace(label_join(sum by (server, server_id, library_id, library, video_resolution) (plex_library_resolution_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, video_resolution) sum by (server, server_id, library_id, library, video_resolution) (plex_library_resolution_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1))) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library, video_resolution) label_replace((label_replace(label_join(sum by (server, server_id, library_id, library, video_resolution) (plex_library_resolution_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, video_resolution) sum by (server, server_id, library_id, library, video_resolution) (plex_library_resolution_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1))), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library, video_resolution) label_replace(label_replace(label_join(sum by (server, server_id, library_id, library, video_resolution) (plex_library_resolution_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, video_resolution) sum by (server, server_id, library_id, library, video_resolution) (plex_library_resolution_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)), \"name\", \"$1\", \"library\", \"(.*)\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "groupingToMatrix", "spec": { "options": { "columnField": "video_resolution", "rowField": "name", "valueField": "Value", "emptyValue": "zero" } } }, { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": {}, "indexByName": { "name\\video_resolution": 0, "2160": 1, "1080": 2, "720": 3, "576": 4, "480": 5, "sd": 6, "other": 7, "unknown": 8 }, "renameByName": { "name\\video_resolution": "Library", "2160": "4K", "1080": "1080p", "720": "720p", "576": "576p", "480": "480p", "sd": "SD", "other": "Other", "unknown": "Unknown" } } } }, { "kind": "Transformation", "group": "calculateField", "spec": { "options": { "mode": "reduceRow", "reduce": { "reducer": "sum" }, "alias": "Total", "replaceFields": false } } }, { "kind": "Transformation", "group": "sortBy", "spec": { "options": { "sort": [ { "field": "Total", "desc": true } ] } } }, { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Total": true } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "barchart", "version": "", "spec": { "options": { "orientation": "horizontal", "stacking": "normal", "showValue": "never", "xField": "Library", "barWidth": 0.7, "groupWidth": 0.7, "xTickLabelRotation": 0, "xTickLabelMaxLength": 24, "legend": { "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "desc" } }, "fieldConfig": { "defaults": { "unit": "decbytes", "min": 0, "noValue": "Not read yet", "color": { "mode": "palette-classic" }, "custom": { "fillOpacity": 85, "lineWidth": 0 } }, "overrides": [] } } } } }, "panel-108": { "kind": "Panel", "spec": { "id": 108, "title": "Storage by video codec", "description": "Disk space in each library by video codec, one bar per library. H.264 files take roughly twice the space of H.265 or AV1 at the same quality, so a large H.264 share is where re-encoding saves the most space. Items whose file size Plex does not report are left out, see Exporter health.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (server_id, library_id, name, video_codec) ((label_join(label_replace(label_join((label_replace(label_join(sum by (server, server_id, library_id, library, video_codec) (plex_library_codec_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, video_codec) sum by (server, server_id, library_id, library, video_codec) (plex_library_codec_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1))) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library, video_codec) label_replace((label_replace(label_join(sum by (server, server_id, library_id, library, video_codec) (plex_library_codec_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, video_codec) sum by (server, server_id, library_id, library, video_codec) (plex_library_codec_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1))), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library, video_codec) label_replace(label_replace(label_join(sum by (server, server_id, library_id, library, video_codec) (plex_library_codec_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, video_codec) sum by (server, server_id, library_id, library, video_codec) (plex_library_codec_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)), \"name\", \"$1\", \"library\", \"(.*)\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "groupingToMatrix", "spec": { "options": { "columnField": "video_codec", "rowField": "name", "valueField": "Value", "emptyValue": "zero" } } }, { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": {}, "indexByName": { "name\\video_codec": 0, "h264": 1, "hevc": 2, "av1": 3, "vp9": 4, "mpeg2video": 5, "mpeg4": 6, "vc1": 7, "other": 8, "unknown": 9 }, "renameByName": { "name\\video_codec": "Library", "h264": "H.264", "hevc": "H.265", "av1": "AV1", "vp9": "VP9", "mpeg2video": "H.262", "mpeg4": "DivX or Xvid", "vc1": "VC-1", "other": "Other", "unknown": "Unknown" } } } }, { "kind": "Transformation", "group": "calculateField", "spec": { "options": { "mode": "reduceRow", "reduce": { "reducer": "sum" }, "alias": "Total", "replaceFields": false } } }, { "kind": "Transformation", "group": "sortBy", "spec": { "options": { "sort": [ { "field": "Total", "desc": true } ] } } }, { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Total": true } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "barchart", "version": "", "spec": { "options": { "orientation": "horizontal", "stacking": "normal", "showValue": "never", "xField": "Library", "barWidth": 0.7, "groupWidth": 0.7, "xTickLabelRotation": 0, "xTickLabelMaxLength": 24, "legend": { "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "desc" } }, "fieldConfig": { "defaults": { "unit": "decbytes", "min": 0, "noValue": "Not read yet", "color": { "mode": "palette-classic" }, "custom": { "fillOpacity": 85, "lineWidth": 0 } }, "overrides": [] } } } } }, "panel-109": { "kind": "Panel", "spec": { "id": 109, "title": "Recently added", "description": "The 10 newest items on each selected server, newest first, from the hourly catalog read. A show is listed once, with its newest episode in the Episode column. Select a title to open it in Plex.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "(label_join(label_replace(label_join((label_replace(label_join(plex_library_recent_item_added_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"} * 1000 * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, rating_key) plex_library_recent_item_added_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"} * 1000 * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, rating_key) label_replace((label_replace(label_join(plex_library_recent_item_added_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"} * 1000 * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, rating_key) plex_library_recent_item_added_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"} * 1000 * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, rating_key) label_replace(label_replace(label_join(plex_library_recent_item_added_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"} * 1000 * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, rating_key) plex_library_recent_item_added_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"} * 1000 * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1), \"name\", \"$1\", \"library\", \"(.*)\")", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "__name__": true, "__tenant_id__": true, "instance": true, "job": true, "hostname": true, "Time": true, "Time 1": true, "Time 2": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time #D": true, "Time #E": true, "Time #F": true, "Time #G": true, "Time #H": true, "Time #I": true, "Time #J": true, "Time #K": true, "Time #L": true, "Time #N": true, "server": true, "library_type": true, "library_id": true, "Value #B": true, "library": true }, "indexByName": { "title": 0, "episode": 1, "Value": 2, "name": 3, "year": 4, "server_id": 5, "rating_key": 6 }, "renameByName": { "title": "Title", "episode": "Episode", "Value": "Added", "name": "Library", "year": "Year" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "sortBy": [ { "displayName": "Added", "desc": true } ], "cellHeight": "sm", "frozenColumns": { "left": 1 } }, "fieldConfig": { "defaults": { "noValue": "Nothing added yet, or the libraries have not been read yet", "custom": { "align": "auto", "cellOptions": { "type": "auto" } } }, "overrides": [ { "matcher": { "id": "byName", "options": "Title" }, "properties": [ { "id": "links", "value": [ { "title": "Open in Plex", "url": "https://app.plex.tv/desktop/#!/server/${__data.fields.server_id}/details?key=%2Flibrary%2Fmetadata%2F${__data.fields.rating_key}", "targetBlank": true } ] }, { "id": "custom.minWidth", "value": 150 }, { "id": "custom.wrapText", "value": true } ] }, { "matcher": { "id": "byName", "options": "server_id" }, "properties": [ { "id": "custom.hidden", "value": true } ] }, { "matcher": { "id": "byName", "options": "rating_key" }, "properties": [ { "id": "custom.hidden", "value": true } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] }, { "matcher": { "id": "byName", "options": "Added" }, "properties": [ { "id": "unit", "value": "dateTimeFromNow" }, { "id": "custom.width", "value": 130 } ] }, { "matcher": { "id": "byName", "options": "Episode" }, "properties": [ { "id": "custom.width", "value": 112 } ] }, { "matcher": { "id": "byName", "options": "Year" }, "properties": [ { "id": "custom.width", "value": 88 } ] }, { "matcher": { "id": "byName", "options": "Library" }, "properties": [ { "id": "custom.minWidth", "value": 140 } ] } ] } } } } }, "panel-110": { "kind": "Panel", "spec": { "id": 110, "title": "Never played", "description": "Disk space held by items nobody on this server has ever played, counted across every account, and the first place to look when you need space. An item marked watched without being played, or played before its watch history was deleted, also counts here. The figure stays hidden until every library has been read, every item has a size and watch history is complete, and if it stays hidden, a tile on Overview says why.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "label_replace(label_join((sum by (server, server_id) (plex_library_watch_age_bytes{server=~\"$server\", library_id=~\"$library_id\", last_watched=\"never\"}) and on (server, server_id) (plex_library_walk_complete == 1) and on (server, server_id) (sum by (server, server_id) (plex_library_unsized_items) == 0) and on (server, server_id) (plex_library_watch_age_complete == 1)) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id) label_replace((sum by (server, server_id) (plex_library_watch_age_bytes{server=~\"$server\", library_id=~\"$library_id\", last_watched=\"never\"}) and on (server, server_id) (plex_library_walk_complete == 1) and on (server, server_id) (sum by (server, server_id) (plex_library_unsized_items) == 0) and on (server, server_id) (plex_library_watch_age_complete == 1)), \"name\", \"$1\", \"server\", \"(.*)\")", "legendFormat": "{{name}}", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "decbytes", "noValue": "Waiting for a full read", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "thresholds" } }, "overrides": [] } } } } }, "panel-112": { "kind": "Panel", "spec": { "id": 112, "title": "Extra versions", "description": "Disk space held by the extra copies of items that have more than one version, counting every version except the largest. Removing a duplicate or an old lower-quality copy frees this space. The figure stays hidden until every library has been read and every item has a known size.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "label_replace(label_join((sum by (server, server_id) (plex_library_extra_version_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id) (plex_library_walk_complete == 1) and on (server, server_id) (sum by (server, server_id) (plex_library_unsized_items) == 0)) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id) label_replace((sum by (server, server_id) (plex_library_extra_version_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id) (plex_library_walk_complete == 1) and on (server, server_id) (sum by (server, server_id) (plex_library_unsized_items) == 0)), \"name\", \"$1\", \"server\", \"(.*)\")", "legendFormat": "{{name}}", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "decbytes", "noValue": "Hidden until every library has been read and every item has a known size, see Exporter health", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "thresholds" } }, "overrides": [] } } } } }, "panel-114": { "kind": "Panel", "spec": { "id": 114, "title": "Space by when it was last watched", "description": "Disk space in each library read while watch history was complete, by when anyone on this server last watched it, counted back from now whatever the time range. Red is space held by things nobody has ever played and orange by things last played over a year ago, where deleting frees the most space for the least loss. Select a bar and choose Open its unplayed items in Plex to list them in Plex Web. Plex counts only your own account's plays there, so its list can be longer than the red part.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row, name, server_id, library_id) (label_join((label_join(label_replace(label_join((label_replace(label_join((sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library_id) (count by (server, server_id, library_id) (plex_library_watch_age_bytes{server=~\"$server\", library_id=~\"$library_id\"}))) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) (sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library_id) (count by (server, server_id, library_id) (plex_library_watch_age_bytes{server=~\"$server\", library_id=~\"$library_id\"})))) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library) label_replace((label_replace(label_join((sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library_id) (count by (server, server_id, library_id) (plex_library_watch_age_bytes{server=~\"$server\", library_id=~\"$library_id\"}))) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) (sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library_id) (count by (server, server_id, library_id) (plex_library_watch_age_bytes{server=~\"$server\", library_id=~\"$library_id\"})))), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library) label_replace(label_replace(label_join((sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library_id) (count by (server, server_id, library_id) (plex_library_watch_age_bytes{server=~\"$server\", library_id=~\"$library_id\"}))) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) (sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library_id) (count by (server, server_id, library_id) (plex_library_watch_age_bytes{server=~\"$server\", library_id=~\"$library_id\"}))), \"name\", \"$1\", \"library\", \"(.*)\"), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(sum by (server, server_id, library_id) (plex_library_watch_age_bytes{server=~\"$server\", library_id=~\"$library_id\", last_watched=\"never\"}), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "B", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(sum by (server, server_id, library_id) (plex_library_watch_age_bytes{server=~\"$server\", library_id=~\"$library_id\", last_watched=\"over_1y\"}), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "C", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(sum by (server, server_id, library_id) (plex_library_watch_age_bytes{server=~\"$server\", library_id=~\"$library_id\", last_watched=\"90d_1y\"}), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "D", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(sum by (server, server_id, library_id) (plex_library_watch_age_bytes{server=~\"$server\", library_id=~\"$library_id\", last_watched=\"under_90d\"}), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "E", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "joinByField", "spec": { "options": { "byField": "row", "mode": "outer" } } }, { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Time": true, "Time 1": true, "Time 2": true, "Time 3": true, "Time 4": true, "Time 5": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time #D": true, "Time #E": true, "row": true, "Value #A": true }, "indexByName": { "name": 0, "Value #B": 1, "Value #C": 2, "Value #D": 3, "Value #E": 4, "server_id": 5, "library_id": 6 }, "renameByName": { "name": "Library", "Value #B": "Never played", "Value #C": "Over a year ago", "Value #D": "90 days to a year ago", "Value #E": "Within 90 days" } } } }, { "kind": "Transformation", "group": "calculateField", "spec": { "options": { "mode": "reduceRow", "reduce": { "reducer": "sum", "include": [ "Never played", "Over a year ago", "90 days to a year ago", "Within 90 days" ] }, "alias": "Total", "replaceFields": false } } }, { "kind": "Transformation", "group": "sortBy", "spec": { "options": { "sort": [ { "field": "Total", "desc": true } ] } } }, { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Total": true } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "barchart", "version": "", "spec": { "options": { "orientation": "horizontal", "stacking": "normal", "showValue": "never", "xField": "Library", "barWidth": 0.7, "groupWidth": 0.7, "xTickLabelRotation": 0, "xTickLabelMaxLength": 24, "legend": { "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "desc" } }, "fieldConfig": { "defaults": { "unit": "decbytes", "min": 0, "noValue": "Not read yet, or watch history is not complete", "color": { "mode": "palette-classic" }, "custom": { "fillOpacity": 85, "lineWidth": 0 }, "links": [ { "title": "Open its unplayed items in Plex", "url": "https://app.plex.tv/desktop/#!/media/${__data.fields.server_id}/com.plexapp.plugins.library?source=${__data.fields.library_id}&key=%2Flibrary%2Fsections%2F${__data.fields.library_id}%2Funwatched&pageType=list", "targetBlank": true } ] }, "overrides": [ { "matcher": { "id": "byName", "options": "Never played" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "red" } } ] }, { "matcher": { "id": "byName", "options": "Over a year ago" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "orange" } } ] }, { "matcher": { "id": "byName", "options": "90 days to a year ago" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "yellow" } } ] }, { "matcher": { "id": "byName", "options": "Within 90 days" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "green" } } ] }, { "matcher": { "id": "byName", "options": "server_id" }, "properties": [ { "id": "custom.hideFrom", "value": { "legend": true, "tooltip": true, "viz": true } }, { "id": "unit", "value": "none" }, { "id": "decimals", "value": 0 } ] }, { "matcher": { "id": "byName", "options": "library_id" }, "properties": [ { "id": "custom.hideFrom", "value": { "legend": true, "tooltip": true, "viz": true } }, { "id": "unit", "value": "none" }, { "id": "decimals", "value": 0 } ] } ] } } } } }, "panel-115": { "kind": "Panel", "spec": { "id": 115, "title": "Items with extra versions", "description": "Items in each library that have more than one version, such as a 4K and a 1080p copy of one film. Every extra version uses disk space, so a high count is worth a cleanup pass in Plex. A library with none shows 0.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sort_desc((label_join(label_replace(label_join((label_replace(label_join(max by (server, server_id, library_id, library) (plex_library_multi_version_items{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) (plex_library_multi_version_items{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1))) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library) label_replace((label_replace(label_join(max by (server, server_id, library_id, library) (plex_library_multi_version_items{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) (plex_library_multi_version_items{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1))), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library) label_replace(label_replace(label_join(max by (server, server_id, library_id, library) (plex_library_multi_version_items{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) (plex_library_multi_version_items{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)), \"name\", \"$1\", \"library\", \"(.*)\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "__name__": true, "__tenant_id__": true, "instance": true, "job": true, "hostname": true, "Time": true, "Time 1": true, "Time 2": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time #D": true, "Time #E": true, "Time #F": true, "Time #G": true, "Time #H": true, "Time #I": true, "Time #J": true, "Time #K": true, "Time #L": true, "Time #N": true, "server": true, "server_id": true, "library_id": true, "library": true, "library_type": true, "activity_type": true, "user": true }, "indexByName": { "name": 0, "Value": 1 }, "renameByName": { "name": "Library", "Value": "Items" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "cellHeight": "sm", "sortBy": [ { "displayName": "Items", "desc": true } ] }, "fieldConfig": { "defaults": { "unit": "short", "noValue": "Not read yet", "min": 0, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "fixed", "fixedColor": "blue" }, "decimals": 0, "custom": { "align": "auto", "cellOptions": { "type": "auto" } } }, "overrides": [ { "matcher": { "id": "byName", "options": "Items" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "gauge", "mode": "basic", "valueDisplayMode": "text" } } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] }, { "matcher": { "id": "byName", "options": "Items" }, "properties": [ { "id": "custom.width", "value": 112 } ] }, { "matcher": { "id": "byName", "options": "Library" }, "properties": [ { "id": "custom.wrapText", "value": true } ] } ] } } } } }, "panel-116": { "kind": "Panel", "spec": { "id": 116, "title": "Largest items on $server", "description": "The 10 largest items in each library of this server, with when any account last played them. Sort by Last played to find large items nobody watches, and oldest first lists Unknown, then Never, then the oldest plays. Never means no recorded play, and Unknown means watch history has not been read in full yet, and if that lasts, the Watch history stale or Watch figures hidden tile on Overview says why. A show is the sum of its episodes and is ranked only when every episode has a readable size, and selecting a title opens it in Plex.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "label_join(label_join(label_replace(label_join((label_replace(label_join(plex_library_top_item_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, rating_key) plex_library_top_item_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\"), \"name\", \": \", \"name\", \"library\") or on (server, server_id, library_id, rating_key) label_replace(label_replace(label_join(plex_library_top_item_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id, rating_key) plex_library_top_item_bytes{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1), \"name\", \"$1\", \"library\", \"(.*)\"), \"item\", \"/\", \"server_id\", \"library_id\", \"rating_key\")", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (item) (label_join(plex_library_top_item_last_played_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"}, \"item\", \"/\", \"server_id\", \"library_id\", \"rating_key\")) * 1000 or max by (item) (label_join(0 * plex_library_top_item_bytes{server=~\"$server\", library_id=~\"$library_id\"}, \"item\", \"/\", \"server_id\", \"library_id\", \"rating_key\")) - 1", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "B", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "joinByField", "spec": { "options": { "byField": "item", "mode": "outer" } } }, { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "__name__": true, "__tenant_id__": true, "instance": true, "job": true, "hostname": true, "Time": true, "Time 1": true, "Time 2": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time #D": true, "Time #E": true, "Time #F": true, "Time #G": true, "Time #H": true, "Time #I": true, "Time #J": true, "Time #K": true, "Time #L": true, "Time #N": true, "server": true, "library_type": true, "library_id": true, "item": true, "library": true }, "indexByName": { "title": 0, "Value #A": 1, "Value #B": 2, "name": 3, "year": 4, "server_id": 5, "rating_key": 6 }, "renameByName": { "title": "Title", "Value #A": "Size", "Value #B": "Last played", "name": "Library", "year": "Year" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "sortBy": [ { "displayName": "Size", "desc": true } ], "cellHeight": "sm", "frozenColumns": { "left": 1 } }, "fieldConfig": { "defaults": { "noValue": "No library has been read yet", "custom": { "align": "auto", "cellOptions": { "type": "auto" } } }, "overrides": [ { "matcher": { "id": "byName", "options": "Title" }, "properties": [ { "id": "links", "value": [ { "title": "Open in Plex", "url": "https://app.plex.tv/desktop/#!/server/${__data.fields.server_id}/details?key=%2Flibrary%2Fmetadata%2F${__data.fields.rating_key}", "targetBlank": true } ] }, { "id": "custom.minWidth", "value": 150 }, { "id": "custom.wrapText", "value": true } ] }, { "matcher": { "id": "byName", "options": "server_id" }, "properties": [ { "id": "custom.hidden", "value": true } ] }, { "matcher": { "id": "byName", "options": "rating_key" }, "properties": [ { "id": "custom.hidden", "value": true } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] }, { "matcher": { "id": "byName", "options": "Size" }, "properties": [ { "id": "unit", "value": "decbytes" }, { "id": "custom.width", "value": 95 } ] }, { "matcher": { "id": "byName", "options": "Last played" }, "properties": [ { "id": "unit", "value": "dateTimeFromNow" }, { "id": "custom.width", "value": 144 }, { "id": "noValue", "value": "Unknown" }, { "id": "mappings", "value": [ { "type": "value", "options": { "0": { "index": 0, "text": "Never" }, "-1": { "index": 1, "text": "Unknown" } } } ] } ] }, { "matcher": { "id": "byName", "options": "Year" }, "properties": [ { "id": "custom.width", "value": 88 } ] }, { "matcher": { "id": "byName", "options": "Library" }, "properties": [ { "id": "custom.minWidth", "value": 140 } ] } ] } } } } }, "panel-120": { "kind": "Panel", "spec": { "id": 120, "title": "Transcode time", "description": "Hours of video transcoding, paused streams included, stacked by where Plex decoded and encoded the video. Green full-hardware time is cheap, and a growing orange Software band on a server set up for hardware transcoding means streams run on the CPU, so check the per-player table below. Each bar covers an equal slice of the range, an hour at 24 hours and a day at 30 days, and the newest bar grows until its slice ends. The legend total adds up the bars, which start at the first whole slice inside the range, and a missing bar means no video transcode ran in that slice.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(sum_over_time((plex_session_video_transcode{server=~\"$server\", decode=\"hardware\", encode=\"hardware\"} and on () (vector(time()) <= $__to / 1000))[$__interval:1m] offset -$__interval)) / 60 and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Hardware decode and encode" } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(sum_over_time((plex_session_video_transcode{server=~\"$server\", decode=\"software\", encode=\"hardware\"} and on () (vector(time()) <= $__to / 1000))[$__interval:1m] offset -$__interval)) / 60 and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Hardware encode only" } }, "refId": "B", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(sum_over_time((plex_session_video_transcode{server=~\"$server\", decode=\"hardware\", encode=\"software\"} and on () (vector(time()) <= $__to / 1000))[$__interval:1m] offset -$__interval)) / 60 and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Hardware decode only" } }, "refId": "C", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(sum_over_time((plex_session_video_transcode{server=~\"$server\", decode=\"software\", encode=\"software\"} and on () (vector(time()) <= $__to / 1000))[$__interval:1m] offset -$__interval)) / 60 and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Software" } }, "refId": "D", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(sum_over_time(((plex_session_video_transcode{server=~\"$server\", decode=\"unknown\"} or plex_session_video_transcode{server=~\"$server\", encode=\"unknown\"}) and on () (vector(time()) <= $__to / 1000))[$__interval:1m] offset -$__interval)) / 60 and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Unknown" } }, "refId": "E", "hidden": false } } ], "transformations": [], "queryOptions": { "maxDataPoints": 25, "interval": "1h" } } }, "vizConfig": { "kind": "VizConfig", "group": "timeseries", "version": "", "spec": { "options": { "legend": { "calcs": [ "sum" ], "displayMode": "table", "placement": "right", "width": 300 }, "tooltip": { "mode": "multi", "sort": "desc" } }, "fieldConfig": { "defaults": { "unit": "suffix:h", "min": 0, "noValue": "No video transcode in this range", "color": { "mode": "palette-classic" }, "custom": { "drawStyle": "bars", "fillOpacity": 80, "lineWidth": 1, "showPoints": "never", "stacking": { "mode": "normal", "group": "A" }, "barAlignment": 1 } }, "overrides": [ { "matcher": { "id": "byName", "options": "Hardware decode and encode" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "green" } } ] }, { "matcher": { "id": "byName", "options": "Hardware encode only" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "blue" } } ] }, { "matcher": { "id": "byName", "options": "Hardware decode only" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "purple" } } ] }, { "matcher": { "id": "byName", "options": "Software" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "orange" } } ] }, { "matcher": { "id": "byName", "options": "Unknown" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "#8e8e8e" } } ] } ] } } } } }, "panel-121": { "kind": "Panel", "spec": { "id": 121, "title": "Hardware encode share", "description": "The share of video transcode time, paused streams included, that Plex encoded on the GPU. A drop on a server with hardware transcoding turned on usually follows a driver, image or Plex update. Each bar covers an equal slice of the range, an hour at 24 hours and a day at 30 days, and the newest bar grows until its slice ends. A missing bar means no video transcode ran in that slice.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(sum_over_time((plex_session_video_transcode{server=~\"$server\", encode=\"hardware\"} and on () (vector(time()) <= $__to / 1000))[$__interval:1m] offset -$__interval)) / (sum(sum_over_time((plex_session_video_transcode{server=~\"$server\"} and on () (vector(time()) <= $__to / 1000))[$__interval:1m] offset -$__interval)) > 0) and on () (vector(time()) >= $__from / 1000)", "legendFormat": "Encoded on hardware" } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": { "maxDataPoints": 25, "interval": "1h" } } }, "vizConfig": { "kind": "VizConfig", "group": "timeseries", "version": "", "spec": { "options": { "legend": { "calcs": [ "mean" ], "displayMode": "table", "placement": "right", "width": 300 }, "tooltip": { "mode": "multi", "sort": "desc" } }, "fieldConfig": { "defaults": { "unit": "percentunit", "min": 0, "noValue": "No video transcode in this range", "color": { "mode": "palette-classic" }, "custom": { "drawStyle": "bars", "fillOpacity": 80, "lineWidth": 1, "showPoints": "never", "stacking": { "mode": "none", "group": "A" }, "barAlignment": 1 }, "max": 1 }, "overrides": [ { "matcher": { "id": "byName", "options": "Encoded on hardware" }, "properties": [ { "id": "color", "value": { "mode": "fixed", "fixedColor": "green" } } ] } ] } } } } }, "panel-122": { "kind": "Panel", "spec": { "id": 122, "title": "Transcode time by player", "description": "Video transcoding time in the selected range, paused streams included, for the 8 player and encoder pairs with the most, with Encoder saying whether Plex encoded on hardware or software. A player that transcodes a lot is often fixed with a client setting, such as raising its streaming quality on your network. Software time on a server with a GPU means Plex could not use the GPU for those streams. Check the hardware acceleration settings in Plex, the GPU's limit on simultaneous encodes and the Plex log.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sort_desc((topk(8, sum by (device_type, encode) (sum_over_time((plex_session_video_transcode{server=~\"$server\"} * on (server, server_id, session) group_left (device_type) topk by (server, server_id, session) (1, max by (server, server_id, session, device_type) (plex_plays_active{server=~\"$server\"})))[$__range:1m])))) / 60)", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Time": true }, "indexByName": { "device_type": 0, "encode": 1, "Value": 2 }, "renameByName": { "device_type": "Player", "encode": "Encoder", "Value": "Time" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "cellHeight": "sm", "sortBy": [ { "displayName": "Time", "desc": true } ] }, "fieldConfig": { "defaults": { "unit": "suffix:h", "min": 0, "noValue": "No video transcode in this range", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "fixed", "fixedColor": "blue" }, "custom": { "align": "auto", "cellOptions": { "type": "auto" } } }, "overrides": [ { "matcher": { "id": "byName", "options": "Player" }, "properties": [ { "id": "custom.minWidth", "value": 100 }, { "id": "custom.wrapText", "value": true } ] }, { "matcher": { "id": "byName", "options": "Encoder" }, "properties": [ { "id": "custom.width", "value": 112 }, { "id": "mappings", "value": [ { "type": "value", "options": { "hardware": { "index": 0, "text": "Hardware" }, "software": { "index": 1, "text": "Software" }, "unknown": { "index": 2, "text": "Unknown" } } } ] } ] }, { "matcher": { "id": "byName", "options": "Time" }, "properties": [ { "id": "custom.minWidth", "value": 88 }, { "id": "custom.cellOptions", "value": { "type": "gauge", "mode": "basic", "valueDisplayMode": "text" } } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] } ] } } } } }, "panel-123": { "kind": "Panel", "spec": { "id": 123, "title": "Transcode time by codec", "description": "Video transcoding time in the selected range, paused streams included, by the codec of the file Plex converted, top 8, with Encoder saying whether Plex encoded on hardware or software. H.265 or AV1 files that transcode often are the ones to keep a compatible copy of. Unknown codec means Plex reported no source codec.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sort_desc((label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(topk(8, sum by (source_codec, encode) (sum_over_time(plex_session_video_transcode{server=~\"$server\"}[$__range:1m]))), \"source_codec\", \"H.265\", \"source_codec\", \"hevc\"), \"source_codec\", \"H.264\", \"source_codec\", \"h264\"), \"source_codec\", \"H.262\", \"source_codec\", \"mpeg2video\"), \"source_codec\", \"DivX or Xvid\", \"source_codec\", \"mpeg4\"), \"source_codec\", \"AV1\", \"source_codec\", \"av1\"), \"source_codec\", \"VP9\", \"source_codec\", \"vp9\"), \"source_codec\", \"VC-1\", \"source_codec\", \"vc1\"), \"source_codec\", \"Unknown codec\", \"source_codec\", \"unknown\"), \"source_codec\", \"Other codec\", \"source_codec\", \"other\")) / 60)", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Time": true }, "indexByName": { "source_codec": 0, "encode": 1, "Value": 2 }, "renameByName": { "source_codec": "Codec", "encode": "Encoder", "Value": "Time" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "cellHeight": "sm", "sortBy": [ { "displayName": "Time", "desc": true } ] }, "fieldConfig": { "defaults": { "unit": "suffix:h", "min": 0, "noValue": "No video transcode in this range", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "fixed", "fixedColor": "blue" }, "custom": { "align": "auto", "cellOptions": { "type": "auto" } } }, "overrides": [ { "matcher": { "id": "byName", "options": "Codec" }, "properties": [ { "id": "custom.minWidth", "value": 100 }, { "id": "custom.wrapText", "value": true } ] }, { "matcher": { "id": "byName", "options": "Encoder" }, "properties": [ { "id": "custom.width", "value": 112 }, { "id": "mappings", "value": [ { "type": "value", "options": { "hardware": { "index": 0, "text": "Hardware" }, "software": { "index": 1, "text": "Software" }, "unknown": { "index": 2, "text": "Unknown" } } } ] } ] }, { "matcher": { "id": "byName", "options": "Time" }, "properties": [ { "id": "custom.minWidth", "value": 88 }, { "id": "custom.cellOptions", "value": { "type": "gauge", "mode": "basic", "valueDisplayMode": "text" } } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] } ] } } } } }, "panel-124": { "kind": "Panel", "spec": { "id": 124, "title": "Transcode time by resolution", "description": "Video transcoding time in the selected range, paused streams included, by the resolution of the file Plex converted, top 8, with Encoder saying whether Plex encoded on hardware or software. Software transcoding of 4K files is the heaviest load a Plex server takes. Unknown resolution means Plex reported none for the file.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sort_desc((topk(8, sum by (stream_file_resolution, encode) (label_replace(label_replace(label_replace(label_replace(label_replace(sum_over_time((plex_session_video_transcode{server=~\"$server\"} * on (server, server_id, session) group_left (stream_file_resolution) topk by (server, server_id, session) (1, max by (server, server_id, session, stream_file_resolution) (label_replace(plex_plays_active{server=~\"$server\"}, \"stream_file_resolution\", \"2160\", \"stream_file_resolution\", \"(?i)4k\"))))[$__range:1m]), \"stream_file_resolution\", \"4K\", \"stream_file_resolution\", \"2160\"), \"stream_file_resolution\", \"${1}p\", \"stream_file_resolution\", \"(480|576|720|1080)\"), \"stream_file_resolution\", \"SD\", \"stream_file_resolution\", \"(?i)sd\"), \"stream_file_resolution\", \"Other resolution\", \"stream_file_resolution\", \"other\"), \"stream_file_resolution\", \"Unknown resolution\", \"stream_file_resolution\", \"\")))) / 60)", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Time": true }, "indexByName": { "stream_file_resolution": 0, "encode": 1, "Value": 2 }, "renameByName": { "stream_file_resolution": "Resolution", "encode": "Encoder", "Value": "Time" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "cellHeight": "sm", "sortBy": [ { "displayName": "Time", "desc": true } ] }, "fieldConfig": { "defaults": { "unit": "suffix:h", "min": 0, "noValue": "No video transcode in this range", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "fixed", "fixedColor": "blue" }, "custom": { "align": "auto", "cellOptions": { "type": "auto" } } }, "overrides": [ { "matcher": { "id": "byName", "options": "Resolution" }, "properties": [ { "id": "custom.minWidth", "value": 100 }, { "id": "custom.wrapText", "value": true } ] }, { "matcher": { "id": "byName", "options": "Encoder" }, "properties": [ { "id": "custom.width", "value": 112 }, { "id": "mappings", "value": [ { "type": "value", "options": { "hardware": { "index": 0, "text": "Hardware" }, "software": { "index": 1, "text": "Software" }, "unknown": { "index": 2, "text": "Unknown" } } } ] } ] }, { "matcher": { "id": "byName", "options": "Time" }, "properties": [ { "id": "custom.minWidth", "value": 88 }, { "id": "custom.cellOptions", "value": { "type": "gauge", "mode": "basic", "valueDisplayMode": "text" } } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] } ] } } } } }, "panel-130": { "kind": "Panel", "spec": { "id": 130, "title": "Failed reads by type", "description": "Failed Plex reads in the selected range, by what plex-exporter was reading, listing only the reads that failed. A steady count on one type means that part of the dashboard is stale, and the exporter log names the cause. No failed reads in this range means every read succeeded, or plex-exporter was not scraped.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sort_desc(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace(label_replace((sum by (type) (increase(plex_exporter_errors_total[$__range])) > 0), \"type\", \"Server refresh\", \"type\", \"refresh\"), \"type\", \"Sessions\", \"type\", \"sessions_fetch\"), \"type\", \"Item details\", \"type\", \"metadata_fetch\"), \"type\", \"Invalid item key\", \"type\", \"invalid_rating_key\"), \"type\", \"Metrics server\", \"type\", \"metrics_server\"), \"type\", \"Item counts\", \"type\", \"library_items\"), \"type\", \"Catalog read\", \"type\", \"library_walk\"), \"type\", \"Watch history\", \"type\", \"history_fetch\"), \"type\", \"Background tasks\", \"type\", \"activities_fetch\"), \"type\", \"Library list\", \"type\", \"sections_fetch\"), \"type\", \"Update check\", \"type\", \"updater_fetch\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Time": true }, "indexByName": { "type": 0, "Value": 1 }, "renameByName": { "type": "Read", "Value": "Failed reads" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "cellHeight": "sm", "sortBy": [ { "displayName": "Failed reads", "desc": true } ] }, "fieldConfig": { "defaults": { "unit": "short", "decimals": 0, "min": 0, "noValue": "No failed reads in this range", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "yellow" } ] }, "color": { "mode": "thresholds" } }, "overrides": [ { "matcher": { "id": "byName", "options": "Failed reads" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "color-text" } } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] } ] } } } } }, "panel-135": { "kind": "Panel", "spec": { "id": 135, "title": "Items without a size", "description": "Libraries with items whose file size Plex did not report, so they are left out of every storage figure, with how many. While any library is listed, the server storage totals on Storage cleanup are hidden. A library leaves the list once Plex analyses those files.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "(max by (row, name) (label_join((label_join(label_replace(label_join((label_replace(label_join(max by (server, server_id, library_id, library) (plex_library_unsized_items{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) (plex_library_unsized_items{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1))) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library) label_replace((label_replace(label_join(max by (server, server_id, library_id, library) (plex_library_unsized_items{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) (plex_library_unsized_items{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1))), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library) label_replace(label_replace(label_join(max by (server, server_id, library_id, library) (plex_library_unsized_items{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) (plex_library_unsized_items{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)), \"name\", \"$1\", \"library\", \"(.*)\"), \"row\", \"/\", \"server_id\", \"library_id\"))) > 0", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Time": true, "Time 1": true, "Time 2": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time #D": true, "Time #E": true, "Time #F": true, "Time #G": true, "Time #H": true, "Time #I": true, "Time #J": true, "Time #K": true, "Time #L": true, "Time #N": true, "row": true }, "indexByName": { "name": 0, "Value": 1 }, "renameByName": { "name": "Library", "Value": "Unsized items" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "sortBy": [ { "displayName": "Unsized items", "desc": true } ], "cellHeight": "sm" }, "fieldConfig": { "defaults": { "noValue": "Every item read has a known size", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "yellow" } ] }, "color": { "mode": "thresholds" } }, "overrides": [ { "matcher": { "id": "byName", "options": "Unsized items" }, "properties": [ { "id": "custom.cellOptions", "value": { "type": "color-text" } }, { "id": "decimals", "value": 0 } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] } ] } } } } }, "panel-137": { "kind": "Panel", "spec": { "id": 137, "title": "Catalog read per library", "description": "When plex-exporter last read each library item by item, and how long that read took. Each library is read every hour, so an age well past an hour means its reads are failing, see Failed reads by type. A dash means the library has not been read yet.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row, name) (label_join((label_join(label_replace(label_join((label_replace(label_join(max by (server, server_id, library_id, library) ((time() - plex_library_walk_last_success_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"}) * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) ((time() - plex_library_walk_last_success_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"}) * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1))) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library) label_replace((label_replace(label_join(max by (server, server_id, library_id, library) ((time() - plex_library_walk_last_success_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"}) * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) ((time() - plex_library_walk_last_success_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"}) * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1))), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library) label_replace(label_replace(label_join(max by (server, server_id, library_id, library) ((time() - plex_library_walk_last_success_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"}) * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) ((time() - plex_library_walk_last_success_timestamp_seconds{server=~\"$server\", library_id=~\"$library_id\"}) * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)), \"name\", \"$1\", \"library\", \"(.*)\"), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(max by (server, server_id, library_id, library) (plex_library_walk_duration_seconds{server=~\"$server\", library_id=~\"$library_id\"} * on (server, server_id, library_id) group_left (library) (0 * max by (server, server_id, library_id, library) (plex_library_storage_bytes) + 1)), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "B", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "joinByField", "spec": { "options": { "byField": "row", "mode": "outer" } } }, { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Time": true, "Time 1": true, "Time 2": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time #D": true, "Time #E": true, "Time #F": true, "Time #G": true, "Time #H": true, "Time #I": true, "Time #J": true, "Time #K": true, "Time #L": true, "Time #N": true, "row": true }, "indexByName": { "name": 0, "Value #A": 1, "Value #B": 2 }, "renameByName": { "name": "Library", "Value #A": "Last read", "Value #B": "Read took" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "sortBy": [ { "displayName": "Last read", "desc": true } ], "cellHeight": "sm", "frozenColumns": { "left": 1 } }, "fieldConfig": { "defaults": { "noValue": "No library has been read yet" }, "overrides": [ { "matcher": { "id": "byName", "options": "Last read" }, "properties": [ { "id": "unit", "value": "s" }, { "id": "decimals", "value": 0 } ] }, { "matcher": { "id": "byName", "options": "Read took" }, "properties": [ { "id": "unit", "value": "s" }, { "id": "decimals", "value": 1 } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] }, { "matcher": { "id": "byName", "options": "Library" }, "properties": [ { "id": "custom.wrapText", "value": true } ] } ] } } } } }, "panel-138": { "kind": "Panel", "spec": { "id": 138, "title": "Last full pass took", "description": "How long the last pass over every video library took. A pass starts every hour, or straight after the previous one when it ran longer, so a pass near an hour means the figures lag that much. No value means no full pass has finished yet.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "label_replace(label_join((max by (server, server_id) (plex_library_walk_pass_duration_seconds{server=~\"$server\"})) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id) label_replace((max by (server, server_id) (plex_library_walk_pass_duration_seconds{server=~\"$server\"})), \"name\", \"$1\", \"server\", \"(.*)\")", "legendFormat": "{{name}}", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "s", "noValue": "No pass finished yet", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "thresholds" }, "decimals": 0 }, "overrides": [] } } } } }, "panel-141": { "kind": "Panel", "spec": { "id": 141, "title": "Plex request retries", "description": "Plex requests plex-exporter had to send again in the selected range, after a timeout or a server error. A few retries during a Plex restart are normal, and a steady climb means Plex or the network is struggling. No value means the exporter was not scraped.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(increase(plex_http_retries_total[$__range]))", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "value", "graphMode": "none", "reduceOptions": { "calcs": [ "lastNotNull" ] }, "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "short", "noValue": "Not scraped", "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "blue" } ] }, "color": { "mode": "thresholds" }, "decimals": 0 }, "overrides": [] } } } } }, "panel-150": { "kind": "Panel", "spec": { "id": 150, "title": "plex-exporter", "description": "Shows while the PlexExporterTargetDown or PlexExporterTargetAbsent alert fires for any exporter: Prometheus has failed to scrape plex-exporter for 15 minutes, so every other panel is out of date. The figure is how many exporters are down, and Not scraped means there is no plex-exporter to scrape at all. Without the rules from alerts/promql.yaml, the tile checks their conditions itself on any exporter that sent metrics in the selected range or the last week, which catches one that stopped before a short range. Check that the exporter container runs and that your scrape job, whatever its name, reaches its port, 9594 by default.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "(count(ALERTS{alertname=\"PlexExporterTargetDown\", alertstate=\"firing\"}) or -max(ALERTS{alertname=\"PlexExporterTargetAbsent\", alertstate=\"firing\"})) or ((count((count_over_time((up == 0)[17m:1m]) >= 17) and on (job, instance) (max_over_time(plex_http_reachable[$__range]) or max_over_time(plex_http_reachable[1w]))) or -absent(count_over_time((up)[17m:1m]) and on (job, instance) (max_over_time(plex_http_reachable[$__range]) or max_over_time(plex_http_reachable[1w])))) unless on () count(max_over_time(ALERTS{alertname=~\"PlexExporterTargetDown|PlexExporterTargetAbsent\"}[17m])))", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "background", "graphMode": "none", "justifyMode": "center", "reduceOptions": { "calcs": [ "lastNotNull" ], "values": false }, "textMode": "auto", "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "suffix:down", "decimals": 0, "noValue": "Nothing to report", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "red" } ] }, "mappings": [ { "type": "value", "options": { "-1": { "index": 0, "text": "Not scraped", "color": "red" } } } ] }, "overrides": [] } } } } }, "panel-151": { "kind": "Panel", "spec": { "id": 151, "title": "Plex server", "description": "Shows while the PlexExporterAPIUnreachable alert fires for any exporter: plex-exporter has failed to reach the Plex API for 10 minutes, so the other panels show old values. The usual cause is Plex being down or a revoked or wrong PLEX_TOKEN. The reachability metric carries no server name, so the tile does not follow the Server selection. Without the alert rules from alerts/promql.yaml, the tile checks the same condition itself.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "(0 * max(ALERTS{alertname=\"PlexExporterAPIUnreachable\", alertstate=\"firing\"})) or ((max((plex_http_reachable == 0) and (count_over_time((plex_http_reachable == 0)[12m:1m]) >= 12))) unless on () count(max_over_time(ALERTS{alertname=\"PlexExporterAPIUnreachable\"}[12m])))", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "background", "graphMode": "none", "justifyMode": "center", "reduceOptions": { "calcs": [ "lastNotNull" ], "values": false }, "textMode": "auto", "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "none", "decimals": 0, "noValue": "Nothing to report", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "red" } ] }, "mappings": [ { "type": "value", "options": { "0": { "index": 0, "text": "Unreachable", "color": "red" } } } ] }, "overrides": [] } } } } }, "panel-152": { "kind": "Panel", "spec": { "id": 152, "title": "Session poll", "description": "Shows while the PlexExporterSessionPollFailing alert fires for any exporter: the read of current playback has failed for 10 minutes while the rest of the Plex API answers. Streams and Active sessions are then out of date. If it fails only while something plays, look for a decode error in the exporter log. Without the alert rules from alerts/promql.yaml, the tile checks the same condition itself.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "(0 * max(ALERTS{alertname=\"PlexExporterSessionPollFailing\", alertstate=\"firing\"})) or ((max((plex_session_poll_reachable == 0) and (count_over_time((plex_session_poll_reachable == 0 and plex_http_reachable == 1)[12m:1m]) >= 12))) unless on () count(max_over_time(ALERTS{alertname=\"PlexExporterSessionPollFailing\"}[12m])))", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "background", "graphMode": "none", "justifyMode": "center", "reduceOptions": { "calcs": [ "lastNotNull" ], "values": false }, "textMode": "auto", "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "none", "decimals": 0, "noValue": "Nothing to report", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "red" } ] }, "mappings": [ { "type": "value", "options": { "0": { "index": 0, "text": "Failing", "color": "red" } } } ] }, "overrides": [] } } } } }, "panel-153": { "kind": "Panel", "spec": { "id": 153, "title": "Library lost items", "description": "Shows while the PlexExporterLibraryItemsCollapsed alert fires: a library has held less than half the items it had 1 to 2 hours earlier for 30 minutes. The figure is how many libraries, and Items per library on the Libraries tab shows which. The usual cause is a media folder that went missing or a bulk delete, so check the mount and the library in Plex. Without the alert rules from alerts/promql.yaml, the tile checks the same condition itself.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "(count(ALERTS{alertname=\"PlexExporterLibraryItemsCollapsed\", alertstate=\"firing\", server=~\"$server\"})) or ((count(((max_over_time(plex_library_items{server=~\"$server\"}[2h] offset 30m) - plex_library_items{server=~\"$server\"}) / clamp_min(max_over_time(plex_library_items{server=~\"$server\"}[2h] offset 30m), 1) > 0.5 and max_over_time(plex_library_items{server=~\"$server\"}[2h] offset 30m) > 50) and (count_over_time(((max_over_time(plex_library_items{server=~\"$server\"}[2h] offset 30m) - plex_library_items{server=~\"$server\"}) / clamp_min(max_over_time(plex_library_items{server=~\"$server\"}[2h] offset 30m), 1) > 0.5 and max_over_time(plex_library_items{server=~\"$server\"}[2h] offset 30m) > 50)[32m:1m]) >= 32))) unless on () count(max_over_time(ALERTS{alertname=\"PlexExporterLibraryItemsCollapsed\"}[32m])))", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "background", "graphMode": "none", "justifyMode": "center", "reduceOptions": { "calcs": [ "lastNotNull" ], "values": false }, "textMode": "auto", "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "short", "decimals": 0, "noValue": "Nothing to report", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "red" } ] } }, "overrides": [] } } } } }, "panel-154": { "kind": "Panel", "spec": { "id": 154, "title": "Libraries not read", "description": "Shows while the PlexExporterLibraryWalkStale alert fires: for 30 minutes, plex-exporter has not finished reading a video library item by item within 4 hours plus twice its last full pass, or has never read it. The figure is how many libraries, and their largest items, storage cleanup and watch figures are out of date. The exporter log names the cause in a library walk failed line, and Catalog read per library on Exporter health shows which library. Without the alert rules from alerts/promql.yaml, the tile checks the same condition itself, which like the alert waits 6 hours after the exporter starts.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "(count(ALERTS{alertname=\"PlexExporterLibraryWalkStale\", alertstate=\"firing\", server=~\"$server\"})) or ((count((count_over_time((((time() - plex_library_walk_last_success_timestamp_seconds{server=~\"$server\"}) > on (server, server_id) group_left () (14400 + 2 * plex_library_walk_pass_duration_seconds) or on (server, server_id, library_id) (plex_library_walkable{server=~\"$server\"} unless on (server, server_id, library_id) plex_library_walk_last_success_timestamp_seconds)) and on (job, instance) (time() - process_start_time_seconds > 21600))[32m:1m]) >= 32))) unless on () count(max_over_time(ALERTS{alertname=\"PlexExporterLibraryWalkStale\"}[32m])))", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "background", "graphMode": "none", "justifyMode": "center", "reduceOptions": { "calcs": [ "lastNotNull" ], "values": false }, "textMode": "auto", "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "short", "decimals": 0, "noValue": "Nothing to report", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "yellow" } ] } }, "overrides": [] } } } } }, "panel-155": { "kind": "Panel", "spec": { "id": 155, "title": "Failed reads", "description": "Shows when the PlexExporterCollectionErrors alert fired at any point in the selected time range, for any exporter: plex-exporter kept failing to read part of Plex for 30 minutes. The figure is every failed read in the range, and can be 0 when a short range catches only the end of an alert. Failed reads by type on Exporter health says which part of the dashboard is affected, and also lists the odd failure, such as one during a Plex restart, which does not show here. Without the alert rules from alerts/promql.yaml, the tile shows when their condition held for those 30 minutes in the range.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "(round(sum(increase(plex_exporter_errors_total[$__range]))) or vector(0)) and on () ((count(max_over_time(ALERTS{alertname=\"PlexExporterCollectionErrors\", alertstate=\"firing\"}[$__range])) or count(ALERTS{alertname=\"PlexExporterCollectionErrors\", alertstate=\"firing\"} offset $__range)) or (count(max_over_time(((count_over_time((sum by (type) (rate(plex_exporter_errors_total[15m])) > 0)[32m:1m]) >= 32))[$__range:1m])) unless on () (count(max_over_time(ALERTS{alertname=\"PlexExporterCollectionErrors\"}[$__range])) or count(max_over_time(ALERTS{alertname=\"PlexExporterCollectionErrors\"}[32m] offset $__range)))))", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "background", "graphMode": "none", "justifyMode": "center", "reduceOptions": { "calcs": [ "lastNotNull" ], "values": false }, "textMode": "auto", "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "short", "decimals": 0, "noValue": "Nothing to report", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "yellow" } ] } }, "overrides": [] } } } } }, "panel-156": { "kind": "Panel", "spec": { "id": 156, "title": "Watch history stale", "description": "Shows only when plex-exporter, which reads new plays from Plex every 5 minutes, has not managed a read for 30 minutes, with how long ago the last one worked. It turns red at an hour, when the never-played and last-played figures on Storage cleanup are hidden until a read succeeds. Never read means no watch-history read has worked since the exporter started, and the exporter log names the error. No alert rule covers this.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max((time() - max by (server, server_id) (plex_history_last_success_timestamp_seconds{server=~\"$server\"}) > 1800) or on (server, server_id) (-1 * (max by (server, server_id) (plex_history_read_status{server=~\"$server\", status=\"failed\"}) == 1) unless on (server, server_id) max by (server, server_id) (plex_history_last_success_timestamp_seconds{server=~\"$server\"})))", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "background", "graphMode": "none", "justifyMode": "center", "reduceOptions": { "calcs": [ "lastNotNull" ], "values": false }, "textMode": "auto", "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "s", "decimals": 0, "noValue": "Nothing to report", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "yellow" }, { "value": 3600, "color": "red" } ] }, "mappings": [ { "type": "value", "options": { "-1": { "index": 0, "text": "Never read", "color": "red" } } } ] }, "overrides": [] } } } } }, "panel-157": { "kind": "Panel", "spec": { "id": 157, "title": "Watch figures hidden", "description": "Shows only when the never-played and last-played figures on Storage cleanup are hidden for a reason that does not clear by itself. Unmatched means Plex sent watch-history rows plex-exporter cannot tie to an item, so a watched item could read as never played, until a restart reads the history again without them. Over limit means the server has more than 250,000 plays or the first read took over 20 minutes, and plex-exporter tries again once a day. No alert rule covers this.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max(label_replace(0 * (max by (server, server_id) (plex_history_read_status{server=~\"$server\", status=\"over_limit\"}) == 1) + 2, \"reason\", \"limit\", \"\", \"\") or label_replace(0 * (max by (server, server_id) (plex_history_unmatched_rows{server=~\"$server\"}) > 0) + 1, \"reason\", \"unmatched\", \"\", \"\"))", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "background", "graphMode": "none", "justifyMode": "center", "reduceOptions": { "calcs": [ "lastNotNull" ], "values": false }, "textMode": "auto", "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "none", "decimals": 0, "noValue": "Nothing to report", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "yellow" } ] }, "mappings": [ { "type": "value", "options": { "2": { "index": 0, "text": "Over limit", "color": "yellow" }, "1": { "index": 1, "text": "Unmatched", "color": "yellow" } } } ] }, "overrides": [] } } } } }, "panel-158": { "kind": "Panel", "spec": { "id": 158, "title": "Libraries skipped", "description": "Shows only when the server has more than 32 video libraries, the most plex-exporter reads item by item. The figure is how many it skips. Those libraries stay out of the catalog panels, and the server totals on Storage cleanup stay hidden. No alert rule covers this.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(max by (server, server_id) (plex_library_walk_skipped_libraries{server=~\"$server\"})) > 0", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "background", "graphMode": "none", "justifyMode": "center", "reduceOptions": { "calcs": [ "lastNotNull" ], "values": false }, "textMode": "auto", "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "short", "decimals": 0, "noValue": "Nothing to report", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "yellow" } ] } }, "overrides": [] } } } } }, "panel-159": { "kind": "Panel", "spec": { "id": 159, "title": "Items without a size", "description": "Shows only when Plex has not reported the file size of some items, so they are left out of every storage figure and the server totals on Storage cleanup are hidden. The figure is how many items. It clears once Plex analyses those files, and Exporter health lists them by library. No alert rule covers this.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "sum(plex_library_unsized_items{server=~\"$server\"}) > 0", "legendFormat": "", "instant": true, "range": false } }, "refId": "A", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "stat", "version": "", "spec": { "options": { "colorMode": "background", "graphMode": "none", "justifyMode": "center", "reduceOptions": { "calcs": [ "lastNotNull" ], "values": false }, "textMode": "auto", "text": { "titleSize": 14, "valueSize": 28 } }, "fieldConfig": { "defaults": { "unit": "short", "decimals": 0, "noValue": "Nothing to report", "color": { "mode": "thresholds" }, "thresholds": { "mode": "absolute", "steps": [ { "value": null, "color": "yellow" } ] } }, "overrides": [] } } } } }, "panel-170": { "kind": "Panel", "spec": { "id": 170, "title": "Growth in this range", "description": "How much each library grew over the selected time range: the space and items added, and each as a share of what the library held at the start. A large library can add many gigabytes and still look flat on the stacked charts, so this table and Change per library show the change. A negative figure means more was removed, or replaced by smaller files, than was added. A dash means there is no reading from the start of the range, as for a library added since.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row, name) (label_join((label_join(label_replace(label_join((label_replace(label_join(sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"})) and on (server) (count without (server_id) (count by (server, server_id) (plex_server_info{server=~\"$server\"})) > 1), \"name\", \"|\", \"server\", \"server_id\"), \"name\", \"$1 (id $2)\", \"name\", \"(.*)[|]([^|]{1,8})[^|]*\") or on (server, server_id, library_id, library) label_replace((label_replace(label_join(sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"})), \"name\", \"$1\", \"server\", \"(.*)\"), \"name\", \": \", \"name\", \"library\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) > 1)) or on (server, server_id, library_id, library) label_replace(label_replace(label_join(sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}), \"name\", \"$1\", \"library\", \"(.*)\"), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join((sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) - sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"} offset $__range)), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "B", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(((sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"}) - sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"} offset $__range)) / (sum by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"} offset $__range) > 0)), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "C", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join((sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"}) - sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"} offset $__range)), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "D", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "max by (row) (label_join(((sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"}) - sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"} offset $__range)) / (sum by (server, server_id, library_id, library) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"} offset $__range) > 0)), \"row\", \"/\", \"server_id\", \"library_id\"))", "legendFormat": "", "instant": true, "range": false, "format": "table" } }, "refId": "E", "hidden": false } } ], "transformations": [ { "kind": "Transformation", "group": "joinByField", "spec": { "options": { "byField": "row", "mode": "outer" } } }, { "kind": "Transformation", "group": "organize", "spec": { "options": { "excludeByName": { "Time": true, "Time 1": true, "Time 2": true, "Time 3": true, "Time 4": true, "Time 5": true, "Time #A": true, "Time #B": true, "Time #C": true, "Time #D": true, "Time #E": true, "row": true, "Value #A": true }, "indexByName": { "name": 0, "Value #B": 1, "Value #C": 2, "Value #D": 3, "Value #E": 4 }, "renameByName": { "name": "Library", "Value #B": "Storage added", "Value #C": "Storage growth", "Value #D": "Items added", "Value #E": "Items growth" } } } } ], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "table", "version": "", "spec": { "options": { "showHeader": true, "cellHeight": "sm", "frozenColumns": { "left": 1 }, "sortBy": [ { "displayName": "Storage added", "desc": true } ] }, "fieldConfig": { "defaults": { "noValue": "No libraries yet", "custom": { "align": "auto", "cellOptions": { "type": "auto" } } }, "overrides": [ { "matcher": { "id": "byName", "options": "Storage added" }, "properties": [ { "id": "unit", "value": "decbytes" } ] }, { "matcher": { "id": "byName", "options": "Storage growth" }, "properties": [ { "id": "unit", "value": "percentunit" }, { "id": "decimals", "value": 2 } ] }, { "matcher": { "id": "byName", "options": "Items added" }, "properties": [ { "id": "unit", "value": "none" }, { "id": "decimals", "value": 0 } ] }, { "matcher": { "id": "byName", "options": "Items growth" }, "properties": [ { "id": "unit", "value": "percentunit" }, { "id": "decimals", "value": 2 } ] }, { "matcher": { "id": "byName", "options": "Library" }, "properties": [ { "id": "custom.wrapText", "value": true } ] }, { "matcher": { "id": "byRegexp", "options": ".*" }, "properties": [ { "id": "noValue", "value": "-" } ] } ] } } } } }, "panel-171": { "kind": "Panel", "spec": { "id": 171, "title": "${library_id:text}", "description": "How much this library's storage and item count changed since the start of the time range, storage on the left axis and items on the right. Each axis fits this library's own change, so a few gigabytes added to a library of many terabytes still shows, and a fall below zero means more was removed than added. Items count episodes in a show library and tracks in a music library, read every 15 minutes.", "links": [], "data": { "kind": "QueryGroup", "spec": { "queries": [ { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "label_replace(sum by (server, server_id) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"} - (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"} @ start())), \"name\", \"Storage added\", \"\", \"\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) == 1) or on (server, server_id) label_replace(sum by (server, server_id) (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"} - (plex_library_storage_bytes{server=~\"$server\", library_id=~\"$library_id\"} @ start())), \"name\", \"Storage added on $1\", \"server\", \"(.*)\")", "legendFormat": "{{name}}" } }, "refId": "A", "hidden": false } }, { "kind": "PanelQuery", "spec": { "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "expr": "label_replace(sum by (server, server_id) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"} - (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"} @ start())), \"name\", \"Items added\", \"\", \"\") and on () (count(count by (server_id) (plex_server_info{server=~\"$server\"})) == 1) or on (server, server_id) label_replace(sum by (server, server_id) (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"} - (plex_library_items{server=~\"$server\", library_id=~\"$library_id\"} @ start())), \"name\", \"Items added on $1\", \"server\", \"(.*)\")", "legendFormat": "{{name}}" } }, "refId": "B", "hidden": false } } ], "transformations": [], "queryOptions": {} } }, "vizConfig": { "kind": "VizConfig", "group": "timeseries", "version": "", "spec": { "options": { "legend": { "displayMode": "list", "placement": "bottom", "showLegend": true, "calcs": [] }, "tooltip": { "mode": "multi", "sort": "none" } }, "fieldConfig": { "defaults": { "unit": "decbytes", "noValue": "No storage reading yet", "color": { "mode": "palette-classic" }, "custom": { "drawStyle": "line", "lineWidth": 2, "fillOpacity": 20, "spanNulls": true, "showPoints": "never", "axisPlacement": "left" } }, "overrides": [ { "matcher": { "id": "byRegexp", "options": "^Items.*" }, "properties": [ { "id": "unit", "value": "short" }, { "id": "decimals", "value": 0 }, { "id": "custom.axisPlacement", "value": "right" }, { "id": "custom.lineWidth", "value": 1 }, { "id": "custom.fillOpacity", "value": 0 }, { "id": "custom.lineStyle", "value": { "fill": "dash", "dash": [ 10, 10 ] } } ] } ] } } } } } }, "layout": { "kind": "TabsLayout", "spec": { "tabs": [ { "kind": "TabsLayoutTab", "spec": { "title": "Overview", "layout": { "kind": "RowsLayout", "spec": { "rows": [ { "kind": "RowsLayoutRow", "spec": { "title": "Server overview", "collapse": false, "layout": { "kind": "AutoGridLayout", "spec": { "maxColumnCount": 6, "columnWidthMode": "custom", "rowHeightMode": "custom", "rowHeight": 106, "fillScreen": false, "items": [ { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-4" } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-40" } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-3" } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-102" } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-103" } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-104" } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-150" }, "conditionalRendering": { "kind": "ConditionalRenderingGroup", "spec": { "visibility": "show", "condition": "and", "items": [ { "kind": "ConditionalRenderingData", "spec": { "value": true } } ] } } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-151" }, "conditionalRendering": { "kind": "ConditionalRenderingGroup", "spec": { "visibility": "show", "condition": "and", "items": [ { "kind": "ConditionalRenderingData", "spec": { "value": true } } ] } } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-152" }, "conditionalRendering": { "kind": "ConditionalRenderingGroup", "spec": { "visibility": "show", "condition": "and", "items": [ { "kind": "ConditionalRenderingData", "spec": { "value": true } } ] } } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-153" }, "conditionalRendering": { "kind": "ConditionalRenderingGroup", "spec": { "visibility": "show", "condition": "and", "items": [ { "kind": "ConditionalRenderingData", "spec": { "value": true } } ] } } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-154" }, "conditionalRendering": { "kind": "ConditionalRenderingGroup", "spec": { "visibility": "show", "condition": "and", "items": [ { "kind": "ConditionalRenderingData", "spec": { "value": true } } ] } } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-155" }, "conditionalRendering": { "kind": "ConditionalRenderingGroup", "spec": { "visibility": "show", "condition": "and", "items": [ { "kind": "ConditionalRenderingData", "spec": { "value": true } } ] } } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-156" }, "conditionalRendering": { "kind": "ConditionalRenderingGroup", "spec": { "visibility": "show", "condition": "and", "items": [ { "kind": "ConditionalRenderingData", "spec": { "value": true } } ] } } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-157" }, "conditionalRendering": { "kind": "ConditionalRenderingGroup", "spec": { "visibility": "show", "condition": "and", "items": [ { "kind": "ConditionalRenderingData", "spec": { "value": true } } ] } } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-158" }, "conditionalRendering": { "kind": "ConditionalRenderingGroup", "spec": { "visibility": "show", "condition": "and", "items": [ { "kind": "ConditionalRenderingData", "spec": { "value": true } } ] } } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-159" }, "conditionalRendering": { "kind": "ConditionalRenderingGroup", "spec": { "visibility": "show", "condition": "and", "items": [ { "kind": "ConditionalRenderingData", "spec": { "value": true } } ] } } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-100" }, "conditionalRendering": { "kind": "ConditionalRenderingGroup", "spec": { "visibility": "show", "condition": "and", "items": [ { "kind": "ConditionalRenderingData", "spec": { "value": true } } ] } } } } ], "columnWidth": 235 } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "Streaming", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 24, "height": 8, "element": { "kind": "ElementReference", "name": "panel-20" } } }, { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 8, "width": 24, "height": 8, "element": { "kind": "ElementReference", "name": "panel-21" } } } ] } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "Library work", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 24, "height": 5, "element": { "kind": "ElementReference", "name": "panel-105" } } } ] } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "Host resources", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 12, "height": 8, "element": { "kind": "ElementReference", "name": "panel-30" } } }, { "kind": "GridLayoutItem", "spec": { "x": 12, "y": 0, "width": 12, "height": 8, "element": { "kind": "ElementReference", "name": "panel-31" } } } ] } } } } ] } } } }, { "kind": "TabsLayoutTab", "spec": { "title": "Libraries", "layout": { "kind": "RowsLayout", "spec": { "rows": [ { "kind": "RowsLayoutRow", "spec": { "title": "Totals", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 5, "height": 3, "element": { "kind": "ElementReference", "name": "panel-42" } } }, { "kind": "GridLayoutItem", "spec": { "x": 5, "y": 0, "width": 5, "height": 3, "element": { "kind": "ElementReference", "name": "panel-43" } } }, { "kind": "GridLayoutItem", "spec": { "x": 10, "y": 0, "width": 6, "height": 3, "element": { "kind": "ElementReference", "name": "panel-44" } } }, { "kind": "GridLayoutItem", "spec": { "x": 16, "y": 0, "width": 8, "height": 3, "element": { "kind": "ElementReference", "name": "panel-60" } } } ] } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "Libraries", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 24, "height": 10, "element": { "kind": "ElementReference", "name": "panel-10" } } }, { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 10, "width": 24, "height": 10, "element": { "kind": "ElementReference", "name": "panel-117" } } } ] } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "Growth", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 24, "height": 10, "element": { "kind": "ElementReference", "name": "panel-170" } } }, { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 10, "width": 24, "height": 8, "element": { "kind": "ElementReference", "name": "panel-63" } } }, { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 18, "width": 24, "height": 8, "element": { "kind": "ElementReference", "name": "panel-50" } } } ] } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "Change per library", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 24, "height": 6, "element": { "kind": "ElementReference", "name": "panel-171" }, "repeat": { "mode": "variable", "value": "library_id", "direction": "v" } } } ] } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "Resolution and codec", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 12, "height": 10, "element": { "kind": "ElementReference", "name": "panel-107" } } }, { "kind": "GridLayoutItem", "spec": { "x": 12, "y": 0, "width": 12, "height": 10, "element": { "kind": "ElementReference", "name": "panel-108" } } } ] } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "Recently added", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 24, "height": 12, "element": { "kind": "ElementReference", "name": "panel-109" } } } ] } } } } ] } } } }, { "kind": "TabsLayoutTab", "spec": { "title": "Storage cleanup", "layout": { "kind": "RowsLayout", "spec": { "rows": [ { "kind": "RowsLayoutRow", "spec": { "title": "What you could free", "collapse": false, "layout": { "kind": "AutoGridLayout", "spec": { "maxColumnCount": 2, "columnWidthMode": "custom", "rowHeightMode": "custom", "rowHeight": 106, "fillScreen": false, "items": [ { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-110" } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-112" } } } ], "columnWidth": 180 } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "By library", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 16, "height": 10, "element": { "kind": "ElementReference", "name": "panel-114" } } }, { "kind": "GridLayoutItem", "spec": { "x": 16, "y": 0, "width": 8, "height": 10, "element": { "kind": "ElementReference", "name": "panel-115" } } } ] } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "Largest items", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 24, "height": 12, "element": { "kind": "ElementReference", "name": "panel-116" }, "repeat": { "mode": "variable", "value": "server", "direction": "v" } } } ] } } } } ] } } } }, { "kind": "TabsLayoutTab", "spec": { "title": "Streaming history", "layout": { "kind": "RowsLayout", "spec": { "rows": [ { "kind": "RowsLayoutRow", "spec": { "title": "Watch time in this range", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 12, "height": 12, "element": { "kind": "ElementReference", "name": "panel-72" } } }, { "kind": "GridLayoutItem", "spec": { "x": 12, "y": 0, "width": 12, "height": 12, "element": { "kind": "ElementReference", "name": "panel-73" } } }, { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 15, "width": 24, "height": 22, "element": { "kind": "ElementReference", "name": "panel-74" } } } ] } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "Watching over time", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 12, "height": 8, "element": { "kind": "ElementReference", "name": "panel-70" } } }, { "kind": "GridLayoutItem", "spec": { "x": 12, "y": 0, "width": 12, "height": 8, "element": { "kind": "ElementReference", "name": "panel-71" } } }, { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 8, "width": 24, "height": 8, "element": { "kind": "ElementReference", "name": "panel-75" } } } ] } } } } ] } } } }, { "kind": "TabsLayoutTab", "spec": { "title": "Transcoding", "layout": { "kind": "RowsLayout", "spec": { "rows": [ { "kind": "RowsLayoutRow", "spec": { "title": "Over time", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 24, "height": 8, "element": { "kind": "ElementReference", "name": "panel-120" } } }, { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 8, "width": 24, "height": 8, "element": { "kind": "ElementReference", "name": "panel-121" } } } ] } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "By player and source", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 24, "height": 7, "element": { "kind": "ElementReference", "name": "panel-122" } } }, { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 7, "width": 12, "height": 7, "element": { "kind": "ElementReference", "name": "panel-123" } } }, { "kind": "GridLayoutItem", "spec": { "x": 12, "y": 7, "width": 12, "height": 7, "element": { "kind": "ElementReference", "name": "panel-124" } } } ] } } } } ] } } } }, { "kind": "TabsLayoutTab", "spec": { "title": "Exporter health", "layout": { "kind": "RowsLayout", "spec": { "rows": [ { "kind": "RowsLayoutRow", "spec": { "title": "Reads", "collapse": false, "layout": { "kind": "AutoGridLayout", "spec": { "maxColumnCount": 2, "columnWidthMode": "custom", "rowHeightMode": "custom", "rowHeight": 106, "fillScreen": false, "items": [ { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-138" } } }, { "kind": "AutoGridLayoutItem", "spec": { "element": { "kind": "ElementReference", "name": "panel-141" } } } ], "columnWidth": 180 } } } }, { "kind": "RowsLayoutRow", "spec": { "title": "Detail", "collapse": false, "layout": { "kind": "GridLayout", "spec": { "items": [ { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 0, "width": 12, "height": 8, "element": { "kind": "ElementReference", "name": "panel-130" } } }, { "kind": "GridLayoutItem", "spec": { "x": 12, "y": 0, "width": 12, "height": 8, "element": { "kind": "ElementReference", "name": "panel-135" } } }, { "kind": "GridLayoutItem", "spec": { "x": 0, "y": 8, "width": 24, "height": 9, "element": { "kind": "ElementReference", "name": "panel-137" } } } ] } } } } ] } } } } ] } }, "links": [], "liveNow": false, "preload": true, "tags": [ "plex", "media-server", "streaming", "transcoding" ], "timeSettings": { "timezone": "browser", "from": "now-7d", "to": "now", "autoRefresh": "30s", "autoRefreshIntervals": [ "5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d" ], "hideTimepicker": false, "fiscalYearStartMonth": 0 }, "title": "Plex Exporter", "variables": [ { "kind": "DatasourceVariable", "spec": { "name": "datasource", "pluginId": "prometheus", "refresh": "never", "regex": "", "current": { "text": "Mimir", "value": "mimir" }, "options": [], "multi": false, "includeAll": false, "label": "Data source", "hide": "dontHide", "skipUrlSync": false, "allowCustomValue": true } }, { "kind": "QueryVariable", "spec": { "name": "server", "current": { "text": [ "All" ], "value": [ "$__all" ] }, "label": "Server", "hide": "dontHide", "refresh": "onTimeRangeChanged", "skipUrlSync": false, "description": "The Plex servers to show, by the name each server reports. With several selected, totals add the servers together and each library name starts with its server's name. Two servers that report the same name are selected together, and each shows the first eight characters of its server ID after the name.", "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "query": "label_values(plex_server_info, server)" } }, "regex": "", "sort": "alphabeticalAsc", "definition": "label_values(plex_server_info, server)", "options": [], "multi": true, "includeAll": true, "allValue": ".+", "allowCustomValue": false } }, { "kind": "QueryVariable", "spec": { "name": "library_id", "label": "Library", "hide": "dontHide", "refresh": "onTimeRangeChanged", "skipUrlSync": false, "description": "The libraries the Libraries and Storage cleanup tabs show, listed by name. Plex numbers libraries per server, so with several servers selected one choice shows that library number on each of them. Two libraries with the same name on one server show their number after the name, here and in every panel.", "current": { "text": [ "All" ], "value": [ "$__all" ] }, "query": { "kind": "DataQuery", "group": "prometheus", "version": "v0", "datasource": { "name": "${datasource}" }, "spec": { "query": "query_result(label_replace(label_join(max by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\"}))" } }, "regex": "/library=\"(?(?:[^\"\\\\]|\\\\.)+)\".*library_id=\"(?[^\"]+)\"/", "sort": "alphabeticalAsc", "definition": "query_result(label_replace(label_join(max by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\"}) and on (server, server_id, library) (count by (server, server_id, library) (plex_library_storage_bytes{server=~\"$server\"}) > 1), \"library\", \" (id \", \"library\", \"library_id\"), \"library\", \"$1)\", \"library\", \"(.*)\") or on (server, server_id, library_id) max by (server, server_id, library_id, library) (plex_library_storage_bytes{server=~\"$server\"}))", "options": [], "multi": true, "includeAll": true, "allValue": ".+", "allowCustomValue": false } } ] } }