简介:cronolog-1.6.2 是一款专为 Linux/Unix 环境设计的日志轮询与管理工具,主要面向系统管理员、运维人员以及需要处理大量 Web 日志的开发者和使用者,用于解决应用日志无限制增长导致的磁盘占用、性能下降与服务中断等问题。它支持按天或按小时自动切割日志,将不同时间段的日志写入独立文件,便于后续归档、排查与分析。压缩包内提供完整源码与构建文件,共 42 个文件,以 C 源文件(.c)、头文件(.h)、configure 配置脚本及 Makefile.am/.in 构建脚本为主,同时包含 README、INSTALL、ChangeLog、AUTHORS、COPYING、NEWS 等文档与项目元信息,整体仅 131KB,体积小巧、结构精简。包内目录划分清晰,核心源码、基础工具与文档资料分别存放,既适合运维人员在生产环境编译部署,也适合想学习日志轮询实现、理解时间戳分割机制的开发者研读。CSDN 上已有 2232 人学习下载,是获取 cronolog-1.6.2 源码包的一个可靠途径。 早年在服务器上搜“cronolog-1.6.2.tar.gz 下载”的人,十有八九是被膨胀的access_log逼疯的。我自己就是其中之一:Apache跑了一个业务系统,一个access.log堆到几个GB,vim打开卡到怀疑人生,grep一个IP要等半天,磁盘眼看着就要满了。后来同事甩过来一个cronolog链接,说“日志切割用这个,按天自动切”,我才算真正入了坑。
这篇文章就把cronolog从下载、解压、编译安装到接入Apache和Nginx的完整过程捋一遍,重点讲文档里没写、只有踩过坑才知道的细节。cronolog是一个极其轻量的日志轮转工具,整个源码包只有几十KB,核心原理就是从标准输入读日志流,按文件名里的时间模板把内容实时写入对应文件。适合正在被日志膨胀折磨的运维、后端开发,以及任何想给web服务日志做按天或按小时切分的同学。全文以cronolog-1.6.2这个稳定版本为主线,跟着操作就能落地。
1. 先搞清楚cronolog解决什么问题
1.1 为什么会有日志轮转这种需求
Web服务器的访问日志是无限增长的。以Apache为例,默认配置下所有请求都会追加写入同一个access_log文件,流量越大涨得越快。一个日PV几十万的站点,access_log一天就能给你涨出几百MB甚至上GB。问题不只是占磁盘:单个文件过大的时候,文本编辑器打不开,grep检索变慢,日志分析工具加载困难,备份和传输也全是折磨。
日志轮转要解决的就是这个事:把日志按时间或大小切成多个文件,旧的归档、压缩、清理,新的继续写。系统自带的logrotate可以做到,但它依赖cron定时执行,默认按天或按周跑一次,而且rename文件的时候会有一小段空窗——Apache还握着旧文件句柄,新文件可能没人写。cronolog的思路完全不同:它像一个夹在中间的水管接头,Apache每写一行日志,cronolog就实时判断当前时间,决定把这一行落到哪个文件。到了午夜0点0分0秒,它立刻打开新文件,整个过程没有断流、不丢日志、不需要重启服务。
1.2 cronolog和logrotate、Nginx自带方案怎么选
先说结论:在Apache场景下,cronolog是体验最好的一档;在Nginx场景下,你需要权衡。
| 方案 | 切分时机 | 是否需要cron | 是否断流 | 是否支持管道 | 适用场景 |
|---|---|---|---|---|---|
| logrotate | 按配置周期(天/周/大小) | 是 | 有短暂空窗 | 否 | 通用方案 |
| cronolog | 精确到秒的时间点 | 否 | 无 | 是 | Apache日志实时切分 |
| Nginx内置变量 | 依赖模块与变量粒度 | 否 | 无 | 否 | Nginx自带日志切分 |
logrotate的优势是通用、能自动压缩、能删旧日志,缺点在于它做的是“搬移”而不是“分流”,切分瞬间可能存在请求写入的间隙。cronolog 1.6.2虽然2002年之后就没再更新,但它的核心机制极其简单,这些年被大量生产环境验证过,稳定性反而成了它最大的卖点。如果你用的是Apache,或者说任何能把日志写入管道服务的程序,cronolog就是最省心的选择;如果只用Nginx,优先考虑Nginx自身的切分方案或者logrotate,硬上cronolog反而要处理命名管道,性价比不高。
2. 下载、解压到目录规划:tar.gz的正确打开方式
2.1 cronolog-1.6.2.tar.gz从哪下载、要不要校验
cronolog的官方站点是cronolog.org,1.6.2是公认的稳定版本,下载地址就是 https://cronolog.org/download/cronolog-1.6.2.tar.gz。这个站点偶尔会间歇性连不上,这时候找可靠的开源镜像或者转存资源就行。下载完建议先看一下体积:这个tar.gz大概在40KB上下,如果下载下来的文件只有几KB,那多半是下了一个错误页面,别急着解压。
有洁癖的同学可以校验MD5/SHA,官方页面会给出校验值。实测下来,多数运维下载完就直接解压了,但我还是建议至少看一眼文件类型——用file cronolog-1.6.2.tar.gz命令确认,输出显示gzip compressed data才算正常。这一步花不了十秒钟,能帮你避开“解压出来是乱码/目录结构不对”这类低级问题。归档完整性也可以用gzip -t cronolog-1.6.2.tar.gz验证,测试通过再继续,传输过程中损坏的包解到一半报错是很闹心的事。
2.2 tar.gz解压:-zxvf参数逐个说清楚
tar.gz是两层含义:tar是把多个文件打包成一个归档的格式,gz是对这个归档再做gzip压缩。所以解压命令是:
tar -zxvf cronolog-1.6.2.tar.gz拆开看参数:z表示通过gzip解压,x表示解压(extract),v表示显示解压过程(verbose),f表示后面紧跟的是文件名(file)。这四个参数组合是Linux里解压tar.gz最常用的姿势。如果你拿到的是.tar结尾的归档,说明只有打包没有压缩,就不要加z:tar -xvf xxx.tar。如果是.tar.bz2,要把z换成j:tar -jxvf xxx.tar.bz2。这几个参数的混用,新手基本都踩过。
解压完成后会在当前目录生成cronolog-1.6.2文件夹,里面有configure、Makefile.in、doc等一整套标准C项目结构。解压之前建议先ls看一下当前目录,确认不会把文件散到一堆无关目录里;也可以用tar -ztvf cronolog-1.6.2.tar.gz先列出归档内容预览。顺带一提,tar.gz这种格式不只出现在源码包里,conda生态里离线安装包、环境导出文件也经常用tar.gz或tar.bz2,处理逻辑完全相同。如果conda里拿到的是打包好的环境tar.gz,通常更推荐直接用conda命令创建或导入环境,而不是手动解压,因为conda要维护的是包依赖元数据,不是单纯的文件目录。
3. 编译安装全流程:configure、make、make install
3.1 三步走,每个命令在干什么
cronolog是纯C写的小工具,需要编译安装。进入解压出来的目录,依次执行:
cd cronolog-1.6.2 ./configure --prefix=/usr/local/cronolog make make install./configure负责检查系统里有没有编译器、头文件,根据环境生成Makefile,更关键的是确定安装前缀--prefix。我习惯装到/usr/local/cronolog而不是默认的/usr/local,好处是整个工具自成一体,卸载时直接删掉这个目录就可以,不会和系统自带的程序混在一起。如果你不指定--prefix,默认会装到/usr/local,二进制落在/usr/local/sbin/cronolog。
make是真正的编译过程,把C源码翻译成可执行文件,几秒钟就能完成,毕竟cronolog没有复杂依赖。如果报错提示缺gcc或cc,说明系统没装编译工具链:Debian/Ubuntu下执行apt-get install build-essential,CentOS下执行yum install gcc make,装上再重跑。make install把编译好的二进制和文档复制到前缀目录。三步完成之后检查一下:
ls -la /usr/local/cronolog/sbin/ /usr/local/cronolog/sbin/cronolog -V看到版本号cronolog 1.6.2就说明装好了。如果希望以后在任意目录直接敲cronolog,可以把路径软链到/usr/local/bin下:
ln -s /usr/local/cronolog/sbin/cronolog /usr/local/bin/cronolog我个人的习惯是不做软链,直接在配置文件和脚本里写绝对路径,避免以后升级或迁移时环境变量指向错乱。这个选择后面会再解释。
3.2 装完先做个冒烟测试
装好别急着接生产,先拿管道试一下。cronolog的用法很简单:把日志文本通过管道喂给它,它按文件模板里的时间格式决定写到哪个文件。
echo "test line $(date)" | /usr/local/cronolog/sbin/cronolog /tmp/cronolog_test_%Y%m%d.log ls -l /tmp/cronolog_test_*.log cat /tmp/cronolog_test_$(date +%Y%m%d).log这条命令会生成一个以当天日期命名的文件,比如cronolog_test_20250419.log,内容就是你echo进去的那一行。这一步通过,说明二进制正常、时间模板生效,接下来就可以接Apache了。没通过的话,先看是不是目录权限问题,再确认路径有没有写错。测试的时候多敲几次不同时间格式的模板,看看文件命名是否符合预期,比直接上生产再调要省事得多。
4. 接入Apache与Nginx:从管道到真实业务日志
4.1 Apache:一行CustomLog搞定按天切分
Apache对cronolog的支持可以说是“原生级”的,因为CustomLog指令本身就允许使用管道。找到httpd.conf或者虚拟主机配置文件,把原来的CustomLog行改成这样:
CustomLog "|/usr/local/cronolog/sbin/cronolog --symlink=/var/log/apache/access.log /var/log/apache/access_%Y%m%d.log" combined注意几个细节。第一,管道符|后面必须是cronolog的绝对路径,Apache启动时会用Apache用户的身份去fork这个管道进程,相对路径很容易出问题。第二,--symlink是cronolog很实用的参数,它会在切分的同时维护一个固定路径的软链,始终指向当前正在写的那个日志文件,这样你用tail -f /var/log/apache/access.log查看实时日志时,不用关心今天的文件名是什么。第三,文件模板%Y%m%d写的是最终落盘的日志名,按天就是年月日,按小时就加上%H。
改完配置执行apachectl configtest检查语法,没问题再service apache2 reload或httpd优雅重启。注意是reload不是restart,reload会让Apache重新读取配置并重新拉起管道进程,对业务影响最小。reload之后立刻看ps aux | grep cronolog,确认管道进程被拉起来了,再实际访问两次业务观察日志落盘,这一步别省。
4.2 Nginx:没有管道支持,用FIFO曲线救国
Nginx的access_log默认不支持管道符,这是很多人想给Nginx上cronolog时卡住的地方。想用cronolog,常见做法是做一个命名管道(FIFO),让Nginx往FIFO里写,cronolog从FIFO那头读。
mkfifo /var/log/nginx/access_fifo chown nginx:nginx /var/log/nginx/access_fifonginx.conf里:
access_log /var/log/nginx/access_fifo combined;再单独启动一个cronolog进程读这个FIFO:
/usr/local/cronolog/sbin/cronolog --symlink=/var/log/nginx/access.log /var/log/nginx/access_%Y%m%d.log < /var/log/nginx/access_fifo &这个方案能用,但有几个痛点要先想清楚。FIFO打开时是阻塞的,如果cronolog没先起来,Nginx在open这个FIFO时可能会卡住,所以必须保证cronolog先于Nginx运行;而且FIFO必须有进程在持续读取,否则Nginx写满缓冲区后会阻塞请求。cronolog进程如果意外退出,Nginx同样会被卡住。所以生产环境要配一个守护脚本监控cronolog进程,挂了自动拉起。我的实际建议是:Nginx场景优先考虑Nginx自身的按时间切分能力或logrotate,只有在业务强依赖cronolog做统一日志管理时才走FIFO路线,否则就是给自己找活干。
4.3 时间格式符与轮转周期怎么选
cronolog的时间占位符和strftime一致,常用的几个:
| 格式 | 含义 | 示例 |
|---|---|---|
| %Y | 四位年份 | 2025 |
| %m | 两位月份 | 04 |
| %d | 两位日期 | 19 |
| %H | 24小时制小时 | 14 |
| %M | 分钟 | 05 |
| %j | 一年中的第几天 | 109 |
默认情况下cronolog按天轮转,文件名里的最小时间单位决定了切分粒度:只有%Y%m%d就是按天,加上%H就是按小时。这个逻辑很直观,但也容易踩坑:模板里写了%H却不显式指定周期,实际切分行为可能和你预期不一致。我的建议是,确定好粒度之后,模板和周期参数保持匹配,比如按小时就写成access_%Y%m%d%H.log,并配合-p 1h显式声明周期。另外提醒一点,cronolog切换文件精确到秒,依赖系统时钟,所以服务器时间最好用NTP保持同步,否则跨天切分可能提前或滞后,严重的时候还会出现日期目录错乱。
5. 常见问题与排查技巧实录
5.1 日志文件不生成,Apache报管道错误
最典型的问题:配置改完reload了,业务访问也有,但日志文件一个都没有。这时候先去Apache的错误日志里翻,通常能看到类似could not open pipe的报错。原因基本就这几类:第一,管道命令里的路径写错了,或者cronolog没装到这个路径;第二,Apache用户(www-data/apache/nobody)没有目标日志目录的写权限;第三,目标目录不存在,cronolog不会帮你自动创建目录。
排查顺序我一般是这样:先命令行手动跑一遍cronolog确认二进制正常,再用Apache用户身份测试目录权限(sudo -u www-data touch /var/log/apache/test.log),最后检查配置里有没有多余的空格或引号。Apache里管道命令的引号嵌套最容易翻车,整句必须用双引号包裹,cronolog自己的参数不要再加引号,否则reload时你以为改对了,实际上Apache解析成了两个参数。
5.2 权限与属主:日志文件到底归谁
cronolog生成的文件属主是启动Apache的用户,所以你会看到access日志的属主是www-data,这是正常的。问题往往出现在跨部门协作场景:运维想读日志分析,但文件权限是640且属组不是运维组,于是又来找你“日志读不了”。建议在日志目录上用setfacl或者直接chown赋予合适的属组,而不是每次手动chmod。另一个常见问题是日志目录设在SELinux管控的路径下,Apache写不进去,排查时记得看SELinux的avc拒绝记录,别只顾着检查文件夹权限。
我个人的规范是:日志目录统一放到/var/log/apache下,目录属主设为Apache用户,权限750,属组设为adm或专用日志组,这样既保证web服务能写,运维也能读,还不会把日志暴露给普通用户。日志文件本身的权限cronolog默认按umask来,通常就是644,需要保密的话可以在启动脚本里把umask改成027。
5.3 cronolog挂掉、跨天丢日志、旧日志清理
cronolog进程如果挂了,Apache往管道里写数据会触发SIGPIPE,表现就是日志突然断档。Apache会记录错误并继续尝试,但不会自动帮你拉起cronolog。所以生产环境最好用一个简单脚本监控cronolog进程,发现不在就跑起来,配合crontab每分钟检查一次足够了,不用上太重的守护工具。
跨天丢日志的另一个隐藏原因是系统时间跳变。如果NTP在跨天瞬间做了一次大步调整,cronolog判断时间的基准变了,可能出现当天文件没关、第二天文件没建的情况。这个不用过度焦虑,保证NTP平滑同步、不手动乱改系统时间就行。
旧日志清理是配套功课。cronolog本身不压缩、不删除,我通常会加一条crontab:
0 3 * * * find /var/log/apache -name "access_*.log" -mtime +30 -delete再配合一条压缩前一日日志的定时任务,磁盘压力会小很多。如果对按天归档有更高要求,后续可以再往对象存储里转储,但那是另一个话题了。
5.4 常见问题速查表
| 现象 | 可能原因 | 解决方式 |
|---|---|---|
| 日志完全没生成 | 管道路径错误/目录无权限 | 检查绝对路径与Apache用户写权限 |
| 日志生成了但内容为空 | FIFO没有读取端 | 确认cronolog进程在运行 |
| 按小时切分不生效 | 模板没写%H或周期未指定 | 模板补%H并加-p 1h |
| 跨天不切换文件 | 系统时间跳变 | 检查NTP,避免手动改时间 |
| reload后管道报错 | 引号嵌套错误 | 重写CustomLog整句 |
6. 最后说几点实际操作中我的体会
6.1 什么时候值得用cronolog
用cronolog这些年,最大的感受是“老工具真香”。它不产生额外依赖,一个十几KB的二进制解决了日志切割最核心的痛点,稳定性被大量生产环境验证过。如果问我什么场景值得上cronolog,我的回答是:只要你用的是Apache,且日志量还没大到需要上ELK那套采集管道,cronolog就是性价比最高的方案。它和Apache的管道机制配合得严丝合缝,配置一行就够,整套体系几乎没有可以被攻击的复杂逻辑。
6.2 三个踩坑换来的细节
最后分享三个我实际踩过坑才记住的细节。第一,管道配置一定要写在配置文件里而不是启动脚本里,有人喜欢在rc.local里用nohup手动拉cronolog,结果Apache一重启就丢日志,因为管道和Apache的进程生命周期没有绑定。第二,命令行调试时用cronolog -h看一遍全量参数,确认版本对应的选项,不同版本行为有差异,别拿老经验硬套。第三,用--symlink维护一个current链接,下游所有的分析工具都指向这个固定路径,避免每天改脚本里的文件名。这三点看着不起眼,真到排障的时候能省下大把时间。
本文还有配套的精品资源,点击获取