1 Star 0 Fork 7

ye367 / LinkLog

forked from Rey Wong / OpenLinkLog 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
linklog.md 11.75 KB
一键复制 编辑 原始数据 按行查看 历史
Rey Wong 提交于 2021-08-13 01:57 . update doc/linklog.md.

日志规范 LinkLog体系

LinkLog设计原则

日志范围:

  • 1.日志打印 (覆盖)
  • 2.接口返回日志 (覆盖)
  • 3.链路跟踪 (覆盖)
  • 4.系统监控

LinkLog体系原则:

  • 1.基于现有资源及技术栈
  • 2.减少项目改造风险
  • 3.能快速落地

LinkLog使用方式

1.jvm启动参数 (运维配置)

-Drocketmq.client.log.loadconfig=false  
-Dlinklog.env=sit   
-Dlinklog.kafka.json=kafkaJson   
-Dlinklog.kafka.servers=10.201.1.46:9092  
-Dlinklog.kafka.topic=linklog_std_log  
-Dlinklog.kafka.errortopic=linklog_common_error  
  • rocketmq.client.log.loadconfig : 直接设置为false,解决logback无法自动刷新问题
  • linklog.env : 系统环境 dev|sit|pre|pro
  • linklog.kafka.json : 是否使用linklog的kafkaJson模式,默认为一般模式
  • linklog.kafka.servers: kafka集群地址,默认10.201.1.46:9092
  • linklog.kafka.topic: 日志打印的topic,不填默认为 linklog_std_log
  • linklog.kafka.errortopic: 错误日志打印的topic,不填默认为 linklog_common_error

2.logstash配置 (运维配置)

注:使用ELK模式

logstash.conf

3.添加jar包 (开发只需要关注这个)

<!--如果本地有logback就不用配置-->
<!--start logback 必须为1.2.2以上-->
    <!--  <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

      l
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
        </dependency>
    -->  
<!--end logback-->

<!--start linklog-->
  <dependency>
      <groupId>io.gitee.reywong</groupId>
      <artifactId>ry-linklog</artifactId>
      <version>1.0.1-releases</version>
  </dependency>
<!--end linklog-->

<!--logback-kafka插件-->
    <dependency>
            <groupId>com.github.danielwegener</groupId>
            <artifactId>logback-kafka-appender</artifactId>
            <version>0.2.0-RC2</version>
            <exclusions>
                <!--如果项目中已经存在kafka-clients 则排除-->
                <!--<exclusion>-->
                    <!--<groupId>org.apache.kafka</groupId>-->
                    <!--<artifactId>kafka-clients</artifactId>-->
                <!--</exclusion>-->
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

<!--logback-json插件-->
        <dependency>
            <groupId>net.logstash.logback</groupId>
            <artifactId>logstash-logback-encoder</artifactId>
            <version>6.6</version>
            <exclusions>
                <!--如果项目中已经存在jackson-databind则排除-->
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-databind</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
注:logback 和 kafka-client 的版本按系统目前使用的版本,不要重复引入   
    

4.logback配置

loback.rar

日志字段描述

<!--
                date: 日志打印时间
                ip : 主机ip java.rmi.server.hostname
                env: 应用环境 test | sit | pre | pro
                appname:应用名称
                logtype: 日志类型  LinkLogTrace | LinkLogMonitor | LinkLogData
                level: 日志等级
                linkLog: 日志链路信息
                thread: 线程名称
                class: 输出Logger 的名字
                method:方法名称
                line: 行数
                message: 内容
                stack_trace "%exception{5}",
                -->

日志的用途

  • 回溯系统故障
  • 记录操作轨迹
  • 监控系统运行状况

2.日志存储规范

  1. 错误日志单独打印,理论系统正常情况不应该出现error日志,error日志要及时解决,根据error日志判断系统质量

  2. 日志保存为json格式

  3. 日志统一入kafka,目前使用ELK体系(可以进行变更)

  4. 第三方SDK修成ERROR级别

  5. 关闭无效日志(logback),方便日志查询和问题跟踪

  6. 定时reload日志,减少日志打印量(稳定代码可以降低日志级别,如改成debug)

3.日志采集规范

  1. 日志本地打印,每种类型日志10个文件并且每个文件保存100M,自动清理(防止kafka出问题)

  2. 日志同时直接打印到kafka

4. 日志展示规范

  1. 日志使用 ElasticSeacrh

  2. 日志监控 Grafana

日志配置及使用案例

  • 1.系统出现异常后,需要不重启应用(保留现场)将日志修改成DBUG模式

如:将INFO改成DEBUG,10秒生效

  • 2.当请求并发比较大的时候,不同请求之间的日志可能会串,需要查询关联上下文

可以通过 thread查询 按时间排序

  • 3.需要统一每个接口的实时使用量

通过 appname class method 进行查询汇总,也可以创建dashboard出报表(kibana报表)

Kibaba-dashboard

  • 4.当下单接口异常后,需要找回订单信息

通过 appname class method 查询message(json格式的message会被拆分)

  • 5.需要识别出安全事件,比如某一用户频繁访问

将日志打印成json格式,然后该json会被自动分拆成字段,通过分拆的字段进行查询

  • 6.需要查看某条请求在系统中的整条链路(问题排除,系统优化)

  • 7.无效日志太多需要关闭干扰(精简)日志

1.手工调整代码,将info改成debug,或直接去掉
2.通过修改logback.xml动态生效

问题答疑

  • 需求:完善日志的链路跟踪
    答:日志打印会有全局ID,来贯穿整个日志链路,全局ID信息为: traceId (链路ID),spanId(当然日志所在链路ID), preIP(上级IP),preApp(上级应用名称),preHost(上级主机名)

  • 需求:接口请求/响应参数打印可配置
    答:logback目前已经支持动态刷新,可以通过修改logback.xml实现(运维配置),举例

// xxxx.java
//代码中获取logger对象
  private static final Logger linkLog=LoggerFactory.getLogger("LinkLogMonitor");
 
// logback.xml 配置

 <!--
  name为 代码中logger的名称  
  level: off 为关闭日志   
  additivity:false  为root不再传递 LinkLogMonitor 的日志的配置
  -->
 <logger name="LinkLogMonitor" level="off" additivity="false">
        <appender-ref ref="${kafkaJson}messageText_async_rollingFile"/>
        <appender-ref ref="${kafkaJson}messageText_async_kafka"/>
 </logger>
 
  • 需求:日志级别可动态配置
    答:修改logback配置文件即可,10s生效不需要重启应用(生产环境联系运维修改)

  • 需求:日志打印不能影响应用的性能
    答:1. 目前打印日志采用异步打印
    2. 直接同时打印到kafka和本地文件
    3. 写kafka不等kafka响应(无响应直接丢弃)
    4. 本地文件单个类型保留10个文件每个文件100M,不启用fliebeat
    5. error日志单独打印,性能不够可以只保留error

  • 需求:接口日志支持重发
    答:日志打成了json格式,可以通过 class 和 method 进行查询打印的数据,从es或本地文件提取进行重试


//相当于 LoggerFactory.getLogger("ry.linkLog.LinkLogMonitor");
private static final Logger logger= LoggerFactory.getLogger(TestLinkLog.class);

// 打印日志

 public ResponseParam addUserInfoNew(RequestParam requestParam) {
     logger.info(JSON.toJSONString(requestParam));
 }
class RequestParam {
        String userId;
        String age;

        public String getUserId() {
            return userId;
        }

        public void setUserId(String userId) {
            this.userId = userId;
        }

        public String getAge() {
            return age;
        }

        public void setAge(String age) {
            this.age = age;
        }
    }

//其中 userId,age 被分拆成字段
{
    "ip": "127.0.0.1",
    "type": "linklog_std",
    "message": "{\"userId\":\"linkLog\",\"age\":1}",
    "age": 1,
    "appname": ".",
    "logtype": "LinkLogTrace",
    "stack_trace": "",
    "span": "",
    "userId": "linkLog",
    "class": "cn.ry.LinkLogMonitor",
    "parent": "",
    "traceId": "",
    "date": "2021-03-15T15:22:04.102+0800",
    "method": "?",
    "@version": "1",
    "line": "?",
    "@timestamp": "2021-03-15T07:22:07.222Z",
    "level": "INFO ",
    "env": ".",
    "thread": "main"
  }
    
    

日志修改案例(实时生效)

修改某个类的日志级别

如:将类型 com.ry.doradoLinkLog 日志级别修改成INFO ,以下两种方案选择一种即可

  • 配置中心修改方案:添加 com.ymdd.doradoLinkLog =INFO

  • logback.xml修改方案: 添加 <logger name="com.ry.doradoLinkLog" level="INFO" additivity="true"/>

开启sql打印

以下两种方案选择一种即可

  • 配置中心修改方案:添加 java.sql = DEBUG

  • logback.xml修改方案:添加 <logger name="java.sql" level="DEBUG" additivity="true"/>

    针对mybatis配置

  • 配置中心修改方案:添加 mapper所在包名 = DEBUG

  • logback.xml修改方案:添加 <logger name="mapper所在包名" level="DEBUG" additivity="true"/>

关闭某个类的日志打印

如:想关闭三方日志,或排除日志干扰,可以关闭日志,以下两种方案选择一种即可

  • 配置中心修改方案:添加 org.apache.curator = OFF

  • logback.xml修改方案:添加 <logger name="org.apache.curator" level="OFF"/>

Disconf和Apollo配置中心支持

文件修改实时生效,支持的级别 OFF>FATAL>ERROR>WARN>INFO>DEBUG>TRACE>ALL

##修改方式如下  key=logger名称(默认为类名/包名), value = 日志级别

com.ry=INFO
  • linklog.properties

accessLog开关动态修改(支持disconf和apollo)

# true开启日志 false 关闭日志
linklog.accesslog=false
  • accessLog参数解释
  linkLog.traceId: 日志链路的id,贯穿全局
  linkLog.spanId: 当前节点id,如0.1,具体规则见 备注中的命名规则
  linkLog.preApp: 请求方应用名称
  linkLog.preHost: 请求方主机名
  linkLog.preIp : 请求方IP
  class: 为linkLog,标识linkLog打印的日志
  linkLogAccessType: client为请求方打印 server为接收方打印
  requestURLStr: 请求地址
  linkLogMethod: 请求方式 POST GET DUBBO EDS-RPC 
  filterName: 打印类,判断拦截器类型
  content: 发送的内容

常见问题

异常栈打印不全

在jvm启动参数添加 -XX:-OmitStackTraceInFastThrow

子线程使用线程池,导致traceId重复打印问题

由于 线程池 为复用的模式,ThreadLocal只会在初始化的时候进行传递,所以导致线程数打印的traceId重复

解决方案如下: ExecutorService executorPool = TtlExecutors.getTtlExecutorService(new ThreadPoolExecutor(2, 2, 0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>(), new ThreadFactoryBuilder().setNameFormat("executor-pool-%d").build(), new ThreadPoolExecutor.AbortPolicy()));

通过TtlExecutors.getTtlExecutorService() 对线程池进行包装

附录

Java
1
https://gitee.com/yerongli367/OSSRH-71430.git
git@gitee.com:yerongli367/OSSRH-71430.git
yerongli367
OSSRH-71430
LinkLog
master

搜索帮助