MongoDB之rotate log

719 阅读3分钟

当mongodb实例启动时指定logpath或systemLog.path参数,mongod和mongos实例将向日志文件中持续的记录数据库的活动日志。

而MongoDB默认情况下不会自动的切换日志的,这将会导致服务日志日渐增大,在业务繁忙的场景,日志的增长量会非常大。持续增长的日志文件,不仅占用系统磁盘,并且还会拖慢服务器的运行速度。所以我们需要能对服务日志进行日志切换。

在MongoDB中,切换日志的触发条件有两种:

1、admin库下执行logRotate命令。

use admin    
db.runCommand({logRotate:1})

2、mongod或者mongos进程从操作系统接收SIGUSR1信号。

这种方法对linux或类UNiX系统有效。对于基于Linux和unix的系统,可以使用SIGUSR1信号来切换单个进程的日志。

假设mongod的进程号为7393,如下命令将会为该实例轮转日志。

kill -SIGUSR1 7393

执行上述rotate log的两种方法,会触发mongod切换日志,但是如何进行切换,取决于systemLog.logRotate参数或--logRotate选项设置。

rename

当systemLog.logRotate或--logRotate设置为rename时,mongod将会归档当前日志文件,并启动一个新的日志文件,形式是以ISODate格式在文件名中附加UTC时间戳,重命名当前日志文件,并打开一个新的日志文件,关闭旧的日志,并将新的日志条目发送到新的日志文件。

(base) ackkky@ackkkydeMacBook-Pro mongodb % ps aux|grep mongo
ackkky         7521   0.0  0.0  4268300    684 s006  R+   11:01上午   0:00.00 grep mongo
ackkky         7393   0.0  0.3  5152032  22808   ??  S    10:44上午   0:06.87 ./mongod --dbpath /usr/local/var/mongodb --logpath /usr/local/var/log/mongodb/mongo.log --fork --auth --bind_ip 0.0.0.0 --replSet=test
(base) ackkky@ackkkydeMacBook-Pro mongodb % ls
mongo.log
(base) ackkky@ackkkydeMacBook-Pro mongodb % pwd
/usr/local/var/log/mongodb
(base) ackkky@ackkkydeMacBook-Pro mongodb % kill -SIGUSR1 7393
(base) ackkky@ackkkydeMacBook-Pro mongodb % ls
mongo.log   mongo.log.2021-11-11T03-01-57

可以看到我的logpath目录下多了一个mongo.log.2021-11-11T03-01-57文件。

reopen

--logRotate设置为reopen时,需要与——logappend一起使用。

而且应该使用外部进程重命名日志文件,遵循典型的linux/Unix日志轮转行为。如果我们希望在日志达到一定大小后对其进行轮转,可以将reopen与linux logrotate工具结合使用。

定时执行

在生产环境通常我们需要将日志按日期进行切换,那么我们可以将切换动作写成一个定时任务,每天定时切换任务。

定时任务可以用crontab,脚本可以用python。

示例:

脚本:mongo_log_rotate.py

#!/bin/env python

import subprocess
import psutil
import time
import datetime
import os


def deleteOutdateFiles(path, file_name_patten):
    """
    删除目录下七天前创建的文件
    """
    current_time = time.strftime("%Y-%m-%d", time.localtime(time.time()))
    current_timeList = current_time.split("-")
    current_time_day = datetime.datetime(int(current_timeList[0]), int(current_timeList[1]), int(current_timeList[2]))

    for root, dirs, files in os.walk(path):
        for item in files:
            if file_name_patten in item:
                file_path = os.path.join(root, item)
                create_time = time.strftime("%Y-%m-%d", time.localtime((os.stat(file_path)).st_mtime))
                create_timeList = create_time.split("-")
                create_time_day = datetime.datetime(int(create_timeList[0]), int(create_timeList[1]),
                                                    int(create_timeList[2]))
                time_difference = (current_time_day - create_time_day).days
                if time_difference > 7:
                    os.remove(file_path)


# status, mongo_pids = subprocess.getstatusoutput("/sbin/pidof mongod")
# status, mongo_pids = subprocess.getstatusoutput("ps -A | grep -m1 mongod | awk '{print $1}' ")
# 获取当前机器的mongod进程
status, mongo_pids = subprocess.getstatusoutput("/sbin/pidof mongod")

mongo_pids = mongo_pids.split(" ")

for mongo_pid in mongo_pids:
    if mongo_pid != '':
        p = psutil.Process(int(mongo_pid))
        # rotate日志
        cmd = "/bin/kill -SIGUSR1 %s" % (mongo_pid)
        status, mongo_rotate = subprocess.getstatusoutput(cmd)
        
        # 清理7天前的日志:clean log which > 7 days
        p = psutil.Process(int(mongo_pid))
        cmdline = p.cmdline()
        logpath = "/usr/local/var/log/mongodb/mongo.log"
        for index, i in enumerate(cmdline):
            if i == '--logpath':
                logpath = cmdline[index+1]
                break
        logdir = os.path.split(logpath)[0]
        filename = os.path.split(logpath)[-1]
        deleteOutdateFiles(logdir, filename)

crontab:

0 1 * * * /code/mongo_log_rotate.py >/root/null 2>&1

参考文档: docs.mongodb.com/manual/refe…