anytop

aspect 2012-09-12: I stumbled across the Python version of this utility by accident, and immediately thought that a Tcl implementation would be much neater. It reads stdin continuously, refreshing the display every 250ms with a summary of the most frequent ("top") lines seen on the input. Usage might be something like tail -f /var/log/syslog | awk '{print $4" "$6}' | anytop.tcl to keep track of which hosts are generating the most log messages.

This could well be extended with ideas from A grep-like utility or awk-like behaviour as in owh - a fileless tclsh. It would benefit from better terminal awareness (curses), or could trivially have a GUI attached. One interesting alteration would be a character-based histogram.

#!/usr/bin/tclsh
#
# inspired by https://bitbucket.org/larsyencken/anytop/
# does not include windowing function (limit to last N lines)
# a bit more terminal-awareness would be nice

package require term::ansi::send

fconfigure stdin -blocking 0
fileevent stdin readable consume

set ::status "Reading ..."
set ::start [clock seconds]
set ::lines 0
set ::counts {}
set ::eof 0

proc consume {} {
    if {[gets stdin data]<1} {
        if {[eof stdin]} {
            close stdin
            set ::eof 1
            set ::status "EOF"
        }
    } else {
        incr ::lines
        dict incr ::counts $data
    }
}

proc topN {n counts} {
    lrange [lsort -integer -decreasing -stride 2 [lreverse $counts]] 0 [expr {$n*2}]
}

proc elapsed {} {
    clock format [expr {[clock seconds]-$::start}] -format "%M:%S"
}

proc refresh {} {
    ::term::ansi::send::clear
    puts "[format "%6s" [elapsed]] elapsed, $::lines lines, [dict size $::counts] distinct values"
    puts ""
    foreach {count value} [topN 20 $::counts] {
        puts "[format %6s $count]  $value"
    }
    if {$::eof} {
        puts "\nReached EOF:  Press ^C to exit .."
    } else {
        after 250 refresh
    }
}

refresh
vwait forever