Nginx日志纳入日志系统

目录

一、日志系统

二、Nginx日志

1. access_log

2. error_log

三、Nginx日志分割

1. 分割脚本nginxLogRotate.sh

2. Linux安装crontab

3. 添加定时任务

4. 启动定时任务并验证

四、Nginx日志纳入日志系统

1. 定义日志文件

2. access_log日志格式及内容

3. filebeat配置

4. storm解析日志

5. ES并Kibana查看

五、参考资料


一、日志系统

        日志系统是基于ELK + Storm完成,解决分布式中多节点日志处理。Nginx日志也纳入到日志系统处理,可以解决Nginx问题查看、总流量、本地缓存命中率等问题

        Nginx的日志分为两方面:access_log与error_log。其中access_log可以自定义格式及内容;而error_log是基于Linux系统日志(不方便修改)。所以导致两种日志格式不同,但不影响filebeat对打印日志的收集。

        随着Nginx的日志量变大,需要Linux的定时任务crondtab,定时分割Nginx日志(按天分割),这样查询本地日志很方便。

二、Nginx日志

1. access_log

语法:access_log path [format [buffer=size [flush=time]]];

默认值:access_log logs/access.log combined;

配置段:http, server,location;

http {

	# 定义日志格式
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
	log_format json '$time_iso8601 | {"timestamp": "$time_iso8601", '
                '"remoteAddr": "$remote_addr", '
                '"remoteUser": "$remote_user", '
                '"bodyBytesSent": "$body_bytes_sent", '
                '"requestTime": "$request_time", '
                '"upstreamResponseTime": "$upstream_response_time", '
                '"status": "$status", '
                '"host": "$host", '
                '"request": "$request", '
                '"requestMethod": "$request_method", '
                '"uri": "$uri", '
                '"httpReferrer": "$http_referer", '
                '"size": "$body_bytes_sent", '
                '"userIp": "$http_x_forwarded_for", '
				'"mobile": "$http_Mobile", '
				'"token": "$http_UserToken", '
				'"channel": "$http_Channel", '
				'"appVersion": "$http_AppVersion", '
                '"userAgent": "$http_user_agent" '
                '}';

	# 定义访问日志
    access_log  logs/access.log  json;
	# 关闭访问记录
	# access_log off;

}

2. error_log

语法:error_log file | stderr | syslog:server=address[,parameter=value] [debug | info | notice |

        warn | error | crit | alert | emerg];

默认值:error_log logs/error.log error;

配置段:main,http,server,location;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;


http {
    
	# 自定义日志
	error_log logs/LOG_COMMON.log debug;
	error_log logs/LOG_INFO.log info;

}

三、Nginx日志分割

        Nginx长期使用,导致Nginx日志文件越来越大打开很慢,这就需要日志分割。思路是Linux定时器定时执行启动Nginx,复制日志到其他文件中即可

1. 分割脚本nginxLogRotate.sh

#!/bin/bash

#设置日志文件存放目录
LOG_HOME="/usr/local/openresty/nginx/logs"
PID=$LOG_HOME/nginx.pid

#备分文件名称
LOG_DATE=$(date -d yesterday +"%Y-%m-%d-%H-%M")

# 获取当前年信息和月信息
LOG_DIR=$(date -d yesterday +"%Y%m")
# 获取昨天的日信息
# day=$(date -d yesterday +"%d")
# 按年月创建文件夹
mkdir -p $LOG_HOME/$LOG_DIR

#重命名日志文件
mv $LOG_HOME/access.log $LOG_HOME/$LOG_DIR/access.$LOG_DATE.log
#等3秒后执行下一条
sleep 3
mv $LOG_HOME/error.log $LOG_HOME/$LOG_DIR/error.$LOG_DATE.log
sleep 3
mv $LOG_HOME/LOG_COMMON.log $LOG_HOME/$LOG_DIR/LOG_COMMON.$LOG_DATE.log
sleep 3
mv $LOG_HOME/LOG_INFO.log $LOG_HOME/$LOG_DIR/LOG_INFO.$LOG_DATE.log
sleep 3

# 通过Nginx信号量控制重读日志
kill -USR1 `cat $PID`

2. Linux安装crontab

yum install vixie-cron crontabs     

3. 添加定时任务

修改定时任务:crontab -e

任务内容:定时启动nginx:*/2 * * * * /usr/local/openresty/nginx/logs/nginxLogRotate.sh

查看所有定时任务:crontab -l

4. 启动定时任务并验证

crond start/stop/reload/restart

四、Nginx日志纳入日志系统

1. 定义日志文件

访问日志:access_log  logs/access.log  json;
错误日志:error_log logs/error.log error;
通用日志:error_log logs/LOG_COMMON.log debug;
INFO日志:error_log logs/LOG_INFO.log info;

注意:access_log可以自定义格式,但error_log不能;LOG_COMMON是通用日志,不搜集。

2. access_log日志格式及内容

log_format json '$time_iso8601 | {"timestamp": "$time_iso8601", '
                '"remoteAddr": "$remote_addr", '
                '"remoteUser": "$remote_user", '
                '"bodyBytesSent": "$body_bytes_sent", '
                '"requestTime": "$request_time", '
                '"upstreamResponseTime": "$upstream_response_time", '
                '"status": "$status", '
                '"host": "$host", '
                '"request": "$request", '
                '"requestMethod": "$request_method", '
                '"uri": "$uri", '
                '"httpReferrer": "$http_referer", '
                '"size": "$body_bytes_sent", '
                '"userIp": "$http_x_forwarded_for", '
				'"mobile": "$http_Mobile", '
				'"token": "$http_UserToken", '
				'"channel": "$http_Channel", '
				'"appVersion": "$http_AppVersion", '
                '"userAgent": "$http_user_agent" '
                '}';

3. filebeat配置

# Nginx日志
- type: log
  enabled: true
  paths:
    - /usr/local/openresty/nginx/logs/access.log
  fields: 
    log_type: NGINX_LOG_ACCESS
- type: log
  enabled: true
  paths:
    - /usr/local/openresty/nginx/logs/error.log
  fields: 
    log_type: NGINX_LOG_ERROR
- type: log
  enabled: true
  paths:
    - /usr/local/openresty/nginx/logs/LOG_INFO.log
  fields: 
    log_type: NGINX_LOG_INFO

4. storm解析日志

a. 实体类

package com.migu.storm.entity.nginx;

import com.migu.storm.entity.LogFileBeatContent;
import lombok.Data;

/**
 * @description Nginx日志FileBeat信息
 * @author tcm
 * @version 1.0.0
 * @date 2022/1/25 10:02
 **/
@Data
public class NginxLogFileBeat {

    // 日志FileBeat信息
    private LogFileBeatContent logFileBeatContent;

}
package com.migu.storm.entity.nginx;

import lombok.Data;

/**
 * @description Nginx的access日志
 * @author tcm
 * @version 1.0.0
 * @date 2022/1/25 9:26
 **/
@Data
public class NginxLogAccess extends NginxLogFileBeat {

    // 请求时间戳
    private String timestamp;
    // 请求IP
    private String remoteAddr;
    // 请求用户
//    private String remoteUser;
    // 请求服务器主机:IP + PORT
    private String host;
    // 请求信息:请求方式 + 请求URI + HTTP版本号
    private String request;
    // 请求方式
    private String requestMethod;
    // 请求URI
    private String uri;
    // 请求引用页面地址
//    private String httpReferrer;
    // 用户真实IP地址
//    private String userIp;
    // 手机号
    private String mobile;
    // token
    private String token;
    // 终端类型
    private String channel;
    // 版本号
    private String appVersion;
    // 请求代理
    private String userAgent;
    // 从upstream获取响应的处理时间
    private String upstreamResponseTime;
    // 响应状态
    private String status;
    // 响应体字节数
    private String bodyBytesSent;
    // 请求处理时间
    private String requestTime;
    // 日志内容
    private String message;

}
package com.migu.storm.entity.nginx;

import lombok.Data;

/**
 * @description Nginx的error日志
 * @author tcm
 * @version 1.0.0
 * @date 2022/1/25 10:07
 **/
@Data
public class NginxLogError extends NginxLogFileBeat {

    // 时间戳
    private String timestamp;
    // 日志级别
    private String logLevel;
    // 日志内容
    private String message;

}
package com.migu.storm.entity.nginx;

import lombok.Data;

/**
 * @description Nginx的INFO日志
 * @author tcm
 * @version 1.0.0
 * @date 2022/1/25 10:16
 **/
@Data
public class NginxLogInfo extends NginxLogFileBeat{

    // 时间戳
    private String timestamp;
    // 日志级别
    private String logLevel;
    // 日志内容
    private String message;

}

b. Bolt类

package com.migu.storm.bolt;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.migu.storm.config.ESConfig;
import com.migu.storm.entity.LogFileBeatContent;
import com.migu.storm.entity.nginx.NginxLogAccess;
import com.migu.storm.entity.nginx.NginxLogInfo;
import com.migu.storm.entity.nginx.NginxLogError;
import com.migu.storm.enumeration.NginxLogType;
import com.migu.storm.util.DateUtil;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.BasicOutputCollector;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseBasicBolt;
import org.apache.storm.tuple.Tuple;
import org.elasticsearch.action.bulk.BulkProcessor;
import org.elasticsearch.action.index.IndexRequest;

import java.util.Date;
import java.util.Map;
import java.util.Properties;

/**
 * @description 索引index格式:nginx-日期,如:nginx-2021-03-19
 * @author tcm
 * @version 1.0.0
 * @date 2022/1/25 10:29
 **/
public class NginxLogESBolt extends BaseBasicBolt {
    private Properties properties;

    // ES批量写入:线程安全的批量处理类
    private BulkProcessor bulkProcessor;

    public NginxLogESBolt(Properties properties) {
        this.properties = properties;
    }

    @Override
    public void execute(Tuple tuple, BasicOutputCollector collector) {
        try {
            // 日志公用字段
            String logFileBeatStr = tuple.getStringByField("logFileBeatContent");
            LogFileBeatContent logFileBeatContent = JSON.parseObject(logFileBeatStr, LogFileBeatContent.class);
            // 日志内容
            String message = tuple.getStringByField("message");

            // 索引 - 服务应用名称
            Date timestamp = new Date();
            String index = properties.getProperty("NGINX_LOG") + "-" + DateUtil.dateToString(timestamp);

            // access日志,格式:"日期 | 对象{}"
            if (NginxLogType.NGINX_LOG_ACCESS.name().equals(logFileBeatContent.getLogType())){
                // 转access对象
                String[] messageArray = message.split("\\|");
                if (messageArray.length > 0) {
                    message = messageArray[1].trim();

                    NginxLogAccess nginxLogAccess = JSON.parseObject(message, NginxLogAccess.class);
                    nginxLogAccess.setMessage(message);
                    nginxLogAccess.setLogFileBeatContent(logFileBeatContent);

                    JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(nginxLogAccess));
                    bulkProcessor.add(new IndexRequest(index).source(jsonObject));
                }
            }
            // error日志
            else if (NginxLogType.NGINX_LOG_ERROR.name().equals(logFileBeatContent.getLogType())) {
                // 转error对象
                NginxLogError nginxLogError = new NginxLogError();
                nginxLogError.setMessage(message);
                nginxLogError.setLogFileBeatContent(logFileBeatContent);

                // 内容
                String[] messageArray = message.split("\\[");
                if (messageArray.length > 0) {
                    // 时间戳
                    Date date = DateUtil.stringToDate(messageArray[0].trim(), "yyyy/MM/dd HH:mm:ss");
                    nginxLogError.setTimestamp(DateUtil.dateToString(date, "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
                    // 日志级别
                    String logLevel = messageArray[1].split("\\]")[0].trim();
                    nginxLogError.setLogLevel(logLevel);
                }

                JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(nginxLogError));
                bulkProcessor.add(new IndexRequest(index).source(jsonObject));
            }
            // info日志
            else if (NginxLogType.NGINX_LOG_INFO.name().equals(logFileBeatContent.getLogType())) {
                // 转common对象
                NginxLogInfo nginxLogInfo = new NginxLogInfo();
                nginxLogInfo.setMessage(message);
                nginxLogInfo.setLogFileBeatContent(logFileBeatContent);

                // 内容
                String[] messageArray = message.split("\\[");
                if (messageArray.length > 0) {
                    // 时间戳
                    Date date = DateUtil.stringToDate(messageArray[0].trim(), "yyyy/MM/dd HH:mm:ss");
                    nginxLogInfo.setTimestamp(DateUtil.dateToString(date, "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
                    // 日志级别
                    String logLevel = messageArray[1].split("\\]")[0].trim();
                    nginxLogInfo.setLogLevel(logLevel);
                }

                JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(nginxLogInfo));
                bulkProcessor.add(new IndexRequest(index).source(jsonObject));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {

    }

    /**
     * execute前,准备操作
     * @param stormConf
     * @param context Topology的基本信息
     */
    @Override
    public void prepare(Map stormConf, TopologyContext context) {
        super.prepare(stormConf, context);

        // ES批量写入:BulkProcessor
        this.bulkProcessor = new ESConfig(properties).getBulkProcessor();
//        this.bulkProcessor = bulkProcessor();
    }

}

5. ES并Kibana查看

五、参考资料

日志系统_爱我所爱0505-CSDN博客

https://www.jb51.net/article/117879.htm

https://www.jb51.net/article/52573.htm

Nginx修改日志格式 日志分析 字段分离 ES数据格式的转换及nginx日志参数详解_wpskdsl的博客-CSDN博客

Nginx日志按天切割及日志基本配置说明_黄太洪的博客-CSDN博客_nginx日志按日配置

对Linux定时任务的认识 - 程序员大本营

Nginx Unique Tracing ID_四火流年的博客-CSDN博客_nginx traceid 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值