• 安全管理之日常日志审计


    一、背景

    随着运维的不断深化,体系化建设逐渐规范,对运维工作的日常审计是运维工作人员不得不面对的一项工作,它涉及的面广,且容易被忽略,对此,我们站在审计人员的角度,来看下如何对日志进行配置用作审计检查。

    在这里插入图片描述

    二、日志类别

    1、主机/系统日志:

    linux系统中/var/log/目录日志默认保存四周且并不自动生成系统日志(syslog.log),可以配置/etc/rsyslog.conf或/etc/syslog-ng/syslog-ng.conf让系统生成该日志文件。当用户有规定保存多少天时才去进行修改。系统日志路径为/var/log/。其中依靠的Logrotate是基于CRON来运行的,其脚本是/etc/cron.daily/logrotate,实际运行时,Logrotate会调用配置文件/etc/logrotate.conf。

    系统日志文件保存的时间

    修改/etc/logrotate.conf 中的

    ……
    monthly   #daily,weekly,monthly可选
    # keep 4 weeks worth of backlogs
    rotate 4  #改为rotate 12
    
    /var/log/wtmp {
        monthly
        create 0664 root utmp
        rotate 1 #1改为3,
    }
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    完成后:service rsyslog restart令重启syslog进程。
    在这里插入图片描述

    #cat /etc/cron.daily/logrotate
    #!/bin/sh
    
    /usr/sbin/logrotate /etc/logrotate.conf >/dev/null 2>&1
    EXITVALUE=$?
    if [ $EXITVALUE != 0 ]; then
        /usr/bin/logger -f logrotate "ALERT exited abnormally with [$EXITVALUE]"
    fi
    exit 
    
    #logrotate -d /etc/logrotate.d/nginx   #预演,不实际轮询(切割)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    #cat /etc/logrotate.d/syslog  系统日志
    /var/log/cron
    /var/log/maillog
    /var/log/messages
    /var/log/secure
    /var/log/history
    {
        sharedscripts  ##所有的日志文件都轮转完毕后统一执行一次脚本
        compress
        rotate 12
        monthly
        dateext
        notifempty   #如果日志文件为空,轮循不会进行
        missingok	  #在日志轮循期间,任何错误将被忽略
        postrotate
          /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
        endscript
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    对于windows:cmd输入eventvwr,打开事件查看器:修改策略和存储大小,默认是20M,满了会覆盖之前的
    在这里插入图片描述
    或cmd输入regedit打开注册表:修改如下值
    在这里插入图片描述

    控制面板->管理工具->本地安全策略”,在“本地策略->审核策略或cmd里输入gpedit.msc:
    在这里插入图片描述

    2、业务应用日志

    3、安全日志:

    4、数据库日志:

    三、日志配置

    3.1 Mysql日志审计

    MySQL 中基本就是4种不同的日志,分别:错误日志(error日志或mysqld日志)、二进制日志(binlog 日志)、通用查询日志(general日志)和慢查询日志(slow-query);一般审计要求:日志要保存6个月(180天);

    在这里插入图片描述
    SQL语言类别回顾:

    DQL (Data Query Language-数据查询语言) - Select 查询语句不存在提交问题。
    DML (Data Manipulation Language-数据操作语言) :用来定义数据库记录; Insert、Update、Delete,实现数据的“增删改。”
    DDL (Data Definition Language-数据定义语言) :定义数据库对象:库、表、列,对逻辑结构等有操作的语句,其中包括表结构,视图和索引。有 Create、Alter、Drop,实现表格的“增删改”。
    DTL (Transaction Control Language-事务控制语言) - Commit、Rollback事务提交、回滚语句。
    DCL (Data Control Language-数据控制语言) - Grant、Revoke 权限语句。

    1)错误日志:

    它记录了当 mysqld 启动和停止时,以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时,可以首先查看此日志。它会一致存在直到执行FLUSH ERROR LOGS;生成新的日志;

    [mysqld]
    
    log_error = /var/log/mysql/logs/error.log  #或/var/log/mysql/logs/mysqld.log;它的作用范围为全局或会话级别,属非动态变量,只读的。
    
    //或在mysqld启动时用--log-error参数指定路径
    
    #表示是否记录告警信息到错误日志,0表示不记录告警信息,1表示记录告警信息,大于1表示各类告警信息
    mysql> show variables where variable_name="log_error" or variable_name="log_warnings";
    +---------------+---------------------+
    | Variable_name | Value               |
    +---------------+---------------------+
    | log_error     | /var/log/mysqld.log |
    | log_warnings  | 2                   |
    +---------------+---------------------+
    2 rows in set (0.00 sec)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2)bin-log二进制日志:

    它记录了数据库所有执行的DDL和DML语句(除了数据查询语句select、show等),但不记录SELECT、SHOW等那些不改变数据库的SQL语句,以事件形式记录并保存在二进制文件中。常用于数据恢复和主从复制。执行flush logs;会生产新的binlog;

    [mysqld]
    
    server-id = 50
    
    log-bin = /opt/mysql/datas/
    
    binlog_format = row
    
    expire_logs_days = 15  #保存15天,默认值为0,表示不自动删除,可设置为0~99
    
    max_binlog_size = 512M    #Binlog最大值,最大和默认值是1GB,该设置并不能严格控制Binlog的大小,尤其是Binlog比较靠近最大值而又遇到一个比较大事务时,为了保证事务的完整性,不可能做切换日志的动作,只能将该事务的所有SQL都记录进当前日志,直到事务结束; 如果二进制日志写入的内容超出给定值,日志就会发生滚动。你不能将该变量设置为大于1GB或小于4096字节。 默认值是1GB。
    
    #binlog_expire_logs_seconds;它是8.0里面新增的,优先级比expire_logs_days高
    #sync_binlog=0;Mysql中默认的设置是sync_binlog=0,即不作任何强制性的磁盘刷新指令,这时性能是最好的,但风险也是最大的。一旦系统绷Crash,在文件系统缓存中的所有Binlog信息都会丢失
    
    #当事务提交后,Mysql仅仅是将binlog_cache中的数据写入Binlog文件,但不执行fsync之类的磁盘 同步指令通知文件系统将缓存刷新到磁盘,而让Filesystem自行决定什么时候来做同步,这个是性能最好的。
    
    #sync_binlog=n,在进行n次事务提交以后,Mysql将执行一次fsync之类的磁盘同步指令,同志文件系统将Binlog文件缓存刷新到磁盘。
    
    binlog_do_db  #此参数表示只记录指定数据库的二进制日志
    
    binlog_ignore_db   #此参数表示不记录指定的数据库的二进制日志
    
    max_binlog_cache_size  #此参数表示binlog使用的内存最大的尺寸
    
    binlog_cache_size   #此参数表示binlog使用的内存大小,可以通过状态变量binlog_cache_use和binlog_cache_disk_use来帮助测试。
    
    binlog_cache_use   #使用二进制日志缓存的事务数量
    
    binlog_cache_disk_use   #使用二进制日志缓存但超过binlog_cache_size值并使用临时文件来保存事务中的语句的事务数量
    
    #查询
    mysql> select @@version;
    mysql> show variables like '%expire_log%';
    mysql> show variables like '%expire%';  #5.7.20显示如下
    +--------------------------------+-------+
    | Variable_name                  | Value |
    +--------------------------------+-------+
    | disconnect_on_expired_password | ON    |
    | expire_logs_days               | 0     |
    +--------------------------------+-------+
    2 rows in set (0.02 sec)
    
    mysql> SET @set_value = 1073741824; 
    mysql> SET @@global.max_binlog_size = @set_value; 
    mysql> SELECT @@global.max_binlog_size; 
    mysql> set global expire_logs_days=7;
    mysql> show variables like ‘max_binlog_size’;
    mysql> show variables where variable_name="log_bin" or variable_name="log_bin_basename" or variable_name="max_binlog_size" or variable_name="log_bin_index" or variable_name="binlog_format" or variable_name="sql_log_bin" or variable_name="sync_binlog";
    +------------------+----------------------------------------+
    | Variable_name    | Value                                  |
    +------------------+----------------------------------------+
    | binlog_format    | ROW                                    |
    | log_bin          | ON                                     |
    | log_bin_basename | /usr/local/mysql/data/mysql-bin        |
    | log_bin_index    | /usr/local/mysql/data/master-bin.index |
    | max_binlog_size  | 1073741824(约1G)                             |
    | sql_log_bin      | ON                                     |
    | sync_binlog      | 1                                      |
    +------------------+----------------------------------------+
    7 rows in set (0.00 sec)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    结果说明:

    log_bin_basename:二进制日志文件前缀名,二进制日志就记录在该文件中

    max_binlog_size:二进制日志文件的最大大小,超过此大小,二进制文件会自动滚动

    log_bin_index:二进制日志文件索引文件名,用于记录所有的二进制文件

    binlog_format:决定了二进制日志的记录方式,STATEMENT以语句的形式记录,ROW以数据修改的形式记录,MIXED以语句和数据修改混合形式记录

    sql_log_bin:决定是否对二进制日志进行日志记录,ON表示执行记录,OFF表示不执行记录,默认OFF,这个是会话级别变量可以通SET sql_log_bin = {0|1}来改变该变量值

    sync_binlog:决定二进制日志写入磁盘时机,如果sync_binlog为0,操作系统来决定什么时候写入磁盘,如果sync_binlog为N(N=1,2,3…),则每N次事务提交后,立即将内存中的二进制日志写入磁盘,如何选择取决于安全性与性能的权衡

    二进制日志的三种记录方式说明:

    Statement:记录对数据库做出修改的语句,比如,update A set test=‘test’,如果使用statement模式,那么这条update语句将被记录到二进制日志中,使用statement模式时,优点是binlog日志量少,IO压力小,性能高,缺点是为了尽可能一致的还原操作,除了记录语句本身外,可能还需要记录一些相关信息,而且,在使用一些特定函数时,并不能保证恢复操作与记录完全一致

    ROW:记录对数据库做出的修改的语句所影响到的数据行以及这些行的修改,比如,update A set test=‘test’,如果使用row模式,那么这条update所影响到的行所对应的修改,将会记录在binlog中,使用row模式时,优点是能完还原和复制被日志记录时的操作,缺点是日志量较大,IO压力比较大,性能消耗比较大

    MIXED:混合上述两种模式,一般使用statement方式进行记录,如果遇到一些特殊函数使用row方式进行记录,这种记录方式称为mixed

    3)general日志

    general log记录了数据库执行的所有命令,不管这些语法是否正确,都会被记录;它是 MySQL 中记录最详细的日志,记录了 mysqld 所有相关操作,当 clients 连接或断开连接时,服务器将信息写入此日志,并记录从 clients 收到的每个 SQL 语句。由于数据库操作命令非常多而且比较频繁,开启了查询日志以后,会增大服务器的IO压力,增加很多的系统开销,默认情况下,mysql的查询日志是没有开启的,但是开启查询日志也有助于我们分析那些语句执行密集,执行密集的select语句对应的数据是否能够被缓存,查询日志也可以帮助我们分析问题,所以,如非出于调试排错目的,不建议开启通用查询日志。实际情况一般只是临时开启查询日志,随后使用完毕后再关闭。

    [mysqld]
    
    general_log = 0 //默认值是0,即不开启,可设置为1
    
    general_log_file = /opt/mysql/logs/general.log //指定日志位置及名称
    
    mysql> show variables where variable_name like "%general_log%" or variable_name ="log_output";
    +------------------+-----------------------------------------------+
    | Variable_name    | Value                                         |
    +------------------+-----------------------------------------------+
    | general_log      | ON                                            |
    | general_log_file | /usr/local/mysql/data/HBYGCG-Mysql-Master.log |
    | log_output       | FILE                                          |
    +------------------+-----------------------------------------------+
    3 rows in set (0.01 sec)
    
    #其中,log_output表示当查询日志开启以后,以哪种方式存放。FILE--文件,TABLE--表mysql.general_log中(慢查询存放于表mysql.slow_log),FILE,TABLE表示同时存放于文件和表中,NONE表示不记录日志。log_output不仅控制查询日志,还控制慢查询日志。
    
    mysql> purge master log before 'yyyy-mm-dd hh24:mi:ss'#将删除指定日期前的所有日志
    mysql> purge master logs to 'mysql-bin.xxx   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    binlog可用 mysqlbinlog 工具来查看,对于 statement 格式的文件可以用工具直接查看,对于 row 格式的要加 -v 或 -vv 参数进行读取。

    4)slow query日志

    它记录那些执行花费的时间特别长的sql语句,只要超过指定时间的sql语句,都称为“慢查询”,被记录在慢查询日志中。慢查询日志默认情况下是关闭的,默认设置下,超过10s的语句才会被记录到慢查询日志中。

    [mysqld]
    
    slow_query_log = 1  #是否启用慢查询日志,默认为0;slow_query_log = on
    
    slow_query_log_file = /data/mysql/logs/slow.log
    
    long_query_time = 3   #慢查询执行时间阈值,超过此时间会记录,默认为10,单位为s
    
    log_output = FILE  #慢查询日志输出目标,默认为file,即输出到文件
    
    log_queries_not_using_indexes = on #记录没有使用索引查询语句,到慢查询日志,OFF表示不记录,ON表示记录,默认OFF;
    
    mysql> show variables where variable_name like 'slow_query%' or variable_name='long_query_time' or variable_name='log_queries_not_using_indexes';
    +-------------------------------+----------------------------------------------------+
    | Variable_name                 | Value                                              |
    +-------------------------------+----------------------------------------------------+
    | log_queries_not_using_indexes | OFF                                                |
    | long_query_time               | 10.000000                                          |
    | slow_query_log                | ON                                                 |
    | slow_query_log_file           | /usr/local/mysql/data/HBYGCG-Mysql-Master-slow.log |
    +-------------------------------+----------------------------------------------------+
    4 rows in set (0.00 sec)
    mysql> show variables like “%long_query_time%”;
    
    #查看慢sql
    mysqldumpslow -s r -t 3 /var/lib/log.log  #获取返回记录最多的3个sql;其中s:排序方式,r:逆序,l:锁定时间g:正则匹配模式
    mysqldumpslow -s c -t 3 /var/lib/log.log  #获取访问次数最多的3个sql
    
    mysqldumpslow -s t -t 10 -g "left join" /var/lib/log.log #按照时间排序,前十条包含left join查询语句的sql
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    5)中继日志(relay log):主从架构中

    用于主从复制架构中的从服务器上,从服务器的 slave 进程从主服务器处获取二进制日志的内容并写入中继日志,然后由 IO 进程读取并执行中继日志中的语句。relay log 相关参数一般在从库设置;

    [mysqld]
    
    relay_log = /data/mysql/logs/relay-bin
    
    relay_log_purge = 1  #是否自动清空不再需要中继日志,默认值为1(启用)。
    
    relay_log_recovery = 1  #当 slave 从库宕机后,假如 relay log 损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的 relay log ,并且重新从 master 上获取日志,这样就保证了 relay log 的完整性。默认情况下该功能是关闭的,将 relay_log_recovery 的值设置为1可开启此功能。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果慢查询日志中记录内容很多,可以使用 mysqldumpslow 工具对慢查询日志进行分类汇总。对于 sql 文本完全一致,只是变量不同的语句,mysqldumpslow 将会自动视为同一个语句进行统计,变量值用 N 来代替。这个统计结果将大大增加用户阅读慢查询日志的效率,迅速定位系统的 sql 瓶颈。

    6)日志报错时长

    mysql> show variables like '%logs_days%';  #查看当前过期时间,0为无限制
    
    • 1

    当然可以配置/etc/logrotate.d/mysqld来分隔即限制日志保留时长

    "Mysqld.log" /var/log/mysql/logs/mysqld.log {
            create 600 mysql mysql
            dateext
            notifempty
            monthy
            maxage 182
            rotate 6
            missingok
            compress
            olddir  /var/log/mysql/logs/
        postrotate  #执行命令,刷新日志
            # just if mysqld is really running
            if test -x /usr/local/mysql/bin/mysqladmin &&; \
               /usr/local/mysql/bin/mysqladmin ping  -uroot -pPASSWORD -S /tmp/mysql_3306.sock 2&1 >/dev/null
            then
               /usr/local/mysql/bin/mysqladmin flush-logs -uroot -pPASSWORD -S /tmp/mysql_3306.sock
            fi
        endscript
    #j计划任务
    crontab -e
    59 23 * * * root /usr/sbin/logrotate -f /etc/logrotate.d/mysqld
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    7)日志清理

    #!/usr/bin/env bash
    ##脚本日志为本地执行
    
    source /etc/profile
    
    #定义全局变量, 相当于配置文件, 只是懒得去整.
    
    export LANG=en_US.UTF-8
    export THIS_PID=$$
    umask 0022 #EulerOS之类的默认umask可能不是0022, 会有目录权限问题
    stty erase ^H
    #数据库信息
    MYSQL_HOST='127.0.0.1'
    MYSQL_PORT='3308'
    MYSQL_USER='root'
    MYSQL_PASSWORD='123456'
    MYSQL_SOCKET='/data/mysql_3308/run/mysql.sock' 
    
    
    #SLOW_LOG
    #SLOW_LOG_FILE='/data/mysql_3308/mysqllog/dblogs/slow3308.log'  #为空的话, 就自动查询, 优先使用手动配置的
    SLOW_LOG_MAX_SIZE='52428800' #慢日志最大的大小, 超过之后就切换日志, 并归档
    SLOW_LOG_TAR_EXPIRE_DAYS='60' #切换之后的日志过期时间, 超过之后就删除
    SLOW_LOG_TAR_DIR='' #切换之后的日志的保存目录, 为空的时候,表示原来的路径
    
    #ERROR LOG
    #ERROR_LOG_FILE='/data/mysql_3308/mysqllog/dblogs/mysql3308.err' #为空的话, 就自动查询
    ERROR_LOG_MAX_SIZE='52428800' #错误日志大小, 超过就切换并归档
    ERROR_LOG_TAR_EXPIRE_DAYS='60' #归档的错误日志的最大保存时间, 过期就删除
    ERROR_LOG_TAR_DIR='' #切换之后的日志的保存目录
    
    #GENERAL LOG
    #GENERAL_LOG_FILE='/data/mysql_3308/mysqllog/dblogs/general3308.log' #为空就自动查询
    GENERAL_LOG_MAX_SIZE='524288000' #500MB
    GENERAL_LOG_TAR_EXPIRE_DAYS='60'
    GENERAL_LOG_TAR_DIR=''
    
    #BINLOG  不支持, 就系统自动清理就行, 也可以参考,
    #PURGE BINARY LOGS TO 'mysql-bin.010';
    #PURGE BINARY LOGS BEFORE '2022-04-02 22:46:26';
    
    MYSQL1="mysql --host=${MYSQL_HOST} --port=${MYSQL_PORT} --user=${MYSQL_USER} --password=${MYSQL_PASSWORD}"
    MYSQL2="mysql --socket=${MYSQL_SOCKET} --password=${MYSQL_PASSWORD}"
    
    echo_color(){
    	echo "[$1][$(date +'%Y%m%d %H:%M:%S')] $2"
    }
    
    clear_error_log(){
    	if [ "${ERROR_LOG_FILE}" == "" ];then
    		echo_color "INFO" "error log (var:ERROR_LOG_FILE) is null, will auto get"
    		ERROR_LOG_VAR=`echo $(${MYSQL1} -e "show global variables like 'log_error';" 2>/dev/null) | awk '{print $NF}'`
    		if [ "${ERROR_LOG_VAR:0:1}" == "/" ];then
    			ERROR_LOG_FILE=${ERROR_LOG_VAR}
    		else
    			ERROR_LOG_FILE=${MYSQL_DATA_DIR}${ERROR_LOG_VAR}
    		fi
    	fi
    
    	if [ -f ${ERROR_LOG_FILE} ];then
    		if $(${MYSQL1} -e "FLUSH ERROR LOGS;" 2>/dev/null);then
    			if [ "${ERROR_LOG_TAR_DIR}" == "" ];then ERROR_LOG_TAR_DIR=${ERROR_LOG_FILE%/*};fi
    			ERROR_LOG_FILE_NAME=${ERROR_LOG_FILE##*/}$(date +'%Y%m%d_%H%M%S')"_WILL_BE_DELETE"
    			if [ $(du -sb ${ERROR_LOG_FILE} | awk '{print $1}') -gt ${ERROR_LOG_MAX_SIZE} ];then
    				if mv ${ERROR_LOG_FILE} ${ERROR_LOG_TAR_DIR}/${ERROR_LOG_FILE_NAME};then
    					${MYSQL1} -e "FLUSH ERROR LOGS;" 2>/dev/null || echo_color "ERROR" "maybe flush error log failed."
    					old_tmp_dir=$(pwd)
    					cd ${ERROR_LOG_TAR_DIR}
    					tar -zcf ${ERROR_LOG_FILE_NAME}.tar.gz --remove-files ${ERROR_LOG_FILE_NAME} || echo_color "INFO" "tar -zcvf ${ERROR_LOG_TAR_DIR}/${ERROR_LOG_FILE_NAME}.tar.gz --remove-files ${ERROR_LOG_TAR_DIR}/${ERROR_LOG_FILE_NAME} failed. will be skip"
    					cd ${old_tmp_dir}
    					echo_color "INFO" "Rotation error log success"
    					#tar成功之后, 清除过期的备份日志
    					for need_remove_file in `find ${ERROR_LOG_TAR_DIR} -mtime +${ERROR_LOG_TAR_EXPIRE_DAYS} -name "*_WILL_BE_DELETE.tar.gz"`
    					do
    						if [ -f ${need_remove_file} ];then
    							rm -rf ${need_remove_file} && echo_color "INFO" "delete error log ${need_remove_file} success"
    						fi
    					done
    				else
    					echo_color "ERROR" "mv ${ERROR_LOG_FILE} ${ERROR_LOG_TAR_DIR}/${ERROR_LOG_FILE_NAME} failed, will skip error log"
    				fi
    			else
    				echo_color "INFO" "error log (${ERROR_LOG_FILE}) less than ${ERROR_LOG_MAX_SIZE}, will skip"
    			fi
    		else
    			echo_color "ERROR" "Maybe Access denied; you need (at least one of) the RELOAD privilege(s) for this operation"
    		fi
    	else
    		echo_color "INFO" "error log ${ERROR_LOG_FILE} not exist, will skip"
    	fi
    }
    
    clear_slow_log(){
    	if [ "${SLOW_LOG_FILE}" == "" ];then
    		echo_color "INFO" "slow log (var:SLOW_LOG_FILE) is null, will auto get"
    		SLOW_LOG_VAR=`echo $(${MYSQL1} -e "show global variables like 'slow_query_log_file';" 2>/dev/null) | awk '{print $NF}'`
    		if [ "${SLOW_LOG_VAR:0:1}" == "/" ];then
    			SLOW_LOG_FILE=${SLOW_LOG_VAR}
    		else
    			SLOW_LOG_FILE=${MYSQL_DATA_DIR}${SLOW_LOG_VAR}
    		fi
    	fi
    
    	if [ -f ${SLOW_LOG_FILE} ];then
    		if $(${MYSQL1} -e "FLUSH SLOW LOGS;" 2>/dev/null);then
    			if [ "${SLOW_LOG_TAR_DIR}" == "" ];then SLOW_LOG_TAR_DIR=${SLOW_LOG_FILE%/*};fi
    			SLOW_LOG_FILE_NAME=${SLOW_LOG_FILE##*/}$(date +'%Y%m%d_%H%M%S')"_WILL_BE_DELETE"
    			if [ $(du -sb ${SLOW_LOG_FILE} | awk '{print $1}') -gt ${SLOW_LOG_MAX_SIZE} ];then
    				if mv ${SLOW_LOG_FILE} ${SLOW_LOG_TAR_DIR}/${SLOW_LOG_FILE_NAME};then
    					${MYSQL1} -e "FLUSH SLOW LOGS;" 2>/dev/null || echo_color "ERROR" "maybe flush slow log failed."
    					old_tmp_dir=$(pwd)
    					cd ${SLOW_LOG_TAR_DIR}
    					tar -zcf ${SLOW_LOG_FILE_NAME}.tar.gz --remove-files ${SLOW_LOG_FILE_NAME} || echo_color "INFO" "tar -zcvf ${SLOW_LOG_TAR_DIR}/${SLOW_LOG_FILE_NAME}.tar.gz --remove-files ${SLOW_LOG_TAR_DIR}/${SLOW_LOG_FILE_NAME} failed. will be skip"
    					cd ${old_tmp_dir}
    					echo_color "INFO" "Rotation slow log success"
    					#tar成功之后, 清除过期的备份日志
    					for need_remove_file in `find ${SLOW_LOG_TAR_DIR} -mtime +${SLOW_LOG_TAR_EXPIRE_DAYS} -name "*_WILL_BE_DELETE.tar.gz"`
    					do
    						if [ -f ${need_remove_file} ];then
    							rm -rf ${need_remove_file} && echo_color "INFO" "delete slow log ${need_remove_file} success"
    						fi
    					done
    				else
    					echo_color "ERROR" "mv ${SLOW_LOG_FILE} ${SLOW_LOG_TAR_DIR}/${SLOW_LOG_FILE_NAME} failed, will skip slow log"
    				fi
    			else
    				echo_color "INFO" "slow log (${SLOW_LOG_FILE}) less than ${SLOW_LOG_MAX_SIZE}, will skip"
    			fi
    		else
    			echo_color "ERROR" "Maybe Access denied; you need (at least one of) the RELOAD privilege(s) for this operation"
    		fi
    	else
    		echo_color "INFO" "slow log ${SLOW_LOG_FILE} not exist, will skip"
    	fi
    }
    
    clear_general_log(){
    	if [ "${GENERAL_LOG_FILE}" == "" ];then
    		echo_color "INFO" "GENERAL log (var:GENERAL_LOG_FILE) is null, will auto get"
    		GENERAL_LOG_VAR=`echo $(${MYSQL1} -e "show global variables like 'general_log_file';" 2>/dev/null) | awk '{print $NF}'`
    		if [ "${GENERAL_LOG_VAR:0:1}" == "/" ];then
    			GENERAL_LOG_FILE=${GENERAL_LOG_VAR}
    		else
    			GENERAL_LOG_FILE=${MYSQL_DATA_DIR}${GENERAL_LOG_VAR}
    		fi
    	fi
    
    	if [ -f ${GENERAL_LOG_FILE} ];then
    		if $(${MYSQL1} -e "FLUSH GENERAL LOGS;" 2>/dev/null);then
    			if [ "${GENERAL_LOG_TAR_DIR}" == "" ];then GENERAL_LOG_TAR_DIR=${GENERAL_LOG_FILE%/*};fi
    			GENERAL_LOG_FILE_NAME=${GENERAL_LOG_FILE##*/}$(date +'%Y%m%d_%H%M%S')"_WILL_BE_DELETE"
    			if [ $(du -sb ${GENERAL_LOG_FILE} | awk '{print $1}') -gt ${GENERAL_LOG_MAX_SIZE} ];then
    				if mv ${GENERAL_LOG_FILE} ${GENERAL_LOG_TAR_DIR}/${GENERAL_LOG_FILE_NAME};then
    					${MYSQL1} -e "FLUSH GENERAL LOGS;" 2>/dev/null || echo_color "ERROR" "maybe flush GENERAL log failed."
    					old_tmp_dir=$(pwd)
    					cd ${GENERAL_LOG_TAR_DIR}
    					tar -zcf ${GENERAL_LOG_FILE_NAME}.tar.gz --remove-files ${GENERAL_LOG_FILE_NAME} || echo_color "INFO" "tar -zcvf ${GENERAL_LOG_TAR_DIR}/${GENERAL_LOG_FILE_NAME}.tar.gz --remove-files ${GENERAL_LOG_TAR_DIR}/${GENERAL_LOG_FILE_NAME} failed. will be skip"
    					cd ${old_tmp_dir}
    					echo_color "INFO" "Rotation GENERAL log success"
    					#tar成功之后, 清除过期的备份日志
    					for need_remove_file in `find ${GENERAL_LOG_TAR_DIR} -mtime +${GENERAL_LOG_TAR_EXPIRE_DAYS} -name "*_WILL_BE_DELETE.tar.gz"`
    					do
    						if [ -f ${need_remove_file} ];then
    							rm -rf ${need_remove_file} && echo_color "INFO" "delete GENERAL log ${need_remove_file} success"
    						fi
    					done
    				else
    					echo_color "ERROR" "mv ${GENERAL_LOG_FILE} ${GENERAL_LOG_TAR_DIR}/${GENERAL_LOG_FILE_NAME} failed, will skip GENERAL log"
    				fi
    			else
    				echo_color "INFO" "GENERAL log (${GENERAL_LOG_FILE}) less than ${GENERAL_LOG_MAX_SIZE}, will skip"
    			fi
    		else
    			echo_color "ERROR" "Maybe Access denied; you need (at least one of) the RELOAD privilege(s) for this operation"
    		fi
    	else
    		echo_color "INFO" "GENERAL log ${GENERAL_LOG_FILE} not exist, will skip"
    	fi
    }
    
    if ${MYSQL1} -e "select @@version;" 1>/dev/null 2>&1 ;then
    	export MYSQL_DATA_DIR=`echo $(${MYSQL1} -e "show global variables like 'datadir';" 2>/dev/null) | awk '{print $NF}'`
    	clear_error_log
    	clear_slow_log
    	clear_general_log
    else
    	echo_color "ERROR" "connect failed, please check host:port or user/password"
    fi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188

    3.2、应用日志

    1)Nginx日志切割

    /usr/local/nginx/logs/*log {
        daily
        rotate 365
        missingok
        notifempty
        compress
        dateext
        sharedscripts
        postrotate
        /etc/init.d/nginx reload
        endscript
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    四、日志处理

    4.1、日志切割

    1)Nginx日志shell切割

    #!/bin/sh
    
    function rotate() {
    logs_path=$1
    
    echo Rotating Log: $1
    cp ${logs_path} ${logs_path}.$(date -d "yesterday" +"%Y%m%d")
    > ${logs_path}
        rm -f ${logs_path}.$(date -d "7 days ago" +"%Y%m%d")
    }
    
    for i in $*
    do
            rotate $i
    done
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    #!/bin/bash
    # 日志文件存放目录
    logs_path="/opt/logs/"
    # 日志文件的名字,多个需要空格隔开
    logs_names=(error access pv_access)
    dates=`date -d "yesterday" +"%Y%m%d"`
    mkdir -p ${logs_path}$dates/
    num=${#logs_names[@]}
    for((i=0;i<num;i++));do
    mv ${logs_path}${logs_names[i]}.log ${logs_path}$dates/${logs_names[i]}.log
    done
    #nginx平滑重启
    kill -USR1 `cat /letv/logs/nginx/nginx.pid`   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    #!/bin/bash
    #创建转储日志压缩存放目录
    mkdir -p /data/nginx_logs/days
    #手工对nginx日志进行切割转换
    /usr/sbin/logrotate -vf /etc/logrotate.d/nginx
    #当前时间
    time=$(date -d "yesterday" +"%Y-%m-%d")
    #进入转储日志存放目录
    cd /data/nginx_logs/days
    #对目录中的转储日志文件的文件名进行统一转换
    for i in $(ls ./ | grep "^\(.*\)\.[[:digit:]]$")
    do
    mv ${i} ./$(echo ${i}|sed -n 's/^\(.*\)\.\([[:digit:]]\)$/\1/p')-$(echo $time)
    done
    #对转储的日志文件进行压缩存放,并删除原有转储的日志文件,只保存压缩后的日志文件。以节约存储空间
    for i in $(ls ./ | grep "^\(.*\)\-\([[:digit:]-]\+\)$")
    do
    tar jcvf ${i}.bz2 ./${i}
    rm -rf ./${i}
    done
    #只保留最近7天的压缩转储日志文件
    find /data/nginx_logs/days/* -name "*.bz2" -mtime 7 -type f -exec rm -rf {} \;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    4.2、日志打包

    1)Nginx日志定期打包

    #!/bin/bash
    #按实际情况按需修改
    yesterday=`date -d "-1 days" +'%Y%m%d'`
    cd `dirname $0`
    basedir=`pwd`
    logdir="${basedir}/bak"
    bindir="${basedir%/*}/sbin"
    mkdir -p ${logdir}
    
    for log in `ls *.log 2>/dev/null`
    do
        mv ${log} ${logdir}/${log}.${yesterday}.bak
        # gzip ${logdir}/${log}.${yesterday}
    done
    
    ${bindir}/nginx -s reload
    
    cd ${logdir}
    find . -type f -name "*.bak" -mtime +7 | xargs rm -f
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    #!/usr/bin/sh
    #根据系统/服务/日志保留天数三个参数压缩日志
    #usage: sh clearlog.sh sysname appname keepdays
    sysName=$1
    appName=$2
    keepDay=$3
    logDir=/var/log/${sysName}/${appName}
    logFile=${appName}.*[0-9][0-9].log
    cd ${logDir}
    find ./ -name "${logFile}" -mtime -${keepDay} -exec gzip {} \;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.3 日志查阅

    1)windows

    可以使用WinLogView和FullEventLogView工具,辅助分析;微软公司也自己出品windows的日志分析工具Log Parser,非常实用;

  • 相关阅读:
    Redis入门完整教程:客户端案例分析
    每日leetcode_LCP01猜数字
    曝 iPhone 设计主管明年 2 月离职,将联手 OpenAI 开发一款新 AI 硬件?
    软件流程和管理(四):PMP & Stakeholder Management
    测试工作中的测试用例设计
    单调栈(力扣496、LCR03、503)
    springboot二手交易平台 毕业设计-附源码290915
    【C++】多态“别太离谱!”
    微信小程序 uniapp+vue餐厅美食就餐推荐系统
    ssh-keygen 常用命令与参数
  • 原文地址:https://blog.csdn.net/ximenjianxue/article/details/127383122