我可以使用日志分析器,但通常我需要解析最近的网络日志才能了解当前发生的情况。
我有时会做一些事情,比如找出请求某个文件的前 10 个 IP
cat foo.log | grep request_to_file_foo | awk '{print $1}' | sort -n | uniq -c | sort -rn | head
您的工具箱里有什么?
答案1
仅使用 awk,您就可以对 apache 日志文件进行几乎任何操作。Apache 日志文件基本上是用空格分隔的,您可以假装引号不存在,然后按列号访问您感兴趣的任何信息。只有在您使用组合日志格式并对用户代理感兴趣时,这种情况才会发生,此时您必须使用引号 (") 作为分隔符并运行单独的 awk 命令。以下将向您显示请求索引页的每个用户的 IP,按点击次数排序:
awk -F'[ "]+' '$7 == "/" { ipcount[$1]++ }
END { for (i in ipcount) {
printf "%15s - %d\n", i, ipcount[i] } }' logfile.log
$7 是请求的 URL。您可以在开头添加任何您想要的条件。将 '$7 == "/" 替换为您想要的任何信息。
如果您替换 (ipcount[$1]++) 中的 $1,则可以按其他条件对结果进行分组。使用 $7 将显示访问了哪些页面以及访问频率。当然,您会希望在开始时更改条件。以下将显示来自特定 IP 的用户访问了哪些页面:
awk -F'[ "]+' '$1 == "1.2.3.4" { pagecount[$7]++ }
END { for (i in pagecount) {
printf "%15s - %d\n", i, pagecount[i] } }' logfile.log
您还可以通过 sort 管道传输输出以按顺序获取结果,可以作为 shell 命令的一部分,也可以在 awk 脚本本身中获取:
awk -F'[ "]+' '$7 == "/" { ipcount[$1]++ }
END { for (i in ipcount) {
printf "%15s - %d\n", i, ipcount[i] | sort } }' logfile.log
如果您决定扩展 awk 脚本以打印出其他信息,后者将很有用。这完全取决于您想要查找的内容。这些应该可以作为您感兴趣的任何内容的起点。
答案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-agents 执行相同的操作,那么这真的很棒。如果您的日志以空格分隔,则必须手动进行一些正则表达式匹配或字符串搜索。使用这种格式,很简单:
cut -f 8 log | uniq -c | sort -n
和上面的完全一样。事实上,任何你想做的总结本质上都是完全一样的。
既然 cut 可以以快几个数量级的速度完成我想要的任务,我为何要将系统的 CPU 浪费在 awk 和 grep 上?
答案3
忘掉 awk 和 grep。查看查询语言。当您可以使用类似 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;
答案4
对于访问日志中的 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 $5}' | 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 $2}'\`;do echo -n "$i|"| sed 's/\./\\\./g;';done`127\.|0\.0\.0)" | sort -n | uniq -c | sort -n
这些都是我最喜欢的“俏皮话” :)