Add postgresql charts
* Add temp files chart * Add WAL written chart * Rename previous bgwriter char to checkpointer * Add several bgwriter charts * Add autovacuum chart * Add replication chart
anayrat committed
Feb 7, 2018 at 21:33 UTC
e57a2f1398bd4d5f5d51f062234cbd32f5622aa3
3 files changed
+290
-43
conf.d/python.d/postgres.conf
+12
-3
@@ -82,9 +82,18 @@
82
# a postgres user for netdata and add its password below to allow
83
# netdata connect.
84
#
85
-# Without superuser access, netdata won't be able to generate the write
86
-# ahead log and the background writer charts.
87
-#
85
+# Postgres supported versions are :
86
+# - 9.3 (without autovacuum)
87
+# - 9.4
88
+# - 9.5
89
+# - 9.6
90
+# - 10
91
+#
92
+# Superuser access is needed for theses charts:
93
+# Write-Ahead Logs
94
+# Archive Write-Ahead Logs
95
+#
96
+# Autovacuum charts is allowed since Postgres 9.4
97
# ----------------------------------------------------------------------
98
99
socket:
python.d/postgres.chart.py
+225
-40
@@ -32,6 +32,8 @@ METRICS = dict(
32
'tup_updated',
33
'tup_deleted',
34
'conflicts',
35
+ 'temp_files',
36
+ 'temp_bytes',
37
'size'],
38
BACKENDS=['backends_active',
39
'backends_idle'],
@@ -39,11 +41,20 @@ METRICS = dict(
41
'index_size'],
42
TABLE_STATS=['table_size',
43
'table_count'],
44
+ WAL=['written_wal',
45
+ 'recycled_wal',
46
+ 'total_wal'],
47
ARCHIVE=['ready_count',
48
'done_count',
49
'file_count'],
45
- BGWRITER=['writer_scheduled',
46
- 'writer_requested'],
50
+ BGWRITER=['checkpoint_scheduled',
51
+ 'checkpoint_requested',
52
+ 'buffers_checkpoint',
53
+ 'buffers_clean',
54
+ 'maxwritten_clean',
55
+ 'buffers_backend',
56
+ 'buffers_alloc',
57
+ 'buffers_backend_fsync'],
58
LOCKS=['ExclusiveLock',
59
'RowShareLock',
60
'SIReadLock',
@@ -52,17 +63,41 @@ METRICS = dict(
63
'AccessShareLock',
64
'ShareRowExclusiveLock',
65
'ShareLock',
55
- 'RowExclusiveLock']
66
+ 'RowExclusiveLock'],
67
+ AUTOVACUUM=['analyze',
68
+ 'vacuum_analyze',
69
+ 'vacuum',
70
+ 'vacuum_freeze',
71
+ 'brin_summarize'],
72
+ STANDBY_DELTA=['sent_delta',
73
+ 'write_delta',
74
+ 'flush_delta',
75
+ 'replay_delta']
76
)
77
78
QUERIES = dict(
79
+ WAL="""
80
+SELECT
81
+ count(*) as total_wal,
82
+ count(*) FILTER (WHERE type = 'recycled') AS recycled_wal,
83
+ count(*) FILTER (WHERE type = 'written') AS written_wal
84
+FROM
85
+ (SELECT wal.name,
86
+ pg_{0}file_name(pg_current_{0}_{1}()),
87
+ CASE WHEN wal.name > pg_{0}file_name(pg_current_{0}_{1}()) THEN 'recycled'
88
+ ELSE 'written'
89
+ END AS type
90
+ FROM pg_catalog.pg_ls_dir('pg_{0}') AS wal(name)
91
+ WHERE name ~ '^[0-9A-F]{{24}}$'
92
+ ORDER BY (pg_stat_file('pg_{0}/'||name)).modification, wal.name DESC) sub;
93
+""",
94
ARCHIVE="""
95
SELECT
96
CAST(COUNT(*) AS INT) AS file_count,
97
CAST(COALESCE(SUM(CAST(archive_file ~ $r$\.ready$$r$ as INT)), 0) AS INT) AS ready_count,
98
CAST(COALESCE(SUM(CAST(archive_file ~ $r$\.done$$r$ AS INT)), 0) AS INT) AS done_count
99
FROM
65
- pg_catalog.pg_ls_dir('{0}/archive_status') AS archive_files (archive_file);
100
+ pg_catalog.pg_ls_dir('pg_{0}/archive_status') AS archive_files (archive_file);
101
""",
102
BACKENDS="""
103
SELECT
@@ -86,28 +121,37 @@ WHERE relkind = 'i';""",
121
DATABASE="""
122
SELECT
123
datname AS database_name,
89
- sum(numbackends) AS connections,
90
- sum(xact_commit) AS xact_commit,
91
- sum(xact_rollback) AS xact_rollback,
92
- sum(blks_read) AS blks_read,
93
- sum(blks_hit) AS blks_hit,
94
- sum(tup_returned) AS tup_returned,
95
- sum(tup_fetched) AS tup_fetched,
96
- sum(tup_inserted) AS tup_inserted,
97
- sum(tup_updated) AS tup_updated,
98
- sum(tup_deleted) AS tup_deleted,
99
- sum(conflicts) AS conflicts,
100
- pg_database_size(datname) AS size
124
+ numbackends AS connections,
125
+ xact_commit AS xact_commit,
126
+ xact_rollback AS xact_rollback,
127
+ blks_read AS blks_read,
128
+ blks_hit AS blks_hit,
129
+ tup_returned AS tup_returned,
130
+ tup_fetched AS tup_fetched,
131
+ tup_inserted AS tup_inserted,
132
+ tup_updated AS tup_updated,
133
+ tup_deleted AS tup_deleted,
134
+ conflicts AS conflicts,
135
+ pg_database_size(datname) AS size,
136
+ temp_files AS temp_files,
137
+ temp_bytes AS temp_bytes
138
FROM pg_stat_database
139
WHERE datname IN %(databases)s
103
-GROUP BY datname;
140
+;
141
""",
142
BGWRITER="""
143
SELECT
107
- checkpoints_timed AS writer_scheduled,
108
- checkpoints_req AS writer_requested
109
-FROM pg_stat_bgwriter;""",
110
- LOCKS="""
144
+ checkpoints_timed AS checkpoint_scheduled,
145
+ checkpoints_req AS checkpoint_requested,
146
+ buffers_checkpoint * current_setting('block_size')::numeric buffers_checkpoint,
147
+ buffers_clean * current_setting('block_size')::numeric buffers_clean,
148
+ maxwritten_clean,
149
+ buffers_backend * current_setting('block_size')::numeric buffers_backend,
150
+ buffers_alloc * current_setting('block_size')::numeric buffers_alloc,
151
+ buffers_backend_fsync
152
+FROM pg_stat_bgwriter;
153
+""",
154
+ LOCKS="""
155
SELECT
156
pg_database.datname as database_name,
157
mode,
@@ -122,13 +166,40 @@ SELECT datname
166
FROM pg_stat_database
167
WHERE has_database_privilege((SELECT current_user), datname, 'connect')
168
AND NOT datname ~* '^template\d+';
169
+""",
170
+ FIND_STANDBY="""
171
+SELECT application_name
172
+FROM pg_stat_replication
173
+WHERE application_name IS NOT NULL
174
+GROUP BY application_name;
175
+""",
176
+ STANDBY_DELTA="""
177
+SELECT application_name,
178
+ pg_{0}_{1}_diff(pg_current_{0}_{1}() , sent_{1}) AS sent_delta,
179
+ pg_{0}_{1}_diff(pg_current_{0}_{1}() , write_{1}) AS write_delta,
180
+ pg_{0}_{1}_diff(pg_current_{0}_{1}() , flush_{1}) AS flush_delta,
181
+ pg_{0}_{1}_diff(pg_current_{0}_{1}() , replay_{1}) AS replay_delta
182
+FROM pg_stat_replication
183
+WHERE application_name IS NOT NULL
184
""",
185
IF_SUPERUSER="""
186
SELECT current_setting('is_superuser') = 'on' AS is_superuser;
128
- """,
187
+""",
188
DETECT_SERVER_VERSION="""
189
SHOW server_version_num;
131
- """
190
+""",
191
+ AUTOVACUUM="""
192
+SELECT
193
+ count(*) FILTER (WHERE query LIKE 'autovacuum: ANALYZE%%') AS analyze,
194
+ count(*) FILTER (WHERE query LIKE 'autovacuum: VACUUM ANALYZE%%') AS vacuum_analyze,
195
+ count(*) FILTER (WHERE query LIKE 'autovacuum: VACUUM%%'
196
+ AND query NOT LIKE 'autovacuum: VACUUM ANALYZE%%'
197
+ AND query NOT LIKE '%%to prevent wraparound%%') AS vacuum,
198
+ count(*) FILTER (WHERE query LIKE '%%to prevent wraparound%%') AS vacuum_freeze,
199
+ count(*) FILTER (WHERE query LIKE 'autovacuum: BRIN summarize%%') AS brin_summarize
200
+FROM pg_stat_activity
201
+WHERE query NOT LIKE '%%pg_stat_activity%%';
202
+"""
203
)
204
205
@@ -138,8 +209,11 @@ QUERY_STATS = {
209
QUERIES['LOCKS']: METRICS['LOCKS']
210
}
211
141
-ORDER = ['db_stat_transactions', 'db_stat_tuple_read', 'db_stat_tuple_returned', 'db_stat_tuple_write', 'database_size',
142
- 'backend_process', 'index_count', 'index_size', 'table_count', 'table_size', 'wal', 'background_writer']
212
+ORDER = ['db_stat_temp_bytes', 'db_stat_temp_files', 'db_stat_blks', 'db_stat_tuple_returned', 'db_stat_tuple_write',
213
+ 'db_stat_transactions','db_stat_connections', 'database_size', 'backend_process', 'index_count', 'index_size',
214
+ 'table_count', 'table_size', 'wal', 'archive_wal', 'checkpointer', 'stat_bgwriter_alloc', 'stat_bgwriter_checkpoint',
215
+ 'stat_bgwriter_backend', 'stat_bgwriter_backend_fsync' , 'stat_bgwriter_bgwriter', 'stat_bgwriter_maxwritten',
216
+ 'standby_delta','autovacuum']
217
218
CHARTS = {
219
'db_stat_transactions': {
@@ -155,8 +229,8 @@ CHARTS = {
229
'lines': [
230
['connections', 'connections', 'absolute']
231
]},
158
- 'db_stat_tuple_read': {
159
- 'options': [None, 'Tuple reads from db', 'reads/s', 'db statistics', 'postgres.db_stat_tuple_read', 'line'],
232
+ 'db_stat_blks': {
233
+ 'options': [None, 'Disk blocks reads from db', 'reads/s', 'db statistics', 'postgres.db_stat_blks', 'line'],
234
'lines': [
235
['blks_read', 'disk', 'incremental'],
236
['blks_hit', 'cache', 'incremental']
@@ -176,6 +250,16 @@ CHARTS = {
250
['tup_deleted', 'deleted', 'incremental'],
251
['conflicts', 'conflicts', 'incremental']
252
]},
253
+ 'db_stat_temp_bytes': {
254
+ 'options': [None, 'Temp files written to disk', 'KB/s', 'db statistics', 'postgres.db_stat_temp_bytes', 'line'],
255
+ 'lines': [
256
+ ['temp_bytes', 'size', 'incremental', 1, 1024]
257
+ ]},
258
+ 'db_stat_temp_files': {
259
+ 'options': [None, 'Temp files written to disk', 'files', 'db statistics', 'postgres.db_stat_temp_files', 'line'],
260
+ 'lines': [
261
+ ['temp_files', 'files', 'incremental']
262
+ ]},
263
'database_size': {
264
'options': [None, 'Database size', 'MB', 'database size', 'postgres.db_size', 'stacked'],
265
'lines': [
@@ -208,17 +292,71 @@ CHARTS = {
292
['table_size', 'size', 'absolute', 1, 1024 * 1024]
293
]},
294
'wal': {
211
- 'options': [None, 'Write-Ahead Logging Statistics', 'files/s', 'write ahead log', 'postgres.wal', 'line'],
295
+ 'options': [None, 'Write-Ahead Logs', 'files', 'wal', 'postgres.wal', 'line'],
296
+ 'lines': [
297
+ ['written_wal', 'written', 'absolute'],
298
+ ['recycled_wal', 'recycled', 'absolute'],
299
+ ['total_wal', 'total', 'absolute']
300
+ ]},
301
+ 'archive_wal': {
302
+ 'options': [None, 'Archive Write-Ahead Logs', 'files/s', 'archive wal', 'postgres.archive_wal', 'line'],
303
'lines': [
304
['file_count', 'total', 'incremental'],
305
['ready_count', 'ready', 'incremental'],
306
['done_count', 'done', 'incremental']
307
]},
217
- 'background_writer': {
218
- 'options': [None, 'Checkpoints', 'writes/s', 'background writer', 'postgres.background_writer', 'line'],
308
+ 'checkpointer': {
309
+ 'options': [None, 'Checkpoints', 'writes', 'checkpointer', 'postgres.checkpointer', 'line'],
310
+ 'lines': [
311
+ ['checkpoint_scheduled', 'scheduled', 'incremental'],
312
+ ['checkpoint_requested', 'requested', 'incremental']
313
+ ]},
314
+ 'stat_bgwriter_alloc': {
315
+ 'options': [None, 'Buffers allocated', 'kilobytes/s', 'bgwriter', 'postgres.stat_bgwriter_alloc', 'line'],
316
'lines': [
220
- ['writer_scheduled', 'scheduled', 'incremental'],
221
- ['writer_requested', 'requested', 'incremental']
317
+ ['buffers_alloc', 'alloc', 'incremental', 8, 1024]
318
+ ]},
319
+ 'stat_bgwriter_checkpoint': {
320
+ 'options': [None, 'Buffers written during checkpoints', 'kilobytes/s', 'bgwriter', 'postgres.stat_bgwriter_checkpoint', 'line'],
321
+ 'lines': [
322
+ ['buffers_checkpoint', 'checkpoint', 'incremental', 8, 1024]
323
+ ]},
324
+ 'stat_bgwriter_backend': {
325
+ 'options': [None, 'Buffers written directly by a backend', 'kilobytes/s', 'bgwriter', 'postgres.stat_bgwriter_backend', 'line'],
326
+ 'lines': [
327
+ ['buffers_backend', 'backend', 'incremental', 8, 1024]
328
+ ]},
329
+ 'stat_bgwriter_backend_fsync': {
330
+ 'options': [None, 'Fsync by backend', 'times', 'bgwriter', 'postgres.stat_bgwriter_backend_fsync', 'line'],
331
+ 'lines': [
332
+ ['buffers_backend_fsync', 'backend fsync', 'incremental']
333
+ ]},
334
+ 'stat_bgwriter_bgwriter': {
335
+ 'options': [None, 'Buffers written by the background writer', 'kilobytes/s', 'bgwriter', 'postgres.bgwriter_bgwriter', 'line'],
336
+ 'lines': [
337
+ ['buffers_clean', 'clean', 'incremental', 8, 1024]
338
+ ]},
339
+ 'stat_bgwriter_maxwritten': {
340
+ 'options': [None, 'Too many buffers written', 'times', 'bgwriter', 'postgres.stat_bgwriter_maxwritten', 'line'],
341
+ 'lines': [
342
+ ['maxwritten_clean', 'maxwritten', 'incremental']
343
+ ]},
344
+ 'autovacuum': {
345
+ 'options': [None, 'Autovacuum workers', 'workers', 'autovacuum', 'postgres.autovacuum', 'line'],
346
+ 'lines': [
347
+ ['analyze', 'analyze', 'absolute'],
348
+ ['vacuum', 'vacuum', 'absolute'],
349
+ ['vacuum_analyze', 'vacuum analyze', 'absolute'],
350
+ ['vacuum_freeze', 'vacuum freeze', 'absolute'],
351
+ ['brin_summarize', 'brin summarize', 'absolute']
352
+ ]},
353
+ 'standby_delta': {
354
+ 'options': [None, 'Standby delta', 'kilobytes', 'replication delta', 'postgres.standby_delta', 'line'],
355
+ 'lines': [
356
+ ['sent_delta', 'sent delta', 'absolute', 1, 1024],
357
+ ['write_delta', 'write delta', 'absolute', 1, 1024],
358
+ ['flush_delta', 'flush delta', 'absolute', 1, 1024],
359
+ ['replay_delta', 'replay delta', 'absolute', 1, 1024]
360
]}
361
}
362
@@ -237,6 +375,7 @@ class Service(SimpleService):
375
self.data = dict()
376
self.locks_zeroed = dict()
377
self.databases = list()
378
+ self.secondaries = list()
379
self.queries = QUERY_STATS.copy()
380
381
def _connect(self):
@@ -270,6 +409,7 @@ class Service(SimpleService):
409
cursor = self.connection.cursor()
410
self.databases = discover_databases_(cursor, QUERIES['FIND_DATABASES'])
411
is_superuser = check_if_superuser_(cursor, QUERIES['IF_SUPERUSER'])
412
+ self.secondaries = discover_secondaries_(cursor, QUERIES['FIND_STANDBY'])
413
self.server_version = detect_server_version(cursor, QUERIES['DETECT_SERVER_VERSION'])
414
cursor.close()
415
@@ -286,29 +426,44 @@ class Service(SimpleService):
426
return False
427
428
def add_additional_queries_(self, is_superuser):
429
+
430
+ if self.server_version >= 100000:
431
+ wal = 'wal'
432
+ lsn = 'lsn'
433
+ else:
434
+ wal = 'xlog'
435
+ lsn = 'location'
436
+
437
+ self.queries[QUERIES['BGWRITER']] = METRICS['BGWRITER']
438
+ self.queries[QUERIES['STANDBY_DELTA'].format(wal,lsn)] = METRICS['STANDBY_DELTA']
439
+
440
if self.index_stats:
441
self.queries[QUERIES['INDEX_STATS']] = METRICS['INDEX_STATS']
442
if self.table_stats:
443
self.queries[QUERIES['TABLE_STATS']] = METRICS['TABLE_STATS']
444
if is_superuser:
294
- self.queries[QUERIES['BGWRITER']] = METRICS['BGWRITER']
295
- if self.server_version >= 100000:
296
- wal_dir_name = 'pg_wal'
297
- else:
298
- wal_dir_name = 'pg_xlog'
299
- self.queries[QUERIES['ARCHIVE'].format(wal_dir_name)] = METRICS['ARCHIVE']
445
+ self.queries[QUERIES['ARCHIVE'].format(wal)] = METRICS['ARCHIVE']
446
+ if self.server_version >= 90400:
447
+ self.queries[QUERIES['WAL'].format(wal,lsn)] = METRICS['WAL']
448
+ if self.server_version >= 90400:
449
+ self.queries[QUERIES['AUTOVACUUM']] = METRICS['AUTOVACUUM']
450
451
def create_dynamic_charts_(self):
452
453
for database_name in self.databases[::-1]:
454
self.definitions['database_size']['lines'].append([database_name + '_size',
455
database_name, 'absolute', 1, 1024 * 1024])
306
- for chart_name in [name for name in CHARTS if name.startswith('db_stat')]:
456
+ for chart_name in [name for name in self.order if name.startswith('db_stat')]:
457
add_database_stat_chart_(order=self.order, definitions=self.definitions,
458
name=chart_name, database_name=database_name)
459
460
add_database_lock_chart_(order=self.order, definitions=self.definitions, database_name=database_name)
461
462
+ for application_name in self.secondaries[::-1]:
463
+ add_replication_delta_chart_(order=self.order, definitions=self.definitions,
464
+ name='standby_delta', application_name=application_name)
465
+
466
+
467
def _get_data(self):
468
result, error = self._connect()
469
if result:
@@ -332,7 +487,12 @@ class Service(SimpleService):
487
cursor.execute(query, dict(databases=tuple(self.databases)))
488
for row in cursor:
489
for metric in metrics:
335
- dimension_id = '_'.join([row['database_name'], metric]) if 'database_name' in row else metric
490
+ if 'database_name' in row:
491
+ dimension_id = '_'.join([row['database_name'], metric])
492
+ elif 'application_name' in row:
493
+ dimension_id = '_'.join([row['application_name'], metric])
494
+ else:
495
+ dimension_id = metric
496
if metric in row:
497
self.data[dimension_id] = int(row[metric])
498
elif 'locks_count' in row:
@@ -347,6 +507,14 @@ def discover_databases_(cursor, query):
507
result.append(db)
508
return result
509
510
+def discover_secondaries_(cursor, query):
511
+ cursor.execute(query)
512
+ result = list()
513
+ for sc in [standby[0] for standby in cursor]:
514
+ if sc not in result:
515
+ result.append(sc)
516
+ return result
517
+
518
519
def check_if_superuser_(cursor, query):
520
cursor.execute(query)
@@ -398,3 +566,20 @@ def add_database_stat_chart_(order, definitions, name, database_name):
566
definitions[chart_name] = {
567
'options': [name, title + ': ' + database_name, units, 'db ' + database_name, context, chart_type],
568
'lines': create_lines(database_name, chart_template['lines'])}
569
+
570
+def add_replication_delta_chart_(order, definitions, name, application_name):
571
+ def create_lines(standby, lines):
572
+ result = list()
573
+ for line in lines:
574
+ new_line = ['_'.join([standby, line[0]])] + line[1:]
575
+ result.append(new_line)
576
+ return result
577
+
578
+ chart_template = CHARTS[name]
579
+ chart_name = '_'.join([application_name, name])
580
+ position = order.index('database_size')
581
+ order.insert(position, chart_name)
582
+ name, title, units, family, context, chart_type = chart_template['options']
583
+ definitions[chart_name] = {
584
+ 'options': [name, title + ': ' + application_name, units, 'replication delta', context, chart_type],
585
+ 'lines': create_lines(application_name, chart_template['lines'])}
web/dashboard_info.js
+53
@@ -984,6 +984,59 @@ netdataDashboard.context = {
984
'</ul>'
985
},
986
987
+ // ------------------------------------------------------------------------
988
+ // POSTGRESQL
989
+
990
+
991
+ 'postgres.db_stat_blks': {
992
+ info: 'Blocks reads from disk or cache.<ul>' +
993
+ '<li><strong>blks_read:</strong> number of disk blocks read in this database.</li>' +
994
+ '<li><strong>blks_hit:</strong> number of times disk blocks were found already in the buffer cache, so that a read was not necessary (this only includes hits in the PostgreSQL buffer cache, not the operating system's file system cache)</li>' +
995
+ '</ul>'
996
+ },
997
+ 'postgres.db_stat_tuple_write': {
998
+ info: '<ul><li>Number of rows inserted/updated/deleted.</li>' +
999
+ '<li><strong>conflicts:</strong> number of queries canceled due to conflicts with recovery in this database. (Conflicts occur only on standby servers; see <a href="https://www.postgresql.org/docs/10/static/monitoring-stats.html#PG-STAT-DATABASE-CONFLICTS-VIEW" target="_blank">pg_stat_database_conflicts</a> for details.)</li>' +
1000
+ '</ul>'
1001
+ },
1002
+ 'postgres.db_stat_temp_bytes': {
1003
+ info: 'Temporary files can be created on disk for sorts, hashes, and temporary query results.'
1004
+ },
1005
+ 'postgres.db_stat_temp_files': {
1006
+ info: '<ul>' +
1007
+ '<li><strong>files:</strong> number of temporary files created by queries. All temporary files are counted, regardless of why the temporary file was created (e.g., sorting or hashing).</li>' +
1008
+ '</ul>'
1009
+ },
1010
+ 'postgres.archive_wal': {
1011
+ info: 'WAL archiving.<ul>' +
1012
+ '<li><strong>total:</strong> total files.</li>' +
1013
+ '<li><strong>ready:</strong> WAL waiting to be archived.</li>' +
1014
+ '<li><strong>done:</strong> WAL successfully archived' +
1015
+ 'Ready WAL can indicate archive_command is in error, see <a href="https://www.postgresql.org/docs/current/static/continuous-archiving.html" target="_blank">Continuous Archiving and Point-in-Time Recovery</a>.</li>' +
1016
+ '</ul>'
1017
+ },
1018
+ 'postgres.checkpointer': {
1019
+ info: 'Number of checkpoints.<ul>' +
1020
+ '<li><strong>scheduled:</strong> when checkpoint_timeout is reached.</li>' +
1021
+ '<li><strong>requested:</strong> when max_wal_size is reached.</li>' +
1022
+ '</ul>' +
1023
+ 'For more information see <a href="https://www.postgresql.org/docs/current/static/wal-configuration.html" target="_blank">WAL Configuration</a>.'
1024
+ },
1025
+ 'postgres.autovacuum': {
1026
+ info: 'PostgreSQL databases require periodic maintenance known as vacuuming. For many installations, it is sufficient to let vacuuming be performed by the autovacuum daemon.' +
1027
+ 'For more information see <a href="https://www.postgresql.org/docs/current/static/routine-vacuuming.html#AUTOVACUUM" target="_blank">The Autovacuum Daemon</a>.'
1028
+ },
1029
+ 'postgres.standby_delta': {
1030
+ info: 'Streaming replication delta.<ul>' +
1031
+ '<li><strong>sent_delta:</strong> replication delta sent to standby.</li>' +
1032
+ '<li><strong>write_delta:</strong> replication delta written to disk by this standby.</li>' +
1033
+ '<li><strong>flush_delta:</strong> replication delta flushed to disk by this standby server.</li>' +
1034
+ '<li><strong>replay_delta:</strong> replication delta replayed into the database on this standby server.</li>' +
1035
+ '</ul>' +
1036
+ 'For more information see <a href="https://www.postgresql.org/docs/current/static/warm-standby.html#SYNCHRONOUS-REPLICATION" target="_blank">Synchronous Replication</a>.'
1037
+ },
1038
+
1039
+
1040
// ------------------------------------------------------------------------
1041
// APACHE
1042