Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 96504be

Browse files
author
Dementii Priadko
committed
Merge branch 'fix-index-table' into 'main'
Fix index table See merge request postgres-ai/postgres_ai!33
2 parents 0c3fcf1 + c970f31 commit 96504be

File tree

2 files changed

+75
-38
lines changed

2 files changed

+75
-38
lines changed

‎config/grafana/dashboards/Dashboard_8_Index health.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@
165165
}
166166
}
167167
],
168-
"title": "New panel",
168+
"title": "",
169169
"transformations": [
170170
{
171171
"id": "calculateField",

‎flask-backend/app.py‎

Lines changed: 74 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -337,17 +337,45 @@ def list_metrics():
337337
except Exception as e:
338338
return jsonify({"error": str(e)}), 500
339339

340+
@app.route('/debug/metrics', methods=['GET'])
341+
def debug_metrics():
342+
"""
343+
Debug endpoint to check what metrics are actually available in Prometheus
344+
"""
345+
try:
346+
prom = get_prometheus_client()
347+
348+
# Get all available metrics
349+
all_metrics = prom.all_metrics()
350+
351+
# Filter for pg_btree_bloat metrics
352+
btree_metrics = [m for m in all_metrics if 'btree_bloat' in m]
353+
354+
# Get sample data for each btree metric
355+
sample_data = {}
356+
for metric in btree_metrics[:5]: # Limit to first 5 to avoid overwhelming
357+
try:
358+
result = prom.get_current_metric_value(metric_name=metric)
359+
sample_data[metric] = {
360+
'count': len(result),
361+
'sample_labels': [entry.get('metric', {}) for entry in result[:2]] # First 2 entries
362+
}
363+
except Exception as e:
364+
sample_data[metric] = {'error': str(e)}
365+
366+
return jsonify({
367+
'all_metrics_count': len(all_metrics),
368+
'btree_metrics': btree_metrics,
369+
'sample_data': sample_data
370+
})
371+
except Exception as e:
372+
return jsonify({"error": str(e)}), 500
373+
374+
340375
@app.route('/btree_bloat/csv', methods=['GET'])
341376
def get_btree_bloat_csv():
342377
"""
343-
Get current pg_btree_bloat metrics as a CSV table.
344-
345-
Query parameters:
346-
- cluster_name: Cluster name filter (optional)
347-
- node_name: Node name filter (optional)
348-
- schemaname: Schema name filter (optional)
349-
- tblname: Table name filter (optional)
350-
- idxname: Index name filter (optional)
378+
Get the most recent pg_btree_bloat metrics as a CSV table.
351379
"""
352380
try:
353381
# Get query parameters
@@ -372,24 +400,28 @@ def get_btree_bloat_csv():
372400
filters.append(f'idxname="{idxname}"')
373401
if db_name:
374402
filters.append(f'datname="{db_name}"')
403+
375404
filter_str = '{' + ','.join(filters) + '}' if filters else ''
376405

377-
# Metrics to fetch
378-
metric_names = [
379-
'pgwatch_pg_btree_bloat_real_size_mib',
380-
'pgwatch_pg_btree_bloat_extra_size',
381-
'pgwatch_pg_btree_bloat_extra_pct',
382-
'pgwatch_pg_btree_bloat_fillfactor',
383-
'pgwatch_pg_btree_bloat_bloat_size',
384-
'pgwatch_pg_btree_bloat_bloat_pct',
385-
'pgwatch_pg_btree_bloat_is_na',
406+
# Metrics to fetch with last_over_time to get only the most recent value
407+
metric_queries = [
408+
f'last_over_time(pgwatch_pg_btree_bloat_real_size_mib{filter_str}[1d])',
409+
f'last_over_time(pgwatch_pg_btree_bloat_extra_size{filter_str}[1d])',
410+
f'last_over_time(pgwatch_pg_btree_bloat_extra_pct{filter_str}[1d])',
411+
f'last_over_time(pgwatch_pg_btree_bloat_fillfactor{filter_str}[1d])',
412+
f'last_over_time(pgwatch_pg_btree_bloat_bloat_size{filter_str}[1d])',
413+
f'last_over_time(pgwatch_pg_btree_bloat_bloat_pct{filter_str}[1d])',
414+
f'last_over_time(pgwatch_pg_btree_bloat_is_na{filter_str}[1d])',
386415
]
416+
387417
prom = get_prometheus_client()
388-
# Fetch all metrics
389418
metric_results = {}
390-
for metric in metric_names:
419+
420+
for query in metric_queries:
391421
try:
392-
result = prom.get_current_metric_value(metric_name=metric + filter_str)
422+
# Use custom_query instead of get_current_metric_value
423+
result = prom.custom_query(query=query)
424+
393425
for entry in result:
394426
metric_labels = entry.get('metric', {})
395427
key = (
@@ -398,30 +430,33 @@ def get_btree_bloat_csv():
398430
metric_labels.get('tblname', ''),
399431
metric_labels.get('idxname', '')
400432
)
433+
401434
if key not in metric_results:
402435
metric_results[key] = {
403436
'database': metric_labels.get('datname', ''),
404437
'schemaname': metric_labels.get('schemaname', ''),
405438
'tblname': metric_labels.get('tblname', ''),
406439
'idxname': metric_labels.get('idxname', ''),
407440
}
408-
logger.warning(f"metric: {metric}")
409-
if metric.endswith('real_size_mib'):
410-
metric_results[key]['real_size_mib'] = float(entry['value'][1]) if entry.get('value') else None
411-
elif metric.endswith('extra_size'):
412-
metric_results[key]['extra_size'] = float(entry['value'][1]) if entry.get('value') else None
413-
elif metric.endswith('extra_pct'):
414-
metric_results[key]['extra_pct'] = float(entry['value'][1]) if entry.get('value') else None
415-
elif metric.endswith('fillfactor'):
416-
metric_results[key]['fillfactor'] = float(entry['value'][1]) if entry.get('value') else None
417-
elif metric.endswith('bloat_size'):
418-
metric_results[key]['bloat_size'] = float(entry['value'][1]) if entry.get('value') else None
419-
elif metric.endswith('bloat_pct'):
420-
metric_results[key]['bloat_pct'] = float(entry['value'][1]) if entry.get('value') else None
421-
elif metric.endswith('is_na'):
422-
metric_results[key]['is_na'] = int(float(entry['value'][1])) if entry.get('value') else None
441+
442+
# Extract metric type from query and store value
443+
if 'real_size_mib' in query:
444+
metric_results[key]['real_size_mib'] = float(entry['value'][1])
445+
elif 'extra_size' in query and 'extra_pct' not in query:
446+
metric_results[key]['extra_size'] = float(entry['value'][1])
447+
elif 'extra_pct' in query:
448+
metric_results[key]['extra_pct'] = float(entry['value'][1])
449+
elif 'fillfactor' in query:
450+
metric_results[key]['fillfactor'] = float(entry['value'][1])
451+
elif 'bloat_size' in query:
452+
metric_results[key]['bloat_size'] = float(entry['value'][1])
453+
elif 'bloat_pct' in query:
454+
metric_results[key]['bloat_pct'] = float(entry['value'][1])
455+
elif 'is_na' in query:
456+
metric_results[key]['is_na'] = int(float(entry['value'][1]))
457+
423458
except Exception as e:
424-
logger.warning(f"Failed to query metric {metric}: {e}")
459+
logger.warning(f"Failed to query: {query}, error: {e}")
425460
continue
426461

427462
# Prepare CSV output
@@ -435,14 +470,16 @@ def get_btree_bloat_csv():
435470
writer.writeheader()
436471
for row in metric_results.values():
437472
writer.writerow(row)
473+
438474
csv_content = output.getvalue()
439475
output.close()
440476

441477
# Create response
442478
response = make_response(csv_content)
443479
response.headers['Content-Type'] = 'text/csv'
444-
response.headers['Content-Disposition'] = 'attachment; filename=btree_bloat_metrics.csv'
480+
response.headers['Content-Disposition'] = 'attachment; filename=btree_bloat_latest.csv'
445481
return response
482+
446483
except Exception as e:
447484
logger.error(f"Error processing btree bloat request: {e}")
448485
return jsonify({"error": str(e)}), 500

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /