nas-metrics-prometheus/app.py

62 lines
1.8 KiB
Python

from flask import Flask
from prometheus_client import Gauge, generate_latest, CONTENT_TYPE_LATEST
import subprocess
import time
import os
import threading
app = Flask(__name__)
pv_usage_bytes = Gauge('nfs_pv_usage_bytes', 'PV usage in bytes', ['pv_name'])
pv_last_check = Gauge('nfs_pv_last_check_timestamp', 'Last check timestamp', ['pv_name'])
cache = {}
CACHE_TTL = 300
du_lock = threading.Lock() # 동시 du 방지
def get_pv_usage(pv_name):
now = time.time()
# 캐시 확인 (락 없이)
if pv_name in cache and now - cache[pv_name]['time'] < CACHE_TTL:
return cache[pv_name]['bytes']
# du는 한 번에 하나만
with du_lock:
# 락 획득 후 다시 캐시 확인
if pv_name in cache and time.time() - cache[pv_name]['time'] < CACHE_TTL:
return cache[pv_name]['bytes']
path = f"/mnt/pvs/{pv_name}"
if not os.path.exists(path):
return None
result = subprocess.run(
['ionice', '-c', '3', 'nice', '-n', '19', 'du', '-sb', path],
capture_output=True, text=True, timeout=300
)
if result.returncode != 0:
return None
usage = int(result.stdout.split()[0])
cache[pv_name] = {'bytes': usage, 'time': time.time()}
pv_usage_bytes.labels(pv_name=pv_name).set(usage)
pv_last_check.labels(pv_name=pv_name).set(time.time())
return usage
@app.route('/usage/<pv_name>')
def usage(pv_name):
result = get_pv_usage(pv_name)
if result is None:
return {'error': 'PV not found or timeout'}, 404
return {'pv_name': pv_name, 'bytes': result}
@app.route('/metrics')
def metrics():
return generate_latest(), 200, {'Content-Type': CONTENT_TYPE_LATEST}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, threaded=True)