计算基于时间的指标(每小时)

Posted

技术标签:

【中文标题】计算基于时间的指标(每小时)【英文标题】:Calculate time based metrics(hourly) 【发布时间】:2013-06-12 14:30:16 【问题描述】:

如何根据日志文件数据计算基于时间的指标(每小时平均值)?

让我更清楚地说明这一点,考虑一个包含以下条目的日志文件:每个 UID 在日志中只出现两次。它们将采用嵌入的 xml 格式。而且它们可能会出现乱序。而且日志文件只有一天的数据,所以只有一天的记录。

日志文件中的 UID 数量为 200 万。

我必须找出这些请求的平均每小时响应时间。下面在日志文件中有请求和响应。 UID 是关联黑白请求和响应的关键。

2013-04-03 08:54:19,451 INFO  [Logger] <?xml version="1.0" encoding="UTF-8" standalone="yes"?><log-event><message-time>2013-04-03T08:54:19.448-04:00</message-time><caller>PCMC.common.manage.springUtil</caller><body>&lt;log-message-body&gt;&lt;headers&gt;&amp;lt;FedDKPLoggingContext id="DKP_DumpDocumentProperties" type="context.generated.FedDKPLoggingContext"&amp;gt;&amp;lt;logFilter&amp;gt;7&amp;lt;/logFilter&amp;gt;&amp;lt;logSeverity&amp;gt;255&amp;lt;/logSeverity&amp;gt;&amp;lt;schemaType&amp;gt;PCMC.MRP.DocumentMetaData&amp;lt;/schemaType&amp;gt;&amp;lt;UID&amp;gt;073104c-4e-4ce-bda-694344ee62&amp;lt;/UID&amp;gt;&amp;lt;consumerSystemId&amp;gt;JTR&amp;lt;/consumerSystemId&amp;gt;&amp;lt;consumerLogin&amp;gt;jbserviceid&amp;lt;/consumerLogin&amp;gt;&amp;lt;logLocation&amp;gt;Beginning of Service&amp;lt;/logLocation&amp;gt;&amp;lt;/fedDKPLoggingContext&amp;gt;&lt;/headers&gt;&lt;payload&gt;  
&amp;lt;ratedDocument&amp;gt;  
    &amp;lt;objectType&amp;gt;OLB_BBrecords&amp;lt;/objectType&amp;gt;  
    &amp;lt;provider&amp;gt;JET&amp;lt;/provider&amp;gt;  
    &amp;lt;metadata&amp;gt;&amp;amp;lt;BooleanQuery&amp;amp;gt;&amp;amp;lt;Clause   occurs=&amp;amp;quot;must&amp;amp;quot;&amp;amp;gt;&amp;amp;lt;TermQuery   fieldName=&amp;amp;quot;RegistrationNumber&amp;amp;quot;&amp;amp;gt;44565153050735751&amp;amp;lt;/TermQuery&amp;amp;gt;&amp;amp;lt;/Clause&amp;amp;gt;&amp;amp;lt;/BooleanQuery&amp;amp;gt;&amp;lt;/metadata&amp;gt;  
&amp;lt;/ratedDocument&amp;gt;  
&lt;/payload&gt;&lt;/log-message-body&gt;</body></log-event>

2013-04-03 08:54:19,989 INFO  [Logger] <?xml version="1.0" encoding="UTF-8" standalone="yes"?><log-event><message-time>2013-04-03T08:54:19.987-04:00</message-time><caller>PCMC.common.manage.springUtil</caller><body>&lt;log-message-body&gt;&lt;headers&gt;&amp;lt;fedDKPLoggingContext id="DKP_DumpDocumentProperties" type="context.generated.FedDKPLoggingContext"&amp;gt;&amp;lt;logFilter&amp;gt;7&amp;lt;/logFilter&amp;gt;&amp;lt;logSeverity&amp;gt;255&amp;lt;/logSeverity&amp;gt;&amp;lt;schemaType&amp;gt;PCMC.MRP.DocumentMetaData&amp;lt;/schemaType&amp;gt;&amp;lt;UID&amp;gt;073104c-4e-4ce-bda-694344ee62&amp;lt;/UID&amp;gt;&amp;lt;consumerSystemId&amp;gt;JTR&amp;lt;/consumerSystemId&amp;gt;&amp;lt;consumerLogin&amp;gt;jbserviceid&amp;lt;/consumerLogin&amp;gt;&amp;lt;logLocation&amp;gt;Successful Completion of    Service&amp;lt;/logLocation&amp;gt;&amp;lt;/fedDKPLoggingContext&amp;gt;&lt;/headers&gt;&lt;payload&gt;0&lt;/payload&gt;&lt;/log-message-body&gt;</body></log-event>

这是我编写的 bash 脚本。

uids=cat $i|grep "Service" |awk 'BEGIN FS="lt;";RS ="gt;" print $2;'| sort -u
for uid in $uids; do  
    count=`grep "$uid" test.log|wc -l`
    if [ "$count" -ne "0" ]; then
        unique_uids[counter]="$uid"
        let counter=counter+1   
    fi   
done


echo $unique_uids[@]   
echo $counter  
echo " Unique No:" $#unique_uids[@]
echo uid StartTime EndTime" > $log

for unique_uids in $unique_uids[@] ; do
    responseTime=`cat $i|grep "$unique_uids" |awk 'split($2,Arr,":|,"); print Arr[1]*3600000+Arr[2]*60000+Arr[3]*1000+Arr[4]'|sort -n`
    echo $unique_uids $responseTime >> $log
done

输出应该是这样的 操作来自id,Consumer来自documentmetadata,hour是时间08:54:XX 因此,如果我们有多个请求和响应,则需要平均该时间的请求响应时间。

操作消费者 HOUR 平均响应时间(毫秒) DKP_DumpDocumentProperties MRP 08 538

【问题讨论】:

使用更强大的工具,比如 Python 怎么样?使用awk/sed/bash/... 这样做有点疯狂,恕我直言... 我没有看到响应时间。是989,389吗?但是你可以只使用两个长度为 24 的数组。一个做总和,一个做计数。 获得所需的输出以使其更清晰会有所帮助。 @random_thoughts 你的问题听起来真的像“我不懂 Python,请给我写一些代码”。这对 SO 来说不是一个好问题,您可能应该聘请一名程序员 这是简单的文本处理,你不需要 Python,它是 awk 被发明用来做的并且做得很好的唯一一件事。它加入了所有其他的 shell 工具和结构,让你的代码变得如此混乱。 【参考方案1】:

鉴于您发布的输入文件:

$ cat file
2013-04-03 08:54:19,989 INFO [LOGGER] <?xml version="1.0" encoding="UTF-8" standalone="yes"?><event><body>&amp;lt;UId&amp;gt;904c-be-4e-bbda-3e62&amp;lt;/UId&amp;gt;&amp;lt;</body></event>
2013-04-03 08:54:39,389 INFO [LOGGER] <?xml version="1.0" encoding="UTF-8" standalone="yes"?><event><body>&amp;lt;UId&amp;gt;904c-be-4e-bbda-3e62&amp;lt;/UId&amp;gt;&amp;lt;</body></event>
2013-04-03 08:54:34,979 INFO [LOGGER] <?xml version="1.0" encoding="UTF-8" standalone="yes"?><event><body>&amp;lt;UId&amp;gt;edfc-fr-5e-bced-3443&amp;lt;/UId&amp;gt;&amp;lt;</body></event>
2013-04-03 08:55:19,569 INFO [LOGGER] <?xml version="1.0" encoding="UTF-8" standalone="yes"?><event><body>&amp;lt;UId&amp;gt;edfc-fr-5e-bced-3443&amp;lt;/UId&amp;gt;&amp;lt;</body></event>

此 GNU awk 脚本(您使用的是 GNU awk,因为您在问题中发布的脚本中将 RS 设置为多字符串)

$ cat tst.awk

    date = $1
    time = $2
    guid = gensub(/.*;gt;([^&]+).*/,"\\1","")

    print guid, date, time

会抽出我认为是你关心的信息:

$ gawk -f tst.awk file
904c-be-4e-bbda-3e62 2013-04-03 08:54:19,989
904c-be-4e-bbda-3e62 2013-04-03 08:54:39,389
edfc-fr-5e-bced-3443 2013-04-03 08:54:34,979
edfc-fr-5e-bced-3443 2013-04-03 08:55:19,569

剩下的就是简单的数学,对吧?并在这个 awk 脚本中执行 - 不要将 awk 输出通过管道传递到一些愚蠢的 shell 循环!

【讨论】:

感谢 Ed,我正在尝试了解 gensub 的工作原理,如果有帮助会发表评论 Ed,一个问题 - 我的日志文件有一些不需要的行。如何过滤它们,或者更清楚地说,我需要带有 UID 的行 cat test.log |grep INFO| awk -f tst.awk > uid.log 更新您的问题以显示您真实的、有代表性的输入和预期输出。从您的 cmets 中不清楚您想要什么,例如您是否要选择仅包含单词 INFO 的行或符合描述 UID 或其他内容的某些模式的行?对于 gensub() - 它基本上像 sed 一样工作,请阅读手册页 gnu.org/software/gawk/manual/gawk.html#String-Functions。 从日志文件中添加了请求和响应【参考方案2】:

扩展Ed Morton's解决方案:

script.awk 的内容

function parse_time (date, time,        newtime) 
    gsub(/-/, " ", date)
    gsub(/:/, " ", time)
    gsub(/,.*/, "", time)
    newtime = date" "time
    return newtime


(gensub(/.*;gt;([^&]+).*/,"\\1","") in starttime) 
    etime = parse_time($1, $2)
    endtime[gensub(/.*;gt;([^&]+).*/,"\\1","")] = etime
    next


    stime = parse_time($1, $2)
    starttime[gensub(/.*;gt;([^&]+).*/,"\\1","")] = stime


END 
    for (x in starttime) 
        for (y in endtime) 
            if (x==y) 
                diff = mktime(endtime[x]) - mktime(starttime[y])
                diff = sprintf("%dh:%dm:%ds",diff/(60*60),diff%(60*60)/60,diff%60)
                print x, diff
                delete starttime[x]
                delete endtime[y]
             
        
    

测试:修改了测试的guid顺序

$ cat log.file 
2013-04-03 08:54:19,989 INFO [LOGGER] <?xml version="1.0" encoding="UTF-8" standalone="yes"?><event><body>&amp;lt;UId&amp;gt;904c-be-4e-bbda-3e62&amp;lt;/UId&amp;gt;&amp;lt;</body></event>
2013-04-03 08:54:34,979 INFO [LOGGER] <?xml version="1.0" encoding="UTF-8" standalone="yes"?><event><body>&amp;lt;UId&amp;gt;edfc-fr-5e-bced-3443&amp;lt;/UId&amp;gt;&amp;lt;</body></event>
2013-04-03 08:54:39,389 INFO [LOGGER] <?xml version="1.0" encoding="UTF-8" standalone="yes"?><event><body>&amp;lt;UId&amp;gt;904c-be-4e-bbda-3e62&amp;lt;/UId&amp;gt;&amp;lt;</body></event>
2013-04-03 08:55:19,569 INFO [LOGGER] <?xml version="1.0" encoding="UTF-8" standalone="yes"?><event><body>&amp;lt;UId&amp;gt;edfc-fr-5e-bced-3443&amp;lt;/UId&amp;gt;&amp;lt;</body></event>
$ awk -f script.awk log.file 
904c-be-4e-bbda-3e62 0h:0m:20s
edfc-fr-5e-bced-3443 0h:0m:45s

【讨论】:

感谢杰帕尔!我试图了解 AWK gensub,我观察到我的日志文件有嵌套的 xml。如果有效,会尽快回复您。 另一个条件是:这些 uid 应该成对出现,以表明请求已完成。如果日志中只有一个 uid,我不想要响应时间。 Jaypal,有什么方法可以计算以毫秒为单位的响应时间。 08:54:19.989 这里 989 以毫秒为单位。

以上是关于计算基于时间的指标(每小时)的主要内容,如果未能解决你的问题,请参考以下文章

如何使用谷歌分析每小时,每天,每月查询

熊猫 - 计算每小时平均滚动 10 分钟

Java计算两个日期时间相差几天,几小时,几分钟等

Java计算两个日期时间相差几天,几小时,几分钟等

富士康里的UPPH和UPH分别是啥意思,求解

计算由时间间隔分隔的连续每小时记录块的平均值