Πώς βρίσκουμε με ένα query τα alerts σε PostgreSQL μέσα από τα Plain Text Logs

Πώς βρίσκουμε με ένα query τα alerts σε PostgreSQL μέσα από τα Plain Text Logs
Πώς βρίσκουμε με ένα query τα alerts σε PostgreSQL μέσα από τα Plain Text Logs

Ως Database Administrators, έχουμε συνηθίσει σε περιβάλλοντα όπως η Oracle να διαβάζουμε τα alerts σαν κανονικούς πίνακες από το v$diag_alert_ext με απλά SQL queries. Στην PostgreSQL, τα πράγματα είναι λίγο διαφορετικά, από προεπιλογή τα logs του είναι plain text αρχεία κειμένου και όχι σε κάποιο εσωτερικό view.

Αν θέλουμε να ελέγχουμε τα τελευταία σφάλματα απευθείας μέσα από τη βάση μας χρησιμοποιώντας SQL, μπορούμε να αξιοποιήσουμε την function ανάγνωσης αρχείων της Postgres pg_read_file. Αντί να ψάχνουμε ποια μέρα είναι ή ποιο είναι το ακριβές όνομα του αρχείου, το pg_ls_logdir() σαρώνει τον φάκελο και επιλέγει αυτόματα το πιο πρόσφατο τροποποιημένο αρχείο log.

Το Query

Το παρακάτω script διαβάζει απευθείας το τρέχον plain text αρχείο log και μας επιστρέφει μια καθαρή λίστα με τα σοβαρά σφάλματα ERROR, FATAL, PANIC ταξινομημένα χρονολογικά:

WITH latest_log AS (
    SELECT 'log/' || name AS log_file 
    FROM pg_catalog.pg_ls_logdir() 
    ORDER BY modification DESC 
    LIMIT 1
),
raw_lines AS (
    SELECT 
        line_number,
        log_line,
        COUNT(CASE WHEN log_line ~ '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}' THEN 1 END) OVER (ORDER BY line_number) AS event_id
    FROM (
        SELECT line_number, log_line
        FROM unnest(string_to_array(pg_read_file((SELECT log_file FROM latest_log)), e'\n')) WITH ORDINALITY AS t(log_line, line_number)
    ) s
),
grouped_events AS (
    SELECT 
        event_id,
        MIN(log_line) AS header_line,
        string_agg(log_line, e'\n' ORDER BY line_number) AS full_multiline_block
    FROM raw_lines
    WHERE event_id > 0
    GROUP BY event_id
)
SELECT 
    substring(header_line from '^([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})') AS log_time,
    
    CASE 
        WHEN full_multiline_block LIKE '%FATAL%' THEN 'FATAL'
        WHEN full_multiline_block LIKE '%PANIC%' THEN 'PANIC'
        ELSE 'ERROR'
    END AS severity,
    
    REGEXP_REPLACE(full_multiline_block, '^.*?(ERROR|FATAL|PANIC):\s*', '\1: ', 's') AS error_message

FROM grouped_events
WHERE full_multiline_block LIKE '%ERROR%' 
   OR full_multiline_block LIKE '%FATAL%' 
   OR full_multiline_block LIKE '%PANIC%'
  AND full_multiline_block NOT LIKE '%canceling statement due to user request%'
ORDER BY log_time DESC;
Πώς βρίσκουμε με ένα query τα alerts σε PostgreSQL μέσα από τα Plain Text Logs

Πηγές:

Μοιράσου το

Αφήστε μία απάντηση