前言

三位学弟完成前台编写后,需要进行集成测试,但是这个时候我却因为无法实现日志系统犯了难。最后自己查来查去发现潘老师竟然有这个博客,由此是让自己大概理解了这个实现过程。

日志系统描述

我们希望在当前系统在发生warning或者error后,我们能够及时的获取到错误信息,以便进行及时有效的处理。 日志系统应运而生,他的主要功能是记录每个系统发生指定level的情况。

我的尝试过程

首先去查:如何获取日志,选择下图圈中的(第一个是广告,可以认为他就是第一个)。
image.png

了解log4j2

Log4jApache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台文件GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。log4j2则是log4j的升级版。

log4j2使用:添加依赖

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.7</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.7</version>
    <type>test-jar</type>
    <scope>test</scope>
</dependency>

image.png
然后我就:

ERROR in ch.qos.logback.core.joran.spi.Interpreter@3:16 - no applicable action for [Appenders], current ElementPath  is [[Configuration][Appenders]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@4:61 - no applicable action for [Console], current ElementPath  is [[Configuration][Appenders][Console]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@6:80 - no applicable action for [PatternLayout], current ElementPath  is [[Configuration][Appenders][Console][PatternLayout]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@9:14 - no applicable action for [Loggers], current ElementPath  is [[Configuration][Loggers]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@10:29 - no applicable action for [Root], current ElementPath  is [[Configuration][Loggers][Root]]
ERROR in ch.qos.logback.core.joran.spi.Interpreter@11:49 - no applicable action for [AppenderRef], current ElementPath  is [[Configuration][Loggers][Root][AppenderRef]]

查了之后发现说需要把Springboot内置的lockBack删了,删了之后又来了其他的问题:JsonView的依赖也被删了。
image.png

目前来看这条路我就走死了。如果有同样问题可以参考:Logback configuration error detected的终极解决方案

项目日志系统实现

详细代码实现和测试可以参考文章:spring-boot下使用LogBack,使用HTTP协议将日志推送到日志服务器

1.添加依赖:

第一个依赖是

        <!--http log-->
        <dependency>
            <groupId>org.logback-extensions</groupId>
            <artifactId>logback-ext-loggly</artifactId>
            <version>0.1.5</version>
        </dependency>

        <!--log to json-->
        <dependency>
            <groupId>ch.qos.logback.contrib</groupId>
            <artifactId>logback-jackson</artifactId>
            <version>0.1.5</version>
        </dependency>

        <!--log to json-->
        <dependency>
            <groupId>ch.qos.logback.contrib</groupId>
            <artifactId>logback-json-classic</artifactId>
            <version>0.1.5</version>
        </dependency>

配置lockback:新建lockback.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--启用debug模式后,将在`spring-boot 大LOG`上方打印中logBack的配置信息-->
<configuration debug="true">
    <!--包含配置文件 org/springframework/boot/logging/logback/defaults.xml-->
    <include resource="org/springframework/boot/logging/logback/defaults.xml" />

    <!--引入第三方appender, 起名为http-->
    <appender name="HTTP" class="ch.qos.logback.ext.loggly.LogglyAppender">
        <!--请求的地址-->
        <endpointUrl>http://localhost:8081/log</endpointUrl>
    </appender>

    <!--定义日志等级-->
    <root level="WARNING">
        <!--启用第三个appender为HTTP-->
        <appender-ref ref="HTTP" />
    </root>
</configuration>

我们看一下LogglyAppender内容:

  /**
   * 事件传入
   */
  protected void append(E var1) {
    String var2 = this.layout.doLayout(var1);
    
    // 调用方法向loggly传输的方法
    this.postToLoggly(var2);
  }

  private void postToLoggly(String var1) {
    try {
      assert this.endpointUrl != null;

      // endpointUrl为xml配置文件的传入属性值
      URL var2 = new URL(this.endpointUrl);
      HttpURLConnection var3;
      if (this.proxy == null) {
        // 与日志系统连接,例localhost:8005/api/batchSave
        var3 = (HttpURLConnection)var2.openConnection();
      } else {
        var3 = (HttpURLConnection)var2.openConnection(this.proxy);
      }

      var3.setRequestMethod("POST");
      var3.setDoOutput(true);
      var3.addRequestProperty("Content-Type", this.layout.getContentType());
      var3.connect();
      this.sendAndClose(var1, var3.getOutputStream());
      var3.disconnect();
      int var4 = var3.getResponseCode();
      if (var4 != 200) {
        String var5 = this.readResponseBody(var3.getInputStream());
        this.addError("Loggly post failed (HTTP " + var4 + ").  Response body:\n" + var5);
      }
    } catch (IOException var6) {
      this.addError("IOException while attempting to communicate with Loggly", var6);
    }

每条日志都会发送一次,这无疑给系统增加了很大的难度,接下来改成自己的logglyAppender,进而实现多少条或者多久发送一次。

private void postToLoggly(final String event) {
        events.add(event);
        Calendar calendar = Calendar.getInstance();
        // 日志条数够100条或者距离上次发送够6分钟,则发送到日志系统批量保存
        if (events.size() >= 100 || (calendar.getTimeInMillis() - lastSendTime.getTimeInMillis() >= 6000)) {
            try {
                lastSendTime = calendar;
                List<String> sendEvents = events;
                events = new ArrayList<>();

                assert this.endpointUrl != null;
                URL endpoint = new URL(this.endpointUrl);
                final HttpURLConnection connection;
                if (this.proxy == null) {
                    connection = (HttpURLConnection) endpoint.openConnection();
                } else {
                    connection = (HttpURLConnection) endpoint.openConnection(this.proxy);
                }
                connection.setRequestMethod("POST");
                connection.setDoOutput(true);
                connection.addRequestProperty("Content-Type", this.layout.getContentType());
                connection.connect();
                this.sendAndClose(sendEvents, connection.getOutputStream());
                connection.disconnect();
                final int responseCode = connection.getResponseCode();
                if (responseCode != 200) {
                    final String message = this.readResponseBody(connection.getInputStream());
                    this.addError("Loggly post failed (HTTP " + responseCode + ").  Response body:\n" + message);
                }
            } catch (final IOException e) {
                this.addError("IOException while attempting to communicate with Loggly", e);
            }
        }
    }

有个疑问:他为啥有时候过5分钟自动请求,有时又没反应:
image.png

总结

经验比较缺乏,在找团队项目使用的库一直没找到,自己找的也不会用,还是需要不断的积累经验。最后也是感谢团队,因为有了团队的资源才能让自己看的更远。


郝泽龙_HZ
182 声望2 粉丝