細說 Java 主流日誌工具庫

2022-02-05 Java後端

作者 | 靜默虛空  

連結 | juejin.im/post/5c8f35bfe51d4545cc650567

在項目開發中,為了跟蹤代碼的運行情況,常常要使用日誌來記錄信息。在 Java 世界,有很多的日誌工具庫來實現日誌功能,避免了我們重複造輪子。

我們先來逐一了解一下主流日誌工具。

日誌框架
java.util.logging (JUL)

JDK1.4 開始,通過 java.util.logging 提供日誌功能。

它能滿足基本的日誌需要,但是功能沒有 Log4j 強大,而且使用範圍也沒有 Log4j 廣泛。

Log4j

Log4j 是 apache 的一個開源項目,創始人 Ceki Gulcu。

Log4j 應該說是 Java 領域資格最老,應用最廣的日誌工具。從誕生之日到現在一直廣受業界歡迎。

Log4j 是高度可配置的,並可通過在運行時的外部文件配置。它根據記錄的優先級別,並提供機制,以指示記錄信息到許多的目的地,諸如:資料庫,文件,控制臺,UNIX 系統日誌等。

Log4j 中有三個主要組成部分:

appenders - 負責發布日誌信息,以不同的首選目的地。layouts - 負責格式化不同風格的日誌信息。http://logging.apache.org/log4j/2.x/LogbackLogback 是由 log4j 創始人 Ceki Gulcu 設計的又一個開源日記組件,目標是替代 log4j。logback 當前分成三個模塊:logback-core、logback-classic 和 logback-access。logback-core - 是其它兩個模塊的基礎模塊。logback-classic - 是 log4j 的一個 改良版本。此外 logback-classic 完整實現 SLF4J API 使你可以很方便地更換成其它日記系統如 log4j 或 JDK14 Logging。logback-access - 訪問模塊與 Servlet 容器集成提供通過 Http 來訪問日記的功能。Log4j2http://logging.apache.org/log4j/2.x/按照官方的說法,Log4j2 是 Log4j 和 Logback 的替代。Log4j vs Logback vs Log4j2按照官方的說法,Log4j2 大大優於 Log4j 和 Logback。那麼,Log4j2 相比於先問世的 Log4j 和 Logback,它具有哪些優勢呢?Log4j2 旨在用作審計日誌記錄框架。Log4j 1.x 和 Logback 都會在重新配置時丟失事件。Log4j 2 不會。在 Logback 中,Appender 中的異常永遠不會對應用程式可見。在 Log4j 中,可以將 Appender 配置為允許異常滲透到應用程式。Log4j2 在多線程場景中,異步 Loggers 的吞吐量比 Log4j 1.x 和 Logback 高 10 倍,延遲低幾個數量級。Log4j2 對於獨立應用程式是無垃圾的,對於穩定狀態日誌記錄期間的 Web 應用程式來說是低垃圾。這減少了垃圾收集器的壓力,並且可以提供更好的響應時間性能。Log4j2 使用插件系統,通過添加新的 Appender、Filter、Layout、Lookup 和 Pattern Converter,可以非常輕鬆地擴展框架,而無需對 Log4j 進行任何更改。由於插件系統配置更簡單。配置中的條目不需要指定類名。Log4j 和 Logback 的 Layout 返回的是字符串,而 Log4j2 返回的是二進位數組,這使得它能被各種 Appender 使用。Syslog Appender 支持 TCP 和 UDP 並且支持 BSD 系統日誌。Log4j2 利用 Java5 並發特性,儘量小粒度的使用鎖,減少鎖的開銷。日誌門面日誌門面是對不同日誌框架提供的一個 API 封裝,可以在部署的時候不修改任何配置即可接入一種日誌實現方案。common-loggingcommon-logging 是 apache 的一個開源項目。也稱Jakarta Commons Logging,縮寫 JCL。common-logging 的功能是提供日誌功能的 API 接口,本身並不提供日誌的具體實現(當然,common-logging 內部有一個 Simple logger 的簡單實現,但是功能很弱,直接忽略),而是在運行時動態的綁定日誌實現組件來工作(如 log4j、java.util.loggin)。http://commons.apache.org/proper/commons-logging/slf4j全稱為 Simple Logging Facade for Java,即 java 簡單日誌門面。什麼,作者又是 Ceki Gulcu!這位大神寫了 Log4j、Logback 和 slf4j,專注日誌組件開發五百年,一直只能超越自己。類似於 Common-Logging,slf4j 是對不同日誌框架提供的一個 API 封裝,可以在部署的時候不修改任何配置即可接入一種日誌實現方案。但是,slf4j 在編譯時靜態綁定真正的 Log 庫。使用 SLF4J 時,如果你需要使用某一種日誌實現,那麼你必須選擇正確的 SLF4J 的 jar 包的集合(各種橋接包)。Tips:大家可以關注微信公眾號:Java後端,獲取更多推送。common-logging vs slf4jslf4j 庫類似於 Apache Common-Logging。但是,他在編譯時靜態綁定真正的日誌庫。這點似乎很麻煩,其實也不過是導入橋接 jar 包而已。slf4j 一大亮點是提供了更方便的日誌記錄方式:不需要使用logger.isDebugEnabled()來解決日誌因為字符拼接產生的性能問題。slf4j 的方式是使用{}作為字符串替換符,形式如下:

logger.debug("id: {}, name: {} ", id, name);

總結綜上所述,使用 slf4j + Logback 可謂是目前最理想的日誌解決方案了。實施日誌解決方案常見的各種日誌解決方案的第 2 步和第 3 步基本一樣,實施上的差別主要在第 1 步,也就是使用不同的庫。引入 jar 包這裡首選推薦使用 slf4j + logback 的組合。如果你習慣了 common-logging,可以選擇 common-logging+log4j。強烈建議不要直接使用日誌實現組件(logback、log4j、java.util.logging),理由前面也說過,就是無法靈活替換日誌庫。還有一種情況:你的老項目使用了 common-logging,或是直接使用日誌實現組件。如果修改老的代碼,工作量太大,需要兼容處理。在下文,都將看到各種應對方法。註:據我所知,當前仍沒有方法可以將 slf4j 橋接到 common-logging。如果我孤陋寡聞了,請不吝賜教。slf4j 直接綁定日誌組件logback-classic-1.0.13.jar 會自動將 slf4j-api-1.7.21.jar 和 logback-core-1.0.13.jar 也添加到你的項目中。slf4j-log4j12-1.7.21.jar 會自動將 slf4j-api-1.7.21.jar 和 log4j-1.2.17.jar 也添加到你的項目中。

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>1.7.21</version>
</dependency>

slf4j + java.util.loggingslf4j-jdk14-1.7.21.jar 會自動將 slf4j-api-1.7.21.jar 也添加到你的項目中。

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-jdk14</artifactId>
  <version>1.7.21</version>
</dependency>

slf4j 兼容非 slf4j 日誌組件假如你正在開發應用程式所調用的組件當中已經使用了 common-logging,這時你需要 jcl-over-slf4j.jar 把日誌信息輸出重定向到 slf4j-api,slf4j-api 再去調用 slf4j 實際依賴的日誌組件。這個過程稱為橋接。下圖是官方的 slf4j 橋接策略圖:從圖中應該可以看出,無論你的老項目中使用的是 common-logging 或是直接使用 log4j、java.util.logging,都可以使用對應的橋接 jar 包來解決兼容問題。

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>jcl-over-slf4j</artifactId>
  <version>1.7.12</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>log4j-over-slf4j</artifactId>
    <version>1.7.12</version>
</dependency>

slf4j 兼容 java.util.logging

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jul-to-slf4j</artifactId>
    <version>1.7.12</version>
</dependency>

spring 集成 slf4j做 java web 開發,基本離不開 spring 框架。很遺憾,spring 使用的日誌解決方案是 common-logging + log4j。(系統的學習spring全家桶,可以在Java知音公眾號內回復「Springboot聚合」)所以,你需要一個橋接 jar 包:logback-ext-spring。

<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.1.3</version>
</dependency>
<dependency>
  <groupId>org.logback-extensions</groupId>
  <artifactId>logback-ext-spring</artifactId>
  <version>0.1.2</version>
</dependency>
<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>jcl-over-slf4j</artifactId>
  <version>1.7.12</version>
</dependency>

common-logging 綁定日誌組件

<dependency>
  <groupId>commons-logging</groupId>
  <artifactId>commons-logging</artifactId>
  <version>1.2</version>
</dependency>
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.17</version>
</dependency>

使用 APIslf4j 用法使用 slf4j 的 API 很簡單。使用LoggerFactory初始化一個Logger實例,然後調用 Logger 對應的列印等級函數就行了。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class App {
    private static final Logger log = LoggerFactory.getLogger(App.class);
    public static void main(String[] args) {
        String msg = "print log, current level: {}";
        log.trace(msg, "trace");
        log.debug(msg, "debug");
        log.info(msg, "info");
        log.warn(msg, "warn");
        log.error(msg, "error");
    }
}

common-logging 用法common-logging 用法和 slf4j 幾乎一樣,但是支持的列印等級多了一個更高級別的:fatal。此外,common-logging 不支持{}替換參數,你只能選擇拼接字符串這種方式了。

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class JclTest {
    private static final Log log = LogFactory.getLog(JclTest.class);

    public static void main(String[] args) {
        String msg = "print log, current level: ";
        log.trace(msg + "trace");
        log.debug(msg + "debug");
        log.info(msg + "info");
        log.warn(msg + "warn");
        log.error(msg + "error");
        log.fatal(msg + "fatal");
    }
}

log4j2 配置

<?xml version="1.0" encoding="UTF-8"?>;
<Configuration>
  <Properties>
    <Property name="name1">value</property>
    <Property name="name2" value="value2"/>
  </Properties>
  <Filter type="type" ... />
  <Appenders>
    <Appender type="type" name="name">
      <Filter type="type" ... />
    </Appender>
    ...
  </Appenders>
  <Loggers>
    <Logger name="name1">
      <Filter type="type" ... />
    </Logger>
    ...
    <Root level="level">
      <AppenderRef ref="name"/>
    </Root>
  </Loggers>
</Configuration>

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug" strict="true" name="XMLConfigTest"
               packages="org.apache.logging.log4j.test">
  <Properties>
    <Property name="filename">target/test.log</Property>
  </Properties>
  <Filter type="ThresholdFilter" level="trace"/>

  <Appenders>
    <Appender type="Console" name="STDOUT">
      <Layout type="PatternLayout" pattern="%m MDC%X%n"/>
      <Filters>
        <Filter type="MarkerFilter" marker="FLOW" onMatch="DENY" onMismatch="NEUTRAL"/>
        <Filter type="MarkerFilter" marker="EXCEPTION" onMatch="DENY" onMismatch="ACCEPT"/>
      </Filters>
    </Appender>
    <Appender type="Console" name="FLOW">
      <Layout type="PatternLayout" pattern="%C{1}.%M %m %ex%n"/>
      <Filters>
        <Filter type="MarkerFilter" marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
        <Filter type="MarkerFilter" marker="EXCEPTION" onMatch="ACCEPT" onMismatch="DENY"/>
      </Filters>
    </Appender>
    <Appender type="File" name="File" fileName="${filename}">
      <Layout type="PatternLayout">
        <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
      </Layout>
    </Appender>
  </Appenders>

  <Loggers>
    <Logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
      <Filter type="ThreadContextMapFilter">
        <KeyValuePair key="test" value="123"/>
      </Filter>
      <AppenderRef ref="STDOUT"/>
    </Logger>

    <Logger name="org.apache.logging.log4j.test2" level="debug" additivity="false">
      <AppenderRef ref="File"/>
    </Logger>

    <Root level="trace">
      <AppenderRef ref="STDOUT"/>
    </Root>
  </Loggers>

</Configuration>

logback 配置作用:<configuration> 是 logback 配置文件的根元素。要點:它有 <appender>、<logger>、<root> 三個子元素。作用:將記錄日誌的任務委託給名為 appender 的組件。要點:可以配置零個或多個;它有 <file>、<filter>、<layout>、<encoder> 四個子元素。level:設置日誌級別。不區分大小寫。可選值:TRACE、DEBUG、INFO、WARN、ERROR、ALL、OFF。additivity:可選值:true 或 false。要點:只能配置一個;除了 level,不支持任何屬性。level 屬性和 <logger> 中的相同;有一個子元素 <appender-ref>,與 <logger> 中的相同。完整的 logback.xml 參考示例在下面的配置文件中,我為自己的項目代碼(根目錄:org.zp.notes.spring)設置了五種等級:TRACE、DEBUG、INFO、WARN、ERROR,優先級依次從低到高。因為關注 spring 框架本身的一些信息,我增加了專門列印 spring WARN 及以上等級的日誌。

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


<configuration scan="true" scanPeriod="60 seconds" debug="false">

  <property name="DIR_NAME" value="spring-helloworld"/>

  
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
    </encoder>
  </appender>

  
  <appender name="ALL" class="ch.qos.logback.core.rolling.RollingFileAppender">
    
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${user.dir}/logs/${DIR_NAME}/all.%d{yyyy-MM-dd}.log</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>

    
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>30MB</maxFileSize>
    </triggeringPolicy>

    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
    </encoder>
  </appender>

  <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
    
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${user.dir}/logs/${DIR_NAME}/error.%d{yyyy-MM-dd}.log</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>

    
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>10MB</maxFileSize>
    </triggeringPolicy>

    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>ERROR</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>

    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
    </encoder>
  </appender>

  <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
    
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${user.dir}/logs/${DIR_NAME}/warn.%d{yyyy-MM-dd}.log</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>

    
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>10MB</maxFileSize>
    </triggeringPolicy>

    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>WARN</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>

    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
    </encoder>
  </appender>

  <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
    
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${user.dir}/logs/${DIR_NAME}/info.%d{yyyy-MM-dd}.log</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>

    
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>10MB</maxFileSize>
    </triggeringPolicy>

    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>INFO</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>

    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
    </encoder>
  </appender>

  <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
    
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${user.dir}/logs/${DIR_NAME}/debug.%d{yyyy-MM-dd}.log</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>

    
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>10MB</maxFileSize>
    </triggeringPolicy>

    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>DEBUG</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>

    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
    </encoder>
  </appender>

  <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${user.dir}/logs/${DIR_NAME}/trace.%d{yyyy-MM-dd}.log</fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>

    
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>10MB</maxFileSize>
    </triggeringPolicy>

    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>TRACE</level>
      <onMatch>ACCEPT</onMatch>
      <onMismatch>DENY</onMismatch>
    </filter>

    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
    </encoder>
  </appender>

  <appender name="SPRING" class="ch.qos.logback.core.rolling.RollingFileAppender">
    
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${user.dir}/logs/${DIR_NAME}/springframework.%d{yyyy-MM-dd}.log
      </fileNamePattern>
      <maxHistory>30</maxHistory>
    </rollingPolicy>

    
    <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
      <maxFileSize>10MB</maxFileSize>
    </triggeringPolicy>

    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] [%-5p] %c{36}.%M - %m%n</pattern>
    </encoder>
  </appender>
  

  
  
  <logger name="org.zp.notes.spring" level="TRACE" additivity="false">
    <appender-ref ref="STDOUT"/>
    <appender-ref ref="ERROR"/>
    <appender-ref ref="WARN"/>
    <appender-ref ref="INFO"/>
    <appender-ref ref="DEBUG"/>
    <appender-ref ref="TRACE"/>
  </logger>

  
  <logger name="org.springframework" level="WARN" additivity="false">
    <appender-ref ref="SPRING"/>
  </logger>

  <root level="TRACE">
    <appender-ref ref="ALL"/>
  </root>
  

</configuration>

log4j 配置完整的 log4j.xml 參考示例log4j 的配置文件一般有 xml 格式或 properties 格式。這裡為了和 logback.xml 做個對比,就不介紹 properties 了,其實也沒太大差別。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>

  <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern"
             value="%d{yyyy-MM-dd HH:mm:ss,SSS\} [%-5p] [%t] %c{36\}.%M - %m%n"/>
    </layout>

    
    <filter class="org.apache.log4j.varia.LevelRangeFilter">
      <param name="levelMin" value="debug"/>
      <param name="levelMax" value="fatal"/>
      <param name="AcceptOnMatch" value="true"/>
    </filter>
  </appender>


  <appender name="ALL" class="org.apache.log4j.DailyRollingFileAppender">
    <param name="File" value="${user.dir}/logs/spring-common/jcl/all"/>
    <param name="Append" value="true"/>
    
    <param name="DatePattern" value="'-'yyyy-MM-dd'.log'"/>
    
    
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern"
             value="%d{yyyy-MM-dd HH:mm:ss,SSS\} [%-5p] [%t] %c{36\}.%M - %m%n"/>
    </layout>
  </appender>

  
  <logger name="org.zp.notes.spring" additivity="false">
    <level value="error"/>
    <appender-ref ref="STDOUT"/>
    <appender-ref ref="ALL"/>
  </logger>

  
  <root>
    <level value="warn"/>
    <appender-ref ref="STDOUT"/>
  </root>
</log4j:configuration>

參考[1] http://www.slf4j.org/manual.html
[2] http://logback.qos.ch/
[3] http://logging.apache.org/log4j/1.2/
[4] http://commons.apache.org/proper/commons-logging/
[5] http://blog.csdn.net/yycdaizi/article/details/8276265

 

如果看到這裡,說明你喜歡這篇文章,請轉發、點讚。微信搜索「web_resource」,關注後回復「進群」或者掃描下方二維碼即可進入無廣告交流群。

5.  團隊開發中 Git 最佳實踐

 學Java,請關注公眾號:Java後端 

在看 

相關焦點

  • Java各類日誌組件分析匯總
    作為一名開發人員,相信大家對日誌工具不會陌生,Java 也擁有功能和性能都非常強大的日誌庫;不過這麼多日誌工具&第三方的包,怎樣保證每個組件裡都能使用約定好的日誌工具
  • 10大最高效的Java庫盤點
    包含Java中可用的所有集合和數據結構● java.io:I/O流● java.nio:它實際上是java.io的替代品,代表非阻塞I / O。● java.math:提供了使用任意精度decimal(BigDecimal)和integer(BigInteger)值的功能● java.net:被用於處理套接字,創建連接,或者創建網絡應用程式在Java中,我們也會用到GUI庫,我們甚至可以用java.sound播放音樂和創建MIDI文件2.
  • 運維利器:9個 Java 日誌分析工具(文末沒有彩蛋)
    日誌這東西,作為很基礎的組件,那必須得是挑好的用,男人吶,得會居家。(文末真的沒有彩蛋)它根據記錄的優先級別,並提供機制,以指示記錄信息到許多的目的地,諸如:資料庫,文件,控制臺,UNIX系統日誌等。Graylog(我發誓文末沒有彩蛋)Graylog是強大的日誌管理、分析工具。它基於 Elasticsearch, Java和MongoDB。Graylog可以收集監控多種不同應用的日誌。但是為了示範說明,我只收集syslog。
  • 為 Java 程式設計師而生的 10 + 最佳庫
    (點擊上方公眾號,可快速關注)來源:開源中國,www.oschina.net/translate/useful-java-libraries-for-java-programmers
  • 為 Java 程式設計師而生的 10+ 最佳庫
    (點擊上方公眾號,可快速關注)來源:開源中國,www.oschina.net/translate/useful-java-libraries-for-java-programmers
  • JAVA程式設計師一定知道的優秀第三方庫(2016版)
    下面便是我整理的,在大部分項目中使用到的優秀JAVA第三方庫 ,供大家參考:JAVA核心擴展正如前面說到的字符串判斷的例子,JAVA的標準庫雖然提供了那些最基本的數據類型操作方法,但仍然對一些常見的需求場景,缺少實用的工具類。而另一些則是JAVA標準庫本身不夠完善,需要第三方庫去加以補充的。
  • Java日誌記錄最佳實踐
    所以,日誌的作用就是在測試、生產環境沒有 Debug 調試工具時開發和測試人員定位問題的手段。日誌打得好,就能根據日誌的軌跡快速定位並解決線上問題,反之,日誌輸出不好,不僅無法輔助定位問題反而可能會影響到程序的運行性能和穩定性。
  • 25個Java機器學習工具&庫
    本列表總結了25個Java機器學習工具&庫:1. Weka集成了數據挖掘工作的機器學習算法。
  • Java 日誌框架:logback 詳解
    」是name=」java.lang」的父級,root是所有<logger>的父級。」這個<logger>,將日誌級別大於等於warn的使用」STDOUT」這個<appender>列印出來name=」java.lang」這個<logger>沒有配置additivity,那麼additivity=true,列印信息向上傳遞,傳遞給父級name=」java」這個<logger>name=」java」這個<
  • Java開發者值得關注的7款新工具
    作為老牌語言Java,其生態圈也出來了一些有關雲服務、監控、文檔分享方面的工具。本文總結了7款較新的Java工具,大家不妨看下。1. JClarity——性能監控JClarity目前提供兩款有關Java性能的工具:Illuminate和Censum,Illuminate是一款性能監控工具,而Censum是一款專注於垃圾回收的日誌分析工具。
  • 主流Java資料庫連接池比較及前瞻
    關鍵技術,第一時間送達主流資料庫連接池常用的主流開源資料庫連接池有C3P0、DBCP
  • 主流日誌框架使用及性能對比,看這篇就夠了!
    以 Java 程式語言為例,列印日誌的方式有很多,例如通過System.out.print()方法將關鍵信息輸出到控制臺,也可以通過 JDK 自帶的日誌Logger類輸出,雖然 JDK 從1.4開始支持日誌輸出,但是功能單一,無法更好的滿足商業要求,於是誕生了很多第三方日誌庫,像我們所熟悉的主流框架log4j、log4j2、logback等,提供的
  • Java程式設計師最常用的8個Java日誌框架
    (Log4jTest.class);PropertyConfigurator.configure("src/log4j.properties");log.debug("yes,debug");log.info("yes,info");log.error("yes,error");log.warn("yes,warn");}}2、gclogviewer – Java日誌查看工具
  • 2018年不能錯過的 14 個 Java 庫!
    下面是整理給你的 2018 年不應該錯過的 14 個 Java 庫包清單,多多少少大家應該都接觸過一些,如果還沒聽過那就OUT了。
  • 十個非常有用的第三方Java庫
    在本文中,我們為大家介紹幾種Java庫來幫助開發人員解決編程中遇到的各種相關問題。這些庫包含了允許擴展功能的軟體包,迎合不同類型的Java應用程式。Commons Math是Apache上一個輕量級自容器的數學和統計計算方法包,包含大多數常用的數值算法。
  • 盤點最流行的Java工具
    開發者經常使用這個工具配合其他的測試框架,來測試大型Web應用。最流行的:Cucumber-JVM, SpockCucumber最開始只是一個Ruby項目,但是現在已經用各大主流程式語言實現了。Spock支持JVM驅動的語言Groovy,當然也支持Java。Mockito能做的事情它基本上都能做。
  • Java接口自動化之log4j日誌框架
    以下主要介紹Java日誌框架Log4j。1 log4j介紹Log4j(log for java)是java流行的日誌框架,可以方便的記錄日誌。Log4j默認日誌級別為INFO,規則是只輸出比默認日誌級別高的等級,即只輸出INFO、WARN、ERROR和FATAL等級,DEBUG等級則不會輸出。
  • 「神器」:Oracle日誌採集分析工具——TFA
    本人最近向Oracle提交SR,因為是兩節點的RAC環境,提交異常日誌信息特別繁瑣,遂想起OSWatcher工具,查看文章OSWatcher (Includes: [Video]) (文檔 ID 301137.1)一文時看到更為強大的TFA工具,因此有了此文。本文將講述省心省力的一個搜集/分析工具TFA。本文較長,耐心看,值得看。
  • 你的Java代碼對JIT編譯友好麼?
    因為盲目地修改可能會對程序的性能帶來不可預料的影響。由於內聯會對代碼的性能有大幅提升,因此讓儘可能多的方法達到內聯條件尤為重要。這裡我們介紹一款叫做Jarscan的工具來幫助我們檢測程序中有多少方法是對內聯友好的。Jarscan工具是分析JIT編譯的JITWatch開源工具套件中的一部分。
  • 2017不能錯過的 Java 庫及史上最全的 Java 新手問題匯總
    下面有一些 Project Lombok 的 feature:Simple Logging Facade for Java (SLF4J)The Simple Logging Facade for Java (SLF4J) 是一個日誌庫抽象層,並非真正的日誌庫,可以支持不同的日誌實現,如java.util.logging, logback, log4j。