一、背景简介

项目中日志的管理是基础功能之一,不同的用户和场景下对日志都有特定的需求,从而需要用不同的策略进行日志采集和管理,如果是在分布式的项目中,日志的体系设计更加复杂。

  • 日志类型:业务操作、信息打印、请求链路;
  • 角色需求:研发端、用户端、服务级、系统级;

用户与需求

  • 用户端:核心数据的增删改,业务操作日志;
  • 研发端:日志采集与管理策略,异常日志监控;
  • 服务级:关键日志打印,问题发现与排查;
  • 系统级:分布式项目中链路生成,监控体系;

不同的场景中,需要选用不同的技术手段去实现日志采集管理,例如日志打印、操作记录、ELK体系等,注意要避免日志管理导致程序异常中断的情况。

越是复杂的系统设计和业务场景,就越依赖日志的输出信息,在大规模的架构中,通常还会搭建独立的日志平台,提供日志数据的采集、存储、分析等整套解决方案。

二、Slf4j组件

1、外观模式

日志的组件遵守外观设计模式,Slf4j作为日志体系的外观对象,定义规范日志的标准,日志能力的具体实现交由各个子模块去实现;Slf4j明确日志对象的加载方法和功能接口,与客户端交互提供日志管理功能;

private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(Impl.class) ;

通常禁止直接使用Logback、Log4j等具体实现组件的API,避免组件替换带来不必要的麻烦,可以做到日志的统一维护。

2、SPI接口

从Slf4j和Logback组件交互来看,在日志的使用过程中,基本的切入点即使用Slf4j的接口,识别并加载Logback中的具体实现;SPI定义的接口规范,通常作为第三方(外部)组件的实现。

上述SPI作为两套组件的连接点,通过源码大致看下加载过程,追溯LoggerFactory的源码即可:

public final class org.slf4j.LoggerFactory {private final static void performInitialization() {bind();}private final static void bind() {try {StaticLoggerBinder.getSingleton();} catch (NoClassDefFoundError ncde) {String msg = ncde.getMessage();if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");}}}
}

此处只贴出了几行示意性质的源码,在LoggerFactory中执行初始化绑定关联的时候,如果没有找到具体的日志实现组件,是会报告出相应的异常信息,并且采用的是System.err输出错误提示。

三、自定义组件

1、功能封装

对于日志(或其他)常用功能,通常会在代码工程中封装独立的代码包,作为公共依赖,统一管理和维护,对于日志的自定义封装可以参考之前的文档,这里通常涉及几个核心点:

  • starter加载:封装包配置成starter组件,可以被框架扫描和加载;
  • aop切面编程:通常在相关方法上添加日志注解,即可自动记录动作;
  • annotation注解:定义日志记录需要标记的核心参数和处理逻辑;

至于如何组装日志内容,适配业务语义,以及后续的管理流程,则根据具体场景设计相应的策略即可,比如日志怎么存储、是否实时分析、是否异步执行等。

2、对象解析

在自定义注解中,会涉及到对象解析的问题,即在注解中放入要从对象中解析的属性,并且把值拼接到日志内容中,可以增强业务日志的语义可读性。

import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
public class Test {public static void main(String[] args) {// Map集合HashMap<String,Object> infoMap = new HashMap<>() ;infoMap.put("info","Map的描述") ;// List集合ArrayList<Object> arrayList = new ArrayList<>() ;arrayList.add("List-00");arrayList.add("List-01");// User对象People oldUser = new People("Wang",infoMap,arrayList) ;People newUser = new People("LiSi",infoMap,arrayList) ;// 包装对象WrapObj wrapObj = new WrapObj("WrapObject",oldUser,newUser) ;// 对象属性解析SpelExpressionParser parser = new SpelExpressionParser();// objNameExpression objNameExp = parser.parseExpression("#root.objName");System.out.println(objNameExp.getValue(wrapObj));// oldUserExpression oldUserExp = parser.parseExpression("#root.oldUser");System.out.println(oldUserExp.getValue(wrapObj));// newUser.userNameExpression userNameExp = parser.parseExpression("#root.newUser.userName");System.out.println(userNameExp.getValue(wrapObj));// newUser.hashMap[info]Expression ageMapExp = parser.parseExpression("#root.newUser.hashMap[info]");System.out.println(ageMapExp.getValue(wrapObj));// oldUser.arrayList[1]Expression arr02Exp = parser.parseExpression("#root.oldUser.arrayList[1]");System.out.println(arr02Exp.getValue(wrapObj));}
}
@Data
@AllArgsConstructor
class WrapObj {private String objName ;private People oldUser ;private People newUser ;
}
@Data
@AllArgsConstructor
class People {private String userName ;private HashMap<String,Object> hashMap ;private ArrayList<Object> arrayList ;
}

注意上面使用的SpelExpressionParser解析器,即Spring框架的原生API;业务中遇到的很多问题,建议都优先从核心依赖(Spring+JDK)中寻找解决方式,多花时间熟悉系统中核心组件的全貌,对开发视野和思路会有极大的帮助。

3、模式设计

这里看一个比较复杂的自定义日志解决思路,通过AOP模式识别日志注解,并解析注解中要记录的对象属性,构建相应的日志主体,最后根据注解标记的场景去适配不同的业务策略:

对于功能的通用性要求越高,在封装时内置的适配策略就要越抽象,在处理复杂的逻辑流程时,要善于将不同的组件搭配使用,可以分担业务支撑的压力,形成稳定可靠的解决方案。

四、分布式链路

1、链路识别

基于微服务实现的分布式系统,处理一个请求会经过多个子服务,如果过程中某个服务发生异常,需要定位这个异常归属的请求动作,从而更好的去判断异常原因并复现解决。

定位的动作则依赖一个核心的标识:TraceId-轨迹ID,即请求在各个服务流转时,会携带该请求绑定的TraceId,这样可以识别不同服务的哪些动作为同一个请求产生的。

通过TraceId和SpanId即可还原出请求的链路视图,再结合相关日志打印记录等动作,则可以快速解决异常问题。在微服务体系中Sleuth组件提供了该能力的支撑。

链路视图的核心参数可以集成Slf4j组件中,这里可以参考org.slf4j.MDC语法,MDC提供日志前后的参数传递映射能力,内部包装Map容器管理参数;在Logback组件中,StaticMDCBinder提供该能力的绑定,这样日志打印也可以携带链路视图的标识,做到该能力的完整集成。

2、ELK体系

链路视图产生的日志是非常庞大的,那这些文档类的日志如何管理和快速查询使用同样是个关键问题,很常见的一个解决方案即ELK体系,现在已更新换代为ElasticStack产品。

  • Kibana:可以在Elasticsearch中使用图形和图表对数据进行可视化;
  • Elasticsearch:提供数据的存储,搜索和分析引擎的能力;
  • Logstash:数据处理管道,能够同时从多个来源采集、转换、推送数据;

Logstash提供日志采集和传输能力,Elasticsearch存储大量JSON格式的日志记录,Kibana则可以视图化展现数据。

3、服务与配置

配置依赖:需要在服务中配置Logstash地址和端口,即日志传输地址,以及服务名称;

spring:application:name: app_serve
logstash:destination: uri: Logstash-地址port: Logstash-端口

配置读取:Logback组件配置中加载上述核心参数,这样在配置上下文中可以通过name的值使用该参数;

<springProperty scope="context" name="APP_NAME" source="spring.application.name" defaultValue="butte_app" />
<springProperty scope="context" name="DES_URI" source="logstash.destination.uri" />
<springProperty scope="context" name="DES_PORT" source="logstash.destination.port" />

日志传输:对传输内容做相应的配置,指定LogStash服务配置,编码,核心参数等;

<appender name="LogStash" class="net.logstash.logback.appender.LogstashTcpSocketAppender"><!-- 日志传输地址 --><destination>${DES_URI:- }:${DES_PORT:- }</destination><!-- 日志传输编码 --><encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"><providers><timestamp><timeZone>UTC</timeZone></timestamp><!-- 日志传输参数 --><pattern><pattern>{"severity": "%level","service": "${APP_NAME:-}","trace": "%X{X-B3-TraceId:-}","span": "%X{X-B3-SpanId:-}","exportable": "%X{X-Span-Export:-}","pid": "${PID:-}","thread": "%thread","class": "%logger{40}","rest": "%message"}</pattern></pattern></providers></encoder>
</appender>

输出格式:还可以通过日志的格式设定,管理日志文件或者控制台的输出内容;

<pattern>%d{yyyy-MM-dd HH:mm:ss} %contextName [%thread] %-5level %logger{100} - %msg %n</pattern>

关于Logback组件日志的其他配置,例如输出位置,级别,数据传输方式等,可以多参考官方文档,不断优化。

4、数据通道

再看看数据传输到Logstash服务后,如何再传输到ES的,这里也需要相应的传输配置,注意logstash和ES推荐使用相同的版本,本案例中是6.8.6版本。

配置文件:logstash-butte.conf

input {tcp {host => "192.168.37.139"port => "5044"codec => "json"}
}output {elasticsearch {hosts => ["http://localhost:9200"]index => "log-%{+YYYY.MM.dd}"}
}
  • 输入配置:指定logstash连接的host和端口,并且指定数据格式为json类型;
  • 输出配置:指定日志数据输出的ES地址,并指定index索引按天的创建方式;

启动logstash服务

/opt/logstash-6.8.6/bin/logstash -f /opt/logstash-6.8.6/config/logstash-butte.conf

这样完整的ELK日志管理链路就实现了,通过使用Kibana工具就可以查看日志记录,根据TraceId就可以找到视图链路。

日志管理系统,多种方式总结相关推荐

  1. 商业日志管理系统发展史

    商业日志管理系统发展史 bt0sea 2016-03-26 共39519人围观,发现4个不明物体 安全管理观点 * 原创作者:bt0sea 0×00.前言 日志管理系统是信息安全发展过程中一直存在的业 ...

  2. 《Android深度探索(卷1):HAL与驱动开发》——6.4节使用多种方式测试Linux驱动...

    本节书摘来自异步社区<Android深度探索(卷1):HAL与驱动开发>一书中的第6章,第6.4节使用多种方式测试Linux驱动,作者李宁,更多章节内容可以访问云栖社区"异步社区 ...

  3. Spring学习总结(一)——Spring实现IoC的多种方式

    一.Spring框架概述 Spring是一个开源免费的框架,为了解决企业应用开发的复杂性而创建.Spring框架是一个轻量级的解决方案,可以一站式地构建企业级应用.Spring是模块化的,所以可以只使 ...

  4. 利用对象存储多种方式 保障OSS数据安全

    本文介绍如何通过对象存储OSS提供的加密.访问控制.日志与监控及数据保护等多种方式来保障OSS的数据安全性. 加密 OSS提供服务器端加密.客户端加密以及数据传输加密三种数据加密方式. 服务器端加密 ...

  5. 利用最新的开源软件构建日志管理系统

    我们已经知道OSSIM是目前为数不多的几个开源的SIEM/安全管理平台之一,而目前还没有什么集成化的日志管理(LM)系统. 不过,只要你愿意,可以自己DIY一个日志管理系统,并且用到的都是最新的技术. ...

  6. ELK日志管理系统的搭建

    ELK日志管理系统的搭建 环境准备 Linux安装Elasticsearch 使用的 Elasticsearch的版本是7.6.2.Elasticsearch7.x要求 Linux内核必须是4+版本以 ...

  7. linux查看日志的多种方法集合

    linux查看日志的多种方法集合 Linux查看日志的命令有多种: tail.cat.tac.head.echo等 tail 参数 命令格式: tail[必要参数][选择参数][文件] -f 循环读取 ...

  8. Linux 多种方式实现文件共享

    文件共享服务在Linux系统上有多种方式,最常用的有Samba,vsftp,iSCSI,NFS这四种方式,如下将分别配置四种不同的文件共享服务. VSFTP 文件传输 FTP是文件传输协议.用于Int ...

  9. 开源服务器日志实时查看系统,开源日志管理系统

    开源日志管理系统 内容精选 换一换 鲲鹏工程师培训及认证为客户提供鲲鹏认证伙伴基于open系开源内核构建的商业软件培训,包含商业软件介绍.特性描述.操作使用.开发指导等内容. 来自:其他 MindX ...

  10. 论文php的工作日志,工作日志管理系统毕业论文-.doc

    工作日志管理系统毕业论文- 东 莞 理 工 学 院 本 科 毕 业 设 计 毕业设计题目:工作日志管理系统的设计与实现 学生姓名:李明敏 学 号:0641402249 系 别:计算机学院 专业班级:0 ...

最新文章

  1. 谷歌提出纯 MLP 构成的视觉架构,无需卷积、注意力 !
  2. 网站PC端跟移动端有哪些不同的区别所在?
  3. 20135337朱荟潼 Linux第八周学习总结——进程的切换和系统的一般执行过程
  4. Android 版本适配:9.0 Pie(API 级别 28)
  5. Python的系统管理_08_python_异常处理
  6. jsf集成spring_Spring JSF集成
  7. 网络编程多人聊天c语言,socket网络编程--简单的多人聊天
  8. 【Python】排序函数 sort、sorted 对复杂列表排序
  9. 数据库系统概论完整笔记
  10. faster rcnn理论讲解
  11. 项目成本管理的5项原则
  12. 结构思考力-有逻辑的表达,有结构的思考
  13. oracle数据库导出数据为csv包含clob数据
  14. 线性代数可以做些什么?(之一)
  15. “Android开发3年老板嫌我工资高,把我辞了
  16. python 圆周率代码_基于Python计算圆周率pi代码实例
  17. 如何利用Maven查找依赖信息
  18. C语言位操作--判断整数的符号
  19. win10降win7_软硬兼施Win7:8核笔记本/移动工作站出坑记
  20. 永远的优客李林——Just for you

热门文章

  1. matlab的数值求解实验报告,偏微分方程数值及matlab实验报告
  2. SmartPhone和PPC手机的区别
  3. AutoResetEvent和ManualResetEvent用法
  4. 开源加速器Gemmini代码解析(一):脉动阵列
  5. MATLAB 求导diff
  6. 【热门主题:银魂win7主题】
  7. android矢量地图画法_Android 我们的矢量地图,放大不失真
  8. 数据通信与计算机网复习题,数据通信与计算机网络 复习题总.doc
  9. python中if else语句用法_Python条件语句详解:if、else、switch都有了
  10. Adobe Premiere(pr)2021 安装教程【64位】