0

コンマ区切りの大きなログファイルがあります。いくつかの情報を解析したいと思います。

 2010-02-10 10:00:00.000 171.606 bad_gateway
 2010-02-10 10:00:00.234 400.680 bad_gateway
 2010-02-10 10:00:00.410 212.308 login_from
 2010-02-10 10:00:00.601 222.251 bad_gateway

問題は、時間範囲 (例: 10:00:00.000 から 11:00:00.000 の間) でオカレンスを書き出す必要があり、期間の長さで 1 分間に何回あったかをカウントする必要があることです。次のような出力ファイルを作成しようとしています。

 bad_gateway
 10:00
       AVG     <1ms     1-10ms   10-100ms  100-500ms     500+ms
       264.845                                     3

 login_from
 10:00
       AVG     <1ms     1-10ms   10-100ms  100-500ms     500+ms
       212.308                                     1

 bad_gateway                                
 10:01
       AVG     <1ms     1-10ms   10-100ms  100-500ms     500+ms
       xxx.xxx                                     x

awkで理解しようとしましたが、立ち往生しました。助けてくれてありがとう!

これが私が今まで得たものです:

   BEGIN {
low["<1ms"]=0;high["<1ms"]=1
low["1-10ms"]=1;high["1-10ms"]=10
low["10-100ms"]=10;high["10-100ms"]=100
low["100-500ms"]=100;high["100-500ms"]=500
low[">500ms"]=500;high[">500ms"]=1000000000
 }
 {
    for (i in high) {
    if ((duration > low[i]) && (duration <= high[i]) ) {
    total+=duration
    bin[i]++
    count++
}
}
}

END セクションでは、printf を実行します。

4

2 に答える 2

3

徹底的にテストするには、入力データが不足しています。ここに、awk探していることを多かれ少なかれ実行するスクリプトがあります。完全にコメントされているので、ここから必要に応じて変更できます。

の内容script.awk:

BEGIN {
    header = sprintf( "\t%-10s\t%10s\t%10s\t%10s\t%10s\t%10s", "AVG", "<1ms", "1-10ms", "10-100ms", "100-500ms", "500+ms" )

    ## Output slices if time.
    slices = "1 10 100 500"
    split( slices, slices_a )

    ## Hardcoded start and end times.
    start_time = mktime( "2010 02 10 10 00 00" )
    end_time = mktime( "2010 02 10 11 00 00" )
}

{
    ## Extract hour, minute and second from time.
    fields = split( $2, time, /[:.]/ )
    if ( fields != 4 ) { print "WARNING: Skipped line " FNR " because had bad formatted time." }

    ## Save previous time to be able to compare if a second has passed. First line is
    ## a special case because there is not yet a saved value.
    if ( FNR == 1 ) { 
        prev_time = mktime( "2010 02 10 " time[1] " " time[2] " " time[3] )
    }
    else { 
        curr_time = mktime( "2010 02 10 " time[1] " " time[2] " " time[3] )

        ## When a second has passed, print all extracted data.
        if ( curr_time - prev_time > 59 ) {

            print_minute_info(duration, prev_time, header, slices_a)

            ## Initialize data.
            prev_time = curr_time
            delete duration
        }
    }

    ## For each name (last field) concatenate durations.
    duration[ $NF ] = duration[ $NF] "|" $3
}

END {
    print_minute_info(duration, prev_time, header, slices_a)
}

## Traverse hash with following format (example):
## duration[ bad_gateway ] = "|34.567|234.918|56.213|"
##
## So, for each key split with pipe, sum its values and try to
## print a formatted output.
function print_minute_info(duration,prev_time,header,slices_a,       name,sum,times,times_a,num_times,i,times_avg,printed) {
    for ( name in duration ) {
        sum = 0
        times = substr( duration[name], 2 )
        split( times, times_a, /\|/ )
        num_times = length( times_a )
        for ( i = 1; i <= num_times; i++ ) {
            sum = sum + times_a[i]
        }
        times_avg = sum / num_times

        printf "%s\n", name
        printf "%s\n", strftime( "%H:%M", prev_time )
        printf "%s\n", header
        printf  "\t%-10s", times_avg

        ## This part tries to print the number of ocurrences just
        ## below its header. It can be improved.
        for ( i = 1; i <= length( slices_a ); i++ ) {
            if ( times_avg < slices_a[i] ) {
                printf "%10d\n", num_times
                printed = 1
                break
            }
            else {
                printf "\t%10s", ""
            }
        }
        if ( ! printed ) {
            printf "%10d\n", num_times
        }
        printf "\n"
    }
}

そして、次のことを前提としていますinfile

2010-02-10 10:00:00.000 171.606 bad_gateway
2010-02-10 10:00:00.234 400.680 bad_gateway
2010-02-10 10:00:00.410 212.308 login_from
2010-02-10 10:00:00.601 223.251 bad_gateway
2010-02-10 10:01:00.401 224.251 bad_gateway
2010-02-10 10:01:00.701 225.251 bad_gateway
2010-02-10 10:01:04.401 226.251 login_to
2010-02-10 10:02:04.401 1.251 login_to

次のように実行します。

awk -f script.awk infile

これにより、次の結果が得られます。

login_from
10:00
    AVG               <1ms      1-10ms    10-100ms   100-500ms      500+ms
    212.308                                                1

bad_gateway
10:00
    AVG               <1ms      1-10ms    10-100ms   100-500ms      500+ms
    265.179                                                3

bad_gateway
10:01
    AVG               <1ms      1-10ms    10-100ms   100-500ms      500+ms
    224.751                                                2

login_to
10:01
    AVG               <1ms      1-10ms    10-100ms   100-500ms      500+ms
    226.251                                                1

login_to
10:02
    AVG               <1ms      1-10ms    10-100ms   100-500ms      500+ms
    1.251                          1
于 2013-05-27T10:18:02.960 に答える
1

私は awk に十分に精通していませんが、perl で行うのは非常に簡単です... データをバケットにビン化するには、通常、ハッシュまたは配列データ構造を使用する必要があります。フィールドを正規表現で抽出し、ハッシュを使用してカウンターであるバケットを作成し、出現ごとにカウンターを次のようにインクリメントします。

while( <> ) { # iterate over input file
   // extract fields here... e.g.
   //   $errType =~ /(\S+)$/;
   // etc.
   $bins->{$errType}{$time}{$duration}++;
}

# now iterate over hashes and print out your report
foreach $key1 ( keys %$bins ) {
    foreach ...
}

あなたが探していた答えではありませんが、正しい道に進むことができるかもしれません。

于 2013-05-26T23:03:00.947 に答える