\x89PNG\r\n\x1a\n\x00\x00\x00\x0DIHDR\x00\x00\x00\x01\x00 \x00\x00\x01\x08\x06\x00\x00\x00\x1F\x15\xC4\x89\x00\x00\x00 \x0AIDATx\x9Ccb\x00\x00\x00\x06\x00\x03\x1A\x05\x9D\x00\x00 \x00\x00IEND\xAE\x42\x60\x82 csarite.com
KUJUNTI.ID MINISH3LL
Path : /var/www/html/yedekledb24/DatabaseBackupMasterv8/DatabaseBackupMaster/
(S)h3ll Cr3at0r :
F!le Upl0ad :

B-Con CMD Config cPanel C-Rdp D-Log Info Jump Mass Ransom Symlink vHost Zone-H

Current File : /var/www/html/yedekledb24/DatabaseBackupMasterv8/DatabaseBackupMaster/database_performance_fixed.py


"""
PostgreSQL veritabanı performans metrikleri için yardımcı fonksiyonlar.
Bu modül, pg_stat_statements kullanarak sunucularda çalışan sorguların performans verilerini alır.
"""

import psycopg2
import logging

# Logging ayarla
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def pg_stat_statements_enabled(connection):
    """
    PostgreSQL sunucusunda pg_stat_statements'ın etkin olup olmadığını kontrol eder.
    
    Args:
        connection: PostgreSQL bağlantı nesnesi
        
    Returns:
        bool: Modül yüklüyse True, değilse False
    """
    try:
        cursor = connection.cursor()
        
        # Modülün etkin olup olmadığını kontrol et
        cursor.execute("""
        SELECT count(*) FROM pg_extension WHERE extname = 'pg_stat_statements'
        """)
        result = cursor.fetchone()
        
        # Ayrıca, sorgu çalıştırmayı da dene (izinler kontrol etmek için)
        try:
            cursor.execute("SELECT query FROM pg_stat_statements LIMIT 1")
            cursor.fetchone()
            access_granted = True
        except Exception:
            access_granted = False
            
        cursor.close()
        
        # Hem modül yüklenmiş hem de erişim varsa True
        return result[0] > 0 and access_granted
    except Exception as e:
        logger.error("pg_stat_statements kontrolünde hata: {}".format(str(e)))
        return False

def enable_pg_stat_statements(connection):
    """
    PostgreSQL sunucusunda pg_stat_statements'ı etkinleştirir.
    
    Args:
        connection: PostgreSQL bağlantı nesnesi
        
    Returns:
        dict: İşlem sonucu (success, message)
    """
    try:
        cursor = connection.cursor()
        
        # Önce kontrol et
        cursor.execute("""
        SELECT count(*) FROM pg_extension WHERE extname = 'pg_stat_statements'
        """)
        result = cursor.fetchone()
        
        if result[0] > 0:
            # Extension zaten var, güncellemeyi dene
            cursor.execute("ALTER EXTENSION pg_stat_statements UPDATE")
            connection.commit()
            
            # Rolü güncelle
            # db_user = connection.info.user
            # cursor.execute("GRANT pg_read_all_stats TO {}".format(db_user))
            
            cursor.close()
            return {
                "success": True,
                "message": "pg_stat_statements modülü başarıyla güncellendi."
            }
        else:
            # Extension'ı kur
            cursor.execute("CREATE EXTENSION pg_stat_statements")
            connection.commit()
            
            cursor.close()
            return {
                "success": True,
                "message": "pg_stat_statements modülü başarıyla kuruldu. Değişikliklerin etkili olması için veritabanı sunucusunu yeniden başlatmanız gerekebilir."
            }
            
    except Exception as e:
        logger.error("pg_stat_statements etkinleştirme hatası: {}".format(str(e)))
        return {
            "success": False,
            "message": "pg_stat_statements modülü etkinleştirilemedi: {}".format(str(e))
        }

def get_top_queries(db_conn, limit=20, order_by='total_time', interval=None):
    """
    PostgreSQL sunucusunda en çok kaynak tüketen sorguları alır.
    
    Args:
        db_conn: PostgreSQL bağlantı bilgileri (dict)
        limit (int): Alınacak sorgu sayısı
        order_by (str): Sıralama kriteri ('total_time', 'calls', 'rows')
        interval (str): Zaman aralığı ('hour', 'day', 'week', 'all')
        
    Returns:
        dict: Sorgu istatistikleri ile birlikte başarı durumu
    """
    # Verileri saklayacak boş liste
    data = []
    pg_version = "N/A"
    
    # Varsayılan özet veri yapısı
    summary_data = {
        "total_calls": 0,
        "total_rows": 0,
        "total_exec_time": "0.00 ms",
        "query_count": 0,
        "pg_version": "N/A"
    }
    
    # Bağlantı bilgilerini hazırla
    conn_str = "host={} port={} user={} password={} dbname={}".format(
        db_conn['host'], db_conn['port'], db_conn['username'], db_conn['password'], db_conn['database']
    )
    
    # Reset isteği varsa istatistikleri sıfırla
    if interval and interval == 'reset':
        try:
            connection = psycopg2.connect(conn_str)
            connection.autocommit = True
            
            cursor = connection.cursor()
            cursor.execute("SELECT pg_stat_statements_reset()")
            
            cursor.close()
            connection.close()
            
            return {"success": True, "message": "Sorgu istatistikleri sıfırlandı.", "data": []}
        except Exception as e:
            error_msg = "İstatistikleri sıfırlarken hata: {}".format(str(e))
            logger.error(error_msg)
            return {"success": False, "message": error_msg, "data": []}
    
    try:
        # 1. Bağlantı kur
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        cursor = connection.cursor()
        
        # 2. PostgreSQL sürümünü al
        cursor.execute("SHOW server_version")
        pg_version_result = cursor.fetchone()
        pg_version = pg_version_result[0] if pg_version_result else "N/A"
        
        # 3. Sıralama kriterini belirle (PostgreSQL 13+ için uygun değeri kullan)
        time_column = "total_exec_time"
        order_column = time_column + " DESC"
        
        if order_by == 'calls':
            order_column = "calls DESC"
        elif order_by == 'rows':
            order_column = "rows DESC"
        
        # 4. Ana sorguyu çalıştır
        query = f"""
        SELECT 
            query,
            calls,
            rows,
            {time_column},
            CASE WHEN calls > 0 THEN {time_column} / calls ELSE 0 END as avg_time,
            CASE 
                WHEN SUM({time_column}) OVER() > 0 
                THEN 100.0 * {time_column} / SUM({time_column}) OVER() 
                ELSE 0 
            END as percentage_cpu
        FROM pg_stat_statements
        WHERE calls > 0 AND dbid = (SELECT oid FROM pg_database WHERE datname = current_database())
        ORDER BY {order_column}
        LIMIT %s
        """
        
        cursor.execute(query, (limit,))
        results = cursor.fetchall()
        
        # Cursor description NULL ise veya boşsa güvenli şekilde işle
        if not cursor.description:
            columns = []
        else:
            columns = [desc[0] for desc in cursor.description]
        
        # 5. Sonuçları işle
        if not columns:
            logger.warning("Sütun bilgisi alınamadı, veri işlenemeyecek.")
        else:
            for row in results:
                if not row:
                    continue  # Boş satırları atla
                    
                row_dict = {}
                try:
                    for i, col in enumerate(columns):
                        if i >= len(row):
                            logger.warning(f"Sütun indeksi ({i}) satır uzunluğunu ({len(row)}) aşıyor, atlanıyor.")
                            continue
                        
                        value = row[i]
                        
                        try:
                            if col == 'query' and value:
                                # Uzun sorguları kısalt
                                row_dict[col] = value[:500] + '...' if len(value) > 500 else value
                            elif col in ['total_exec_time', 'avg_time']:
                                # Süre değerlerini formatla - sabit string formatı kullan
                                row_dict[col] = "{:.2f} ms".format(float(value)) if value is not None else "N/A"
                                # Şablonda kullanılan alan adıyla eşleşmesi için total_time alias'ı da ekle
                                if col == 'total_exec_time':
                                    row_dict['total_time'] = row_dict[col]
                            elif col == 'percentage_cpu':
                                # CPU yüzdesini formatla - sabit string formatı kullan
                                # % işareti format dizesinde sorun yaratmaması için önceden oluşturulmuş değer kullan
                                formatted_value = "{:.2f}".format(float(value)) if value is not None else "0.00"
                                row_dict[col] = formatted_value + "%"
                            else:
                                # Diğer değerleri doğrudan aktar
                                row_dict[col] = value
                        except Exception as format_error:
                            logger.error(f"Sütun '{col}' için değer biçimlendirilirken hata: {format_error}")
                            # Hatada bile güvenli bir değer ata
                            row_dict[col] = "Error" 
                    
                    data.append(row_dict)
                except Exception as row_error:
                    logger.error(f"Satır işlenirken hata: {row_error}")
                    # Hata durumunda bu satırı atla ve diğer satırlarla devam et
        
        # 6. Özet bilgileri al
        summary_query = f"""
        SELECT 
            COALESCE(sum(calls), 0) as total_calls,
            COALESCE(sum(rows), 0) as total_rows,
            COALESCE(sum({time_column}), 0) as total_exec_time,
            count(*) as query_count
        FROM pg_stat_statements
        WHERE calls > 0 AND dbid = (SELECT oid FROM pg_database WHERE datname = current_database())
        """
        cursor.execute(summary_query)
        summary = cursor.fetchone()
        
        if summary and len(summary) >= 4:
            # Float'a dönüştür ve sabit string formatla
            total_calls = float(summary[0]) if summary[0] is not None else 0
            total_rows = float(summary[1]) if summary[1] is not None else 0
            total_exec_time = float(summary[2]) if summary[2] is not None else 0
            query_count = int(summary[3]) if summary[3] is not None else 0
            
            # Şablondaki alanlara uygun olarak veri hazırla
            formatted_exec_time = "{:.2f} ms".format(total_exec_time)
            summary_data = {
                "total_calls": int(total_calls),  # Int'e çevir
                "total_rows": int(total_rows),    # Int'e çevir
                "total_exec_time": formatted_exec_time,  # Sabit string formatı
                "total_time": formatted_exec_time,  # Şablonda kullanılan alanla uyumlu olması için
                "query_count": query_count,
                "pg_version": pg_version
            }
        
        cursor.close()
        connection.close()
        
        return {
            "success": True,
            "message": "Veriler başarıyla alındı",
            "data": data,
            "summary": summary_data,
            "pg_version": pg_version
        }
        
    except Exception as e:
        error_msg = "Sorgu performans verileri alınırken hata: {}".format(str(e))
        logger.error(error_msg)
        return {
            "success": False, 
            "message": error_msg, 
            "data": [],
            "summary": summary_data,
            "pg_version": pg_version
        }

def get_database_stats(db_conn):
    """
    PostgreSQL veritabanı hakkında genel istatistikleri getirir.
    
    Args:
        db_conn: PostgreSQL bağlantı bilgileri (dict)
        
    Returns:
        dict: Veritabanı istatistikleri
    """
    # Varsayılan değerler hazırla
    data = {
        "db_size": "N/A",
        "table_count": 0,
        "index_count": 0,
        "active_connections": 0,
        "largest_tables": [],
        "most_accessed_tables": [],
        "least_used_indexes": []
    }
    
    # Bağlantı bilgilerini hazırla
    conn_str = "host={} port={} user={} password={} dbname={}".format(
        db_conn['host'], db_conn['port'], db_conn['username'], db_conn['password'], db_conn['database']
    )
    
    # 1. Veritabanı boyutu
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        cursor.execute("SELECT pg_size_pretty(pg_database_size(current_database()))")
        result = cursor.fetchone()
        
        if result and result[0]:
            data["db_size"] = result[0]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Veritabanı boyutu alınırken hata: {}".format(str(e)))
    
    # 2. Tablo ve indeks sayısı
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        cursor.execute("SELECT count(*) FROM information_schema.tables WHERE table_schema NOT IN ('pg_catalog', 'information_schema')")
        result = cursor.fetchone()
        
        if result and result[0] is not None:
            data["table_count"] = result[0]
        
        # İndeks sayısı
        cursor.execute("SELECT count(*) FROM pg_indexes WHERE schemaname NOT IN ('pg_catalog', 'information_schema')")
        result = cursor.fetchone()
        
        if result and result[0] is not None:
            data["index_count"] = result[0]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Tablo ve indeks sayısı alınırken hata: {}".format(str(e)))
    
    # 3. Aktif bağlantı sayısı
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        cursor.execute("SELECT count(*) FROM pg_stat_activity WHERE state = 'active'")
        result = cursor.fetchone()
        
        if result and result[0] is not None:
            data["active_connections"] = result[0]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Aktif bağlantı sayısı alınırken hata: {}".format(str(e)))
    
    # 4. En büyük tablolar
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        cursor.execute("""
        SELECT 
            relname as table_name, 
            pg_size_pretty(pg_total_relation_size(relid)) as total_size
        FROM pg_catalog.pg_statio_user_tables
        ORDER BY pg_total_relation_size(relid) DESC
        LIMIT 5
        """)
        results = cursor.fetchall()
        
        if results:
            data["largest_tables"] = [
                {"table_name": row[0], "size": row[1]} for row in results
            ]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("En büyük tablolar alınırken hata: {}".format(str(e)))
    
    # 5. En sık kullanılan tablolar
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        cursor.execute("""
        SELECT 
            relname as table_name, 
            seq_scan + idx_scan as total_scans
        FROM pg_stat_user_tables
        ORDER BY total_scans DESC
        LIMIT 5
        """)
        results = cursor.fetchall()
        
        if results:
            data["most_accessed_tables"] = [
                {"table_name": row[0], "scans": row[1]} for row in results
            ]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("En sık kullanılan tablolar alınırken hata: {}".format(str(e)))
    
    # 6. En az kullanılan indeksler
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        cursor.execute("""
        SELECT
            indexrelname as index_name,
            relname as table_name,
            idx_scan as scans
        FROM pg_stat_user_indexes
        ORDER BY idx_scan ASC
        LIMIT 5
        """)
        results = cursor.fetchall()
        
        if results:
            data["least_used_indexes"] = [
                {"index_name": row[0], "table_name": row[1], "scans": row[2]} for row in results
            ]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("En az kullanılan indeksler alınırken hata: {}".format(str(e)))
    
    # 7. Tüm verileri döndür
    return {
        "success": True,
        "message": "Veritabanı istatistikleri başarıyla alındı",
        "data": data
    }

def get_table_stats(db_conn, table_name):
    """
    Belirli bir tablo hakkında detaylı istatistikleri getirir.
    
    Args:
        db_conn: PostgreSQL bağlantı bilgileri (dict)
        table_name (str): Tablo adı
        
    Returns:
        dict: Tablo istatistikleri
    """
    # Varsayılan veri yapısı
    data = {
        "table_name": table_name,
        "table_size": "N/A",
        "row_count": 0,
        "seq_scan": 0,
        "seq_tup_read": 0,
        "idx_scan": 0,
        "idx_tup_fetch": 0,
        "n_tup_ins": 0,
        "n_tup_upd": 0,
        "n_tup_del": 0,
        "n_live_tup": 0,
        "n_dead_tup": 0,
        "last_vacuum": None,
        "last_autovacuum": None,
        "last_analyze": None,
        "last_autoanalyze": None,
        "indexes": [],
        "columns": []
    }
    
    # Bağlantı bilgisi
    conn_str = "host={} port={} user={} password={} dbname={}".format(
        db_conn['host'], db_conn['port'], db_conn['username'], db_conn['password'], db_conn['database']
    )
    
    # 1. Tablo mevcut mu kontrol et
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        table_query = "SELECT * FROM pg_stat_user_tables WHERE relname = %s"
        cursor.execute(table_query, (table_name,))
        stats = cursor.fetchone()
        
        if not stats:
            cursor.close()
            connection.close()
            return {"success": False, "message": "Tablo bulunamadı: {}".format(table_name), "data": {}}
        
        # Temel tablo istatistiklerini kaydet
        if stats:
            data["seq_scan"] = stats[4] if stats[4] is not None else 0
            data["seq_tup_read"] = stats[5] if stats[5] is not None else 0
            data["idx_scan"] = stats[6] if stats[6] is not None else 0
            data["idx_tup_fetch"] = stats[7] if stats[7] is not None else 0
            data["n_tup_ins"] = stats[8] if stats[8] is not None else 0
            data["n_tup_upd"] = stats[9] if stats[9] is not None else 0
            data["n_tup_del"] = stats[10] if stats[10] is not None else 0
            data["n_live_tup"] = stats[12] if stats[12] is not None else 0
            data["n_dead_tup"] = stats[13] if stats[13] is not None else 0
            data["last_vacuum"] = stats[14]
            data["last_autovacuum"] = stats[15]
            data["last_analyze"] = stats[16]
            data["last_autoanalyze"] = stats[17]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Tablo istatistikleri alınırken hata: {}".format(str(e)))
        # Hata olsa bile diğer sorgulara devam et
    
    # 2. Tablo boyutu
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        size_query = "SELECT pg_size_pretty(pg_total_relation_size(%s))"
        cursor.execute(size_query, (table_name,))
        result = cursor.fetchone()
        
        if result and result[0]:
            data["table_size"] = result[0]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Tablo boyutu alınırken hata: {}".format(str(e)))
    
    # 3. Satır sayısı (yaklaşık)
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        count_query = "SELECT reltuples::bigint FROM pg_class WHERE relname = %s"
        cursor.execute(count_query, (table_name,))
        result = cursor.fetchone()
        
        if result and result[0] is not None:
            data["row_count"] = result[0]
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Satır sayısı alınırken hata: {}".format(str(e)))
    
    # 4. İndeks bilgileri
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        index_query = """
        SELECT
            indexrelname as index_name,
            idx_scan as scans,
            pg_size_pretty(pg_relation_size(indexrelid)) as index_size
        FROM pg_stat_user_indexes
        WHERE relname = %s
        ORDER BY idx_scan DESC
        """
        cursor.execute(index_query, (table_name,))
        results = cursor.fetchall()
        
        indexes = []
        for row in results:
            indexes.append({
                "index_name": row[0] if row[0] is not None else "",
                "scans": row[1] if row[1] is not None else 0,
                "index_size": row[2] if row[2] is not None else "N/A"
            })
        
        data["indexes"] = indexes
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("İndeks bilgileri alınırken hata: {}".format(str(e)))
    
    # 5. Sütun bilgileri
    try:
        connection = psycopg2.connect(conn_str)
        connection.autocommit = True
        
        cursor = connection.cursor()
        column_query = """
        SELECT
            column_name,
            data_type,
            character_maximum_length
        FROM information_schema.columns
        WHERE table_name = %s
        ORDER BY ordinal_position
        """
        cursor.execute(column_query, (table_name,))
        results = cursor.fetchall()
        
        columns = []
        for row in results:
            columns.append({
                "column_name": row[0] if row[0] is not None else "",
                "data_type": row[1] if row[1] is not None else "",
                "max_length": row[2]  # max_length NULL olabilir
            })
        
        data["columns"] = columns
        
        cursor.close()
        connection.close()
    except Exception as e:
        logger.error("Sütun bilgileri alınırken hata: {}".format(str(e)))
    
    # 6. Tüm verileri döndür
    return {
        "success": True,
        "message": "{} tablosu istatistikleri başarıyla alındı".format(table_name),
        "data": data
    }

© KUJUNTI.ID