@cryptotaxi247 / netdata-1 / commits / e57a2f139

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&#39;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