☰
glog日志持久化配置实战:从缓冲刷盘到崩溃安全
2026/10/12 14:36:38 网站建设 项目流程

1. 从一次日志丢失事故说起:为什么glog的持久化值得单独拿出来讲

去年帮一个团队排查线上服务偶发崩溃的问题,现象很诡异:进程挂掉之后,日志文件里最后几行是空的,关键的崩溃堆栈压根没落盘。当时第一反应是代码里日志没打全,翻了一遍发现该打的都打了,级别也没问题。后来把glog的配置逐行过了一遍,才定位到根因——他们用的是默认的日志缓冲策略,进程异常终止时缓冲区里的内容还没来得及刷到磁盘,日志就跟着进程一起没了。这件事让我意识到,glog这个库虽然上手极快,但“配置”和“持久化”这两件事,恰恰是大多数人只知其一不知其二的地方。

glog是Google开源的一套C++日志库,全称Google Logging Library。它的定位很明确:轻量、高性能、线程安全,适合在C++服务端程序里做分级日志记录。你只需要在代码里写LOG(INFO) << "something",它就能自动帮你处理日志级别、文件切分、条件日志、崩溃时的堆栈输出等一堆琐事。但“自动”这两个字是有代价的——默认配置为了性能做了不少取舍,如果你不主动干预,某些场景下就会踩坑。

这篇文章面向的是已经在用或者准备用glog的C++开发者,尤其是那些把服务部署到生产环境、对日志可靠性有要求的人。我会把glog的配置体系拆开讲清楚,重点落在“怎么让日志真正持久化、不丢、可追溯”上。包括日志目录怎么设、文件命名和切分怎么控制、缓冲与刷盘怎么权衡、崩溃时怎么保证关键信息落盘,以及多进程、多线程环境下那些文档里不会明说的细节。读完你至少能做到:知道每个配置项背后的取舍逻辑,能根据自己服务的特性调出一套靠谱的持久化方案,而不是照抄一段初始化代码就完事。

2. glog的配置入口:那些初始化时你必须做的选择

2.1 初始化函数的调用时机与参数含义

glog的配置几乎全部集中在google::InitGoogleLogging()这一个入口上。它的原型是void InitGoogleLogging(const char* argv0),参数通常传程序名,用来在日志文件命名和崩溃信息里标识是哪个程序产生的日志。很多人随手传个argv[0]就完事,但其实这个字符串会直接影响日志文件名的前缀,后面讲文件命名时会再展开。

调用时机是个容易被忽略的点。InitGoogleLogging必须在任何LOG()宏被调用之前执行,否则glog会用一套内部的默认行为,而且会打印一条警告说初始化晚了。更麻烦的是,如果你在多线程环境里,第一个线程已经开始打日志了,主线程才去初始化,那前面那些日志的配置就是默认的,后面又变成你设的,行为不一致。所以标准做法是在main函数的最开头,做完最基本的参数解析之后就立刻初始化。

还有一个细节:InitGoogleLogging本身不是线程安全的,它设计上就是让你在单线程阶段调用一次。如果你在动态库的构造函数里调用它,而动态库被多个线程同时加载,就可能出问题。稳妥的做法是把它放在一个明确的、单线程执行的初始化阶段。

2.2 日志目录设置:FLAGS_log_dir与环境变量的优先级

glog默认把日志写到/tmp目录下,这在生产环境里几乎不可接受——/tmp可能被清理,可能空间很小,而且多实例部署时容易混在一起。所以第一件事就是设置日志目录。

有两种方式:一是通过FLAGS_log_dir这个全局标志,二是通过环境变量GOOGLE_LOG_DIR。两者的优先级是这样的:如果你在代码里显式设置了FLAGS_log_dir,那它优先;如果没设,glog会去读环境变量;如果环境变量也没有,才落到默认的/tmp。

这里有个坑:FLAGS_log_dir的设置必须在InitGoogleLogging之前完成,因为初始化的时候glog会去解析这个目录并做检查。如果你在初始化之后才改,新的日志文件可能会写到新目录,但已经打开的旧文件句柄还指向老目录,行为就很混乱。我一般建议在代码里统一设置,不依赖环境变量,这样部署时少一个变量,排查问题时也少一个不确定因素。

另外,目录必须提前存在。glog不会帮你创建多级目录,如果FLAGS_log_dir指向的路径不存在,它会退回到默认目录并打印警告。所以初始化之前用mkdir -p或者代码里的std::filesystem::create_directories确保目录存在,是个好习惯。

2.3 日志级别与输出目标的组合控制

glog的日志级别有四级:INFO、WARNING、ERROR、FATAL。默认情况下,INFO级别的日志只写到文件,不输出到stderr;WARNING及以上会同时输出到stderr和文件。这个默认行为在生产环境里其实挺合理——INFO量太大,全打到终端会拖慢性能;WARNING以上需要运维及时看到。

但你可以通过FLAGS_stderrthreshold来调整这个分界线。比如设成google::ERROR,那只有ERROR和FATAL才会同时进stderr。设成google::INFO则所有级别都进stderr,调试时有用,生产环境慎用。

还有一个FLAGS_minloglevel,控制的是“低于这个级别的日志直接丢弃,连文件都不写”。默认是INFO,也就是所有日志都记录。如果你把FLAGS_minloglevel设成WARNING,那所有INFO日志在编译期之后就被运行时过滤掉了,连格式化的开销都省了。这个在性能敏感的场景下很有用,但要注意:一旦设了,INFO日志就彻底没了,排查问题时可能会后悔。

我通常的做法是:生产环境FLAGS_minloglevel保持INFO,但通过日志切分和定期清理来控制磁盘占用;FLAGS_stderrthreshold设成WARNING,避免INFO刷屏。这样既保留了完整的日志,又不会让终端被淹没。

3. 日志文件的生命周期:命名、切分与清理策略

3.1 文件命名规则与程序名的隐藏影响

glog的日志文件名格式是:程序名.主机名.用户名.log.级别.日期时间.进程号。举个例子,一个叫my_service的程序在主机node01上以用户app运行,产生的INFO日志可能叫my_service.node01.app.log.INFO.20240515-103045.12345。

这个命名规则里,程序名来自InitGoogleLogging的参数,主机名和用户名是glog自动获取的。这里有个实际问题:如果你的程序名里带了路径(比如直接传了argv[0],而argv[0]是/opt/app/bin/my_service),那glog会把路径里的斜杠也带进文件名,导致文件名里出现目录分隔符,在某些文件系统上会创建失败或者行为异常。所以传参时最好只传basename,或者自己传一个干净的标识符。

主机名和用户名的作用是区分不同机器、不同用户产生的日志。在容器化部署里,主机名往往是容器ID,用户名可能是root,这些信息对排查问题其实帮助有限,但glog没有提供直接关闭它们的选项。如果你实在不想要这些,可以在初始化之前用FLAGS_log_prefix之类的标志调整,但更彻底的做法是自己在日志目录上做文章,比如按实例分目录。

3.2 按大小切分:FLAGS_max_log_size的取舍

glog默认的单个日志文件大小上限是1800MB,这个值大得离谱。一个日志文件涨到1.8G,用tail看都费劲,更别说用编辑器打开了。所以FLAGS_max_log_size是必须调的。

设成多少合适?这取决于你的日志量和排查习惯。我一般设成100MB到200MB之间。太小了会导致文件数量爆炸,目录里一堆小文件,管理起来烦;太大了单文件打开慢,而且一旦损坏丢失的信息多。100MB是个比较平衡的值,用less打开还能接受,grep起来也快。

需要注意的是,FLAGS_max_log_size的单位是MB,而且它控制的是“单个级别”的文件大小。也就是说,INFO日志和WARNING日志是分开计数的,各自达到上限后各自切分。这跟有些日志库“所有级别共用一个文件、按总大小切分”的行为不一样,配置的时候要心里有数。

切分后的文件不会自动删除,glog只是新建一个文件继续写,老文件留在原地。所以磁盘清理必须你自己做,后面会讲。

3.3 按天切分与文件名中的时间戳

除了按大小切分,glog还会在每天零点自动切分一次日志文件。这个行为是内置的,没有开关可以关掉。切分后的文件名里带日期,所以你能很清楚地知道每个文件是哪天的。

这个特性在排查“昨天还好好的,今天出问题了”这类问题时特别有用——直接找对应日期的文件就行。但要注意时区问题:glog用的是本地时间,如果你的服务器时区设置不对,切分点就会偏移。生产环境里建议统一用UTC,或者至少确保所有机器的时区一致,否则日志时间戳会对不上。

还有一个细节:如果进程在零点前后正好在写日志,切分的那一瞬间可能会有极短的时间窗口,日志写到旧文件还是新文件取决于具体的时序。这个窗口极小,一般不影响排查,但如果你做严格的日志审计,需要知道这个边界的存在。

3.4 磁盘清理:没有自动删除,就得自己动手

glog不提供自动清理旧日志的功能,这是它设计上的一个明确取舍——它只管写,不管删。所以你必须自己搞一套清理机制。

最简单的做法是写个定时任务,每天跑一次,找出日志目录下超过N天的文件删掉。用find命令一行就能搞定:

find /var/log/my_service -name "*.log.*" -mtime +7 -delete

但这里有个坑:正在被写入的文件,-mtime判断的是修改时间,如果进程一直在写,修改时间就是当前,不会被误删。但如果进程停了,文件不再更新,-mtime就会按最后写入时间算,超过7天就被删。这通常是符合预期的。

更稳妥的做法是在程序内部起一个清理线程,定期扫描日志目录,按文件名的日期部分判断,删除超过保留期的文件。这样不依赖外部定时任务,部署时少一个依赖。但要注意清理线程的权限——它得有删除文件的权限,而且不能误删其他程序的文件。所以日志目录最好独立,不要和其他程序混用。

我个人的习惯是保留7天的日志,同时监控日志目录的磁盘占用,超过阈值就告警。7天足够覆盖大多数“周末出问题、周一才发现”的场景,又不至于占太多空间。

4. 持久化的核心:缓冲、刷盘与崩溃安全

4.1 glog的写入缓冲机制与FLAGS_logbufsecs

这是整篇文章最核心的部分,也是开头那个事故的根因所在。

glog默认不是每写一条日志就立刻刷到磁盘的。它有一个缓冲机制,日志先写到内存缓冲区,然后由后台线程定期刷盘。控制这个定期的标志就是FLAGS_logbufsecs,默认值是30秒。也就是说,最坏情况下,你写的日志可能在内存里待了将近30秒才落盘。如果进程在这30秒内崩溃,这部分日志就丢了。

30秒对于调试来说太长了。你想想,一个请求处理到一半崩溃了,最后30秒的日志全没了,那还排查什么?所以FLAGS_logbufsecs必须调小。设成0会怎样?设成0意味着“每次写日志都立刻刷盘”,也就是关闭缓冲。这最安全,但性能开销最大——每条日志都触发一次系统调用,高并发场景下会成为瓶颈。

那设成多少合适?我的经验是:对于大多数服务,设成1到5秒是个不错的平衡。1秒的窗口,即使崩溃,最多丢1秒的日志,通常不影响定位问题;同时刷盘频率不至于太高,性能可以接受。如果服务对日志完整性要求极高(比如金融交易),那就设0,用性能换安全。如果服务日志量极大且对丢失不敏感(比如访问日志),可以保持默认或设大一点。

这里要澄清一个常见误解:FLAGS_logbufsecs控制的是“定期刷盘”的间隔,但glog在遇到ERROR和FATAL级别日志时,会立即刷盘,不受这个间隔限制。所以崩溃前如果打了ERROR日志,那条是能落盘的。但崩溃往往发生在ERROR之前,或者崩溃本身就是段错误,来不及打ERROR,所以不能指望这个机制。

4.2 崩溃时的日志落盘:信号处理与FATAL行为

glog对FATAL日志有特殊处理:当一条FATAL日志被写入时,glog会先刷盘,然后终止程序。这个“先刷盘再终止”的顺序保证了FATAL日志本身不会丢。所以如果你在代码里对致命错误打了FATAL,那条日志是安全的。

但问题在于,很多崩溃不是通过FATAL触发的,而是段错误、除零、断言失败等信号导致的。glog默认会安装信号处理器,在收到SIGSEGV、SIGABRT等信号时,打印堆栈信息并尝试刷盘。这个堆栈信息对排查崩溃非常有用,但它的可靠性取决于信号处理器的实现和当时的进程状态。

有一个配置叫FLAGS_log_stacktrace,控制是否在崩溃时输出堆栈。默认是开的,建议保持。但要注意,堆栈信息的符号化需要编译时带-g选项,并且链接时不要strip掉符号。生产环境如果为了减小体积strip了符号,那堆栈就是一堆地址,意义不大。折中方案是保留符号表但用objcopy把调试信息单独存一个文件,崩溃时用地址去那个文件里查。

还有一个更隐蔽的问题:如果崩溃发生在信号处理器执行期间(比如信号处理器本身又触发了信号),glog的处理器可能无法正常工作。这种情况极少见,但一旦遇到,日志就完全丢了。对于极端可靠性要求,可以在外部用core dump配合gdb做离线分析,不完全依赖glog的崩溃日志。

4.3 多进程写入同一目录的冲突与规避

glog的文件名里带了进程号,所以多个进程写同一个日志目录时,文件名不会冲突,各写各的。这看起来没问题,但实际使用中有两个坑。

第一个坑是磁盘空间。多个进程同时写,日志量是叠加的,磁盘消耗速度比你预期的快。如果清理策略是按文件数量或总大小,多进程场景下需要重新计算阈值。

第二个坑是日志的关联性。多个进程的日志分散在不同文件里,排查一个跨进程的问题时,你得同时打开好几个文件对照时间戳。glog没有提供跨进程的日志聚合,这是它的定位决定的——它就是个库,不是日志收集系统。如果确实需要聚合,得在glog之上再搭一层,比如用syslog转发,或者自己写个收集器。

规避冲突的实用做法是:每个进程实例用独立的日志目录,目录名里带实例标识。比如/var/log/my_service/instance-01/、/var/log/my_service/instance-02/。这样清理时可以按实例粒度控制,排查时也清楚哪个日志属于哪个实例。代价是目录结构深了一层,但换来的是清晰性,值得。

4.4 性能与安全的平衡:实测数据与调参建议

光讲理论不够,我做过一组简单的实测,在一台普通开发机上,单线程循环写INFO日志,每条日志约100字节,测不同FLAGS_logbufsecs下的吞吐量。

logbufsecs每秒写入条数(约)崩溃时最大丢失窗口
012万0
185万1秒
5110万5秒
30(默认)120万30秒

这个数据不是精确基准,但能看出趋势:从0到1,吞吐量提升巨大,因为避免了每条日志一次系统调用;从1到30,提升幅度变小,因为刷盘频率降低带来的收益递减。而丢失窗口从0到1秒是可接受的,从1秒到30秒就有点危险了。

所以我的调参建议是:默认设1秒。如果实测发现刷盘成为瓶颈(比如用strace看到大量write系统调用),再考虑放宽到5秒。设0只在日志量小且对完整性要求极高的场景下用。30秒的默认值,除非你的服务能容忍丢半分钟日志,否则不要用。

另外,FLAGS_logbufsecs是全局的,影响所有级别的日志。如果你想让ERROR级别更及时,可以单独对ERROR日志做处理,但glog没有提供按级别设缓冲的接口,只能靠ERROR触发立即刷盘的机制来兜底。

5. 进阶配置:让日志更贴合你的排查习惯

5.1 日志前缀定制:FLAGS_log_prefix与时间格式

glog默认的日志行格式是:级别 日期 时间 进程号 文件名:行号] 消息内容。这个格式信息量够,但有时候你想调整。比如去掉进程号(单进程场景下没用),或者调整时间格式。

FLAGS_log_prefix可以控制是否输出前缀,设成false就只剩消息内容。这个一般不用关,前缀里的文件名和行号是定位问题的关键。但如果你在做日志解析,前缀格式固定反而方便写正则。

时间格式方面,glog用的是YYYYMMDD HH:MM:SS.uuuuuu,微秒精度。这个精度对大多数场景够用,但如果你做高频交易或者性能分析,可能需要纳秒。glog没有提供纳秒选项,只能自己在消息里带时间戳。

还有一个FLAGS_log_year_in_prefix,控制前缀里是否带年份。默认是带的,但在跨年时如果日志文件按天切分,文件名里已经有日期了,前缀里再带年份有点冗余。这个看个人习惯,我一般保持默认。

5.2 条件日志与频率限制:避免日志洪水

glog提供了一组条件日志宏,比如LOG_IF(INFO, condition),只有条件为真时才打日志。还有LOG_EVERY_N(INFO, n),每n次执行打一次。这些宏在循环里特别有用,避免刷屏。

但这里有个坑:LOG_EVERY_N的计数是每个宏调用点独立的,不是全局的。也就是说,你在两个不同的地方各写一个LOG_EVERY_N(INFO, 100),它们各自计数,互不影响。这通常是符合预期的,但如果你以为它们是共享计数,就会困惑为什么日志比预期多。

还有一个LOG_FIRST_N(INFO, n),只在前n次执行时打日志。这个适合打“初始化完成”之类的日志,打几次就够了,后面不用重复。

频率限制的另一个维度是FLAGS_log_backtrace_at,可以在特定文件行号处触发堆栈打印。这个用得少,但在排查“为什么走到这里”的问题时有用。

5.3 自定义日志级别与VLOG的启用

glog除了四个标准级别,还有一套VLOG机制,也就是verbose log。VLOG(1) << "detail"这样的日志,默认是不输出的,需要设置FLAGS_v来启用。FLAGS_v设成1,则所有VLOG(1)及以下的都输出;设成2,则VLOG(2)及以下的都输出,以此类推。

这套机制的好处是:你可以在代码里埋大量详细日志,用不同的VLOG级别区分详细程度,生产环境默认关闭,需要排查时通过命令行参数临时打开,不用重新编译。这对于“线上问题复现不了,需要加日志”的场景特别有用。

但要注意,VLOG的级别是全局的,不能按模块单独设。如果你的服务有多个模块,想只打开某个模块的详细日志,glog本身做不到。变通做法是用不同的VLOG级别区间给不同模块,比如模块A用1-10,模块B用11-20,然后通过FLAGS_v控制打开到哪一档。这需要团队内部约定好,不然会乱。

5.4 与外部日志系统的对接思路

glog写的是本地文件,但现代运维往往需要把日志集中收集。glog没有内置的网络输出功能,但提供了google::InstallFailureWriter之类的钩子,可以自定义日志的写入目标。

一个常见的做法是:用glog写本地文件作为第一手记录,同时起一个轻量的转发进程,用tail -F跟踪日志文件,把新内容转发到日志收集系统。这样glog本身不用改,转发进程独立部署,互不影响。

另一个做法是重定向glog的输出。glog在初始化之后,可以通过freopen把stderr重定向到管道,然后从管道读日志。但这种方式会丢失文件写入,而且管道满了会阻塞,不推荐。

如果对实时性要求高,可以考虑用InstallFailureWriter只接管崩溃日志,正常日志还是走文件。崩溃日志量小,实时转发压力不大,而且崩溃信息最需要及时告警。

6. 那些文档里不会写的踩坑记录

6.1 初始化顺序导致的配置失效

前面提过InitGoogleLogging要在打日志之前调用,但还有一个更隐蔽的顺序问题:FLAGS_log_dir的设置和InitGoogleLogging的调用之间,如果插入了其他会打日志的代码(比如某个全局对象的构造函数里打了日志),那这条日志会用默认配置,而且可能触发glog的“未初始化”警告。

C++的全局对象构造顺序是不确定的,所以如果你有全局对象在构造函数里打日志,而InitGoogleLogging在main里调用,那构造顺序就决定了日志是否正常。稳妥的做法是:要么避免在全局对象构造函数里打日志,要么用一个明确的初始化函数,在main开头调用,并且确保没有全局对象在它之前打日志。

6.2 日志文件句柄耗尽与文件描述符限制

glog每写一个级别的日志就打开一个文件句柄,四个级别就是四个句柄。加上切分时新旧文件交替,瞬时句柄数可能更多。一般情况下没问题,但如果你的进程本身已经接近文件描述符上限(比如高并发网络服务),glog再占几个就可能触发EMFILE错误。

表现是:日志突然不写了,或者写一半报错。排查时用lsof -p 进程号 | wc -l看句柄数,如果接近ulimit -n,就要调大限制或者减少其他地方的句柄占用。

glog本身没有提供“用完就关”的选项,它设计上就是保持文件打开以提高性能。所以只能从系统层面解决。

6.3 容器环境下的日志目录挂载陷阱

在容器里跑服务时,日志目录通常挂载自宿主机。这里有个坑:如果挂载的是宿主机的一个目录,而容器里的用户ID和宿主机上的目录权限不匹配,glog会写不进去。表现是日志文件创建失败,glog打印警告后退回到默认目录(容器内的/tmp),而/tmp在容器销毁后就没了。

解决办法是在容器启动时确保挂载目录的权限对容器内用户可写,或者用root跑容器(不推荐),或者在Dockerfile里创建对应用户并设好权限。这个坑在Kubernetes环境里尤其常见,因为Pod的securityContext和挂载卷的权限是分开配置的,容易顾此失彼。

6.4 日志时间戳与系统时钟跳变

glog的时间戳来自系统时钟。如果系统时钟发生跳变(比如NTP同步时大幅调整),日志的时间戳会出现回退或跳跃。这在排查问题时会造成困惑:明明是按时间顺序发生的事,日志里时间却是乱的。

更严重的是,如果时钟跳变发生在日志切分的判断时刻,可能导致切分逻辑异常,比如同一天切分了两次,或者该切分时没切。glog没有对时钟跳变做特殊处理,它信任系统时钟。

规避方法是:确保NTP配置合理,避免大幅跳变;如果对时间顺序要求严格,可以在日志消息里自己带一个单调递增的序列号,不依赖时间戳排序。

6.5 多线程下日志顺序的错觉

glog是线程安全的,多个线程同时打日志不会导致内容交错或崩溃。但“线程安全”不等于“顺序确定”。两个线程几乎同时打日志,谁先谁后是不确定的,即使代码里看起来有先后关系。

这在排查并发问题时会造成误导:你以为日志A在日志B之前,所以A对应的操作先发生,但实际上可能相反。要确定顺序,得靠日志里的其他信息,比如请求ID、线程ID,或者自己加序列号。

glog的前缀里有进程号但没有线程号,所以多线程场景下光看日志分不清是哪个线程打的。如果需要线程号,得自己在消息里带,或者用pthread_self()之类的接口获取后拼进去。

7. 一套可直接抄的配置模板与落地检查清单

7.1 初始化代码模板

把前面讲的整合起来,一个比较稳妥的初始化流程大概长这样:

#include <glog/logging.h> #include <filesystem> void InitLogging(const std::string& program_name, const std::string& log_dir) { // 确保目录存在 std::filesystem::create_directories(log_dir); // 设置日志目录 FLAGS_log_dir = log_dir; // 单个文件最大100MB FLAGS_max_log_size = 100; // 缓冲1秒,平衡性能与安全 FLAGS_logbufsecs = 1; // INFO不输出到stderr,WARNING及以上输出 FLAGS_stderrthreshold = google::WARNING; // 保留所有级别的日志到文件 FLAGS_minloglevel = google::INFO; // 崩溃时输出堆栈 FLAGS_log_stacktrace = true; // 初始化,传basename避免路径污染文件名 google::InitGoogleLogging(program_name.c_str()); }

调用时传干净的program_name,比如"my_service",不要传带路径的argv[0]。

7.2 上线前的配置检查清单

在把服务部署到生产环境之前,对照这个清单过一遍:

  • 日志目录是否独立且可写?权限是否正确?
  • FLAGS_max_log_size是否从默认的1800调到了合理值?
  • FLAGS_logbufsecs是否从默认的30调到了1或更小?
  • FLAGS_stderrthreshold是否设置,避免INFO刷屏?
  • 是否有日志清理机制,保留期是否明确?
  • 磁盘空间监控是否覆盖日志目录?
  • 容器环境下挂载目录权限是否验证过?
  • 崩溃堆栈的符号是否保留(编译带-g,不strip)?
  • 多进程部署时日志目录是否按实例隔离?
  • 系统时钟同步是否配置,避免大幅跳变?

这份清单看着简单,但每一条背后都对应着一个真实的坑。我见过太多团队在出问题之后才回头补这些配置,而那时候日志已经丢了,补也补不回来。

7.3 日志量估算与磁盘规划

最后说一个实操中经常被低估的事:磁盘规划。很多人配完glog就不管了,直到磁盘满了服务挂掉才慌。

估算日志量的方法是:先估算每秒日志条数,乘以平均每条日志的字节数,再乘以保留时间。比如每秒100条,每条200字节,保留7天,那就是100 * 200 * 86400 * 7 ≈ 12GB。这还没算切分产生的额外文件头和可能的重复。

实际值往往比估算高,因为高峰期日志量可能是平均值的几倍,而且ERROR日志可能带堆栈,单条就好几KB。所以规划磁盘时至少留2到3倍的余量。如果磁盘紧张,要么缩短保留期,要么降低日志级别,要么把INFO日志单独存到便宜的大容量存储上。

我一般建议日志目录单独挂一块盘,不要和系统盘或数据盘混用。这样日志写满不会影响服务本身,清理时也放心,不会误删其他数据。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询