Rework postgres_mixin dashboard

Rework the postgres_mixing dashboard to be more composable. The goal is for this to be more maintainable long term. I don't know jsonnet very well, but following other projects, this appears to be in line.

This replaces the postgres-overview.json dashboard with an overview.json dashboard with the same panels. While the dashboard does not match perfectly, it does include the same data but with the correct metrics.

Signed-off-by: Joe Adams <github@joeadams.io>
This commit is contained in:
Joe Adams 2023-09-11 16:02:26 -04:00
parent 31ef4ed5a2
commit 5d10f23241
11 changed files with 367 additions and 1414 deletions

1
.gitignore vendored
View File

@ -20,3 +20,4 @@
/.metrics.*.removed
/tools/src
/vendor
vendor/

View File

@ -1,5 +1,8 @@
{
_config+:: {
postgresExporterSelector: '',
dashboardNamePrefix: 'Postgres Exporter / ',
dashboardTags: ['postgres-exporter-mixin'],
},
}

View File

@ -0,0 +1,3 @@
local dashboards = (import 'mixin.libsonnet').grafanaDashboards;
{ [name]: dashboards[name] for name in std.objectFields(dashboards)}

View File

@ -1,5 +1,41 @@
local g = import 'g.libsonnet';
local dashboard = g.dashboard;
local row = g.panel.row;
local panels = import './panels.libsonnet';
local variables = import './variables.libsonnet';
local queries = import './queries.libsonnet';
// import config
local c = import '../config.libsonnet';
{
grafanaDashboards+:: {
'postgres-overview.json': (import 'postgres-overview.json'),
},
'overview.json':
dashboard.new('%s Overview' % $._config.dashboardNamePrefix)
+ dashboard.withTags($._config.dashboardTags)
+ dashboard.withRefresh('1m')
+ dashboard.time.withFrom(value='now-1h')
+ dashboard.graphTooltip.withSharedCrosshair()
+ dashboard.withVariables([
variables.datasource,
])
+ dashboard.withPanels(
g.util.grid.makeGrid([
row.new('Overview')
+ row.withPanels([
panels.stat.qps('QPS', queries.qps),
panels.timeSeries.ratio1('Cache Hit Ratio', queries.cacheHitRatio),
panels.timeSeries.base('Active Connections', queries.activeConnections)
]),
row.new('server')
+ row.withPanels([
panels.timeSeries.base('Conflicts/Deadlocks', [queries.conflicts, queries.deadlocks]),
panels.timeSeries.base('Buffers', [queries.buffersAlloc, queries.buffersBackendFsync, queries.buffersBackend, queries.buffersClean, queries.buffersCheckpoint]),
panels.timeSeries.base('Rows', [queries.databaseTupFetched, queries.databaseTupReturned, queries.databaseTupInserted, queries.databaseTupUpdated, queries.databaseTupDeleted]),
]),
])
)
}
}

View File

@ -0,0 +1 @@
import 'github.com/grafana/grafonnet/gen/grafonnet-latest/main.libsonnet'

View File

@ -0,0 +1,30 @@
local g = import 'g.libsonnet';
{
stat: {
local stat = g.panel.stat,
base(title, targets):
stat.new(title)
+stat.queryOptions.withTargets(targets),
qps: self.base,
},
timeSeries: {
local timeSeries = g.panel.timeSeries,
base(title, targets):
timeSeries.new(title)
+timeSeries.queryOptions.withTargets(targets),
ratio(title, targets):
self.base(title, targets)
+ timeSeries.standardOptions.withUnit('percentunit'),
ratio1(title, targets):
self.ratio(title, targets)
+ timeSeries.standardOptions.withUnit('percentunit')
+ timeSeries.standardOptions.withMax(1)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,223 @@
local g = import './g.libsonnet';
local prometheusQuery = g.query.prometheus;
local variables = import './variables.libsonnet';
{
/*
General overview queries
*/
qps:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
irate(
pg_stat_database_xact_commit{}[$__rate_interval]
)
)
+
sum(
irate(
pg_stat_database_xact_rollback{}[$__rate_interval]
)
)
|||
),
cacheHitRatio:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum by (datname) (
rate(
pg_stat_database_blks_hit{}
[$__rate_interval])
) / (
sum by (datname) (
rate(
pg_stat_database_blks_hit{}
[$__rate_interval])
) + sum by (datname) (
rate(
pg_stat_database_blks_read{}
[$__rate_interval])
)
)
|||
)
+ prometheusQuery.withLegendFormat(|||
{{datname}}
|||),
activeConnections:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
pg_stat_database_numbackends{}
|||
)
+ prometheusQuery.withLegendFormat(|||
{{datname}}
|||),
deadlocks:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
rate(
pg_stat_database_deadlocks{}[$__rate_interval]
)
)
|||
)
+ prometheusQuery.withLegendFormat(|||
deadlocks
|||),
conflicts:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
rate(
pg_stat_database_conflicts{}[$__rate_interval]
)
)
|||
)
+ prometheusQuery.withLegendFormat(|||
conflicts
|||),
/* ----------------------
Buffers
---------------------- */
buffersAlloc:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
irate(
pg_stat_bgwriter_buffers_alloc_total{}[$__rate_interval]
)
|||
)
+ prometheusQuery.withLegendFormat('allocated'),
buffersBackendFsync:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
irate(
pg_stat_bgwriter_buffers_backend_fsync_total{}[$__rate_interval]
)
|||
)
+ prometheusQuery.withLegendFormat('backend fsyncs'),
buffersBackend:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
irate(
pg_stat_bgwriter_buffers_backend_total{}[$__rate_interval]
)
|||
)
+ prometheusQuery.withLegendFormat('backend'),
buffersClean:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
irate(
pg_stat_bgwriter_buffers_clean_total{}[$__rate_interval]
)
|||
)
+ prometheusQuery.withLegendFormat('clean'),
buffersCheckpoint:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
irate(
pg_stat_bgwriter_buffers_checkpoint_total{}[$__rate_interval]
)
|||
)
+ prometheusQuery.withLegendFormat('checkpoint'),
/* ----------------------
Database Tups
---------------------- */
databaseTupFetched:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
irate(
pg_stat_database_tup_fetched{}[$__rate_interval]
)
)
|||
)
+ prometheusQuery.withLegendFormat('fetched'),
databaseTupReturned:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
irate(
pg_stat_database_tup_returned{}[$__rate_interval]
)
)
|||
)
+ prometheusQuery.withLegendFormat('returned'),
databaseTupInserted:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
irate(
pg_stat_database_tup_inserted{}[$__rate_interval]
)
)
|||
)
+ prometheusQuery.withLegendFormat('inserted'),
databaseTupUpdated:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
irate(
pg_stat_database_tup_updated{}[$__rate_interval]
)
)
|||
)
+ prometheusQuery.withLegendFormat('updated'),
databaseTupDeleted:
prometheusQuery.new(
'$' + variables.datasource.name,
|||
sum(
irate(
pg_stat_database_tup_deleted{}[$__rate_interval]
)
)
|||
)
+ prometheusQuery.withLegendFormat('deleted'),
}

View File

@ -0,0 +1,7 @@
local g = import './g.libsonnet';
local var = g.dashboard.variable;
{
datasource:
var.datasource.new('datasource', 'prometheus')
}

View File

@ -0,0 +1,15 @@
{
"version": 1,
"dependencies": [
{
"source": {
"git": {
"remote": "https://github.com/grafana/grafonnet.git",
"subdir": "gen/grafonnet-latest"
}
},
"version": "main"
}
],
"legacyImports": true
}

View File

@ -0,0 +1,46 @@
{
"version": 1,
"dependencies": [
{
"source": {
"git": {
"remote": "https://github.com/grafana/grafonnet.git",
"subdir": "gen/grafonnet-latest"
}
},
"version": "f86c6b155b8ea527d36cd7194b2cb42dac437166",
"sum": "sVzVlSLbxPkAurwO19YERigLMmRfVsViMcWC0gkTTqU="
},
{
"source": {
"git": {
"remote": "https://github.com/grafana/grafonnet.git",
"subdir": "gen/grafonnet-v10.0.0"
}
},
"version": "f86c6b155b8ea527d36cd7194b2cb42dac437166",
"sum": "brWLY/BpeCL2ThiWlLtLcs4KwgMvouGtPrKAagBnG8g="
},
{
"source": {
"git": {
"remote": "https://github.com/jsonnet-libs/docsonnet.git",
"subdir": "doc-util"
}
},
"version": "7c865ec0606f2b68c0f6b2721f101e6a99cd2593",
"sum": "zjjufxN4yAIevldYEERiZEp27vK0BJKj1VvZcVtWiOo="
},
{
"source": {
"git": {
"remote": "https://github.com/jsonnet-libs/xtd.git",
"subdir": ""
}
},
"version": "0256a910ac71f0f842696d7bca0bf01ea77eb654",
"sum": "zBOpb1oTNvXdq9RF6yzTHill5r1YTJLBBoqyx4JYtAg="
}
],
"legacyImports": false
}