Rest接口/Nginx日志记录和采集

文章目录

  • 一、Rest接口日志
  • 二、Nginx日志
  • 三、采集日志
  • 四、夜莺查看Nginx日志
  • 五、夜莺查看Rest接口日志


一、Rest接口日志

  • 记录日志字典定义
接口URL接口名称,类别,入参全记录,出参全记录,入参字段1:中文名1/入参字段2:中文名2,出参字段1:中文名1
/test/api/login账户登录,登录,false,false,accountName:账户名,accessToken:Token/expiresTime:有效期/person.name:姓名
/test/api/role/findById查询角色,应用,true,true,role.roleId:角色ID,role.roleName:角色名
  • RestLogAspect.java
package cn.test.manage.config.aspect;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * @description Rest接口日志记录
 */
@Aspect
@Component
public class RestLogAspect {
    private static Log logger = LogFactory.getLog(RestLogAspect.class);

    @Resource
    private RedisTemplate redisTemplate;

    @Value("${server.servlet.application-display-name}")
    private String system;

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'+08:00'");
    private static DecimalFormat df = new DecimalFormat ("#.##");

    @Pointcut("execution(public * cn.test.manage.web.rest.*.*.*(..))")
    private void pointcut() {
    }

    @Around(value = "pointcut()")
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        Date date = new Date();
        Object result = joinPoint.proceed();
        try {
            // 第一个参数固定为请求参数,第二个参数固定为HttpServletRequest
            HttpServletRequest request = (HttpServletRequest) joinPoint.getArgs()[1];
            // 从字典获取需要记录日志的接口
            Object dict = redisTemplate.opsForHash().get("DICT_", system + "_logs" + "." + request.getRequestURI());
            if (dict == null || StringUtils.isEmpty(dict.toString())) {
                return result;
            }
            JSONObject json = new JSONObject();
            json.put("logtype", "customize");                           // 固定标识, 用于日志采集
            json.put("client", request.getRemoteAddr());                // 客户端IP
            json.put("host", request.getRemoteHost());                  // 服务端IP
            json.put("port", request.getServerPort());                  // 服务端端口
            json.put("starttime", sdft.format(date));                   // 接口开始时间
            json.put("url", request.getRequestURI());                   // 接口URL
            json.put("system", system);                                 // 系统名称
            setArgInfo(json, joinPoint.getArgs()[0], result, dict.toString());
            // 获取token
            String token = request.getParameter("token");
            if (StringUtils.isEmpty(token) || "null".equals(token)) {
                token = request.getHeader("Authorization");
                if (token != null && token.startsWith("Bearer ")) {
                    token = token.substring(7);
                }
            }
            json.put("token", token);                                   // token
            String accountId = (String) redisTemplate.opsForValue().get("token-" + token);
            if (accountId != null) {
                Map<String, String> map = (Map<String, String>) redisTemplate.opsForValue().get(accountId);
                if (map != null) {
                    json.put("accountid", map.get("accountId"));        // 账户ID
                    json.put("accountname", map.get("accountName"));    // 账户名
                    json.put("username", map.get("name"));              // 用户名
                }
            }
            // 接口代码执行时间,会小于响应时间
            json.put("resptime", df.format((double)(new Date().getTime()-date.getTime())/1000));
            logger.info("\n"+JSONObject.toJSONString(json));
        } catch (Exception e) {
            logger.error(e);
        }
        return result;
    }

    /**
     * 设置参数信息
     */
    private void setArgInfo(JSONObject json, Object request, Object response, String argstr) {
        String requeststr = JSONObject.toJSONString(request);
        String responsestr = JSONObject.toJSONString(response);
        JSONObject requestObject = JSONObject.parseObject(requeststr);
        JSONObject responseObject = JSONObject.parseObject(responsestr);
        String[] args = argstr.split(",");
        json.put("apidesc", args[0]);                               // 接口描述
        json.put("apitype", args[1]);                               // 接口类型
        if (responseObject.getString("operateSuccess") == null || "false".equals(responseObject.getString("operateSuccess"))) {
            json.put("level", "ERROR");                             // 日志级别
        } else {
            json.put("level", "INFO");
        }
        json.put("msg", responseObject.getString("operateSuccess") + " " + responseObject.getString("msg"));
        if ("true".equals(args[2])) {
            json.put("request", requeststr);                        // 请求完整内容
        }
        if ("true".equals(args[3])) {
            json.put("response", responsestr);                      // 响应完整内容
        }
        json.put("req", getInfo(json, requestObject, args[4]));     // 请求概要内容
        json.put("resp", getInfo(json, responseObject, args[5]));   // 响应概要内容
    }

    /**
     * 获取参数概要信息,集合只取第一个元素
     */
    private String getInfo(JSONObject json, JSONObject object, String argstr) {
        String str = "";
        for (String obj : argstr.split("/")) {
            Object jsonObject = object;
            String fields = obj.split(":")[0];
            String desc = obj.split(":")[1];
            for (String field : fields.split("\\.")) {
                if (jsonObject instanceof JSONObject) {
                    jsonObject = ((JSONObject) jsonObject).get(field);
                } else if (jsonObject instanceof JSONArray)  {
                    while (jsonObject instanceof JSONArray) {
                        jsonObject = ((JSONArray) jsonObject).get(0);
                    }
                    jsonObject = ((JSONObject) jsonObject).get(field);
                } else {
                    logger.info(jsonObject);
                    break;
                }
            }
            str += desc + ": " + jsonObject + ", ";
        }
        str = str.endsWith(", ") ? str.substring(0,str.length()-2) : str;
        return str;
    }
}

二、Nginx日志

  • nginx.conf 中日志配置
		# 日志配置
		open_log_file_cache max=1000 inactive=20s valid=1m min_uses=3;
		#  客户端地址 时间 协议 响应状态 响应字节数 响应时间 客户端
		log_format main '{"logtype":"customize",'				# 固定标识, 用于日志采集
			   '"starttime":"$time_iso8601",'					# 日志写入时间
			   '"url":"$uri",'									# 请求的URL
			   '"protocol":"$server_protocol",'					# 请求使用的协议
			   '"upgrade":"$http_upgrade",'						# 是否升级 WebSocket
			   '"status":"$status",'							# 响应状态
			   '"host": "$http_host",'							# 服务端地址(客户端请求的)
			   '"client": "$remote_addr",'						# 客户端地址
			   '"reqsize": $request_length,'					# 请求内容大小(byte)
			   '"respsize": $bytes_sent,'						# 响应内容大小 byte)
			   '"resptime": $request_time,'						# 响应时间(s)
			   '"connnum": $connection_requests,' 				# 当前通过一个连接获得的请求数量
			   '"agent": "$http_user_agent"}';					# 用户终端代理
    	access_log /var/log/nginx/access.log main buffer=32k flush=5s;
    	error_log /var/log/nginx/error.log warn;

三、采集日志

  • filebeat.yml
filebeat.inputs:
- type: filestream
  paths:
    - /home/nginx/logs/access.log
  tags: ["nginx-access"]
  processors:
    - decode_json_fields:
        fields: ["message"]
        target: "nginx"
        max_depth: 1

- type: filestream
  paths:
    - /home/nginx/logs/error.log
  tags: ["nginx-error"]
  
- type: filestream
  paths:
    - /home/docker/logs/*
  tags: ["crontab-log"]

- type: filestream
  paths:
    - /home/logs/test/all.log
  tags: ["test"]
  processors:
    - decode_json_fields:
        fields: ["message"]
        target: "test"
        max_depth: 1

output.elasticsearch:
  hosts: ["192.168.1.12:9200"]
  preset: balanced
  protocol: "http"
  username: "elastic"
  password: "123456"
  indices:
    - index: filebeat-6.13-nginx-%{+yyyy.MM}
      when.contains: {tags: nginx, nginx.logtype: customize}
    - index: filebeat-6.13-ser-%{+yyyy.MM}
      when.contains: {tags: test, test.logtype: customize}
    - index: filebeat-6.13-%{+yyyy.MM}

setup.template.settings:
  index.number_of_shards: 1
  index.codec: best_compression

processors:
  - drop_fields:
      fields: ["log","host","input","agent","ecs"]
  • filebeat服务重启
sudo systemctl restart filebeat
sudo systemctl status filebeat

四、夜莺查看Nginx日志

  • 日志分析 > 索引模式 > 创建索引模式

在这里插入图片描述

  • 日志分析 > 索引模式 > 编辑 字段别名

在这里插入图片描述

  • 日志分析 > 即时查询

在这里插入图片描述

五、夜莺查看Rest接口日志

  • 日志分析 > 索引模式 > 创建索引模式

在这里插入图片描述- 日志分析 > 索引模式 > 编辑 字段别名

在这里插入图片描述

  • 日志分析 > 即时查询

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/562526.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java-单列集合List详解

一、List概述 ​​​​​​​List 接口继承自 Collection 接口。这意味着所有 List 类型的对象都是 Collection 类型的对象&#xff0c;它们共享 Collection 接口中定义的所有方法。 List集合的特点&#xff1a; 1、有序&#xff1a;存和取得元素顺序一致 2、有索引&#xf…

Java- Object根父类

在java中&#xff0c;所有的类都有一个公共的父类&#xff0c;这个java.lang.Object类 * * * Object所有类的根&#xff0c;成为超类。 1.证明Object是根 public class A_Object01 {public static void main(String[] args) {//证明Object是根//基本数据类型int a 0;Object…

【硬十宝典】——1.4【基础知识】电源完整性——理解与设计

定义&#xff1a; 电源完整性&#xff08;Power integrity&#xff09;简称PI&#xff0c;是确认电源来源及目的端的电压及电流是否符合需求。 电源完整性在现今的电子产品中相当重要。有几个有关电源完整性的层面&#xff1a;芯片层面、芯片封装层面、电路板层面及系统层面。…

18-Echarts 配置系列之:数据集 dataset

简介&#xff1a; 数据集&#xff08;dataset&#xff09;是专门用来管理数据的组件。简化在每一个系列中设置数据&#xff0c;这一个配置是在Echarts4 中开始支持。 通过数据集配置&#xff0c;避免为每一个系列创建一个数据&#xff0c;避免格式转化的痛苦。 简单举例&…

开启智慧之旅,AI与机器学习驱动的微服务设计模式探索

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 &#x1f680; 转载自热榜文章&#x1f525;&#xff1a;探索设计模式的魅力&#xff1a;开启智慧…

2024年腾讯云免费服务器最新申请入口链接

腾讯云免费服务器申请入口 txybk.com/go/free 免费服务器可选轻量应用服务器和云服务器CVM&#xff0c;轻量配置可选2核2G3M、2核8G7M和4核8G12M&#xff0c;CVM云服务器可选2核2G3M和2核4G3M配置&#xff0c;腾讯云百科txybk.com分享2024年最新腾讯云免费服务器申请入口、限制…

YOLOv8操作指南-下载+配置环境

下载&#xff1a;github&#xff0c;进入搜索YOLOv8 就这个&#xff0c;点开 下载就可以了&#xff0c;然后解压一下 配置环境&#xff1a; 安装Pytorch 先看一下这个&#xff1a; 如果电脑有GPU的话&#xff1a; 判断自己电脑GPU&#xff1a;打开任务管理器 我的是英伟达3…

sherpa + ncnn 离线语音识别

目录结构 前言音视频格式转为wavsherpa-ncnn编译LinuxWindowswindows编译中遇到的问题问题“nmake -? failed with: no such file or directory”编译失败原因 成功编译截图 可执行程序说明模型下载语言识别测试LinuxWindows 参考文献 前言 小编需要实现离线音视频语言部分识…

vulfocus靶场couchdb 权限绕过 (CVE-2017-12635)

Apache CouchDB是一个开源数据库&#xff0c;专注于易用性和成为"完全拥抱web的数据库"。它是一个使用JSON作为存储格式&#xff0c;JavaScript作为查询语言&#xff0c;MapReduce和HTTP作为API的NoSQL数据库。应用广泛&#xff0c;如BBC用在其动态内容展示平台&…

完结撒花! java算法day60 | 84.柱状图中最大的矩形

84.柱状图中最大的矩形 思路&#xff1a; 这道题和接雨水很像&#xff0c;不过有两点差别&#xff1a; 这道题需要找到一个位置前一个比他小的数和后一个比他小的数&#xff0c;而接雨水是找到前一个和后一个比他大的数。需要在原数组前后各补上0&#xff0c;防止忽略一些边缘…

Excel数据处理:高级筛选、查找定位、查找函数(VLOOKUP)

高级筛选 先去选中筛选区域 如果筛选的条件在同一行那么就是且的关系 如果筛选的条件不在同一行那么就是或的关系 查找定位空值 使用VLOOKUP函数

C语言中, 文件包含处理,#include< > 与 #include ““的区别

文件包含处理 指一个源文件可以将另外一个文件的全部内容包含进来 &#xff23;语言提供了#include命令用来实现文件包含的操作 #include< > 与 #include ""的区别 <> 表示系统直接按系统指定的目录检索 "" 表示系统先在 "" 指定…

PACS/RIS影像管理系统源码,医院影像科室PACS系统源码,三维医学影像系统源码 支持图像后处理与重建

PACS/RIS影像管理系统源码&#xff0c;支持图像后处理与重建 医院影像科室PACS系统源码&#xff0c;三维医学影像系统源码 PACS&#xff0c;全称为Picture Archiving and Communication Systems&#xff0c;中文意思是医学影像存档与通讯系统。它主要是应用在医院影像科室中&a…

java算法day4

删除链表的倒数第N个结点链表相交环形链表 删除链表的倒数第N个结点 解法&#xff1a;双指针&#xff08;快慢指针&#xff09; 首先一定要有删除结点的思想。所以这个题是用虚拟头结点比较方便。 先上模拟图&#xff0c;然后看流程&#xff1a; 这里后移根据不同的想法有不同…

java优先级队列(堆)详解

一、优先级概念 什么是优先级&#xff1a;比如女士优先&#xff0c;个子低的优先排到前面去&#xff0c;有一部分数据具备优先级&#xff0c;要以优先级的顺序将顺序存储起来。 前面介绍过队列&#xff0c;队列是一种先进先出(FIFO)的数据结构&#xff0c;但有些情况下&#…

OceanBase开发者大会2023届视频及PPT汇总

数据库技术趋势 我眼中的数据库技术 阳振坤OceanBase 首席科学家 观看视频 下载 PDF 未来&#xff0c;中国需要什么样的数据库&#xff1f; 周傲英华东师范大学副校长&#xff0c;CCF 会士 观看视频 下载 PDF 云原生技术趋势解读 Keith ChanCNCF 云原生计算基金会中国区总监 …

开发工具的使用

IDEA的安装与使用&常用快捷键 文章目录 IDEA的安装与使用&常用快捷键一、认识IntelliJ IDEA二、IDEA 的下载&卸载三、IEAD相关设置3.1 JDK的相关设置3.2 系统设置&#xff08;启动项/自动更新&#xff09;3.3 设置整体主题&#xff08;主题/字体/背景&#xff09;3…

Linux--链表 第二十五天

1. 链表 t1.next -> data t1.next->next->data .(点号)的优先级比->的大 所以 t1.next->data 就可以了 不用(t1.next)->data 2. 链表的静态增加和动态遍历 打印链表算法&#xff0c; void printLink(struct Test *head) { struct Te…

如何做一个优秀的系统工程师?

一、背景 做好一个优秀系统工程师的关键在于其在产品开发生命周期中对需求分析的有效把握与运用&#xff0c;这个过程直接影响到系统的整体架构设计、规格参数的明确设定以及业务流程的深度挖掘与优化。需求分析不仅是理解用户实际问题的核心环节&#xff0c;更是界定系统开发…

Java基础之JVM对象内存分配机制简介

一 对象内存分配 1.1 运行时数据区域 1.2 常见java应用启动JVM参数&#xff1a; -Xss&#xff1a;每个线程的栈大小(单位kb)-Xms&#xff1a;堆的初始大小&#xff0c;默认物理内存的1/64,示例&#xff1a;-Xms:4g -Xms:10m-Xmx&#xff1a;堆的最大可用大小&#xff0c;默认物…