我可以使用日志分析器,但是通常我需要解析最近的Web日志以了解当前发生的情况。
我有时会做一些事情来弄清楚需要某个文件的前10个ips
cat foo.log | grep request_to_file_foo | awk '{print }' | sort -n | uniq -c | sort -rn | head
您的工具箱中有什么? br />
#1 楼
仅使用awk,您就可以使用apache日志文件执行几乎所有操作。 Apache日志文件基本上是用空格分隔的,您可以假装引号不存在,并可以按列号访问任何您感兴趣的信息。只有当您具有合并的日志格式并且对用户代理感兴趣时,这种情况才会出现问题,这时您必须使用引号(“)作为分隔符并运行单独的awk命令。以下内容将向您显示IP每个请求索引页的用户均按命中数排序:awk -F'[ "]+' ' == "/" { ipcount[]++ }
END { for (i in ipcount) {
printf "%15s - %d\n", i, ipcount[i] } }' logfile.log
$ 7是请求的网址。您可以在开头添加任何条件。替换'$ 7 ==“ /”带有您想要的任何信息。
如果您将(ipcount [$ 1] ++)中的$ 1替换为,则可以按其他条件对结果进行分组。使用$ 7将显示访问了哪些页面以及访问了多久。当然,您首先需要更改条件,以下内容将显示用户从特定IP访问了哪些页面:
awk -F'[ "]+' ' == "1.2.3.4" { pagecount[]++ }
END { for (i in pagecount) {
printf "%15s - %d\n", i, pagecount[i] } }' logfile.log
您还可以通过管道将输出通过排序以按顺序获取结果,这既可以作为shell命令的一部分,也可以在awk脚本本身中进行:
awk -F'[ "]+' ' == "/" { ipcount[]++ }
END { for (i in ipcount) {
printf "%15s - %d\n", i, ipcount[i] | sort } }' logfile.log
如果您决定扩展awk脚本以输出其他信息,则后者将很有用。这完全取决于您要查找的内容。这些应该作为您感兴趣的任何内容的起点。
评论
是的,看到疯狂的长cat / grep / awk管道总是很奇怪。一旦您进入awk,通常就足够了。原始帖子的前三个子句可以简单地写为“ awk'/ request_to_file_foo / {print $ 1}'foo.log”。 awk可以将文件作为输入,并且可以使用正则表达式知道要关注的行。
–扎克·汤普森(Zac Thompson)
09年6月4日在6:06
优雅而简单。好。
–奥利维尔·杜拉克(Olivier Dulac)
2015年2月12日下午6:53
当心,在“ authuser”(第3个)字段中似乎允许使用空格,这会破坏所有内容,我个人认为应该禁止这样做,以允许我们这样做;-)
–曼达克
15年6月16日在9:31
#2 楼
出于我无法想象的原因,我从未见过别人做过的一件事,就是将Apache日志文件格式更改为一个更易解析的版本,其中包含实际对您重要的信息。例如,我们从不使用HTTP基本身份验证,因此我们不需要记录这些字段。我对每个请求的处理时间感兴趣,因此我们将其添加进去。对于一个项目,我们还想知道(在负载均衡器上)是否有任何服务器在处理请求的速度比其他服务器慢,因此我们记录该名称我们要代理回去的服务器。
这是一台服务器的apache配置的摘录:
# We don't want to log bots, they're our friends
BrowserMatch Pingdom.com robot
# Custom log format, for testing
#
# date proto ipaddr status time req referer user-agent
LogFormat "%{%F %T}t %p %a %>s %D %r %{Referer}i %{User-agent}i" standard
CustomLog /var/log/apache2/access.log standard env=!robot
真正不能做什么由此可知,每个字段之间是一个文字制表符(\ t)。这意味着,如果我想用Python做一些分析,例如显示非200状态,我可以这样做:
for line in file("access.log"):
line = line.split("\t")
if line[3] != "200":
print line
或者如果我想做谁在热链接图像?
if line[6] in ("","-") and "/images" in line[5]:
对于访问日志中的IP计数,上一个示例:
grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" logfile | sort -n | uniq -c | sort -n
像这样的东西:
cut -f 3 log | uniq -c | sort -n
易于阅读和理解,并且计算量大为减少(无正则表达式),这在9 GB的日志上使时间长短有很大的不同它需要。当这变得很整洁时,就是要对User-agent做同样的事情。如果日志是用空格分隔的,则必须手动进行一些正则表达式匹配或字符串搜索。使用这种格式,很简单:
cut -f 8 log | uniq -c | sort -n
与上述完全相同。实际上,您想要执行的任何摘要基本上是完全相同的。
为什么在切割时我会在awk和grep上花费系统的CPU来完成我想要的数量级更快的事情?
评论
新格式的示例实际上仍然过于复杂-IP计数已减少-f 3 log | uniq -c |排序-n,用户代理剪切-f 8日志| uniq -c |排序-n。
–Creshal
2012-04-25 13:40
没错,这很简单。我已经更新了示例以反映这一点。
–丹·乌迪(Dan Udey)
2012年5月28日在22:15
“猫文件| grep字符串”是没有用的,为什么不“ grep字符串文件”呢?
–c4f4t0r
15年1月27日在13:28
我没有任何借口,并相应地更新了示例。
–丹·乌迪(Dan Udey)
15年2月27日在21:56
#3 楼
忘记awk和grep。检出asql。当您可以使用类似sql的语法查询日志文件时,为什么还要编写不可读的脚本。例如asql v0.6 - type 'help' for help.
asql> load /home/skx/hg/engaging/logs/access.log
Loading: /home/skx/hg/engaging/logs/access.log
sasql> select COUNT(id) FROM logs
46
asql> alias hits SELECT COUNT(id) FROM logs
ALIAS hits SELECT COUNT(id) FROM logs
asql> alias ips SELECT DISTINCT(source) FROM logs;
ALIAS ips SELECT DISTINCT(source) FROM logs;
asql> hits
46
asql> alias
ALIAS hits SELECT COUNT(id) FROM logs
ALIAS ips SELECT DISTINCT(source) FROM logs;
评论
有趣,但是如果您认为日志特别大,可能会遇到问题。还可以很好地处理自定义日志格式吗?
– Vagnerr
2009年6月5日13:39
我目前正在尝试,加载时间太慢(至少在0.9版中)。加载200Mb日志需要花费超过五分钟的时间。
–古迹
2011-12-15 11:17
我必须说,加载时间(花费了大约15分钟)之后,该程序的语法很棒,您可以对它进行排序,计数和分组。非常好。
–古迹
2011-12-15 17:19
Apache HTTPD提供了一种可以有效地将日志发送到数据库的方法。是的,写操作可能会花费很长时间,但是线程代理可能只是做中间的正确事情。无论如何,这将使查询类似语法的SQL的日志快得多。也不涉及加载-数据库服务器永久处于“ ON”状态。
–earearora
2012年5月28日23:16
我不知道这样的事情存在!对于已经非常熟悉SQL的Web开发人员,这是一个不错的选择。
– rinogo
20-09-21在20:20
#4 楼
这是一个脚本,用于从最近的N个日志条目中查找顶部URL,顶部引荐来源网址和顶部用户代理。#!/bin/bash
# Usage
# ls-httpd type count
# Eg:
# ls-httpd url 1000
# will find top URLs in the last 1000 access log entries
# ls-httpd ip 1000
# will find top IPs in the last 1000 access log entries
# ls-httpd agent 1000
# will find top user agents in the last 1000 access log entries
type=
length=
if [ "" == "" ]; then
log_file="/var/log/httpd/example.com-access_log"
else
log_file=""
fi
if [ "$type" = "ip" ]; then
tail -n $length $log_file | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | sort -n | uniq -c | sort -n
elif [ "$type" = "agent" ]; then
tail -n $length $log_file | awk -F\" '{print }'| sort -n | uniq -c | sort -n
elif [ "$type" = "url" ]; then
tail -n $length $log_file | awk -F\" '{print }'| sort -n | uniq -c | sort -n
fi
源
#5 楼
访问日志中的IP计数:cat log | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | sort -n | uniq -c | sort -n
有点难看,但是可以。我还将以下内容与netstat一起使用(以查看活动的连接):
netstat -an | awk '{print }' | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | egrep -v "(`for i in \`ip addr | grep inet |grep eth0 | cut -d/ -f1 | awk '{print }'\`;do echo -n "$i|"| sed 's/\./\\./g;';done`127\.|0\.0\.0)" | sort -n | uniq -c | sort -n
它们是我最喜欢的“一个衬里” :)
#6 楼
建立常见问题列表将是此问题答案的重要索引。我的常见问题是:为什么命中率发生变化?
为什么总响应时间在增加?'。
我通过监视发现这种变化服务器状态页(通过mod_status),用于
命中率和活动请求和最近完成的请求的近似响应时间
(知道我很想念大量数据,但是样本足够好)。
我使用以下LogFormat指令(%T确实有用)
LogFormat "%h %l %u %t \"%r\" %>s %b
\"%{Referer}i\" \"%{User-Agent}i\" %T" custom
我正在寻找因果关系以及发生了什么首先...
通常是关于日志中特定模式的子集,
所以对于任何给定的模式/正则表达式,我需要了解以下内容:
hitcounts给定模式(ip地址或cgi字符串或参数等)的每个间隔(分钟或小时)
近似响应时间的直方图(使用%T参数)
我通常使用perl,因为最终它变得足够复杂,值得使用。
非Perl的示例对于非200状态代码,le将是每分钟的快速命中率:
tail -9000 access_log | grep -v '" 200 ' | cut -d: -f2,3 | uniq -c
是的,我正在欺骗该grep,假定quote-space-200-space仅匹配http状态代码。...可以使用awk或perl隔离该字段,但要记住这可能是不准确的。
perl中更复杂的示例可能是可视化一个
下面的脚本有很多东西值得咀嚼,特别是如果您不熟悉perl的话。
读stdin以便您可以使用部分日志,使用尾部(尤其是带有尾部-f的尾部),
带有或不带有毛刺以及其他过滤功能...
欺骗时期的时间戳记,并带有正则表达式并使用Date :: Manip
您只能对其进行少量修改以提取响应时间或其他任意数据
代码如下:
#!/usr/bin/perl
# script to show changes in hitrates for any regex pattern
# results displayed with arbitrary intervals
# and ascii indication of frequency
# gaps are also displayed properly
use Date::Manip;
use POSIX qw(strftime);
$pattern=shift || ".";
$ival=shift || 60;
$tick=shift || 10;
$minb=undef;
while (<>){
next unless /$pattern/;
$stamp=" " if m[(../.../....):(..:..:..)];
$epoch = UnixDate(ParseDate($stamp),"%s");
$bucket= int($epoch/$ival)*$ival;
$minb=$bucket if $bucket<$minb || !defined($minb);
$maxb=$bucket if $bucket>$maxb;
$count{$bucket}++;
}
# loop thru the min/max range to expose any gaps
for($t=$minb;$t<=$maxb;$t+=$ival){
printf "%s %s %4d %s\n",
$t,
strftime("%m/%d/%Y %H:%M:%S",localtime($t)),
$count{$t}+0,
substr("x"x100,0,$count{$t}/$tick
);
}
如果您只想处理标准指标,请结帐
“ mergelog”以将所有日志(如果您在负载均衡器后面有多个补丁)放在一起,并
webalizer(或awstats或其他常见分析器)。
#7 楼
在我的“ sed”示例中,它读取apache日志的默认格式,并将其转换为更便于自动处理的格式。整行定义为正则表达式,变量保存并写入输出,并以'#'作为分隔符。输入的简化表示法是:
%s%s%s [ %s]“%s”%s%s“%s”“%s”
示例输入行:
xx.xx.xx.xx--[2011年3月29日:12:33:02 +0200]“ GET /index.html HTTP / 1.0” 200 9443“-”“ Mozilla / 4.0”
示例输出行:
xx.xx.xx .xx#-#-#29 / Mar / 2011:12:33:02 + 0200#GET /index.html HTTP / 1.0#200#9443#-#Mozilla / 4.0
cat access.log | \
sed 's/^\(.*\) \(.*\) \(.*\) \[\(.*\)\] \"\(.*\)\" \(.*\) \(.*\) \"\(.*\)\" \"\(.*\)\"$/########/g'
感受正则表达式的力量:-)
评论
这使得使用AWK进行处理变得轻而易举。正在寻找一种设置通用分隔符的快速方法,因此非常有用。
– Citricguy
2014年6月12日在3:07
我已经感受到了正则表达式的强大功能,只是想通过我自己的调整来删除“ HTML / 1.1”,并将协议(可能是非标准的兼容方式)分成自己的领域。享受:```cat access.log | sed's /^(.*)(。*)(。*)[(。*)] \“([[:::)] \ +)(。*)HTTP \ / 1 \ .1 \”( 。*)(。*)\“(。*)\” \“(。*)\” $ / \ 1#\ 2#\ 3#\ 4#\ 5#\ 6#\ 7#\ 8#\ 9#\ 10 / g'```
–乔什·朗姆布(Josh Rumbut)
2015年10月6日在18:30
#8 楼
我通过拖尾或整理文件来大量使用awk。每天晚上,我都会为每个服务器提供一份网络报告。根据您的日志文件和LogFormat,您需要编辑一些衬板才能使用。..这是一个简单的示例:
如果我想要仅将404/500状态代码记录在服务器上的日志中,我将这样做:
# is the status code in my log file
tail -f ${APACHE_LOG} | awk ' ~ /(404|500)/ {print }'
echo ""
#echo "Hits by source IP:"
echo "======================================================================"
awk '{print }' "" | grep -ivE "(127.0.0.1|192.168.100.)" | sort | uniq -c | sort -rn | head -25
echo ""
echo ""
#echo "The 25 most popular pages:"
echo "======================================================================"
awk '{print }' "" | grep -ivE '(mod_status|favico|crossdomain|alive.txt)' | grep -ivE '(.gif|.jpg|.png)' | \
sed 's/\/$//g' | sort | \
uniq -c | sort -rn | head -25
echo ""
echo ""
echo "The 25 most popular pages (no js or css):"
echo "======================================================================"
awk '{print }' "" | grep -ivE '(mod_status|favico|crossdomain|alive.txt)' | grep -ivE '(.gif|.jpg|.png|.js|.css)' | \
sed 's/\/$//g' | sort | \
uniq -c | sort -rn | head -25
echo ""
#echo "The 25 most common referrer URLs:"
echo "======================================================================"
awk '{print }' "" | \
grep -vE "(^"-"$|/www.$host|/$host)" | \
sort | uniq -c | sort -rn | head -25
echo ""
#echo "Longest running requests"
echo "======================================================================"
awk '{print ,}' "" | grep -ivE '(.gif|.jpg|.png|.css|.js)' | awk '{secs=0.000001*;req=;printf("%.2f minutes req time for %s\n", secs / 60,req )}' | sort -rn | head -50
exit 0
snip>
#9 楼
谁在热链接您的图像:awk -F\" '( ~ /\.(jpg|gif)/ && !~ /^http:\/\/www\.mydomain\.com/){print }' access_log | sort | uniq -c | sort
#10 楼
我通常大部分时间都在做的事情是基于时间读取日志的各个部分,因此我使用sed编写了以下脚本来提取我感兴趣的时间段,它适用于我所访问的每个日志文件可以处理存档的日志。#!/bin/bash #This script should return a set of lines between 2 values, the main purpose is for searching a log file between 2 times #Script usage: logship.sh "start" "stop" file #If the file contains any "/" in the date range the following 2 lines add the escape character so that the search can be performed for those characters start=$(echo "" | sed 's/\//\\//g') stop=$(echo "" | sed 's/\//\\//g') zipped=$(echo "" | grep -c "gz$") #figures out if the file is zipped or not if [ "$zipped" == "1" ]; then #If the file is zipped then pass it through zcat before sed zcat | sed -n "/$start/,/$stop/p"; else sed -n "/$start/,/$stop/p" ; #if it's not zipped just run sed fi
#11 楼
虽然不sed或awk,但我发现有两件事可用于处理apache和icecast日志文件。AWStats有一个非常有用的脚本,称为logresolvemerge.pl,它将组合多个压缩或未压缩的日志文件。 ,剥离重复并按时间戳排序。它还可以进行DNS查找,并配置为运行多线程。当与awstats一起使用时,它特别有用,因为awstats不能添加时间戳比当前数据库旧的日志行,因此必须按顺序添加所有日志行,但这非常容易,因为您只需将所有内容都放在logresolvemerge.pl中,然后所有内容就会弹出。 sed和awk在处理日期方面非常糟糕,因为它们通常将它们视为字符串。 awk具有一些时间和日期功能,但它们的功能并不完善。例如,如果文件中没有出现那些确切的时间戳(即使它们之间的值确实存在),则很难提取出两个时间戳之间的行范围-克里斯的示例正是有这个问题。为了解决这个问题,我编写了一个PHP脚本,该脚本报告日志文件的时间戳范围,并且还可以使用您喜欢的任何日期或时间格式(无需与日志文件的时间戳格式匹配)按时间戳范围提取块。 br />
要保持这一主题,这里有一些有用的警告:
从apache或icecast日志中获取服务的字节总数:
cat access.log | awk '{ sum += } END { print sum }'
从冰封日志中获取连接的总秒数:
cat access.log | awk '{ sum += } END { print sum }'
评论
+1用于使用awk的简单字节求和Apache日志
– rymo
13年5月31日下午6:54
评论
实际上,我有一个手工编写的美丽的正则表达式,用于将我所有的Apache自定义日志解析为单个字段,以提交到数据库中。我正在踢自己,我已经没有了。那是一个班轮。给您每个日志元素一个变量-然后我将其插入MySQL。如果找到它,我会在这里发布。