#!/usr/bin/perl
# ilf - input line frequency/time event visualization (slf@dreamscape.
+org)
# a steven fountain creation most definitely:) hire me?
# i do it all for the praise and the word of mouth
#
# psuedo-math for 'blinky light over time' w/duct tape for general uni
+xy things
#
# screenshots of its predecessor's output at http://dreamscape.org/swi
+m/index.php/article/1120892317
# this version is capable of much much more:)
# >> instant war room <<
# screenshots @ http://dreamscape.org/code/ilf-war.png
# (using xterm's) http://dreamscape.org/code/ilf-war
# (using eterm's) http://dreamscape.org/code/ilf-war-eterm
#
# Come back later and check out this file again at http://dreamscape.o
+rg/code/ilf
# as it may be updated and improved!
#
$usage = "------------------------------------------------------------
+--------
ilf - input line frequency/time event visualization
DSC Ops Research Group - http://dreamscape.org/ (slf@)
organicly evolved from: http://dreamscape.org/code/tdpc
--------------------------------------------------------------------
you will see two things: symbols that show timechanges
(also indicating a line was seen), and secondly symbols
that happen so quickly a timechange has not happened.
you can customize the colors of each of these w/ -c -t
--------------------------------------------------------------------
psuedo-math for 'blinky light over time' w/ducttape
it all started because I pondered to myself
. o O \"I wonder how frequently I make my neighbors
w/love:) wireless light blink..\" ..then it evolved!
--------------------------------------------------------------------
screenshots of its predecessor's output can be found at
http://dreamscape.org/swim/index.php/article/1120892317
this version is capable of much much more:)
screenshots @ http://dreamscape.org/code/ilf-war.png
>> instant war room <<
(using xterm's) http://dreamscape.org/code/ilf-war
(using eterm's) http://dreamscape.org/code/ilf-war-eterm
--------------------------------------------------------------------
General options:
-b 'REGEX' pattern that allways triggers bold
-i 'REGEX' pattern that allways triggers reverse
-F 'REGEX' pattern that allways triggers blink
-r 'REGEX' pattern that triggers reverse ON
-R 'REGEX' pattern that triggers reverse OFF
-k 'REGEX' pattern that triggers blinking ON
-K 'REGEX' pattern that triggers blinking OFF
-f 'STR' color choice for \"he's on fire!\" mode
-L INT the limit that triggers \"he's on fire!\" mode
(the default is 50 within .1s (1 ms))
-l enable internal logging to ilf.log
($0 | tee -a ilf.log.color is cooler)
-m INT number of lines to represent on each line in
our visualization (the default is 50)
-c 'STR' color choice for really fast lines
-t 'STR' color choice for time changes
-h display this help
-H drop this help text to ilf.txt and less it
-z FLOAT sleep this much time instead of default 1s
\"builtin\" function:
-N [-n[O]] [-d] : track output of lsof (network status)
-S [-n[O]] [-d] : track output of lsof (system status)
-W [-n[0]] [-d] : track output of who (login activity)
-s [-n[O]] [-d] : track output of ps auxfw (process activity)
-D 'command line' [-n[o]] [-d] : track \"command\" output
Usage:
$0 'command line'
$0 -- command [args ...]
$0 -d command [args ...] (is equivilant to -- but with debug)
$0 builtin {-D|-N|-S|-W|-s} [options ...]
$0 builtin -D 'tail -1000 /var/log/*.log' -n
$0 -w
$0 -H
";
use Term::ANSIColor;
use Time::HiRes qw(time);
$|=1; # autoflushing (required)
use Getopt::Std;
$specificly = shift || die "$usage";
if ($specificly =~ /^-H/)
{
open HELP, "> ilf.txt";
print HELP "$usage";
close HELP;
system "less ilf.txt";
print "The help file exists as ilf.txt if you need to refer to it ag
+ain.\n";
exit;
}
sub printandorlog
{ # no color for the log, sorry ;) just perl ilf -- blah | tee -a ilf.
+log.color
my $msg=shift;
print "$msg";
print LOG "$msg" if ($l eq 1);
}
if ($specificly eq '-d')
{
printandorlog "# Letting you get away with ghetto option evading. ;)
+\n";
$specificly = join ' ', @ARGV;
printandorlog "# Enabling debugging too. This is the only option you
+ get. ;);)\n";
$d = 1;
}
elsif ($specificly eq '-w')
{
print "Retrieving http://dreamscape.org/code/ilf-war to ./ilf-war ..
+\n";
system "wget -O ilf-war http://dreamscape.org/code/ilf-war";
print "Adding execute bit to ./ilf-war ..\n";
system "chmod +x ilf-war";
print "Running ./ilf-war ..\n";
system "./ilf-war &";
exit;
}
elsif ($specificly eq '--')
{
printandorlog "# Letting you get away with ghetto option evading. ;)
+\n";
$specificly = join ' ', @ARGV;
}
else
{
getopts('i:b:K:k:m:c:t:D:F:r:R:L:hlsdSNWnoHwz', \%switches);
(print "$usage" and exit) if ($specificly =~ /^-(?:h|help|\-help)(?:
+$|\s)/);
foreach(sort keys %switches) {
$usedaswitch=1;
${$_}= "$switches{$_}";
(print "$usage" and exit) if ($h eq 1);
#warn "# * Hint: -D usage is supposed to be something like -D 'tai
+l /var/log/messages' and NOT 'tail -f /var/log/messages'\n * M
+aybe you might want $0 \'$D\' instead if you dont see changes.\n" if
+($D && $D =~ /(?:tail|tcpdump|watch)/);
printandorlog "# * $_ is \"$switches{$_}\"";
if ($switches{$_} eq '1') { printandorlog " (ON)"; }
if ($switches{$_} eq '0') { printandorlog " (OFF)"; }
printandorlog "\n";
}
}
if ($l eq 1)
{
system "mv ilf.log.2ago ilf.log.3ago 2>/dev/null";
system "mv ilf.log.1ago ilf.log.2ago 2>/dev/null";
system "mv ilf.log ilf.log.1ago 2>/dev/null";
die "I tried to move ilf.log out of the way but it's still there? Y
+o?\n" if (-e "ilf.log");
open LOG, "+>> ilf.log" or die "Cant create ilf.log, given reason is
+: $!\n";
printandorlog "# Logging enabled to ilf.log\n";
}
$SLEEP=$z || "1s"; # the number of seconds to sleep when diffing outpu
+t
$max=$m || 50; # the number of lines to represent on one line
$hesonfire=$L || 50; # the number of lines that trigger the special "h
+e's on fire!" mode
$reallyfastcolor = $c || "blue"; #(items within the same second are d
+isplayed as this color)
$hesonfirecolor = $f || "red"; #(items that have triggered the "he's
+on fire!" mode are displayed as this color)
$timechangecolor = $t || "cyan"; #(time changes are represented by th
+is color)
$na = " - - NOT APPLICABLE - - (?: never..) "; #(hopefully you arent r
+unning ilf 'cat ilf' ? ;)
$blinkon = $k || $na;
$blinkoff = $K || $na;
$reverseon = $r || $na;
$reverseoff = $R || $na;
$whenbold = $b || $na;
$whenreverse = $i || $na;
$whenblink = $F || $na;
$blinkon =~ /NOT APPLICABLE/ ? 1 : printandorlog "
+ pattern that hilights everything bold: /$whenbold/\n";
$blinkoff =~ /NOT APPLICABLE/ ? 1 : printandorlog " p
+attern that hilights everything reverse: /$whenreverse/\n";
$whenbold =~ /NOT APPLICABLE/ ? 1 : printandorlog " pattern that fl
+ips the blink switch to the ON position: /$blinkon/\n";
$whenreverse =~ /NOT APPLICABLE/ ? 1 : printandorlog "pattern that fli
+ps the blink switch to the OFF position: /$blinkoff/\n";
$c eq '' ? 1 : printandorlog "reallyfastcolor: $reallyfastcolor\n";
$t eq '' ? 1 : printandorlog "timechangecolor: $timechangecolor\n";
$char = ">"; # input lines are flowing character (if you see nothing b
+ut these, we never successfully encoded a symbol)
$otime = " "; # intialize it to something so NEW!=OLD works w/no bs
$oldsize = 0; # initializing the byte-counter & byte-incremental math
if ($n eq 1 && $o eq 1) { $diffmethod = '[<>]'; }
elsif ($n eq 1) { $diffmethod = '>'; }
elsif ($o eq 1) { $diffmethod = '<'; }
else { $diffmethod = '[<>]'; }
# control-C binding
$SIG{INT} = sub { close LOG if $l; die " <- ok, exiting.\n"; };
# open TD, "tcpdump -n -i $device -s 2000 -l $specificly 2>/dev/null |
+" or die "cannot open $specificly because of: $!\n";
sub rndStr{local $"=''; "@_[map{rand$#_} 1 .. shift]"; }
$magic = `mcookie 2> /dev/null && date 2> /dev/null` || rndStr 16, 'A'
+..'Z', 0..9, 'a-z';
$magic =~ s/\n/__/g;
$magic =~ s/ /_/g;
if ($s eq 1 && $specificly eq 'builtin') { $specificly = "while true;
+do mv /tmp/diff.now.$magic /tmp/.diff.then.$magic ; ps auxfw | grep -
+v auxfw | grep -v grep | grep -v builtin | grep -v sleep > /tmp/diff.
+now.$magic 2> /dev/null ; diff /tmp/.diff.then.$magic /tmp/diff.now.$
+magic 2>/dev/null | grep \"^$diffmethod\" 2> /dev/null ; sleep ${SLEE
+P}; done"; }
if (defined $D && $specificly eq 'builtin') { open DTEST, "$D 2\>\&1 |
+" or die "couldnt execute $D: $!\n"; close DTEST; $specificly = "whil
+e true; do mv /tmp/.custom.now.$magic /tmp/.custom.then.$magic 2> /de
+v/null ; $D > /tmp/.custom.now.$magic 2> /dev/null ; diff /tmp/.custo
+m.then.$magic /tmp/.custom.now.$magic | grep \"^$diffmethod\" 2> /dev
+/null ; sleep ${SLEEP}; done"; }
if (defined $N && $specificly eq 'builtin') { open LSOF, "lsof -n 2\>\
+&1 |" or die "couldnt execute lsof: $!\n"; close LSOF; $specificly =
+"while true; do mv /tmp/.custom.now.$magic /tmp/.custom.then.$magic 2
+> /dev/null ; lsof -i -n > /tmp/.custom.now.$magic 2> /dev/null ; dif
+f /tmp/.custom.then.$magic /tmp/.custom.now.$magic | grep \"^$diffmet
+hod\" 2> /dev/null ; sleep ${SLEEP}; done"; }
if (defined $S && $specificly eq 'builtin') { open LSOF, "lsof -n 2\>\
+&1 |" or die "couldnt execute lsof: $!\n"; close LSOF; $specificly =
+"while true; do mv /tmp/.custom.now.$magic /tmp/.custom.then.$magic 2
+> /dev/null ; lsof -n | grep -v $$ | grep -v grep | grep -v lsof > /t
+mp/.custom.now.$magic 2> /dev/null ; diff /tmp/.custom.then.$magic /t
+mp/.custom.now.$magic | grep -E \"^$diffmethod\" 2> /dev/null ; sleep
+ ${SLEEP}; done"; }
if (defined $W && $specificly eq 'builtin') { open WHO, "who -a 2\>\&1
+ |" or die "couldnt execute who: $!\n"; close WHO; $specificly = "whi
+le true; do mv /tmp/.custom.now.$magic /tmp/.custom.then.$magic 2> /d
+ev/null ; who > /tmp/.custom.now.$magic 2> /dev/null ; diff /tmp/.cus
+tom.then.$magic /tmp/.custom.now.$magic | grep \"^$diffmethod\" 2> /d
+ev/null ; sleep ${SLEEP}; done"; }
printandorlog "# Opening: $specificly 2\>\&1\n";
open TD, "$specificly 2\>\&1 |" or die "cannot open $specificly becaus
+e of: $!\n";
printandorlog "# high-res legend: !=0.0-0.1 sec, @=0.1-0.2, #=0.2-0.3
+... )=0.9-1 seconds\n";
printandorlog "# bulk-res legend: 0=.'s 1..9=1..9 10..35=a..z >35=C
+ >40=D >50=E >60=F\n";
printandorlog "# " . showtime() . "ilf - input line frequency/time eve
+nt visualization (slf\@dreamscape.org)\n";
printandorlog "#(freq/time)";
#printandorlog "# input lines: ";
while(<TD>)
{
# This will strip out all ANSI characters in your input.
s/\e\[.*?m//go;
# Store our previous time measurements.
if (defined $timenow) { $oldtime = $timenow; }
# Take a time measurement.
$timenow = time;
$time = $timenow;
# Determine if this is a ordinary line or one that is also a timecha
+nge & then act
if (defined $time && defined $oldtime) {
# how much time has elapsed since the last input line?
$diff = $time - $oldtime;
# the sensitivity of this is currently fixed at 1 millisecond.
if ($diff > 0.01)
{
# we dont care about 1.2345 etc...
if ($diff > 1) { $diff = int($diff); }
# reset the reallyfastlines counter whenever we do a timechange
$pcount=0;
# encode the timechange symbol (could be high resolution)
$char=whatchar($diff);
# allways reset before changing colors.
print color 'reset';
# our timechanges are generally allways supposed to be bold.
print color 'bold';
# change the color to our configured timechangecolor setting.
print color "$timechangecolor";
# increment the timechanges bean counter.
$timechanges++;
}
else
{
$pcount++;
$OLDdiff = $diff;
$diff = $pcount;
# encode the character to a symbol (could be high resolution)
$char=whatchar($diff);
# then begin coloring it.
# allways reset before we add options.
print color 'reset';
# clean the spoon we will use to feed the options.
$cmode = ""; ### (clean off the spoon)
# determine if we should be blinking.
if (/${blinkon}/o) { $blinkswitch = "ON"; }
if (/${blinkoff}/o) { $blinkswitch = "OFF"; }
if ($blinkswitch eq 'ON') { $cmode .= "blink "; }
# determine if we should be reversing.
if (/${reverseon}/o) { $reverseswitch = "ON"; }
if (/${reverseoff}/o) { $reverseswitch = "OFF"; }
if ($reverseswitch eq 'ON') { $cmode .= "reverse "; }
# allways blink when we match this pattern
$cmode .= "blink " if (/$whenblink/o);
# allways reverse when we match this pattern
$cmode .= "reverse " if (/$whenreverse/o);
# allways bold when we match this pattern
$cmode .= "bold " if (/$whenbold/o);
# then finally add the color we'll be using.
$cmode .= "$reallyfastcolor";
# and then eat up! the colors! the colors! ;)
print color "$cmode";
$reallyfastlines++;
}
}
$pnum++;
# if ($char eq '.') { print color 'red'; }
if ($lastchar eq $char) { $prun++; }
if ($lastchar ne $char) { $prun=0; }
# he's on fire! override color decisions when we've seen way too
+many packets within .1 second
if ($prun > $hesonfire) { print color 'reset'; print color "bold $h
+esonfirecolor"; $prun++; }
if ($prun > ($hesonfire * 2) ) { print color 'reset'; print color "r
+everse blink bold $hesonfirecolor"; }
# ^^^ go craz
+y if we're he's on fire 2x! ;)
# (yes this could have been pnum, but what happens when you wrap lin
+es and are still on fire? ;))
# Actually print the coded character
printandorlog "$char";
# Reset immediately for good measure (you never know when you might
+control-C or lose link, eh?)
print color 'reset';
# To help determine when we're running at ludacris speed.
$lastchar = "$char";
# How many seconds have elapsed since the last gain on the clock?
$secondssince = time - $timehere;
$secondssince = $1 if ($secondssince =~ /^(\d+(?:|\.\ddd|\.\d\d|\.\d
+))/o);
# If you want to add something special at the end of each line, make
+ it look like this.
if ($pnum eq $max) { printandorlog " ${secondssince}s since" if (def
+ined $notthefirstlineplzthxu); }
# when we have filled up your screen (maxxed out the setting in -m),
+ what happens on the next line?
if ($pnum eq $max)
{
if (not defined $notthefirstlineplzthxu) { $notthefirstlineplzthxu
+=1 }
printandorlog "\n";
$nclock = showtime();
if ($otime ne $nclock)
{
printandorlog "#\n";
printandorlog "# Gain since last clockchange: ";
$timehere = time;
if (not defined $timechanges) { $timechanges="no" }
printandorlog " \+${reallyfastlines} within .1s, ${timechanges}
+timechange";
if ($timechanges > 1 || $timechanges eq 0) { printandorlog "s";
+}
printandorlog ".\n";
$reallyfastlines=0;
$timechanges=0;
}
printandorlog "# $nclock" if ($otime ne $nclock);
printandorlog "# " if ($otime eq $nclock);
printandorlog " " x 10 if ($otime eq $nclock);
$otime = $nclock;
$pnum=0;
}
## $char = "." if ($char ne '.'); # normal printing character
# normal printing character
printandorlog " $_" if ($d);
}
close TD;
printandorlog " The program finished..?\n";
exit;
sub strftime ($@)
{
my ($format,$second,$minute,$hour,$day,$month,$year) = @_;
my %convert = (
Y => $year + 1900,
m => sprintf( '%02d',$month + 1 ),
d => sprintf( '%02d',$day ),
H => sprintf( '%02d',$hour ),
M => sprintf( '%02d',$minute ),
S => sprintf( '%02d',$second ),
);
$format =~ s#%(.)#$convert{$1}#sg;
return $format;
}
sub showtime
{
my ($time2,$time,$hour,$min,$lclock,$clock,$pad,$extra);
$time2 = strftime( '%H%M%S', localtime() );
$time = $1 if ($time2 =~ /^(\d\d\d\d)\d\d/o);
$hour = $1 if ($time =~ /^(\d\d)\d\d/o);
$min = $1 if ($time =~ /^\d\d(\d\d)/o);
if ($hour > 12) { $extra = "pm"; $hour -= 12; }
else
{
if ($hour < 1) { $hour += 12; }
$extra = "am";
}
$clock = "$hour:${min}$extra";
$lclock = length $clock;
$pad = 10 - $lclock;
$clock .= " " x $pad;
return $clock;
}
sub whatchar
{
my $diff = shift; # pass a parameter rather than checking a globa
+l
my $char; # return this value rather than setting a global
my @zeroto1 = qw/! @ # $ % ^ & * ( )/; # characters for values <1
# (the hash mark there will generate a warning, but it's okay)
if ( $diff <= 0 ) {
$char = ' '; # differs from OP code
}
elsif ( $diff < 1 ) {
$char = $zeroto1[int( $diff * 10 )];
}
elsif ( $diff < 10 ) {
$char = ( $diff < 9 ) ? chr( int( $diff ) + ord( '1' )) : '0';
# are you sure "234567890" is better than "123456789" ??
# ... $char = chr( int( $diff ) + ord( '0' )) seems okay to me
}
elsif ( $diff <= 35 ) {
$char = chr( int( $diff - 10 ) + ord( 'a' ));
}
else {
$diff = 260 if ( $diff > 260 );
$char = chr( int( $diff/10 ) - 3 + ord( 'C' ));
}
return $char;
}
#--------------------------------------------------------
#wishlist...
# min..avg-range..max dynamic granular highlighting
# choose-your-own-adventure legend writing
#--------------------------------------------------------
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.