Another python util I've created a while back, and usually use in conjunction with tgraph, is a running (or moving) average util that can also be piped into. So, as another exercise, I created an Erlang/escript version.
The main use case is when I'm looking into a problem, and tailing a log. Too much data. Awk/perl/pyline the interesting numbers and tail that. Numbers running too fast or changing too often to see a pattern. So I then pipe the number stream through a running average and then to tgraph.
tail -f some.log | awk -F" " '{print $10}' | ./runavg.escript | ./tgraph.escript
Another similar case is to run a whole or portion of an existing log through runavg/tgraph to look for a pattern. Make sure you set your terminal's buffer size to 2-3K before trying that.
tail -10000 some.log | awk -F" " '{print $10}' | ./runavg.escript -s 10 -i 10 | ./tgraph.escript -t 1000
runavg.escript
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp disable
%% Author: Drew Gulino
-module(runavg).
-export([main/1]).
main(CmdLine) ->
OptSpecList = option_spec_list(),
case getopt:parse(OptSpecList, CmdLine) of
{ok, {Options, NonOptArgs}} ->
true;
{error, {Reason, Data}} ->
Options = [],
NonOptArgs = [],
io:format("Error: ~s ~p~n~n", [Reason, Data]),
version(),
getopt:usage(OptSpecList, "runavg")
end,
SampleSize = get_opt_value(size,Options),
OutputInterval = get_opt_value(interval,Options),
case NonOptArgs of
[] ->
F = standard_io;
_ ->
{ok, F} = file:open(NonOptArgs, read)
end,
%io:format("~p,~p,~p~n",[F, SampleSize, OutputInterval]),
proc_file(F, SampleSize, OutputInterval ).
proc_file(F, SampleSize, OutputInterval) ->
%io:format("1"),
proc_file(F, SampleSize, OutputInterval, [], 0, 0).
proc_file(F, SampleSize, OutputInterval, SampleAcc, SampleCount, IntervalCount) when IntervalCount >= OutputInterval ->
io:format("~.2f~n",[lists:sum(SampleAcc)/erlang:length(SampleAcc)]),
proc_file(F, SampleSize, OutputInterval, SampleAcc, SampleCount, 0);
proc_file(F, SampleSize, OutputInterval, [_|T] , SampleCount, IntervalCount) when SampleCount >= SampleSize ->
%io:format("T: ~p~n",[T]),
proc_file(F, SampleSize, OutputInterval, T, SampleCount - 1, IntervalCount);
proc_file(F, SampleSize, OutputInterval, SampleAcc, SampleCount, IntervalCount) ->
%io:format("SampleAcc: ~p~n", [SampleAcc]),
L = io:get_line(F, ''),
case L of
eof ->
ok;
"\n" ->
false;
Line ->
Stripped = strip_newlines(Line),
Num = cast_to_integer(Stripped),
proc_file(F, SampleSize, OutputInterval, [Num] ++ SampleAcc, SampleCount + 1, IntervalCount + 1)
end.
version() ->
io:format("Version: 1.0\n").
get_opt_value(Key, Options) ->
case lists:keyfind(Key,1,Options) of
{Key, Value} ->
Value
end,
Value.
option_spec_list() ->
[
%% {Name, ShortOpt, LongOpt, ArgSpec, HelpMsg}
{help, $h, "help", undefined, "Show the program options"},
{version, $v, "version", undefined, "Version"},
{size, $s, "size", {integer, 5}, "Size of average sample, Default=5"},
{interval, $i, "interval", {integer, 5}, "How many input entries before average is displayed, Default=5"}
].
strip_newlines(String) ->
string:strip(re:replace(String,"(.*)[\n\r]","\\1", [global,{return,list}])).
cast_to_integer([]) ->
[];
cast_to_integer(Input) when is_integer(Input) ->
Input;
cast_to_integer(Input) when is_float(Input) ->
erlang:round(Input);
cast_to_integer(Input) when is_list(Input)->
case lists:member($., Input) of
true ->
erlang:round(erlang:list_to_float(Input));
false ->
erlang:list_to_integer(Input)
end.
A util I use to test numeric pipes is a random number streamer:
randstream.escript:
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp disable
%% Author: Drew Gulino
-module(randstream).
-export([main/1]).
main(_) ->
{A1,A2,A3} = now(),
random:seed(A1, A2, A3),
rand().
rand() ->
Num = random:uniform(100),
io:format("~B~n",[Num]),
rand().
./randstream.escript | ./runavg.escript -s 100 -i 100
should return a list of numbers right around 49 (average between 0 and 100).
No comments:
Post a Comment