summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/guprecords181
-rw-r--r--src/guprecords.raku161
2 files changed, 0 insertions, 342 deletions
diff --git a/src/guprecords b/src/guprecords
deleted file mode 100755
index 3722470..0000000
--- a/src/guprecords
+++ /dev/null
@@ -1,181 +0,0 @@
-#!/usr/bin/env perl
-
-# guprecords (c) 2014, Paul Buetow
-# E-Mail: guprecords@mx.buetow.org WWW: http://codeberg.org/snonux/guprecords
-
-use strict;
-use warnings;
-use v5.14;
-
-use Getopt::Long;
-use POSIX qw(strftime);
-use Term::ANSIColor;
-
-our $VERSION = 'VERSION_DEVEL';
-our $FLAG = 0;
-our $NOW = time();
-
-our %ARGS = (
- all => 0,
- help => 0,
- nofqdn => 0,
- reverse => 0,
- total => 0,
- nocolor => 0,
- 'oldage=i' => 180,
- 'count=i' => 23,
- 'indir=s' => '.',
-);
-
-our %OPTS = map { $_ => \$ARGS{$_} } keys %ARGS;
-GetOptions %OPTS or die "Error in command line arguments. Try --help";
-
-sub help() {
- say "Ths is guprecords Version $VERSION";
- print "Usage: $0\n";
- say "\t--$_" for sort keys %ARGS;
- say 'Please also consult the guprecords manual page.'
-}
-
-sub uptime($) {
- my $uptime = shift;
- my ($s,$m,$h,undef,undef,$y,undef,$d) = localtime($uptime);
-
- $y -= 70;
- $d += $y * 365;
-
- sprintf "%3dd %02d:%02d:%02d", $d, $h, $m, $s;
-}
-
-sub trimlen($$) {
- my ($string,$len) = @_;
-
- if (length $string > $len) {
- substr($string, 0, ($len-2)).'..';
- } else {
- $string;
- }
-}
-
-sub out(\@;$) {
- my ($records,$show_bt) = @_;
-
- $FLAG = 1;
- my $count = 0;
-
- printf "%3s | %17s | %20s | %13s | %24s\n",
- 'Pos',
- 'System',
- 'Kernel',
- 'Uptime',
- (defined $show_bt ? 'Boot time' : '');
-
- map {
- return if $count++ == $ARGS{'count=i'};
-
- my $name = $ARGS{nofqdn} ? $_->{hostname} : $_->{fqdn};
-
- print color 'bold' if !$ARGS{nocolor} and $_->{is_old};
-
- printf "%3d | %17s | %20s | %13s | %24s\n",
- $count,
- trimlen($name,17),
- trimlen($_->{kernel},20),
- uptime($_->{uptime}),
- (defined $show_bt ? ''.localtime($_->{bootime}) : '');
-
- print color 'reset' if !$ARGS{nocolor} and $_->{is_old};
- }
- do {
- unless ($ARGS{reverse}) {
- sort { $b->{uptime} <=> $a->{uptime} } @$records
- } else {
- sort { $a->{uptime} <=> $b->{uptime} } @$records
- }
- };
-}
-
-sub is_old($) {
- my $time = shift;
- # Count per day
- my $oldage = 86400 * $ARGS{'oldage=i'};
-
- return $NOW - $time < $oldage ? 1 : 0;
-}
-
-sub all() {
- my @records;
-
- for my $file (<$ARGS{'indir=s'}/*.records>) {
- my ($fqdn) = $file =~ m#.*/(.*)\.records#;
- my ($hostname) = $fqdn =~m#([^\.]+)#;
-
- my $uptime_total = 0;
-
- open my $fh, $file or die "$file: $!\n";
- while (<$fh>) {
- chomp;
- my ($uptime,$boot,$kernel) = split ':';
-
- push @records, {
- bootime => $boot,
- fqdn => $fqdn,
- hostname => $hostname,
- kernel => $kernel,
- uptime => $uptime,
- is_old => is_old $uptime + $boot,
- };
-
- }
- close $file;
-
- }
-
- out @records, 'show_bt';
-}
-
-sub total() {
- my @records;
-
- for my $file (<$ARGS{'indir=s'}/*.records>) {
- my ($fqdn) = $file =~ m#.*/(.*)\.records#;
-
- my $uptime_ = 0;
- my $kernel_;
-
- my ($highest, $newest) = (0, 0);
-
- open my $fh, $file or die "$file: $!\n";
- while (<$fh>) {
- chomp;
- my ($uptime,$boot,$kernel) = split ':';
-
- $uptime_ += $uptime;
-
- if ($highest < $uptime) {
- $highest = $uptime;
- $kernel_ = $kernel;
- }
-
- $newest = $uptime + $boot if $newest < $uptime + $boot;
- }
- close $file;
-
- push @records, {
- uptime => $uptime_,
- kernel => $kernel_,
- fqdn => $fqdn,
- is_old => is_old $newest,
- };
-
- }
-
- out @records;
-}
-
-help if $ARGS{help};
-all if $ARGS{all};
-total if $ARGS{total};
-
-help unless $FLAG;
-
diff --git a/src/guprecords.raku b/src/guprecords.raku
deleted file mode 100644
index 976a83c..0000000
--- a/src/guprecords.raku
+++ /dev/null
@@ -1,161 +0,0 @@
-#!/usr/bin/env raku
-
-use v6.d;
-
-subset Nat of Int where * >= 0;
-subset Cat of Str where * eq any <host os os-major uname>;
-subset SubCat of Str where * eq any <boots uptime downtime lifespan meta-score>;
-subset HostOnlyCat of Cat where * eq 'host';
-subset BasicSubCat of SubCat where * ne any <downtime lifespan>;
-
-our Nat constant DAY = 1 * 24 * 3600;
-our Nat constant MONTH = 30 * DAY;
-
-class Epoch {
- has Nat $.value is required;
-
- submethod new (Nat $value) { self.bless(:$value) }
-
- method human-duration returns Str {
- my DateTime \dt .= new(Instant.from-posix: $!value);
- "{dt.year-1970} years, {dt.month} months, {dt.day} days";
- }
-
- method human-date returns Str {
- DateTime.new(Instant.from-posix: $!value).yyyy-mm-dd;
- }
-
- method newer-than(Nat:D \limit) returns Bool {
- (DateTime.now - DateTime.new(Instant.from-posix: $!value)) < limit * DAY;
- }
-}
-
-class Aggregate {
- has Str $.name is required;
- has Nat $.uptime;
- has Nat $.first-boot;
- has Nat $.last-seen;
- has Nat $.boots;
-
- method new (Str $name) { self.bless(:$name) }
-
- method add-record(Str:D :$uptime is readonly, Str:D :$boot-time is readonly) {
- my Int $last-seen = $uptime + $boot-time;
- $!uptime += $uptime;
- $!boots++;
-
- $!first-boot = +$boot-time if not defined $!first-boot or $!first-boot > $boot-time;
- $!last-seen = $last-seen if not defined $!last-seen or $!last-seen < $last-seen;
- }
-
- method meta-score returns Nat {
- Nat((($!uptime * 2) + ($!boots * DAY) + (self.is-active ?? MONTH !! 0))/1000000)
- }
-
- method is-active(Nat:D \limit = 90) returns Bool {
- Epoch.new($!last-seen).newer-than: limit;
- }
-}
-
-class HostAggregate is Aggregate {
- method lifespan returns Nat { $.last-seen - $.first-boot }
- method downtime returns Nat { self.lifespan - $.uptime }
- method meta-score returns Nat { Nat(self.downtime / 1000000) + callsame }
-}
-
-class Aggregator {
- has Hash %.aggregates = { host => {}, os => {}, uname => {}, os-major => {} }
-
- method add-file(IO::Path:D $file is readonly) {
- my Str $host = $file.IO.basename.split('.').first;
-
- die "Record file for {$host} already processed - duplicate inputs?"
- if %!aggregates<host>{$host}:exists;
- %!aggregates<host>{$host} = HostAggregate.new($host);
-
- for $file.IO.lines -> Str $line { self!add-line(:$line, :$host) }
- }
-
- method !add-line(Str:D :$line is readonly, Str:D :$host is readonly) {
- my Str ($uptime, $boot-time, $os) = $line.trim.split(':');
- my Str $uname = $os.split(' ').first;
- my Str $os-major = "$uname {$os.split(' ')[1].split('.').first}...";
-
- %!aggregates<os>{$os} //= Aggregate.new($os);
- %!aggregates<uname>{$uname} //= Aggregate.new($uname);
- %!aggregates<os-major>{$os-major} //= Aggregate.new($os-major);
-
- for %!aggregates<host>{$host}, %!aggregates<os>{$os},
- %!aggregates<uname>{$uname}, %!aggregates<os-major>{$os-major} {
- .add-record(:$uptime, :$boot-time);
- }
- }
-}
-
-class Reporter {
- has Cat $.cat is required;
- has SubCat $.sub-cat is required;
- has Nat $.first is required;
- has Hash %.aggregates;
-
- method report {
- say "Top {$.first} {$.sub-cat}'s by {$.cat}:\n";
- my Nat $count = 0;
-
- for self.sort-by($!sub-cat) -> Aggregate $what {
- self!pretty-say($what, $count+1);
- last if ++$count == $.first;
- }
- }
-
- method !pretty-say(Aggregate:D \what, Nat:D \position) {
- my Str \active = what.is-active ?? ' (still active)' !! '';
- say "{position}. {what.name}{active}:\n\t{self.human-str($.sub-cat, what)}";
- }
-
- multi method sort-by('uptime') { self.sort-by: *.uptime }
- multi method sort-by('boots') { self.sort-by: *.boots }
- multi method sort-by('meta-score') { self.sort-by: *.meta-score }
-
- multi method sort-by(Code:D $sort-by) {
- %!aggregates{$!cat}.values.sort(&$sort-by).reverse;
- }
-
- multi method human-str('uptime', Aggregate:D $what) { "Uptime: {Epoch.new($what.uptime).human-duration}" }
- multi method human-str('boots', Aggregate:D $what) { "Number of boots: {$what.boots}" }
- multi method human-str('meta-score', Aggregate:D $what) { "Meta score: {$what.meta-score}" }
-}
-
-class HostReporter is Reporter {
- multi method sort-by('downtime') { self.sort-by: *.downtime }
- multi method sort-by('lifespan') { self.sort-by: *.lifespan }
-
- multi method human-str('downtime', Aggregate:D $what) { "Downtime: {Epoch.new($what.downtime).human-duration}" }
- multi method human-str('lifespan', Aggregate:D $what) { "Lifespan: {Epoch.new($what.lifespan).human-duration}" }
-}
-
-sub do-it(Str:D \stats-dir, Reporter:D \reporter) {
- my Aggregator \aggregator .= new;
- aggregator.add-file($_) for dir(stats-dir, test => { /.records$/ });
- reporter.aggregates = aggregator.aggregates;
- reporter.report;
-}
-
-multi MAIN(
- Str :$stats-dir is required, #= The uptimed raw record input dir.
- HostOnlyCat :$cat = 'host', #= Category, one of host, os os-major and uname.
- SubCat :$sub-cat = 'uptime', #= Sort by one of boots uptime downtime and lifespan.
- Nat :$first = 13, #= Only show top N entries.
-) {
- do-it($stats-dir, HostReporter.new(:$cat, :$sub-cat, :$first));
-}
-
-multi MAIN(
- Str :$stats-dir is required,
- Cat :$cat,
- BasicSubCat :$sub-cat = 'uptime',
- Nat :$first = 13,
-) {
- do-it($stats-dir, Reporter.new(:$cat, :$sub-cat, :$first));
-}
-