Skip to content

Instantly share code, notes, and snippets.

@timo
Created April 17, 2017 10:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timo/42cce4904647f6a0fb2f3dc7d29dfe5a to your computer and use it in GitHub Desktop.
Save timo/42cce4904647f6a0fb2f3dc7d29dfe5a to your computer and use it in GitHub Desktop.
use JSON::Fast;
my %intervals;
my @timestamps;
my $ticks-per-sec;
my $epoch;
my %messages;
class StatsAbsorber {
has %.statsdata;
method collect($obj) {
my $objkey = $obj.WHAT.^name;
for $obj.Capture.Hash -> (:key($k), :value($v)) {
%.statsdata{$objkey}{$k}.push: $v with $v;
}
}
}
enum Kind <IStart IStop IAnnotation TStamp>;
class Interval {...}
class Annotation {
has Str $.subject;
has Str $.message;
has Interval $.owner_interval;
method Capture {
\(:$.subject, :$.message)
}
}
class Interval {
has $.subject;
has $.message;
has $.endmessage is rw;
has @.annotations;
has $.starttime;
has $.duration is rw;
}
class Timestamp {
has $.message;
has $.time;
}
my $absorber;
multi sub MAIN(:$filename = "/dev/stdin") {
$absorber = StatsAbsorber.new;
for $filename.IO.lines() -> $line {
my @parts = $line.words;
my $subject = @parts.shift;
my $interval_id;
my $intervalpart;
my $message;
my $kind;
my $time;
when @parts[0] eq 'Calibration:' {
$ticks-per-sec = +@parts[1];
succeed;
}
when @parts[0] eq 'Epoch' {
$epoch = +@parts[2];
succeed;
}
do {
$message = $line.substr(my $first_quote = $line.index('"') + 1, $line.rindex('"') - $first_quote);
}
try $time = +@parts[0] / $ticks-per-sec;
if @parts[0] eq '???' || @parts[1] eq '(-' || @parts[1] eq '-)' {
$intervalpart = @parts.pop;
die "invalid line in telemetry log: $line" unless $intervalpart.starts-with('(') && $intervalpart.ends-with(')');
$interval_id = +$intervalpart.substr(1, *-1);
}
$kind = IAnnotation if @parts[0] eq '???';
$kind = IStart if @parts[1] eq '(-';
$kind = IStop if @parts[1] eq '-)';
$kind = TStamp if @parts[1] eq '-|-';
with $intervalpart {
given $kind {
when IStart {
%intervals{$interval_id} = new Interval: :$subject, :$message, :starttime($time);
}
when IStop {
given %intervals{$interval_id} {
.duration = $time - .starttime;
.endmessage = $message unless $message eq .message;
$absorber.collect($_);
}
}
when IAnnotation {
given %intervals{$interval_id} {
.annotations.push: new Annotation: :$subject, :$message, :owner_interval($_);
$absorber.collect($_);
}
}
}
}
without $intervalpart {
given $kind {
when TStamp {
@timestamps.push: my $ts = new Timestamp: :$time, :$message;
$absorber.collect($ts);
}
}
}
$*ERR.print(".") if ++$ %% 1000;
note "" if ++$ %% 60000;
}
note "done";
note "writing json";
spurt("statsdata.json", $absorber.statsdata.&to-json(:!pretty));
analyze();
}
multi sub MAIN("from-json", $filename = "statsdata.json") {
$absorber = StatsAbsorber.new: :statsdata(from-json($filename.IO.slurp));
analyze();
}
sub analyze() {
for $absorber.statsdata.pairs -> (:key($typename), :value($_)) {
"$typename stats:".put;
for $_.pairs -> (:key($attrname), :value($_)) {
" $attrname stats:".put;
" $_.elems() entries".put;
if .[0] ~~ Str {
for .Bag -> (:key($entry), :value($_)) {
" $_.fmt("%4d") $entry".put;
}
} elsif .[0] ~~ Real {
my @sorted = .sort;
" ".print;
@sorted[* div 20, * div 4, * div 2, * * 3 div 4, * * 19 div 20].fmt("%10f").put;
}
}
}
}
#my @intervals_sorted = %intervals.pairs.sort(*.value.starttime);
#for @intervals_sorted -> (:key($k), :value($_)) {
#"$k.fmt("%6d"); $_.subject()".put;
#"$_.starttime() ($_.duration()): $_.message()".put;
#for .annotations {
#" $_.message(); $_.subject()".put;
#}
#}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment