关于后端:Java新手学习Java项目打日志

47次阅读

共计 5973 个字符,预计需要花费 15 分钟才能阅读完成。

大家好,我是 3y。在注释之前,先给各位股东汇报下 austin 我的项目进度:

总的来说,我感觉这次的反应是不错的,尽管浏览量不高。但留言的人多了很多,也有很多人都放心我会不会鸽掉(更新一半中途就断了)

我只能说:别慌,相对不鸽,你只管追更就好

我曾经决定每个周末都扛着电脑回家,有空就往左近的图书馆里跑(图书馆是学习的 YYDS,在家的效率就是要比图书馆要低不少)

不多 BB 了,明天持续聊个话题:日志

01、什么是日志

所谓日志,在我了解下就是:记录程序运行时的信息

在 Java 最初期又或是咱们初学阶段,打印日志全凭System.out.println();

这好用吗?有待商讨。

对于大部分初学者来说,好用!我想看的信息,间接在 console 就能看到了,这是如许中央便阿。学习 Java 的第一个运行后果都是由 System.out.println(); 进去的,不须要有任何的学习老本。

对于大部分工作者来说,本地调试能够,但如果程序部署到服务器当前,那就算了。

生产环境跟本地环境是有区别的:

  • 生产环境须要记录的日志会更多(毕竟是作为一个零碎 / 我的项目在线上运行,不可能只打印一点点内容)
  • 生产环境的日志内容须要保留至文件(作为留存,线上不会说第一工夫发现问题,很多须要查找历史日志数据)
  • 生产环境的日志内容须要有肯定的标准格局(至多日志记录的工夫须要有吧)

下面这些要求,System.out.println();都是不具备的。

所以,咱们能够看到在公司里写的我的项目,是没有用 System.out.println(); 记录日志的

02、Java 日志体系

工作了当前,你会发现每次引入一个框架,这个框架下简直都有对应的日志包。

我之前在公司里已经整合过几个我的项目(将原有的几个工程合并到一个我的项目内)。

零碎分久必合合久必分,过后是认为以前的共事把我的项目拆得过于细,造成肯定的资源节约(毕竟每个工程跑在线上至多都会部署两台线上机器),所以有段时间公司就心愿咱们把一些细小的我的项目进行合并。

至于这做得对与错,这块我就不谈了。

在合并的过程中,最最最麻烦的就是解决依赖抵触的问题(都是 Maven 我的项目,会有 Maven 仲裁的问题),而这里边,最显著的就是 Java 日志包的问题。

如果你有那么一丢丢理解 Java 日志,你就应该多多少少据说过以下的名字:Log4j(log for java)、JUL(Java Util Logging)、JCL(Jakarta Commons Logging)、Slf4j(Simple Logging Facade for Java)、LogbackLog4j2

如果你比拟仔细,你会发现,不同的技术框架所采纳的 Java 日志实现都很有可能不一样的。

既然实现不一样,那对应的 API 调用是不是就不一样?(毕竟它还不像是 JDBC,定义了一套接口标准,各个数据库厂商去实现 JDBC 标准,程序员面向 JDBC 接口编程就完事了)

那这这这不是乱套呢?想到这里,血压就逐步就上来了?这别慌,下面提到的 Java 日志 Slf4j(Simple Logging Facade for Java) 干的就相似 JDBC 做的事件。

它定义了日志的接口(门面模式),当我的项目应用别的日志框架时,那就适配它!(留神:JDBC 是定义接口,数据库厂商实现。Slf4j 也定义了接口,然而它适配其余的 Java 日志实现,骚不骚?)

咱们看 Slf4j 官网的一张图,应该就挺好了解了:

扯了这么久,我想表白的是:咱们在我的项目中,最好是应用 Slf4j 提供的 API,至于实在的 LOG 实现,都能够用Slf4j 进行桥接(这样一来,或者未来有一天说要从 log4j 改为 logback,那程序代码也不必改变)

03、日志有什么用?

还没有过生产环境的开发的同学可能认为记录日志就是用来 定位问题 的,其实并不齐全是。

日志一方面咱们用它来定位问题,一方面咱们 很多的数据也是来源于日志

不要感觉存在数据库里的数据才是重要的,咱们 程序运行时记录下的日志数据也同样重要

在大数据畛域里,数据起源有很多:关系型数据库、爬虫、日志等等

举个例子,我以前的公司就有解决日志的一套框架:

  1. 咱们失常把日志信息输入到文件下
  2. 框架提供后盾给予咱们配置(文件的门路以及 Kafka Topic Name)

该框架做的事件说白了就是:把咱们的日志文件内容转成 Kafka 音讯(如果应用方须要将哪个日志文件的内容转为 MQ 音讯,那在平台上配置下就完事了)

有了 Kafka 音讯,那配合流式解决平台(Storm/Spark/Flink)再对日志进行荡涤,是不是就能产生 有价值的数据

04、Austin 日志

扯了这么久的日志根底,只是想让还不理解日志的同学有个认知。

不扯别的了,还是回到咱们还在「新建文件夹」阶段的 austin 我的项目吧。

austin 我的项目的搭建技术框架应用的是 SpringBoot,SpringBoot 默认的日志组合是:Slf4j + logback

我在公司接触到的我的项目简直都是这个组合,所以我就不打算动了,就间接用 logback 作为 austin 的日志实现框架了(要是真有那么一天要改成别的日志实现,实践上只有引入对应的桥接包就完事了)。

05、logback 日志初体验

在无任何配置的前提下,只有咱们引入了 SpringBoot 的包,就能间接应用日志的性能了。具体成果入下图

SpringBoot 是 约定大于配置 的一个框架

SpringBoot 会默认去加载 resources 下名为 logback.xml 或者 logback-spring.xml的配置文件(xml 格局也能够改为 groovy 格局)

如果都不存在,那么 logback 默认地会调用BasicConfigurator,创立一个最小化配置。

最小化配置由一个关联到根 logger 的 ConsoleAppender 组成。输入用模式为%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} – %msg%n 的 PatternLayoutEncoder 进行格式化

06、logback 配置

从下面能够发现的是,默认的 logback 配置是不合乎咱们的要求的(它是打印在 console 的),咱们是心愿把日志记录在文件下的。

所以,咱们会在 resources 下新建一个 logback 配置。常见的配置内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<configuration scan="true" scanPeriod="10 seconds">

    <contextName>austin</contextName>

    <!-- 设置日志输入门路  能够使“${}”来应用变量。TODO 这里前面是须要读配置的 -->
    <property name="log.path" value="logs"/>


    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
            <!-- 格式化输入:%d 示意日期,%thread 示意线程名,%-5level:级别从左显示 5 个字符宽度 %msg:日志音讯,%n 是换行符 -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>


    <!-- 工夫滚动输入 level 为 INFO 日志 -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的门路及文件名 -->
        <file>${log.path}/austin-info.log</file>
        <!-- 日志文件输入格局 -->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档门路以及格局 -->
            <fileNamePattern>${log.path}/logs/austin-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>1000MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!-- 日志文件保留天数 -->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录 info 级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!-- 工夫滚动输入 level 为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的门路及文件名 -->
        <file>${log.path}/austin-error.log</file>
        <!-- 日志文件输入格局 -->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/austin-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>1000MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!-- 日志文件保留天数 -->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录 ERROR 级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <root level="info">
        <!-- TODO console 打印前面能够只针对 dev 环境的 -->
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="INFO_FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </root>

</configuration>

日志的配置不会是变化无穷的,当初我的项目刚搭建进去,就怎么简略怎么来。

07、彩蛋

这篇文章公布的前一个早晨,ZhenDong 忽然问我当初用的什么 MQ 比拟多,我随口一答:Kafka 吧,我接触 MQ 根本都是 Kafka

他说在写一个 好货色,到时候收回来。我这一听,就必定感兴趣了啊。

ZhenDong 发的文章链接:https://mp.weixin.qq.com/s/JC…

文章大略就是美团大佬们他们用 AOP+ 动静模板 封装了一套 SDK,进而优雅地记录操作日志(说人话就是:大佬不想日志写在业务代码上,难以治理。将写日志这个动作形象进去,用注解来对立记录日志)

文章还是很精彩的,我举荐浏览一遍。

ZhenDong 大佬看完文章后,本人实现了一套,曾经差不多快要实现了。顺便我跟他探讨了下应用场景,感觉我的我的项目也能够用那一套货色(有优雅的打日志形式,谁不爱呢

我曾经预约了,到时候他给我发源码,我就学习下实现思路(前面我的项目也用他提供的 SDK 来打日志,有问题就开喷🐶[狗头.jpg])。等他忙完写好文章,我也转载下跟大家一起学习下。

像这种轮子或者说是教训思路,本人学会了当前,就能够在面试的时候吹了。就说本人对我的项目零碎革新了一把,从原来的破鬼样 ( 介绍背景) *,变成当初如此优雅 (** 失去的后果 **),并这个过程中交叉本人的实现思路以及遇到的坑(** 艰苦的过程 **),这种亮点 * 哪个面试官又不爱呢

08、总结

日志在一个我的项目里,我认为是在一个比拟重要的地位上的。咱们的数据和定位问题都离不开日志,有的我的项目的日志相当凌乱,那保护起来就特地特地麻烦。

其实我齐全能够本人写个 logback 配置就把这块给疏忽了,但我还是保持梳理进去,这篇文章依照「我的项目」的维度从头梳理了一遍日志的常识,心愿对大家有帮忙吧。

我的项目源码Gitee 链接:https://gitee.com/austin

我的项目源码GitHub 链接:https://github.com/austin

关注我的微信公众号【Java3y】来聊点不一样的!

【对线面试官 + 从零编写 Java 我的项目】继续高强度更新中!求 star

原创不易!!求三连!!

正文完
 0