日志埋点功能

前言

开发中经常会有日志埋点需求, 用于统计接口的请求量、处理速度等等,为此本篇幅从一下几个维度进行分析,从零到有搭建。

技术架构解析

实现日志埋点功能,从字面意思就可以想到功能大致分为两个方向:
1、 埋点功能(logback + 封装通用SDK方法 + 共享文件夹(如果是多台机子部署服务器))
2、 解析日志(解析logback中约定的文件地址 + 逐个文件解析每行(记录状态)

埋点功能

利用原生的logback,配置好xml即可实现日志保存,不需要考虑批量刷盘等问题,而封装好通用的SDK是为了方便后续系统使用 。 共享文件夹是为了后续不同微服务部署在不同机器上时,设置的绝对路径文件地址能被后续定时任务解析到文件。

解析日志

解析日志就是文件记录+文件解析的过程,可以建立两张表。一张记录有哪些文件,这些文件是否被解析过,状态如何,另一张表即日志文件表,保存每一次埋点的数据。解析过程会严格安装之前的目录进行,涉及到服务器名、时间等需要特别留意。

埋点功能实现

logback.xml

前置知识需要用到logback,不懂的配置logback.xml的同学可以看下下面的链接:logback 从入门到精通 超详细配置说明

多的不说,少的不唠,直接贴上logback的配置(这里只贴埋点功能涉及的配置)

<?xml version="1.0" encoding="UTF-8"?><configuration><contextName>front-oms</contextName><jmxConfigurator /><appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"><layout class="ch.qos.logback.classic.PatternLayout"><pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] [%X{smy.requestFlowNo}|%X{smy.consumerIp}] %logger{56}.%method\(\):%L - %msg%n</pattern></layout><filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>ALL</level></filter></appender><!--埋点相关配置如下--><!--系统编码(填写相应的系统编码)--><substitutionProperty name="sys" value="td-b2b-front" /><appender name="file.biz.log" class="ch.qos.logback.classic.sift.SiftingAppender"><discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator"><key>biz.log.file.name</key><defaultValue>default</defaultValue></discriminator><sift><appender name="file.biz.info-{biz.log.file.name}" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>/bizdata/jss/businessdata/monitor/logs/${sys}/${biz.log.file.name}_${datetime}.txt</file><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!-- 定义文件滚动时的文件名的格式 --><fileNamePattern>/bizdata/jss/businessdata/monitor/logs/${sys}/${biz.log.file.name}_%d{yyyy-MM-dd}.%i.zip</fileNamePattern><!-- 日期大小分割 --><maxFileSize>20MB</maxFileSize><maxHistory>60</maxHistory><totalSizeCap>20GB</totalSizeCap></rollingPolicy><encoder><pattern>%date{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%thread|%X{smy.requestFlowNo}|%X{smy.consumerIp}|%X{class.method.line} - %msg%n</pattern></encoder></appender></sift></appender><logger name="biz.log" additivity="false"><level value="info"/><appender-ref ref="file.biz.log" /></logger></configuration>

logback.xml文件主要就干几件事:
1、配置一个<appender>标签 ,确认埋点的日志文件存在什么目录,目录结构是什么样的,有几层目录
2、每个文件的大小多大,如何打包,日志的显示样式如何
3、配置一个<logger> 标签指定我只解析biz.log 名字的,在后面SDK中体现,LoggerFactory.getLogger(“biz.log”)。
注意
1)<appender>标签中的biz.log.file.name 就是文件名,在后面的SDK通用方法里会存,这里就能读的到
2)目录层级有多少层,后面解析的日志的时候,会从层级里拿sys名字,文件日期等

通用SDK

通用sdk就是如果你有好多个项目要用这个功能,就可以打包成本地仓库,以后maven引一下就可以直接用了

少的不说,多的不唠,这里也直接贴上SDK代码

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;/*** @description 耗时业务日志输出* @Date 2023/9/10 16:50**/
public class MonitorBizLog {private static final Logger bizlogger = LoggerFactory.getLogger("biz.log");/*** mdc-key:类名+方法名+行*/private final static String CLASS_METHOD_LINE = "class.method.line";/*** mdc-key:日志输出文件名*/private final static String FILE_NAME = "biz.log.file.name";private final static String CUR_DATETIME = "datetime";/*** DEFAULT :租户,有用到就用,每用到就default*/private final static String DEFAULT = "default";/*** 获取本机ip*/private final static String ethIpAddress = HostUtil.getEthIpAddress();/*** 记录业务日志** @param subBizNo    业务码 (必穿)* @param logUniqueId 日志唯一标识 (必穿)* @param projectNo   项目号* @param orderNo     订单号* @param transField  透传字段*/public static void info(String subBizNo, String logUniqueId, String projectNo, String orderNo, String transField) {try {String curDate = DateUtil.getCurDate("yyyy-MM-dd");//获取租户编号,获取不到则默认为defaultString fbAccessNo = getFbAccessNo();if (StringUtils.isEmpty(fbAccessNo)) {fbAccessNo = DEFAULT;}//设置mdc值,供logback.xml使用//日志输出使用,因日志由此工具类输出,日志输出的“类.方法.行”为本方法,此处获取调用方“类.方法.行”System.setProperty(CUR_DATETIME, curDate);MDC.put(CLASS_METHOD_LINE, getCallingClassMethodName());//日志输出目录:文件名MDC.put(FILE_NAME, curDate + "/" + fbAccessNo + "_" + ethIpAddress);//日志打印bizlogger.info("业务耗时监控|{}|{}|{}|{}|{}", subBizNo, logUniqueId, projectNo, orderNo, transField);} catch (Exception e) {bizlogger.info("业务耗时异常 info subBizNo:{} logUniqueId:{} projectNo:{} orderNo:{} transField:{}", subBizNo, logUniqueId, projectNo, orderNo, transField, e);} finally {//清空mdc值MDC.remove(FILE_NAME);MDC.remove(CLASS_METHOD_LINE);}}/*** 获取调调用类名+方法+行号** @return 类名+方法+行号*/private static String getCallingClassMethodName() {String name = null;try {StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();if (stackTrace.length >= 4) {StackTraceElement caller = stackTrace[3];name = caller.getClassName() + "." + caller.getMethodName() + ":" + caller.getLineNumber();}} catch (Exception e) {bizlogger.info("业务耗时异常 getCallingClassMethodName", e);}return name;}
}

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;/*** @Date 2022-5-31 17:51:43*/
public class HostUtil {public static void main(String[] args) {String ethIpAddress = getEthIpAddress();System.err.println(ethIpAddress);}public static String getEthIpAddress() {try {// 获取本地主机网络接口列表Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();// 遍历所有网络接口while (interfaces.hasMoreElements()) {NetworkInterface ni = interfaces.nextElement();// 只处理物理网卡if (!ni.isVirtual() && !ni.isLoopback() && !ni.isPointToPoint() && ni.isUp()) {// 获取该接口的所有IP地址Enumeration<InetAddress> addresses = ni.getInetAddresses();// 遍历IP地址列表while (addresses.hasMoreElements()) {InetAddress addr = addresses.nextElement();// 只处理IPv4地址 && eth 網卡地址if (addr instanceof Inet4Address && ni.getName().startsWith("eth")) {// 输出IP地址和子网掩码return addr.getHostAddress();}}}}} catch (SocketException e) {e.printStackTrace();}return null;}
}

SDK主要干这几件事
1、确认subBizNo业务号和logUniqueId, 这会在后面生产日志表的时候使用,其他字段都是选填
2、进一步确定日期文件目录和名称, 按照当前配置最终目录:/bizdata/jss/businessdata/monitor/logs/td-b2b-front/2024-04-01/default_192.168.0.1_2024-04-01.txt
3、设置好动态参数,datetime时间、biz.log.file.name文件名、class.method.line调用类名+方法+行号
注意
这里引入了租户、ip、系统名、日期时间等概念,都应用到了目录命名中,方便后续解析的时候能清楚定位, 如不使用全部设置成defult也行。


解析日志功能实现

大体用到两张表,一张t_log_parse解析日志记录表、t_log_print_detail日志详情表

CREATE TABLE `t_log_parse` (`id` varchar(50) NOT NULL COMMENT 'id',`application_name` varchar(50) DEFAULT NULL COMMENT '应用名称',`ip` varchar(50) NOT NULL COMMENT '所属ip地址',`file_name` varchar(100) DEFAULT NULL COMMENT '文件名称',`file_path` varchar(255) DEFAULT NULL COMMENT '文件路径',`file_line` int(11) DEFAULT NULL COMMENT '文件解析行号',`status` varchar(50) DEFAULT NULL COMMENT '解析状态 init初始化、progressing解析中、finish解析完成\n',`create_datetime` datetime(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',`update_datetime` datetime(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '修改时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='解析日志记录表';CREATE TABLE `t_log_print_detail` (`id` varchar(50) NOT NULL COMMENT 'id',`log_record_id` varchar(50) DEFAULT NULL COMMENT '关联解析文件记录id',`parent_biz_no` varchar(50) DEFAULT NULL COMMENT '父业务码',`sub_biz_no` varchar(50) DEFAULT NULL COMMENT '子业务码',`unique_id` varchar(50) DEFAULT NULL COMMENT '日志唯一标识',`project_no` varchar(50) DEFAULT NULL COMMENT '项目编号',`order_no` varchar(50) DEFAULT NULL COMMENT '订单编号',`trans_field` varchar(50) DEFAULT NULL COMMENT '透传字段',`thread_id` varchar(100) DEFAULT NULL COMMENT '线程id',`type` varchar(4) NOT NULL DEFAULT '01' COMMENT '01 正常 02 卡件',`start_time` datetime(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '开始时间',`end_time` datetime(3) DEFAULT NULL COMMENT '完成时间',`start_datetime` bigint(13) DEFAULT NULL COMMENT '开始时间',`end_datetime` bigint(13) DEFAULT NULL COMMENT '结束时间',`create_datetime` datetime(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',`update_datetime` datetime(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '修改时间',PRIMARY KEY (`id`) USING BTREE,KEY `idx_sub_biz_no_unique_id` (`sub_biz_no`,`unique_id`) USING BTREE COMMENT '业务码+日志唯一id',KEY `idx_sub_biz_no_start_datetime_end_datetime` (`sub_biz_no`,`start_datetime`,`end_datetime`) USING BTREE COMMENT '业务码+开始时间+结束时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='耗时日志详情表';

解析日志记录

起个定时调度, 定时扫描先前约定路径,做好日志文件初始化。
前置准备工作:添加好枚举类、常量、文件Util、HostUtil,定时调度自行选择框架,用Spring原生也行。

前置工作

枚举

public enum LogStatusEnum implements LogEnums{/*** 解析状态*/INIT("INIT", "初始化"),PROGRESSING("PROGRESSING", "解析中"),FINISH("FINISH", "解析完成");private final String code;private final String msg;LogStatusEnum(String code, String msg) {this.code = code;this.msg = msg;}public static LogStatusEnum judgeValue(String code) {LogStatusEnum dataType = null;for (LogStatusEnum t : LogStatusEnum.values()) {if (StringUtils.equals(code, String.valueOf

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Sketch3D:用于草图到3D生成的样式一致性指南

Sketch3D: Style-Consistent Guidance for Sketch-to-3D Generation Sketch3D&#xff1a;用于草图到3D生成的样式一致性指南 Wangguandong Zheng 重试 错误原因 Southeast UniversityChina 重试 错误原因 wgdzhengseu.edu.cnHaifeng Xia 重试 错误原因 Southeast Universit…

设计模式总结-简单工厂模式

简单工厂模式 创建型模式创建型模式概述创建型模式种类 简单工厂模式模式定义模式动机模式结构模式分析模式实例与解析实例一&#xff1a;简单电视机工厂实例二&#xff1a;权限管理 模式优缺点简单工厂模式的优点简单工厂模式的缺点 模式适用环境模式扩展 小结 创建型模式 创…

如何在Ubuntu系统使用docker部署DbGate容器并发布至公网可访问

文章目录 1. 安装Docker2. 使用Docker拉取DbGate镜像3. 创建并启动DbGate容器4. 本地连接测试5. 公网远程访问本地DbGate容器5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定公网地址远程访问 本文主要介绍如何在Linux Ubuntu系统中使用Docker部署DbGate数据库管理工…

Unstructured - 提取非结构化数据

文章目录 一、关于 Unstructured核心概念&#x1f680; Beta 功能&#xff1a;Chipper 模型 二、安装方式一&#xff1a;使用 PYPI方式二&#xff1a;使用源码本地安装安装依赖库测试 三、在Docker运行库添加shell构建自己的 Docker image交互运行 四、PDF文档解析示例 一、关于…

node 的路径分析和文件查找策略

注意本篇文章的内容可以在《深入浅出 nodejs》这一本书中的 2.2 章节中找到详细介绍&#xff0c;这里只说结论 首先必须明确几点 node 中使用的 commonjs 规范commonjs 规范使用 require 导入模块 模块就是文件&#xff0c;每一个文件都是一个模块 所以 node 中路径分析主要是…

【随笔】Git 高级篇 -- 快速定位分支 ^|~(二十三)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

关于鸿蒙HarmonyOS,现在关注什么可以更高效

对于移动端来讲&#xff0c;今年最火的关键词除了裁员&#xff0c;我想就是鸿蒙HarmonyOS了。其实鸿蒙的推出也给安卓端的同学提供了职业发展的新路径或方向。 鸿蒙&#xff0c;原本源自中国神话传说的名字&#xff0c;如今已成为了科技领域的焦点&#xff0c;招聘网站上也出现…

【C语言】C语言题库【附源码+持续更新】

欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 目录 1、练习2-1 Programming in C is fun! 2、练习2-3 输出倒三角图案 3、练习2-4 温度转换 4、练习2-6 计算物体自由下落的距离 5、练习2-8 计算摄氏温度 6、练习2-9 整数四则运算 7、练习2-10 计算分段函数[1…

ELFK (Filebeat+ELK)日志分析系统

一. 相关介绍 Filebeat&#xff1a;轻量级的开源日志文件数据搜集器。通常在需要采集数据的客户端安装 Filebeat&#xff0c;并指定目录与日志格式&#xff0c;Filebeat 就能快速收集数据&#xff0c;并发送给 logstash 进或是直接发给 Elasticsearch 存储&#xff0c;性能上相…

【计算机毕业设计】网上宠物商店管理系统——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…

git 常用命令以及规范

分支命名遵循&#xff1a;master、develop、release-*、hotfix-*、feature-* # 查看本地分支 git branch# 创建一个新分支 git checkout -b feature-xxx # 或执行 git checkout -b feature-xxx develop 基于 develop 分支创建新分支# 切换分支 git checkout feature-xxx# 删除…

DSP笔记8-通用GPIO

电源类 AD引脚类 系统相关JTAG 时钟 GPIO (general purpose input output)复用&#xff0c; 复用&#xff0c;I/O引脚&#xff0c;外设的功能引脚&#xff0c; 88个GPIO引脚&#xff0c;通用的输入输出口&#xff0c;功能复用的。 GPIO特点 输入电平与TTL电平兼容。>2.0V…

Spring的@Bean通过配置文件实现加载控制???

Configuration public class MyConfiguration {BeanConditionalOnProperty(name "myapp.feature.enabled", havingValue "true")public TestBean TestBean() {return new TestBean();} } 在application.yml中配置 myapp:feature:enabled: true TestBea…

大数据开发教程

一、大数据开发概述 大数据开发涉及对海量数据的采集、存储、处理、分析和可视化等一系列过程。大数据技术的应用广泛&#xff0c;包括商业智能、市场趋势分析、客户行为预测等众多领域。掌握大数据开发技术对于现代企业来说至关重要&#xff0c;它能帮助企业更好地洞察市场&a…

Redis(Windows版本下载安装和使用)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

【蓝桥杯】快读快写

快读 import java.io.*; public class test {public static void main(String args[]) throws IOException{StreamTokenizer st new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); st.nextToken();String str st.sval;//读取String类型数据st.ne…

软件包名生成参考

服务名称-分支名称-最后提交时间(精确到秒)-最后提交-编译时间(unix时间戳) 示例&#xff1a;crm_5.2_221024-221020160306-b846f829-1665655859 包名生成脚本参考&#xff1a; 分支名称 export GIT_BRANCH$(git branch|grep "\*"|head -n1|awk {print $NF})git最…

使用aspose相关包将excel转成pdf 并导出

SpringBoot 项目 基于aspose相关jar包 将excel 转换成pdf 导出 1、依赖的jar包 &#xff0c; jar获取链接 aspose相关三方jar &#xff0c;下载解压后,在项目路径下建一个libs包&#xff0c;然后将下图两个jar 拷贝至刚新建的libs目录中 2、pom.xml中加入maven引入 <depend…

成功解决 TypeError: resize() got an unexpected keyword argument ‘reducing_gap‘

最近用到 CLIPScore计算 text 和 image 相似度&#xff0c;运行以下程序&#xff1a; import torch from PIL import Image from torchvision import transforms from torchmetrics.multimodal.clip_score import CLIPScoredef prompt_image_cal(prompt_text, image_path):判断…

电脑与多台罗克韦尔AB PLC无线通讯的搭建方法分为几步?

在实际系统中&#xff0c;同一个车间里分布多台PLC&#xff0c;通过上位机集中控制。通常所有设备距离在几十米到上百米不等。在有通讯需求的时候&#xff0c;如果布线的话&#xff0c;工程量较大耽误工期&#xff0c;这种情况下比较适合采用无线通信方式。本方案以组态王和2台…