Report parser complete
This commit is contained in:
58
htdocs/batch_process.php
Normal file
58
htdocs/batch_process.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
define("SITE_ROOT", realpath(dirname(__file__)));
|
||||
require_once SITE_ROOT . "/lib/init.php";
|
||||
|
||||
set_time_limit(0);
|
||||
|
||||
if (PHP_SAPI != "cli")
|
||||
{
|
||||
header("Content-Type: text/plain");
|
||||
}
|
||||
|
||||
function rrmdir($dir)
|
||||
{
|
||||
foreach(glob($dir . '/*') as $file)
|
||||
{
|
||||
if(is_dir($file))
|
||||
rrmdir($file);
|
||||
else
|
||||
unlink($file);
|
||||
}
|
||||
rmdir($dir);
|
||||
}
|
||||
|
||||
$reports = ReportParser::getUnprocessedIDs();
|
||||
|
||||
print "Working dir set to " . ReportParser::getWorkPath() . "\n";
|
||||
mkdir(ReportParser::getWorkPath());
|
||||
chdir(ReportParser::getWorkPath());
|
||||
|
||||
foreach($reports as $id)
|
||||
{
|
||||
print "Processing report {$id} \n";
|
||||
$r = ReportParser::parse($id);
|
||||
$miniDump = $r["Minidump"];
|
||||
if (!$miniDump || !($miniDump->getData()))
|
||||
{
|
||||
ReportParser::setProcessed($id, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!($version = $r["clientVersion"])|| !($chan = $r["clientChannel"]))
|
||||
{
|
||||
ReportParser::setProcessed($id, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
$stacktrace = ReportParser::getStackTrace("$chan-$version", $r["Minidump"]);
|
||||
$crash = new CrashReport();
|
||||
$crash->init($id, $r, $stacktrace);
|
||||
if ($crash->save())
|
||||
{
|
||||
ReportParser::setProcessed($id, 1);
|
||||
}
|
||||
}
|
||||
|
||||
rrmdir(ReportParser::getWorkPath());
|
||||
|
||||
157
htdocs/lib/CrashReport.php
Normal file
157
htdocs/lib/CrashReport.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
class CrashReport
|
||||
{
|
||||
public $id;
|
||||
public $reported;
|
||||
public $client_version;
|
||||
public $client_channel;
|
||||
public $os;
|
||||
public $os_type;
|
||||
public $os_version;
|
||||
public $cpu;
|
||||
public $gpu;
|
||||
public $opengl_version;
|
||||
public $ram;
|
||||
public $grid;
|
||||
public $region;
|
||||
public $crash_reason;
|
||||
public $crash_address;
|
||||
public $crash_thread;
|
||||
public $modules = array();
|
||||
public $threads = array();
|
||||
public $raw_stacktrace;
|
||||
|
||||
function delete()
|
||||
{
|
||||
global $DB;
|
||||
$DB->query(kl_str_sql("delete from reports where id=!i", $this->id));
|
||||
}
|
||||
|
||||
function save()
|
||||
{
|
||||
global $DB;
|
||||
$this->delete();
|
||||
$q = kl_str_sql("insert into reports (
|
||||
id,
|
||||
reported,
|
||||
client_version,
|
||||
client_channel,
|
||||
os,
|
||||
os_type,
|
||||
os_version,
|
||||
cpu,
|
||||
gpu,
|
||||
opengl_version,
|
||||
ram,
|
||||
grid,
|
||||
region,
|
||||
crash_reason,
|
||||
crash_address,
|
||||
crash_thread,
|
||||
raw_stacktrace
|
||||
) values (!i, !t, !s, !s, !s, !s, !s, !s, !s, !s, !i, !s, !s, !s, !s, !i, !s)",
|
||||
$this->id,
|
||||
$this->reported,
|
||||
$this->client_version,
|
||||
$this->client_channel,
|
||||
$this->os,
|
||||
$this->os_type,
|
||||
$this->os_version,
|
||||
$this->cpu,
|
||||
$this->gpu,
|
||||
$this->opengl_version,
|
||||
$this->ram,
|
||||
$this->grid,
|
||||
$this->region,
|
||||
$this->crash_reason,
|
||||
$this->crash_address,
|
||||
$this->crash_thread,
|
||||
$this->raw_stacktrace);
|
||||
if ($res = $DB->query($q))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function parseStackTrace($stacktrace)
|
||||
{
|
||||
$lines = explode("\n", $stacktrace);
|
||||
foreach($lines as $line)
|
||||
{
|
||||
$elems = explode("|", $line);
|
||||
$type = $elems[0];
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case "OS":
|
||||
$this->os_type = $elems[1];
|
||||
$this->os_version = $elems[2];
|
||||
break;
|
||||
|
||||
case "Crash":
|
||||
$this->crash_reason = $elems[1];
|
||||
$this->crash_address = $elems[2];
|
||||
$this->crash_thread = (int)$elems[3];
|
||||
break;
|
||||
|
||||
case "Module":
|
||||
$m = new stdClass;
|
||||
$m->name = $elems[1];
|
||||
$m->version = $elems[2];
|
||||
$this->modules[] = $m;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (false !== filter_var($type, FILTER_VALIDATE_INT))
|
||||
{
|
||||
$threadID = (int)$type;
|
||||
if (!isset($this->threads[$threadID]))
|
||||
{
|
||||
$t = new stdClass;
|
||||
$t->frames = array();
|
||||
}
|
||||
else
|
||||
{
|
||||
$t = $this->threads[$threadID];
|
||||
}
|
||||
|
||||
$frameID = (int)$elems[1];
|
||||
|
||||
$frame = new stdClass;
|
||||
$frame->module = $elems{2};
|
||||
$frame->function = $elems[3];
|
||||
$frame->source_file = $elems[4];
|
||||
$frame->source_line = $elems[5];
|
||||
$frame->function_offset = $elems[6];
|
||||
$t->frames[$frameID] = $frame;
|
||||
|
||||
$this->threads[$threadID] = $t;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function init($id, $data, $stacktrace)
|
||||
{
|
||||
$this->id = $id;
|
||||
$this->reported = $data["reported"];
|
||||
$this->client_version = $data["clientVersion"];
|
||||
$this->client_channel = $data["clientChannel"];
|
||||
$this->os = $data["DebugLog"]["OSInfo"];
|
||||
$this->gpu = $data["DebugLog"]["GraphicsCard"];
|
||||
$this->cpu = $data["DebugLog"]["CPUInfo"]["CPUString"];
|
||||
$this->opengl_version = $data["DebugLog"]["GLInfo"]["GLVersion"];
|
||||
$this->ram = $data["DebugLog"]["RAMInfo"]["Allocated"];
|
||||
$this->grid = $data["DebugLog"]["GridName"];
|
||||
$this->region = $data["DebugLog"]["CurrentRegion"];
|
||||
unset($data["Minidump"]);
|
||||
$this->raw_stacktrace = $stacktrace;
|
||||
$this->parseStackTrace($this->raw_stacktrace);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ class DBH
|
||||
|
||||
function log($line)
|
||||
{
|
||||
return;
|
||||
static $f = false;
|
||||
static $failed = false;
|
||||
|
||||
|
||||
@@ -33,18 +33,96 @@ require_once SITE_ROOT.'/lib/llsd_decode.php';
|
||||
|
||||
class ReportParser
|
||||
{
|
||||
static $extracted = array();
|
||||
|
||||
function parse($id)
|
||||
{
|
||||
global $DB;
|
||||
$q = kl_str_sql("select * from raw_reports where report_id=!i", $id);
|
||||
if (!$res = $DB->query($q) OR !$row = $DB->fetchRow($res))
|
||||
{
|
||||
return;
|
||||
return new stdClass;
|
||||
}
|
||||
$data = new stdClass;
|
||||
$DB->loadFromDbRow($data, $res, $row);
|
||||
$data->report = llsd_decode($data->raw_data);
|
||||
$data->report["reported"] = $data->reported;
|
||||
unset($data->raw_data);
|
||||
return $data;
|
||||
|
||||
if ($client = $data->report["DebugLog"]["ClientInfo"])
|
||||
{
|
||||
//var_dump($client);
|
||||
$data->report["clientVersion"] = $client["MajorVersion"] . "." . $client["MinorVersion"] . "." . $client["PatchVersion"] . "." .$client["BuildVersion"];
|
||||
$data->report["clientChannel"] = str_replace(" ", "", $client["Name"]);
|
||||
}
|
||||
|
||||
// $data->report["raw"] = $row;
|
||||
return $data->report;
|
||||
}
|
||||
|
||||
function setProcessed($id, $status)
|
||||
{
|
||||
global $DB;
|
||||
$ret = array();
|
||||
$q = kl_str_sql("update raw_reports set processed=!i where report_id=!i", $status, $id);
|
||||
|
||||
if ($res = $DB->query($q))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getUnprocessedIDs()
|
||||
{
|
||||
global $DB;
|
||||
$ret = array();
|
||||
$q = kl_str_sql("select report_id from raw_reports where processed=!i", 0);
|
||||
|
||||
if (!$res = $DB->query($q))
|
||||
{
|
||||
return $ret;
|
||||
}
|
||||
|
||||
while ($row = $DB->fetchRow($res))
|
||||
{
|
||||
$ret[] = (int)$row["report_id"];
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function getWorkPath()
|
||||
{
|
||||
static $p = "";
|
||||
|
||||
if ($p) return $p;
|
||||
|
||||
return $p = sys_get_temp_dir() . "/extract-syms-" . (string)getmypid();
|
||||
}
|
||||
|
||||
function getStackTrace($prefix, $dump)
|
||||
{
|
||||
if (!$dump || !($data = $dump->getData())) return;
|
||||
file_put_contents(self::getWorkPath() . "/working.dmp", $data);
|
||||
|
||||
$match = SITE_ROOT . "/../incoming_symbols/$prefix-symbols-*.tar.bz2";
|
||||
|
||||
foreach(glob($match) as $file)
|
||||
{
|
||||
if (!in_array($file, self::$extracted))
|
||||
{
|
||||
self::$extracted[] = $file;
|
||||
print "Unpacking $file\n";
|
||||
shell_exec("tar xjf " . escapeshellcmd($file));
|
||||
}
|
||||
}
|
||||
|
||||
$cmd = "minidump_stackwalk -m " . self::getWorkPath() . "/working.dmp " . self::getWorkPath();
|
||||
print "Executing: $cmd\n";
|
||||
return shell_exec($cmd);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
drop table if exists reports;
|
||||
drop table if exists raw_reports;
|
||||
drop table if exists users;
|
||||
drop table if exists options;
|
||||
@@ -31,4 +32,25 @@ create table raw_reports(
|
||||
reported timestamp not null default current_timestamp,
|
||||
processed integer not null default 0,
|
||||
raw_data longtext
|
||||
);
|
||||
|
||||
create table reports(
|
||||
id integer not null primary key,
|
||||
reported timestamp,
|
||||
client_version varchar(32),
|
||||
client_channel varchar(32),
|
||||
os varchar(128),
|
||||
os_type varchar(32),
|
||||
os_version varchar(128),
|
||||
cpu varchar(128),
|
||||
gpu varchar(128),
|
||||
opengl_version varchar(128),
|
||||
gpu_driver varchar(128),
|
||||
ram integer,
|
||||
grid varchar(128),
|
||||
region varchar(128),
|
||||
crash_reason varchar(128),
|
||||
crash_address varchar(16),
|
||||
crash_thread integer,
|
||||
raw_stacktrace text
|
||||
);
|
||||
Reference in New Issue
Block a user