@cryptotaxi247 / netdata-1 / commits / ea1bda4d6

postgres_plugin: database size chart added, index and table stats disabled by default, code refactoring

Ilya committed Mar 2, 2017 at 20:37 UTC ea1bda4d613ef9dcb1c230327cccfcbfca6a1a43
1 file changed +249 -245
python.d/postgres.chart.py
+249 -245
@@ -2,13 +2,16 @@
2 # Description: example netdata python.d module
3 # Authors: facetoe, dangtranhoang
4
5 -import re
5 from copy import deepcopy
6
8 -import psycopg2
9 -from psycopg2 import extensions
10 -from psycopg2.extras import DictCursor
11 -from psycopg2 import OperationalError
7 +try:
8 + import psycopg2
9 + from psycopg2 import extensions
10 + from psycopg2.extras import DictCursor
11 + from psycopg2 import OperationalError
12 + PSYCOPG2 = True
13 +except ImportError:
14 + PSYCOPG2 = False
15
16 from base import SimpleService
17
@@ -17,39 +20,70 @@ update_every = 1
20 priority = 90000
21 retries = 60
22
20 -ARCHIVE = """
23 +METRICS = dict(
24 + DATABASE=['connections',
25 + 'xact_commit',
26 + 'xact_rollback',
27 + 'blks_read',
28 + 'blks_hit',
29 + 'tup_returned',
30 + 'tup_fetched',
31 + 'tup_inserted',
32 + 'tup_updated',
33 + 'tup_deleted',
34 + 'conflicts',
35 + 'size'],
36 + BACKENDS=['backends_active',
37 + 'backends_idle'],
38 + INDEX_STATS=['index_count',
39 + 'index_size'],
40 + TABLE_STATS=['table_size',
41 + 'table_count'],
42 + ARCHIVE=['ready_count',
43 + 'done_count',
44 + 'file_count'],
45 + BGWRITER=['writer_scheduled',
46 + 'writer_requested'],
47 + LOCKS=['ExclusiveLock',
48 + 'RowShareLock',
49 + 'SIReadLock',
50 + 'ShareUpdateExclusiveLock',
51 + 'AccessExclusiveLock',
52 + 'AccessShareLock',
53 + 'ShareRowExclusiveLock',
54 + 'ShareLock',
55 + 'RowExclusiveLock']
56 +)
57 +
58 +QUERIES = dict(
59 + ARCHIVE="""
60 SELECT
61 CAST(COUNT(*) AS INT) AS file_count,
62 CAST(COALESCE(SUM(CAST(archive_file ~ $r$\.ready$$r$ as INT)), 0) AS INT) AS ready_count,
63 CAST(COALESCE(SUM(CAST(archive_file ~ $r$\.done$$r$ AS INT)), 0) AS INT) AS done_count
64 FROM
65 pg_catalog.pg_ls_dir('pg_xlog/archive_status') AS archive_files (archive_file);
27 -"""
28 -
29 -BACKENDS = """
66 +""",
67 + BACKENDS="""
68 SELECT
69 count(*) - (SELECT count(*) FROM pg_stat_activity WHERE state = 'idle') AS backends_active,
70 (SELECT count(*) FROM pg_stat_activity WHERE state = 'idle' ) AS backends_idle
33 -FROM
34 - pg_stat_activity;
35 -"""
36 -
37 -TABLE_STATS = """
71 +FROM pg_stat_activity;
72 +""",
73 + TABLE_STATS="""
74 SELECT
39 - ((sum(relpages) * 8) * 1024) AS size_relations,
40 - count(1) AS relations
75 + ((sum(relpages) * 8) * 1024) AS table_size,
76 + count(1) AS table_count
77 FROM pg_class
78 WHERE relkind IN ('r', 't');
43 -"""
44 -
45 -INDEX_STATS = """
79 +""",
80 + INDEX_STATS="""
81 SELECT
47 - ((sum(relpages) * 8) * 1024) AS size_indexes,
48 - count(1) AS indexes
82 + ((sum(relpages) * 8) * 1024) AS index_size,
83 + count(1) AS index_count
84 FROM pg_class
50 -WHERE relkind = 'i';"""
51 -
52 -DATABASE = """
85 +WHERE relkind = 'i';""",
86 + DATABASE="""
87 SELECT
88 datname AS database_name,
89 sum(numbackends) AS connections,
@@ -62,93 +96,108 @@ SELECT
96 sum(tup_inserted) AS tup_inserted,
97 sum(tup_updated) AS tup_updated,
98 sum(tup_deleted) AS tup_deleted,
65 - sum(conflicts) AS conflicts
99 + sum(conflicts) AS conflicts,
100 + pg_database_size(datname) AS size
101 FROM pg_stat_database
102 WHERE NOT datname ~* '^template\d+'
103 GROUP BY database_name;
69 -"""
70 -
71 -BGWRITER = 'SELECT * FROM pg_stat_bgwriter;'
72 -DATABASE_LOCKS = """
104 +""",
105 + BGWRITER="""
106 +SELECT
107 + checkpoints_timed AS writer_scheduled,
108 + checkpoints_req AS writer_requested
109 +FROM pg_stat_bgwriter;""",
110 + LOCKS="""
111 SELECT
112 pg_database.datname as database_name,
113 mode,
76 - count(mode) AS count
114 + count(mode) AS locks_count
115 FROM pg_locks
116 INNER JOIN pg_database ON pg_database.oid = pg_locks.database
117 GROUP BY datname, mode
118 ORDER BY datname, mode;
81 -"""
82 -REPLICATION = """
83 -SELECT
84 - client_hostname,
85 - client_addr,
86 - state,
87 - sent_offset - (
88 - replay_offset - (sent_xlog - replay_xlog) * 255 * 16 ^ 6 ) AS byte_lag
89 -FROM (
90 - SELECT
91 - client_addr, client_hostname, state,
92 - ('x' || lpad(split_part(sent_location::text, '/', 1), 8, '0'))::bit(32)::bigint AS sent_xlog,
93 - ('x' || lpad(split_part(replay_location::text, '/', 1), 8, '0'))::bit(32)::bigint AS replay_xlog,
94 - ('x' || lpad(split_part(sent_location::text, '/', 2), 8, '0'))::bit(32)::bigint AS sent_offset,
95 - ('x' || lpad(split_part(replay_location::text, '/', 2), 8, '0'))::bit(32)::bigint AS replay_offset
96 - FROM pg_stat_replication
97 -) AS s;
98 -"""
99 -
100 -LOCK_TYPES = [
101 - 'ExclusiveLock',
102 - 'RowShareLock',
103 - 'SIReadLock',
104 - 'ShareUpdateExclusiveLock',
105 - 'AccessExclusiveLock',
106 - 'AccessShareLock',
107 - 'ShareRowExclusiveLock',
108 - 'ShareLock',
109 - 'RowExclusiveLock'
110 -]
111 -
112 -ORDER = ['db_stat_transactions', 'db_stat_tuple_read', 'db_stat_tuple_returned', 'db_stat_tuple_write',
119 +""",
120 + FIND_DATABASES="""
121 +SELECT datname FROM pg_stat_database WHERE NOT datname ~* '^template\d+'
122 +""",
123 + IF_SUPERUSER="""
124 +SELECT current_setting('is_superuser') = 'on' AS is_superuser;
125 + """)
126 +
127 +# REPLICATION = """
128 +# SELECT
129 +# client_hostname,
130 +# client_addr,
131 +# state,
132 +# sent_offset - (
133 +# replay_offset - (sent_xlog - replay_xlog) * 255 * 16 ^ 6 ) AS byte_lag
134 +# FROM (
135 +# SELECT
136 +# client_addr, client_hostname, state,
137 +# ('x' || lpad(split_part(sent_location::text, '/', 1), 8, '0'))::bit(32)::bigint AS sent_xlog,
138 +# ('x' || lpad(split_part(replay_location::text, '/', 1), 8, '0'))::bit(32)::bigint AS replay_xlog,
139 +# ('x' || lpad(split_part(sent_location::text, '/', 2), 8, '0'))::bit(32)::bigint AS sent_offset,
140 +# ('x' || lpad(split_part(replay_location::text, '/', 2), 8, '0'))::bit(32)::bigint AS replay_offset
141 +# FROM pg_stat_replication
142 +# ) AS s;
143 +# """
144 +
145 +
146 +QUERY_STATS = {
147 + QUERIES['DATABASE']: METRICS['DATABASE'],
148 + QUERIES['BACKENDS']: METRICS['BACKENDS'],
149 + QUERIES['ARCHIVE']: METRICS['ARCHIVE'],
150 + QUERIES['LOCKS']: METRICS['LOCKS']
151 +}
152 +
153 +ORDER = ['db_stat_transactions', 'db_stat_tuple_read', 'db_stat_tuple_returned', 'db_stat_tuple_write', 'database_size',
154 'backend_process', 'index_count', 'index_size', 'table_count', 'table_size', 'wal', 'background_writer']
155
156 CHARTS = {
157 'db_stat_transactions': {
117 - 'options': [None, 'Transactions on db', 'transactions/s', 'db statistics', 'postgres.db_stat_transactions', 'line'],
158 + 'options': [None, 'Transactions on db', 'transactions/s', 'db statistics', 'postgres.db_stat_transactions',
159 + 'line'],
160 'lines': [
119 - ['db_stat_xact_commit', 'committed', 'incremental'],
120 - ['db_stat_xact_rollback', 'rolled back', 'incremental']
161 + ['xact_commit', 'committed', 'incremental'],
162 + ['xact_rollback', 'rolled back', 'incremental']
163 ]},
164 'db_stat_connections': {
123 - 'options': [None, 'Current connections to db', 'count', 'db statistics', 'postgres.db_stat_connections', 'line'],
165 + 'options': [None, 'Current connections to db', 'count', 'db statistics', 'postgres.db_stat_connections',
166 + 'line'],
167 'lines': [
125 - ['db_stat_connections', 'connections', 'absolute']
168 + ['connections', 'connections', 'absolute']
169 ]},
170 'db_stat_tuple_read': {
171 'options': [None, 'Tuple reads from db', 'reads/s', 'db statistics', 'postgres.db_stat_tuple_read', 'line'],
172 'lines': [
130 - ['db_stat_blks_read', 'disk', 'incremental'],
131 - ['db_stat_blks_hit', 'cache', 'incremental']
173 + ['blks_read', 'disk', 'incremental'],
174 + ['blks_hit', 'cache', 'incremental']
175 ]},
176 'db_stat_tuple_returned': {
134 - 'options': [None, 'Tuples returned from db', 'tuples/s', 'db statistics', 'postgres.db_stat_tuple_returned', 'line'],
177 + 'options': [None, 'Tuples returned from db', 'tuples/s', 'db statistics', 'postgres.db_stat_tuple_returned',
178 + 'line'],
179 'lines': [
136 - ['db_stat_tup_returned', 'sequential', 'incremental'],
137 - ['db_stat_tup_fetched', 'bitmap', 'incremental']
180 + ['tup_returned', 'sequential', 'incremental'],
181 + ['tup_fetched', 'bitmap', 'incremental']
182 ]},
183 'db_stat_tuple_write': {
184 'options': [None, 'Tuples written to db', 'writes/s', 'db statistics', 'postgres.db_stat_tuple_write', 'line'],
185 'lines': [
142 - ['db_stat_tup_inserted', 'inserted', 'incremental'],
143 - ['db_stat_tup_updated', 'updated', 'incremental'],
144 - ['db_stat_tup_deleted', 'deleted', 'incremental'],
145 - ['db_stat_conflicts', 'conflicts', 'incremental']
186 + ['tup_inserted', 'inserted', 'incremental'],
187 + ['tup_updated', 'updated', 'incremental'],
188 + ['tup_deleted', 'deleted', 'incremental'],
189 + ['conflicts', 'conflicts', 'incremental']
190 + ]},
191 + 'database_size': {
192 + 'options': [None, 'Database size', 'MB', 'database size', 'postgres.db_size', 'stacked'],
193 + 'lines': [
194 ]},
195 'backend_process': {
148 - 'options': [None, 'Current Backend Processes', 'processes', 'backend processes', 'postgres.backend_process', 'line'],
196 + 'options': [None, 'Current Backend Processes', 'processes', 'backend processes', 'postgres.backend_process',
197 + 'line'],
198 'lines': [
150 - ['backend_process_active', 'active', 'absolute'],
151 - ['backend_process_idle', 'idle', 'absolute']
199 + ['backends_active', 'active', 'absolute'],
200 + ['backends_idle', 'idle', 'absolute']
201 ]},
202 'index_count': {
203 'options': [None, 'Total indexes', 'index', 'indexes', 'postgres.index_count', 'line'],
@@ -173,15 +222,15 @@ CHARTS = {
222 'wal': {
223 'options': [None, 'Write-Ahead Logging Statistics', 'files/s', 'write ahead log', 'postgres.wal', 'line'],
224 'lines': [
176 - ['wal_total', 'total', 'incremental'],
177 - ['wal_ready', 'ready', 'incremental'],
178 - ['wal_done', 'done', 'incremental']
225 + ['file_count', 'total', 'incremental'],
226 + ['ready_count', 'ready', 'incremental'],
227 + ['done_count', 'done', 'incremental']
228 ]},
229 'background_writer': {
230 'options': [None, 'Checkpoints', 'writes/s', 'background writer', 'postgres.background_writer', 'line'],
231 'lines': [
183 - ['background_writer_scheduled', 'scheduled', 'incremental'],
184 - ['background_writer_requested', 'requested', 'incremental']
232 + ['writer_scheduled', 'scheduled', 'incremental'],
233 + ['writer_requested', 'requested', 'incremental']
234 ]}
235 }
236
@@ -189,15 +238,16 @@ CHARTS = {
238 class Service(SimpleService):
239 def __init__(self, configuration=None, name=None):
240 super(self.__class__, self).__init__(configuration=configuration, name=name)
192 - self.order = ORDER
193 - self.definitions = CHARTS
194 - self.table_stats = configuration.pop('table_stats', True)
195 - self.index_stats = configuration.pop('index_stats', True)
241 + self.order = ORDER[:]
242 + self.definitions = deepcopy(CHARTS)
243 + self.table_stats = configuration.pop('table_stats', False)
244 + self.index_stats = configuration.pop('index_stats', False)
245 self.configuration = configuration
246 self.connection = False
247 self.is_superuser = False
199 - self.data = {}
200 - self.databases = set()
248 + self.data = dict()
249 + self.locks_zeroed = dict()
250 + self.databases = list()
251
252 def _connect(self):
253 params = dict(user='postgres',
@@ -217,91 +267,53 @@ class Service(SimpleService):
267 return True
268
269 def check(self):
270 + if not PSYCOPG2:
271 + self.error('\'python-psycopg2\' module is needed to use postgres.chart.py')
272 + return False
273 + if not self._connect():
274 + self.error('Can\'t connect to %s' % str(self.configuration))
275 + return False
276 try:
221 - if not self._connect():
222 - self.error('Can\'t connect to %s' % str(self.configuration))
223 - return False
277 cursor = self.connection.cursor()
225 - self._discover_databases(cursor)
226 - self._check_if_superuser(cursor)
278 + self.databases = discover_databases_(cursor, QUERIES['FIND_DATABASES'])
279 + is_superuser = check_if_superuser_(cursor, QUERIES['IF_SUPERUSER'])
280 cursor.close()
281
229 - self._create_definitions()
282 + self.locks_zeroed = populate_lock_types(self.databases)
283 + self.add_additional_queries_(is_superuser)
284 + self.create_dynamic_charts_()
285 return True
231 - except Exception as e:
232 - self.error(str(e))
286 + except Exception as error:
287 + self.error(str(error))
288 return False
289
235 - def _discover_databases(self, cursor):
236 - cursor.execute("""
237 - SELECT datname
238 - FROM pg_stat_database
239 - WHERE NOT datname ~* '^template\d+'
240 - """)
241 - self.databases = set(r[0] for r in cursor)
242 -
243 - def _check_if_superuser(self, cursor):
244 - cursor.execute("""
245 - SELECT current_setting('is_superuser') = 'on' AS is_superuser;
246 - """)
247 - self.is_superuser = cursor.fetchone()[0]
248 -
249 - def _create_definitions(self):
250 - for database_name in self.databases:
251 - for chart_template_name in list(CHARTS):
252 - if chart_template_name.startswith('db_stat'):
253 - self._add_database_stat_chart(chart_template_name, database_name)
254 - self._add_database_lock_chart(database_name)
255 -
256 - def _add_database_stat_chart(self, chart_template_name, database_name):
257 - chart_template = CHARTS[chart_template_name]
258 - chart_name = "{0}_{1}".format(database_name, chart_template_name)
259 - if chart_name not in self.order:
260 - self.order.insert(0, chart_name)
261 - name, title, units, family, context, chart_type = chart_template['options']
262 - self.definitions[chart_name] = {
263 - 'options': [
264 - name,
265 - title + ': ' + database_name,
266 - units,
267 - 'db ' + database_name,
268 - context,
269 - chart_type
270 - ]
271 - }
290 + def add_additional_queries_(self, is_superuser):
291 + if self.index_stats:
292 + QUERY_STATS[QUERIES['INDEX_STATS']] = METRICS['INDEX_STATS']
293 + if self.table_stats:
294 + QUERY_STATS[QUERIES['TABLE_STATS']] = METRICS['TABLE_STATS']
295 + if is_superuser:
296 + QUERY_STATS[QUERIES['BGWRITER']] = METRICS['BGWRITER']
297
273 - self.definitions[chart_name]['lines'] = []
274 - for line in deepcopy(chart_template['lines']):
275 - line[0] = "{0}_{1}".format(database_name, line[0])
276 - self.definitions[chart_name]['lines'].append(line)
277 -
278 - def _add_database_lock_chart(self, database_name):
279 - chart_name = "{0}_locks".format(database_name)
280 - if chart_name not in self.order:
281 - self.order.insert(-1, chart_name)
282 - self.definitions[chart_name] = dict(
283 - options=
284 - [
285 - None,
286 - 'Locks on db: ' + database_name,
287 - 'locks',
288 - 'db ' + database_name,
289 - 'postgres.db_locks',
290 - 'line'
291 - ],
292 - lines=[]
293 - )
294 -
295 - for lock_type in LOCK_TYPES:
296 - lock_id = "{0}_{1}".format(database_name, lock_type)
297 - label = re.sub("([a-z])([A-Z])", "\g<1> \g<2>", lock_type)
298 - self.definitions[chart_name]['lines'].append([lock_id, label, 'absolute'])
298 + def create_dynamic_charts_(self):
299 +
300 + for database_name in self.databases[::-1]:
301 + self.definitions['database_size']['lines'].append([database_name + '_size',
302 + database_name, 'absolute', 1, 1024 * 1024])
303 + for chart_name in [name for name in CHARTS if name.startswith('db_stat')]:
304 + add_database_stat_chart_(order=self.order, definitions=self.definitions,
305 + name=chart_name, database_name=database_name)
306 +
307 + add_database_lock_chart_(order=self.order, definitions=self.definitions, database_name=database_name)
308
309 def _get_data(self):
310 if self._connect():
311 cursor = self.connection.cursor(cursor_factory=DictCursor)
312 try:
304 - self.add_stats(cursor)
313 + self.data.update(self.locks_zeroed)
314 + for query, metrics in QUERY_STATS.items():
315 + self.query_stats_(cursor, query, metrics)
316 +
317 except OperationalError:
318 self.connection = False
319 cursor.close()
@@ -312,88 +324,80 @@ class Service(SimpleService):
324 else:
325 return None
326
315 - def add_stats(self, cursor):
316 - self.add_database_stats(cursor)
317 - self.add_backend_stats(cursor)
318 - if self.index_stats:
319 - self.add_index_stats(cursor)
320 - if self.table_stats:
321 - self.add_table_stats(cursor)
322 - self.add_lock_stats(cursor)
323 - self.add_bgwriter_stats(cursor)
324 -
325 - # self.add_replication_stats(cursor)
327 + def query_stats_(self, cursor, query, metrics):
328 + cursor.execute(query)
329 + for row in cursor:
330 + for metric in metrics:
331 + dimension_id = '_'.join([row['database_name'], metric]) if 'database_name' in row else metric
332 + if metric in row:
333 + self.data[dimension_id] = int(row[metric])
334 + elif 'locks_count' in row:
335 + self.data[dimension_id] = row['locks_count'] if metric == row['mode'] else 0
336 +
337 +
338 +def discover_databases_(cursor, query):
339 + cursor.execute(query)
340 + result = list()
341 + for db in [database[0] for database in cursor]:
342 + if db not in result:
343 + result.append(db)
344 + return result
345 +
346 +
347 +def check_if_superuser_(cursor, query):
348 + cursor.execute(query)
349 + return cursor.fetchone()[0]
350 +
351 +
352 +def populate_lock_types(databases):
353 + result = dict()
354 + for database in databases:
355 + for lock_type in METRICS['LOCKS']:
356 + key = '_'.join([database, lock_type])
357 + result[key] = 0
358 +
359 + return result
360 +
361 +
362 +def add_database_lock_chart_(order, definitions, database_name):
363 + def create_lines(database):
364 + result = list()
365 + for lock_type in METRICS['LOCKS']:
366 + dimension_id = '_'.join([database, lock_type])
367 + result.append([dimension_id, lock_type, 'absolute'])
368 + return result
369 +
370 + chart_name = database_name + '_locks'
371 + order.insert(-1, chart_name)
372 + definitions[chart_name] = {
373 + 'options':
374 + [None, 'Locks on db: ' + database_name, 'locks', 'db ' + database_name, 'postgres.db_locks', 'line'],
375 + 'lines': create_lines(database_name)
376 + }
377
327 - if self.is_superuser:
328 - self.add_wal_stats(cursor)
378
330 - def add_database_stats(self, cursor):
331 - cursor.execute(DATABASE)
332 - for row in cursor:
333 - database_name = row.get('database_name')
334 - self.data["{0}_{1}".format(database_name, 'db_stat_xact_commit')] = int(row.get('xact_commit', 0))
335 - self.data["{0}_{1}".format(database_name, 'db_stat_xact_rollback')] = int(row.get('xact_rollback', 0))
336 - self.data["{0}_{1}".format(database_name, 'db_stat_blks_read')] = int(row.get('blks_read', 0))
337 - self.data["{0}_{1}".format(database_name, 'db_stat_blks_hit')] = int(row.get('blks_hit', 0))
338 - self.data["{0}_{1}".format(database_name, 'db_stat_tup_returned')] = int(row.get('tup_returned', 0))
339 - self.data["{0}_{1}".format(database_name, 'db_stat_tup_fetched')] = int(row.get('tup_fetched', 0))
340 - self.data["{0}_{1}".format(database_name, 'db_stat_tup_inserted')] = int(row.get('tup_inserted', 0))
341 - self.data["{0}_{1}".format(database_name, 'db_stat_tup_updated')] = int(row.get('tup_updated', 0))
342 - self.data["{0}_{1}".format(database_name, 'db_stat_tup_deleted')] = int(row.get('tup_deleted', 0))
343 - self.data["{0}_{1}".format(database_name, 'db_stat_conflicts')] = int(row.get('conflicts', 0))
344 - self.data["{0}_{1}".format(database_name, 'db_stat_connections')] = int(row.get('connections', 0))
345 -
346 - def add_backend_stats(self, cursor):
347 - cursor.execute(BACKENDS)
348 - temp = cursor.fetchone()
349 -
350 - self.data['backend_process_active'] = int(temp.get('backends_active', 0))
351 - self.data['backend_process_idle'] = int(temp.get('backends_idle', 0))
352 -
353 - def add_index_stats(self, cursor):
354 - cursor.execute(INDEX_STATS)
355 - temp = cursor.fetchone()
356 - self.data['index_count'] = int(temp.get('indexes', 0))
357 - self.data['index_size'] = int(temp.get('size_indexes', 0))
358 -
359 - def add_table_stats(self, cursor):
360 - cursor.execute(TABLE_STATS)
361 - temp = cursor.fetchone()
362 - self.data['table_count'] = int(temp.get('relations', 0))
363 - self.data['table_size'] = int(temp.get('size_relations', 0))
364 -
365 - def add_lock_stats(self, cursor):
366 - cursor.execute(DATABASE_LOCKS)
367 -
368 - # zero out all current lock values
369 - for database_name in self.databases:
370 - for lock_type in LOCK_TYPES:
371 - self.data["{0}_{1}".format(database_name, lock_type)] = 0
372 -
373 - # populate those that have current locks
374 - for row in cursor:
375 - database_name, lock_type, lock_count = row
376 - self.data["{0}_{1}".format(database_name, lock_type)] = lock_count
377 -
378 - def add_wal_stats(self, cursor):
379 - cursor.execute(ARCHIVE)
380 - temp = cursor.fetchone()
381 - self.data['wal_total'] = int(temp.get('file_count', 0))
382 - self.data['wal_ready'] = int(temp.get('ready_count', 0))
383 - self.data['wal_done'] = int(temp.get('done_count', 0))
384 -
385 - def add_bgwriter_stats(self, cursor):
386 - cursor.execute(BGWRITER)
387 - temp = cursor.fetchone()
388 - self.data['background_writer_scheduled'] = temp.get('checkpoints_timed', 0)
389 - self.data['background_writer_requested'] = temp.get('checkpoints_requests', 0)
390 -
391 -'''
392 - def add_replication_stats(self, cursor):
393 - cursor.execute(REPLICATION)
394 - temp = cursor.fetchall()
395 - for row in temp:
396 - self.add_gauge_value('Replication/%s' % row.get('client_addr', 'Unknown'),
397 - 'byte_lag',
398 - int(row.get('byte_lag', 0)))
399 -'''
379 +def add_database_stat_chart_(order, definitions, name, database_name):
380 + def create_lines(database, lines):
381 + result = list()
382 + for line in lines:
383 + new_line = ['_'.join([database, line[0]])] + line[1:]
384 + result.append(new_line)
385 + return result
386 +
387 + chart_template = CHARTS[name]
388 + chart_name = '_'.join([database_name, name])
389 + order.insert(0, chart_name)
390 + name, title, units, family, context, chart_type = chart_template['options']
391 + definitions[chart_name] = {
392 + 'options': [name, title + ': ' + database_name, units, 'db ' + database_name, context, chart_type],
393 + 'lines': create_lines(database_name, chart_template['lines'])}
394 +
395 +
396 +#
397 +# def add_replication_stats(self, cursor):
398 +# cursor.execute(REPLICATION)
399 +# temp = cursor.fetchall()
400 +# for row in temp:
401 +# self.add_gauge_value('Replication/%s' % row.get('client_addr', 'Unknown'),
402 +# 'byte_lag',
403 +# int(row.get('byte_lag', 0)))