Skip to content

Instantly share code, notes, and snippets.

@will
Created December 5, 2019 19:58
Show Gist options
  • Save will/0a0c4e4741cbc189439fc2eb105a7c61 to your computer and use it in GitHub Desktop.
Save will/0a0c4e4741cbc189439fc2eb105a7c61 to your computer and use it in GitHub Desktop.
parse postgres core dumps
require "fileutils"
require "tmpdir"
class PGCoreDump
attr_reader :file, :term, :bt, :query, :basename, :sha256
def initialize(file, basename)
@basename = basename
@file = file
end
def summary
@bt.map { |l| l.match(/#\d+\s+(0x\w+ in )?(?<fn>\w+)/)[:fn] }.first(7).join(", ")
end
def parse
lines = gdb("-ex bt").split("\n")
@term = lines.find { |l| l =~ /\AProgram terminated with signal/ }
@bt = lines.select { |l| l =~ /\A\#\d/ }.uniq
@query = get_query
@sha256 = `sha256sum #{file}`.split(" ").first
end
def get_query
@bt.find { |f| f =~ /\A#(\d+) 0x[0-9a-f]+ in exec_simple_query/ }
frame = $1
gdb(%(-ex 'F #{frame}' -ex 'printf "%s", query_string')).split("\n").drop_while { |l| !l.start_with?("##{frame}") }[1..-1].join
end
private
def gdb(cmd)
`gdb #{file} --batch #{cmd} -q 2>/dev/null`
end
end
class Extractor
def initialize(file)
@file = file
end
def call
pg = nil
basename = File.basename(@file)
if @file.end_with?(".gz")
Dir.mktmpdir do |dir|
FileUtils.cp(@file, "#{dir}/core.gz")
`gunzip #{dir}/core.gz`
pg = PGCoreDump.new("#{dir}/core", basename)
pg.parse
end
else
pg = PGCoreDump.new(@file, basename)
pg.parse
end
pg
end
end
sumquery = {}
Dir.glob("/dat/tmp/core/*").each do |f|
pg = Extractor.new(f).call
puts "#{pg.basename} #{pg.summary}"
old_q = sumquery[pg.summary] || pg.query + "more"
if pg.query.size < old_q.size
puts "new shortest query"
puts pg.query
sumquery[pg.summary] = pg.query
end
end
sumquery.each do |(k, v)|
puts
puts k
puts v
puts
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment