日志分割解决方案-django/logrotate

线上升级后,发现日志不再分割,记录以下排查过程以及所涉及的知识。

1.配置文件排查

询问老工程师,反馈是通过Python的logging模块进行分割的,其中logging模块介绍如下:
logging模块采用模块化设计思想,主要包括四种模块:

  • Logger:记录器,提供应用程序调用的各种接口;
  • Handler:处理器,处理记录器产生的日志;
  • Filter:过滤器,提供更好的粒度控制;
  • Formatters:格式器,格式化日志内容的组成和消息字段;

其中logging模块详解请见:logging模块详解(转自刘江的博客)
日志处理流程如下图所示:
image.png

Django中的logging配置解释如下,其中Django读取settings.py中的LOGGING配置:

LOGGING = {
    'version': 1, #版本号
    'disable_existing_loggers': False,
    'formatters': { # 格式器
        'verbose': { # 复杂格式名称
            'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
            'style': '{',
        },
        'simple': { # 简洁格式名称
            'format': '{levelname} {message}',
            'style': '{',
        },
    },
    'filters': { # 过滤器
        'special': { # 过滤器名称
            '()': 'project.logging.SpecialFilter',
            'foo': 'bar',
        },
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': { # 处理器
       'logit': { # 名称
            'level': 'DEBUG',
            'class': 'logging.handlers.TimedRotatingFileHandler',# 按某一时间来分割
            'filename': '/tmp/logit.log', # 路径
            'when': 'midnight', # Roll over at midnight
            'backupCount': 10, # 备份数量
            'formatter': 'verbose', # 格式器
        },
        'console': { # 处理器名称
            'level': 'INFO', # 级别
            'filters': ['require_debug_true'], # 过滤器
            'class': 'logging.StreamHandler', # 流处理器
            'formatter': 'simple' # 格式器
        },
        'file': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler', # 文件处理器
            'filename': '/path/to/django/debug.log', # 文件路径
        },
        'mail_admins': { # 名称
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler', # 邮件处理器
            'filters': ['special']
        }
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'propagate': True,
        },
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': False,
        },
        'myproject.custom': {
            'handlers': ['console', 'mail_admins'],
            'level': 'INFO',
            'filters': ['special']
        }
    }
}

但是排查线上配置文件,并未配置TimedRotatingFileHandler处理器。并且查看文件修改记录及git记录,该文件并未修改。所以判断,日志分割使用了其他方法。

logrotate

经过排查代码,确定日志分割的方式是通过crond+logrotate进行分割的。
其中logrotate介绍如下:
logrotate用于管理系统生成的大量日志,可以自动的分割、压缩、移除或者mailing日志文件。
一般,logrotate作为daily cron job运行,除非rotate的标准是基于log文件大小,且logrotate命令明天被执行多次,即自定义了定时任务。再或者手动执行logrotate时添加了-f/--force选项;
logrotate.conf参数说明

# see "man logrotate" for details  
# rotate log files weekly: 每周rotate log文件一次  
weekly  

# keep 4 weeks worth of backlogs: 
# 保存最近4周的log日志,因为上面是每周rotate一次  
rotate 4  

# create new (empty) log files after rotating old ones:
# rotate老日志文件之后,创建一个新的空日志文件  
create  

# use date as a suffix of the rotated file:
#rotate的文件以日期格式为后缀,比如:access_log-20200422,
#如果不加这个选项,rotate的格式为:access_log.1,access_log.2等等。  
dateext  

# uncomment this if you want your log files compressed:
# 如果想压缩rotate后的文件,把下面compress前面的#号去掉就可以了。  
#compress  

# RPM packages drop log rotation information into this directory:
# RPM包的日志rotation配置信息,建议放到/etc/logrotate.d这个文件夹下,
# 实现自定义控制log文件rotate  
include /etc/logrotate.d 

# no packages own wtmp and btmp -- we'll rotate them here:wtmp和btmp
# 这两个不属于任何package,我们就把rotate的规则写到这里
/var/log/wtmp {  
   monthly #每个月执行一次rotate  
   create 0664 root utmp  #创建空文件,权限是664, 所属用户名 所属用户组  
   minsize 1M       #日志文件大小超过1M才执行rotate,否则跳过  
   rotate 1         #rotate时,只保留一份rotate文件  
  }  
/var/log/btmp {  
   missingok  
   monthly  
   create 0600 root utmp  
   rotate 1  
  }  
  
 # system-specific logs may be also be configured here.
 # 其它系统日志也可以在这里配置rotate规则

RPM包的日志配置信息,建议放到/etc/logrotate.d下,具体的日志配置信息如下:

/var/log/xxx.log { # 日志路径
    size=500M # 当日志文件到达指定的大小时才转储/分割,默认的大小单位是bytes
    dateext # 使用当期日期作为命名格式
    rotate 365 # 指定rotate日志文件保留的数量
    compress # 通过gzip压缩然后备份日志
    delaycompress # 延迟压缩旧的日志文件,先rotate,不压缩;等下次rotate时,再压缩;需要跟compress同时使用
    missingok # 如果日志不存在,不产生错误信息
    notifempty # 如果日志为空,不做rotate,与ifempy互斥
    # sharedscripts # 配合prerotate and postrotate 使用
    create 644 root root # rotate之后,创建新文件的日志文件并指定新文件的属性
    postrotate # rotate之后想要执行的脚本,需要放在postrotate 与 endscript中间,这两个选项要单独成行
        /usr/bin/killall -HUP rsyslogd
    endscript
}

为什么备份日志一天一次呢?是因为在/etc/cron.daily下有个logrotate可执行脚本,脚本内容如下:

#!/bin/sh  
/usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf  
EXITVALUE=$?  
if [ $EXITVALUE != 0 ]; then  
   /usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"  
fi  
exit 0
crond

当然也可以自定义crontab计划。
这里再介绍一下crontab的简单用法:
Linux的调度任务分为两类:
系统调度任务,由crond服务来控制,默认随系统启动;
用户调度任务,使用crontab设置任务计划;
image.png
crondtab配置文件如下所示:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin #系统命令路径
MAILTO=root # crond的任务执行信息将通过电子邮件发送给root用户
HOME = / # 执行命令或者脚本时使用的主目录
# For details see man 4 crontabs
# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed
  0  0  *  *  * root       /bin/sh /etc/cron.daily/logrotate
crontab命令详解
crontab [-u user] file
crontab [ -u user ] [ -i ] { -e | -l | -r }
  • -u user:用于设定某个用户的crontab服务;
  • file: file为命令文件名,表示将file作为crontab的任务列表文件并载入crontab;
  • -e:编辑某个用户的crontab文件内容,如不指定用户则表示当前用户;
  • -l:显示某个用户的crontab文件内容,如不指定用户则表示当前用户;
  • -r:从/var/spool/cron目录中删除某个用户的crontab文件。
  • -i:在删除用户的crontab文件时给确认提示。
crontab注意点
  1. crontab有2种编辑方式:直接编辑/etc/crontab文件与crontab –e,其中/etc/crontab里的计划任务是系统中的计划任务,而用户的计划任务需要通过crontab –e来编辑;
  2. 每次编辑完某个用户的cron设置后,cron自动在/var/spool/cron下生成一个与此用户同名的文件,此用户的cron信息都记录在这个文件中,这个文件是不可以直接编辑的,只可以用crontab -e 来编辑。
  3. crontab中的command尽量使用绝对路径,否则会经常因为路径错误导致任务无法执行。
  4. 新创建的cron job不会马上执行,至少要等2分钟才能执行,可从起cron来立即执行。
  5. %在crontab文件中表示“换行”,因此假如脚本或命令含有%,需要使用%来进行转义。

总结:

1.线上配置一般不会更改;
2.线上服务器一定不能在线做修改、删除等操作;
3.最后排查,是docker内的crond服务挂掉,重启crond服务后,日志分割正常;

参考文档:
刘江的博客
Linux自带神器logrotate详解
crontab用法与实例

知识到技能,需要千锤百炼

1 声望
0 粉丝
0 条评论
推荐阅读
Django ORM基本介绍
要从数据库中检索对象,即数据记录,要通过模型类的Manager(默认名称是objects,可以对其重写)构建一个QuerySet。一个QuerySet代表来自数据库中对象的一个集合,对应SQL的SELECT语句,可以通过filters来缩小范...

詹姆斯大胡子阅读 947

Mysql到TiDB迁移,双写数据库兜底方案
TiDB 作为开源 NewSQL 数据库的典型代表之一,同样支持 SQL,支持事务 ACID 特性。在通讯协议上,TiDB 选择与 MySQL 完全兼容,并尽可能兼容 MySQL 的语法。因此,基于 MySQL 数据库开发的系统,大多数可以平滑迁...

京东云开发者阅读 819

封面图
三、djanjo
Django 提示:本文根据b站黑马python课整理链接指引 => 黑马程序员python企业级开发项目-手把手从0到1开发《美多商城》视图介绍和项目准备视图介绍视图就是应用中views.py文件中的函数视图的第一个参数必须为H...

玲小叮当阅读 754

Django 简介
Django简介Django 是 Python 语言的 Web 框架,开源且免费,可以用于满足快速开发网站的需求。Django 接管了 Web 开发过程中的方方面面,所以开发者可以专注于编写应用程序,而不需要重新造轮子。Django 的特点:...

Risejl阅读 728

一、Django
Django 提示:本文根据b站黑马python课整理链接指引 => 黑马程序员python企业级开发项目-手把手从0到1开发《美多商城》一、Django介绍1.1 MVT模式M全拼为Model,与MVC中的M功能相同,负责和数据库交互,进行数...

玲小叮当阅读 654

开源C语言库Melon:Cron格式解析
本文介绍开源C语言库Melon的cron格式解析。关于 Melon 库,这是一个开源的 C 语言库,它具有:开箱即用、无第三方依赖、安装部署简单、中英文文档齐全等优势。Github repo简介cron也就是我们常说的Crontab中的时...

用户bPbzEjV阅读 633

封面图
Django大坑之外键设置外键冲突
用Django开发了一个在线教育网站,众所周知,Django是一个开发后端的一个强大框架,用了它就不用管MySQL里面的增删改查,直接在PyCharm里迁移搞定。想在课程机构页显示课程信息表里的数据,就不得不用到外键。

achievability阅读 436

知识到技能,需要千锤百炼

1 声望
0 粉丝
宣传栏