summaryrefslogtreecommitdiff
path: root/src/guprecords.raku
blob: 6c17bc7dbbfa93cc26979ba2708797b823071a69 (plain)
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
#!/usr/bin/env raku

use v6.d;

class Aggregate {
  has Int $.total-uptime;
  has Int $.first-boot;
  has Int $.last-seen;
  has Int $.elems;

  method aggregate(Str :$uptime is readonly, Str :$boot-time is readonly) {
      $!total-uptime += $uptime;
      $!first-boot = +$boot-time if not defined $!first-boot
                                 or $!first-boot > $boot-time;
      my Int $last-seen = $uptime + $boot-time;
      $!last-seen = $last-seen if not defined $!last-seen
                               or $!last-seen < $last-seen;
      $!elems++;
  }

  method total-downtime { $.last-seen - $.first-boot - $.total-uptime }
  method total-time { self.total-downtime + $.total-uptime }

  method Str returns Str {
    #duration($!total-uptime)
    my Str $active = self.is-active ?? '* ' !! '  ';
    return "$active {duration($!total-uptime)} {date($!last-seen)}";
  }

  method is-active(Int \limit = 90) returns Bool {
    (DateTime.now - DateTime.new(Instant.from-posix: $!last-seen)) < limit * 3600 * 24;
  }

  sub duration(Int \seconds) returns Str {
    my DateTime \dt .= new(Instant.from-posix: seconds);
    return "{dt.year-1970} years, {dt.month} months, {dt.day} days";
  }

  sub date(Int \epoch) returns Str {
    DateTime.new(Instant.from-posix: epoch).yyyy-mm-dd
  }
}

class Aggregator {
  has %.aggregates = { hostname => {}, os => {}, uname => {}, major => {} }

  method aggregate(IO::Path :$file is readonly) {
    my Str $hostname = $file.IO.basename.split('.').first;
    %!aggregates<hostname>{$hostname} //= Aggregate.new;

    for $file.IO.lines {
      my Str ($uptime, $boot-time, $os) = .trim.split(':');
      my Str $uname = $os.split(' ').first;
      my Str $major = "{$uname} {$os.split(' ')[1].split('.').first}...";

      %!aggregates<os>{$os} //= Aggregate.new;
      %!aggregates<uname>{$uname} //= Aggregate.new;
      %!aggregates<major>{$major} //= Aggregate.new;

      for %!aggregates<hostname>{$hostname},
          %!aggregates<os>{$os},
          %!aggregates<uname>{$uname},
          %!aggregates<major>{$major} {
        .aggregate(:$uptime, :$boot-time);
      }
    }
  }
}

sub MAIN(
  Str $in-dir = './stats',
  Str $sort-by = 'uptime';
) {
  my Aggregator $aggregator .= new;

  for dir($in-dir, test => { /\.records$/ }) -> $file {
    $aggregator.aggregate(:$file)
  }

  for $aggregator.aggregates.kv -> $category, $aggregates {
    say "Category $category";
    for $aggregates.kv -> $name, $agg {
      my Str $plural = $agg.elems > 1 ?? 's' !! '';
      say "\t$name $agg (" ~ $agg.elems ~ " record$plural)";
    }
  }
}