-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpg_statementlog_parser.pl
executable file
·110 lines (84 loc) · 3.18 KB
/
pg_statementlog_parser.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/perl
use strict;
use warnings;
use Carp;
use constant {
LINENUMBER => 0,
STATEMENT => 1,
TIMESTAMP => 2,
DURATION => 3,
};
my $pglogchunkre = qr!
\[(\d+)]:\s+ # Backend PID
\[(\d+)-(\d+)\]\s # Logline and Chunk Counter
(.*)!x; # Log Message
my $pglogdurationre = qr!
(.*?)\s+ # Timestamp
LOG:\s+ # Log identifier
duration:\s+([\d.]+)\s+ms\s+ # Duration
statement:\s+(.*) # Statement
!x;
my $threshold = 300 * 10**3; # msec
my $debug = 1;
my @chunkbuffer;
while ( my $line = <ARGV> ) {
next if $line =~ /^\s+$/;
# Does he look like a PostreSQL log line?!
if ( $line =~ m/$pglogchunkre/ ) {
my ( $curbackendpid, $curlinenumber, $curchunknumber, $content )
= ( $1, $2, $3, $4 );
if ( $curchunknumber == 1 ) {
# If this is the first chunk of a log line we might need to flush a
# previously stored log line
if ( $chunkbuffer[$curbackendpid]->[STATEMENT] ) {
logme($curbackendpid);
$chunkbuffer[$curbackendpid]->[STATEMENT] = '';
}
# Does he look like a statement log entry?!
# Extract timestamp, duration and log statement
if ( $content =~ m/$pglogdurationre/ ) {
my ( $timestamp, $duration, $statementpart ) = ( $1, $2, $3 );
# If this statement is of interest, save it's data for now since
# there might be other chunks belonging to this statement
if ( $duration > $threshold ) {
$chunkbuffer[$curbackendpid]->[LINENUMBER]
= $curlinenumber;
$chunkbuffer[$curbackendpid]->[STATEMENT]
= $statementpart;
$chunkbuffer[$curbackendpid]->[TIMESTAMP] = $timestamp;
$chunkbuffer[$curbackendpid]->[DURATION] = $duration;
}
}
else {
if ($debug) {
carp "Skipping unknown entry:\n$content";
}
}
}
# So we're not the first line of a chunk...
# Does this logchunk belong to a log line we want to log?
elsif ($chunkbuffer[$curbackendpid]->[LINENUMBER]
&& $chunkbuffer[$curbackendpid]->[LINENUMBER] == $curlinenumber )
{
$chunkbuffer[$curbackendpid]->[STATEMENT] .= $content;
}
}
else {
croak
"This doesn't look like something I expect in a statement log\nLine\n\n$line";
}
}
# Flush any leftover statements from the chunk buffer
for my $backendpid ( 0 .. @chunkbuffer ) {
if ( $chunkbuffer[$backendpid]->[STATEMENT] ) {
logme($backendpid);
}
}
sub logme {
my ($curbackendpid) = @_;
my $statement = $chunkbuffer[$curbackendpid]->[STATEMENT];
my $timestamp = $chunkbuffer[$curbackendpid]->[TIMESTAMP];
my $duration = $chunkbuffer[$curbackendpid]->[DURATION];
$statement =~ s/\s+/ /g;
print "$timestamp: $duration ms: $statement\n";
}