本文概述
- 我们的PHP日志文件示例项目
- 配置日志文件的提示
- 其他值得一提的日志
- 写入日志文件
- 最大化你的PHP日志文件的价值
- 分析日志文件中的数据
- 其他注意事项
- 总结
- 资源资源
- 附录:在Unix Shell中读取和处理日志文件
实际上, 在许多情况下, PHP日志文件应该是出现问题时寻找线索的第一位。通常, 它们包含的信息可能会大大减少拉动头发以查找过时的臭虫所花费的时间。
但是, 也许更重要的是, 通过一点点创新和深谋远虑, 你的日志文件可以用作使用信息和分析的重要来源。创造性地使用日志文件可以帮助回答以下问题:哪些浏览器最常用于访问我的网站?我的服务器平均响应时间是多少?站点根请求的百分比是多少?自部署最新更新以来, 用法有何变化?还有更多。
文章图片
本文提供了许多有关如何配置日志文件以及如何处理它们包含的信息的技巧, 以最大程度地发挥日志文件的作用。
尽管本文从技术上侧重于PHP开发人员的日志记录, 但本文中提供的许多信息在技术上都是不可知的, 并且还与其他语言和技术堆栈相关。注意:本文假定对Unix shell基本熟悉。对于那些缺乏这些知识的人, 提供了附录, 其中介绍了一些在Unix系统上访问和读取日志文件所需的命令。
我们的PHP日志文件示例项目 作为本文中用于讨论目的的示例项目, 我们将把Symfony Standard当作一个工作项目, 并使用rsyslogd, nginx和PHP-FPM在Debian 7 Wheezy上进行设置。
composer create-project symfony/framework-standard-edition my "2.6.*"
这很快为我们提供了具有良好UI的可运行测试项目。
配置日志文件的提示 以下是有关如何配置日志文件以最大程度地提高其价值的一些提示。
错误日志配置
错误日志代表最基本的日志记录形式;即在发生问题时捕获其他信息和详细信息。因此, 在理想情况下, 你希望没有错误, 并且错误日志为空。但是, 当确实发生问题时(就像它们总是一样), 你的错误日志应该是你在调试跟踪中所做的第一站。
错误日志通常很容易配置。
一方面, 所有错误和崩溃消息都可以以与错误消息完全相同的格式记录在错误日志中, 否则它们将呈现给用户。通过一些简单的配置, 最终用户将不再需要在你的站点上看到这些丑陋的错误跟踪, 而devops仍然可以监视系统并仔细查看所有错误消息。以下是在PHP中设置这种登录方式的方法:
log_errors = On
error_reporting = E_ALL
error_log = /path/to/my/error/log
为防止出现错误的详细级别, 将两行包含在实时站点的日志文件中很重要, 它们是:
display_errors = Off
display_startup_errors = Off
系统日志(syslog)配置
开源世界中syslog守护程序有许多通常兼容的实现, 包括:
- syslogd和sysklogd –最常见于BSD系列系统, CentOS, Mac OS X等
- syslog-ng –现代Gentoo和SuSE构建的默认设置
- rsyslogd –广泛用于Debian和Fedora系列操作系统
基本的syslog配置通常足以捕获系统范围日志文件中的日志消息(通常为/ var / log / syslog;根据发行版的不同, 可能为/ var / log / messages或/var/log/system.log你正在使用)。
系统日志提供了几种日志功能, 其中八种(LOG_LOCAL0至LOG_LOCAL7)保留给用户部署的项目。例如, 这是你可以如何设置LOG_LOCAL0以根据日志记录级别(即错误, 警告, 信息, 调试)写入4个单独的日志文件:
# /etc/rsyslog.d/my.conflocal0.err/var/log/my/err.log
local0.warning/var/log/my/warning.log
local0.info-/var/log/my/info.log
local0.debug-/var/log/my/debug.log
现在, 每当你向LOG_LOCAL0设备写入日志消息时, 错误消息就会转到/var/log/my/err.log, 警告消息将会转到/var/log/my/warning.log, 依此类推。但是请注意, syslog守护程序会根据” 此级别及更高级别” 的规则来过滤每个文件的消息。因此, 在上面的示例中, 所有错误消息都将出现在所有四个已配置的文件中, 警告消息将出现在所有(错误日志除外)中, 信息消息将出现在信息和调试日志中, 而调试消息仅进入debug.log 。
另一项重要说明;在上述配置文件示例中的信息和调试级别文件之前的-号表示应异步执行对这些文件的写入操作(因为这些操作是非阻塞的)。通常, 对于信息和调试日志来说, 这是很好的做法(甚至在大多数情况下甚至建议这样做), 但最好是同步写入错误日志(也可能是警告日志)。
为了关闭次要级别的日志记录(例如, 在生产服务器上), 你可以简单地将相关消息重定向到/ dev / null(即, 无处):
local0.debug/dev/null # -/var/log/my/debug.log
一种特别有用的自定义设置(用于支持我们稍后将在本文中讨论的某些PHP日志文件解析)特别有用, 它是使用tab作为日志消息中的分隔符。通过在/etc/rsyslog.d中添加以下文件, 可以轻松完成此操作:
# /etc/rsyslog.d/fixtab.conf$EscapeControlCharactersOnReceive off
最后, 不要忘记在进行任何配置更改后重新启动syslog守护程序, 以使它们生效:
service rsyslog restart
服务器日志配置
与你可以写入的应用程序日志和错误日志不同, 服务器日志是由每个请求对应的服务器守护程序(例如, Web服务器, 数据库服务器等)专门写入的。你对这些日志的唯一” 控制” 是服务器允许你配置其日志记录功能。尽管这些文件中可能有很多内容需要筛选, 但它们通常是唯一清楚了解服务器” 幕后” 情况的唯一方法。
让我们在具有MySQL存储后端的nginx环境中部署我们的Symfony Standard示例应用程序。这是我们将要使用的nginx主机配置:
server {
server_name my.log-sandbox;
root /var/www/my/web;
location / {
# try to serve file directly, fallback to app.php
try_files $uri /app.php$is_args$args;
}
# DEV
# This rule should only be placed on your development environment
# In production, don't include this and don't deploy app_dev.php or config.php
location ~ ^/(app_dev|config)\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
# PROD
location ~ ^/app\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
# Prevents URIs that include the front controller. This will 404:
# http://domain.tld/app.php/some-path
# Remove the internal directive to allow URIs like this
internal;
}error_log /var/log/nginx/my_error.log;
access_log /var/log/nginx/my_access.log;
}
关于上述最后两个指令:access_log表示常规请求日志, 而error_log表示错误, 并且与应用程序错误日志一样, 值得设置额外的监视以提醒问题, 以便你快速做出反应。
注意:这是一个故意过度简化的nginx配置文件, 仅出于示例目的提供。它几乎不关注安全性和性能, 因此不应在任何” 真实” 环境中原样使用。
这是我们在浏览器中输入http://my.log-sandbox/app_dev.php/并按Enter后在/var/log/nginx/my_access.log中获得的内容。
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /app_dev.php/ HTTP/1.1" 200 6715 "-" "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/framework/css/body.css HTTP/1.1" 200 6657 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/framework/css/structure.css HTTP/1.1" 200 1191 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/css/demo.css HTTP/1.1" 200 2204 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-quick-tour.gif HTTP/1.1" 200 4770 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-demo.gif HTTP/1.1" 200 4053 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /bundles/acmedemo/images/welcome-configure.gif HTTP/1.1" 200 3530 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:28 +0300] "GET /favicon.ico HTTP/1.1" 200 6518 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"
192.168.56.1 - - [26/Apr/2015:16:13:30 +0300] "GET /app_dev.php/_wdt/e50d73 HTTP/1.1" 200 13265 "http://my.log-sandbox/app_dev.php/" "Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"
这表明, 为提供一页服务, 浏览器实际上执行9个HTTP调用。但是, 其中的7个请求是对静态内容的请求, 这些请求是简单明了的。但是, 它们仍然占用网络资源, 而这可以通过使用各种精灵和缩小技术来优化。
尽管这些优化将在另一篇文章中讨论, 但此处的相关之处在于, 我们可以通过使用针对它们的另一个location指令分别将请求记录到静态内容中:
location ~ \.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js)$ {
access_log /var/log/nginx/my_access-static.log;
}
请记住, nginx位置执行简单的正则表达式匹配, 因此你可以包括你希望在站点上分发的尽可能多的静态内容扩展。
解析此类日志与解析应用程序日志没有什么不同。
其他值得一提的日志 值得一提的其他两个PHP日志是调试日志和数据存储日志。
调试日志
关于nginx日志的另一个方便之处是调试日志。我们可以通过将配置的error_log行替换为以下内容来打开它(需要安装nginx调试模块):
error_log /var/log/nginx/my_error.log debug;
相同的设置适用于Apache或你使用的任何其他Web服务器。
顺便说一句, 即使在error_log指令中配置了调试日志, 调试日志也不与错误日志相关。
尽管调试日志确实确实很冗长(例如, 单个nginx请求生成了127KB的日志数据!), 但它仍然非常有用。遍历日志文件可能很麻烦且繁琐, 但是它通常可以快速提供线索和信息, 极大地有助于加快调试过程。
特别是, 调试日志确实可以帮助调试nginx配置, 尤其是最复杂的部分, 例如位置匹配和重写链。
当然, 永远不要在生产环境中启用调试日志。他们还使用的空间量和存储的信息量意味着服务器上的大量I / O负载, 这可能会严重降低整个系统的性能。
数据存储日志
服务器日志的另一种类型(可用于调试)是数据存储日志。在MySQL中, 你可以通过添加以下行来打开它们:
[mysqld]
general_log = 1
general_log_file = /var/log/mysql/query.log
这些日志仅包含按时间顺序服务数据库请求时系统运行的查询列表, 这可能有助于满足各种调试和跟踪需求。但是, 它们不应在生产系统上保持启用状态, 因为它们会产生多余的I / O负载, 从而影响性能。
写入日志文件 PHP本身提供了用于打开, 写入和关闭日志文件的功能(分别为openlog(), syslog()和closelog())。
还为PHP开发人员提供了许多日志记录库, 例如Monolog(在Symfony和Laravel用户中很受欢迎), 以及各种特定于框架的实现, 例如CakePHP中包含的日志记录功能。通常, 像Monolog这样的库不仅包装syslog()调用, 而且还允许使用其他后端功能和工具。
这是有关如何写入日志的简单示例:
<
?phpopenlog(uniqid(), LOG_ODELAY, LOG_LOCAL0);
syslog(LOG_INFO, 'It works!');
我们在这里致电openlog:
- 配置PHP以在脚本有效期内为每个系统日志消息添加唯一标识符
- 将其设置为延迟打开syslog连接, 直到发生第一次syslog()调用
- 将LOG_LOCAL0设置为默认日志记录工具
# cat /var/log/my/info.log
Mar2 00:23:29 log-sandbox 54f39161a2e55: It works!
最大化你的PHP日志文件的价值 既然我们都具备理论和基础知识, 那么让我们看看从对示例Symfony Standard项目进行尽可能少的更改的日志中可以获得多少收益。
首先, 我们创建脚本src / log-begin.php(以正确打开和配置日志)和src / log-end.php(以记录有关成功完成的信息)。请注意, 为简单起见, 我们只将所有消息写入信息日志。
# src/log-begin.php<
?phpdefine('START_TIME', microtime(true));
openlog(uniqid(), LOG_ODELAY, LOG_LOCAL0);
syslog(LOG_INFO, 'BEGIN');
syslog(LOG_INFO, "URI\t{$_SERVER['REQUEST_URI']}");
$browserHash = substr(md5($_SERVER['HTTP_USER_AGENT']), 0, 7);
syslog(LOG_INFO, "CLIENT\t{$_SERVER['REMOTE_ADDR']}\t{$browserHash}");
<
br />
# src/log-end.php<
?phpsyslog(LOG_INFO, "DISPATCH TIME\t" . round(microtime(true) - START_TIME, 2));
syslog(LOG_INFO, 'END');
让我们在app.php中要求以下脚本:
<
?phprequire_once(dirname(__DIR__) . '/src/log-begin.php');
syslog(LOG_INFO, "MODE\tPROD");
# original app.php contentsrequire_once(dirname(__DIR__) . '/src/log-end.php');
对于开发环境, 我们也希望在app_dev.php中也需要这些脚本。这样做的代码与上面的代码相同, 只是我们将MODE设置为DEV而不是PROD。
我们还希望跟踪正在调用哪些控制器, 因此, 在ControllerListener :: onKernelController()方法的开头, 在Acme \ DemoBundle \ EventListener \ ControllerListener中再添加一行:
syslog(LOG_INFO, "CONTROLLER\t" . get_class($event->
getController()[0]));
请注意, 这些更改总共仅增加了15行代码, 但可以共同产生大量信息。
分析日志文件中的数据 首先, 让我们看看为每个页面加载服务需要多少HTTP请求。
根据配置日志的方式, 这是一个请求的日志中的信息:
Mar3 12:04:20 log-sandbox 54f58724b1ccc: BEGIN
Mar3 12:04:20 log-sandbox 54f58724b1ccc: URI/app_dev.php/
Mar3 12:04:20 log-sandbox 54f58724b1ccc: CLIENT 192.168.56.11b101cd
Mar3 12:04:20 log-sandbox 54f58724b1ccc: MODEDEV
Mar3 12:04:23 log-sandbox 54f58724b1ccc: CONTROLLER Acme\DemoBundle\Controller\WelcomeController
Mar3 12:04:25 log-sandbox 54f58724b1ccc: DISPATCH TIME4.51
Mar3 12:04:25 log-sandbox 54f58724b1ccc: END
Mar3 12:04:25 log-sandbox 54f5872967dea: BEGIN
Mar3 12:04:25 log-sandbox 54f5872967dea: URI/app_dev.php/_wdt/59b8b6
Mar3 12:04:25 log-sandbox 54f5872967dea: CLIENT 192.168.56.11b101cd
Mar3 12:04:25 log-sandbox 54f5872967dea: MODEDEV
Mar3 12:04:28 log-sandbox 54f5872967dea: CONTROLLER Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController
Mar3 12:04:29 log-sandbox 54f5872967dea: DISPATCH TIME4.17
Mar3 12:04:29 log-sandbox 54f5872967dea: END
因此, 现在我们知道每个页面加载实际上都由两个HTTP请求提供服务。
实际上, 这里有两点值得一提。首先, 每页加载两个请求是为了在开发模式下使用Symfony(我在本文中一直这样做)。你可以通过搜索/app-dev.php/ URL块来识别开发人员模式调用。其次, 假设每次网页加载均通过Symfony应用的两个后续请求进行。正如我们之前在nginx访问日志中看到的, 实际上有更多的HTTP调用, 其中一些是针对静态内容的。
好的, 现在让我们在演示站点上进行一些浏览(以建立日志文件中的数据), 然后看看我们还能从这些日志中学到什么。
自日志文件开始以来, 总共服务了多少个请求?
# grep -c BEGIN info.log
10
它们中的任何一个是否失败(脚本没有关闭而没有结束)?
# grep -c END info.log
10
我们看到BEGIN和END记录的数量匹配, 因此这告诉我们所有调用都成功。 (如果PHP脚本未成功完成, 则不会执行src / log-end.php脚本。)
站点根请求的百分比是多少?
# `grep -cE "\s/app_dev.php/$" info.log`
2
这告诉我们, 网站根目录有2个页面加载。由于我们先前了解到(a)每个页面加载有2个对应用程序的请求, 并且(b)总共有10个HTTP请求, 因此对网站根目录的请求百分比为40%(即2× 2 / 10)。
哪个控制器类负责为站点根请求提供服务?
# grep -E "\s/$|\s/app_dev.php/$" info.log | head -n1
Mar3 12:04:20 log-sandbox 54f58724b1ccc: URI/app_dev.php/# grep 54f58724b1ccc info.log | grep CONTROLLER
Mar3 12:04:23 log-sandbox 54f58724b1ccc: CONTROLLERAcme\DemoBundle\Controller\WelcomeController
在这里, 我们使用请求的唯一ID来检查与该单个请求相关的所有日志消息。因此, 我们能够确定负责服务站点根请求的控制器类是Acme \ DemoBundle \ Controller \ WelcomeController。
哪些IP地址为192.168.0.0/16的客户端访问了该站点?
# grep CLIENT info.log | cut -d":" -f4 | cut -f2 | sort | uniq
192.168.56.1
在这个简单的测试用例中, 正如预期的那样, 只有我的主机才能访问该站点。当然, 这是一个非常简单的示例, 但是它展示的功能(能够分析到你网站的流量来源)显然是非常强大和重要的。
我的网站有多少流量来自FireFox?将1b101cd作为Firefox User-Agent的哈希值, 我可以按照以下方式回答此问题:
# grep -c 1b101cd info.log
8
# grep -c CLIENT info.log
10
答案:80%(即8/10)
【充分利用PHP日志文件(实用指南)】产生缓慢响应的请求的百分比是多少?就本示例而言, 我们将” 慢” 定义为需要5秒钟以上才能提供响应。因此:
# grep "DISPATCH TIME" info.log | grep -cE "\s[0-9]{2, }\.|\s[5-9]\."
2
答案:20%(即2/10)
有人提供过GET参数吗?
# grep URI info.log | grep \?
不, Symfony标准仅使用URL标记, 因此这也告诉我们, 没有人试图入侵该网站。
这些只是相对原始的几个例子, 这些例子可以创造性地利用日志文件来产生有价值的使用信息甚至基本分析。
其他注意事项 确保事物安全
另一个注意事项是安全性。你可能会认为记录请求是一个好主意, 在大多数情况下确实如此。但是, 在将任何潜在的敏感用户信息存储到日志之前, 请务必格外小心。
战斗日志文件膨胀
由于日志文件是文本文件, 你总是向其添加信息, 因此它们一直在增长。由于这是一个众所周知的问题, 因此存在一些控制日志文件增长的相当标准的方法。
最简单的是旋转日志。轮换日志意味着:
- 定期用新的空文件替换日志以进一步写入
- 存储旧文件以供历史记录
- 删除已” 老化” 到足以释放磁盘空间的文件
- 当这些文件发生更改时, 确保应用程序可以写入已损坏的日志
/var/log/my/debug.log
/var/log/my/info.log
/var/log/my/warning.log
/var/log/my/error.log
{
rotate 7
daily
missingok
notifempty
delaycompress
compress
sharedscripts
postrotate
invoke-rc.d rsyslog rotate >
/dev/null
endscript
}
另一种更高级的方法是使rsyslogd本身将消息写入文件, 并根据当前日期和时间动态创建文件。对于删除较旧的文件, 这仍然需要自定义解决方案, 但是让devops可以精确地管理每个日志文件的时间范围。对于我们的示例:
$template DynaLocal0Err, "/var/log/my/error-%$NOW%-%$HOUR%.log"
$template DynaLocal0Info, "/var/log/my/info-%$NOW%-%$HOUR%.log"
$template DynaLocal0Warning, "/var/log/my/warning-%$NOW%-%$HOUR%.log"
$template DynaLocal0Debug, "/var/log/my/debug-%$NOW%-%$HOUR%.log"
local1.err-?DynaLocal0Err
local1.info-?DynaLocal0Info
local1.warning-?DynaLocal0Warning
local1.debug-?DynaLocal0Debug
这样, rsyslog每小时都会创建一个单独的日志文件, 并且不需要旋转它们并重新启动守护程序。以下是可以删除5天以上的日志文件以完成此解决方案的方法:
find /var/log/my/ -mtime +5 -print0 | xargs -0 rm
远程日志
随着项目的发展, 从日志中解析信息变得越来越耗费资源。这不仅意味着创建额外的服务器负载;这还意味着在解析日志时会在CPU和磁盘驱动器上造成峰值负载, 这可能会降低用户的服务器响应时间(或者在最坏的情况下甚至可能使站点瘫痪)。
要解决此问题, 请考虑设置集中式日志记录服务器。你所需要做的就是打开UDP端口514(默认)的另一个框。要使rsyslogd侦听连接, 请在其配置文件中添加以下行:
$UDPServerRun 514
有了这个, 设置客户端就很容易了:
*.*@HOSTNAME:514
(其中HOSTNAME是你的远程日志记录服务器的主机名)。
总结 尽管本文展示了一些创造性的方法, 日志文件可以提供比你以前想象的更有价值的信息, 但需要强调的是, 我们只是在探索可能的事物。你可以记录的内容的范围, 范围和格式几乎是无限的。这意味着-如果你要从日志中提取使用量或分析数据, 则只需以一种易于随后解析和分析的方式对其进行记录。而且, 该分析通常可以使用标准的Linux命令行工具(例如grep, sed或awk)执行。
确实, PHP日志文件是最强大的工具, 可以带来巨大的好处。
资源资源 GitHub上的代码:https://github.com/isanosyan/srcmini-blog-logs-post-example
附录:在Unix Shell中读取和处理日志文件 这是一些你想熟悉的一些常见的* nix命令行工具的简要介绍, 这些工具用于读取和操作日志文件。
猫也许是最简单的猫。它将整个文件打印到输出流。例如, 以下命令将logfile1打印到控制台:
cat logfile1
> 字符允许用户重定向输出, 例如重定向到另一个文件。在写入模式下打开目标流(这意味着擦除目标内容)。以下是我们将tmpfile的内容替换为logfile1的内容的方法:
cat logfile1 >
tmpfile
> > 重定向输出并以附加模式打开目标流。目标文件的当前内容将被保留, 新行将添加到底部。这会将logfile1内容附加到tmpfile:
cat logfile1 >
>
tmpfile
grep按某种模式过滤文件并仅打印匹配的行。以下命令将仅打印包含Bingo消息的logfile1行:
grep Bingo logfile1
cut打印单列的内容(按数字从1开始)。默认情况下, 搜索制表符作为列之间的分隔符。例如, 如果你的文件充满了时间戳, 格式为YYYY-MM-DD HH:MM:SS, 则仅打印年份:
cut -d"-" -f1 logfile1
head仅显示文件的第一行
尾部仅显示文件的最后几行
对输出中的行进行排序
uniq过滤掉重复的行
wc计算单词(或与-l标志一起使用时的行数)
| (即” 管道” 符号)将一个命令的输出作为输入提供给下一个命令。管道对于组合命令非常方便。例如, 以下是我们如何查找在一组时间戳中发生的2014年的几个月的信息:
grep -E "^2014" logfile1 | cut -d"-" -f2 | sort | uniq
在这里, 我们首先将行与正则表达式” 从2014年开始” 匹配, 然后减少数月。最后, 我们使用sort和uniq的组合仅打印一次事件。
推荐阅读
- React组件如何使UI测试变得容易
- 使用GitHub Webhooks自动部署Web应用程序
- 针对开发人员的设计工作流程教程(按时交付更好的UI/UX)
- CSS布局教程(从经典方法到最新技术)
- Meteor教程(使用Meteor构建实时Web应用程序)
- GWT如何在浏览器中解锁增强现实
- 在使用Baseadapter的Listview中,Android Plus和Minus按钮无法正常工作
- 如何在android中获取ListView反向位置()
- 在listview android中运行复选框时出错