Log Management

Log configuration for the Dubbo framework.

Supported Log Frameworks

Dubbo supports the following logging frameworks, and users can configure based on the logging framework actually used in their business applications.

Third-party Log FrameworkPriorityDescription
Log4jHighest (used by default)Direct adaptation of Log4j, requires adding log4j-core, log4j-api dependencies and log4j.properties
SLF4JSecond highest (currently recommended)Supports log4j, log4j2, logback, etc. For logback, add slf4j-api, logback-classic, logback-core dependencies and logback.xml
Log4j2Second lowestDirect adaptation of Log4j2, requires adding log4j2-core dependency and log4j2.xml configuration
Common Logging (jcl is common logging)Second lowest (used if neither Log4j nor SLF4J is in the project)Rarely used in projects
JDK logLowest (last resort)Rarely used in projects

Note

Regardless of the logging framework used, in addition to configuring on the Dubbo side, ensure the application includes the correct logging framework dependencies and configuration files.

Using slf4j

For Spring Boot users, enable slf4j logging by adding the following configuration to application.yaml or application.properties:

  1. dubbo:
  2. application:
  3. logger: slf4j
  1. dubbo.application.logger=slf4j

Additionally, you can also set it using JVM arguments:

  1. java -Ddubbo.application.logger=slf4j

Using slf4j-log4j2 for Log Output

Add dependencies:

  1. <!-- SLF4J API -->
  2. <dependency>
  3. <groupId>org.slf4j</groupId>
  4. <artifactId>slf4j-api</artifactId>
  5. <version>1.7.30</version>
  6. </dependency>
  7. <!-- Log4j2 to SLF4J Bridge -->
  8. <dependency>
  9. <groupId>org.apache.logging.log4j</groupId>
  10. <artifactId>log4j-slf4j-impl</artifactId>
  11. <version>2.14.1</version>
  12. </dependency>
  13. <!-- Log4j2 Core -->
  14. <dependency>
  15. <groupId>org.apache.logging.log4j</groupId>
  16. <artifactId>log4j-core</artifactId>
  17. <version>2.14.1</version>
  18. </dependency>
  19. <!-- Log4j2 API -->
  20. <dependency>
  21. <groupId>org.apache.logging.log4j</groupId>
  22. <artifactId>log4j-api</artifactId>
  23. <version>2.14.1</version>
  24. </dependency>

Configure a logger with the name “org.apache.dubbo” and associate it with the corresponding appender, as follows:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <Configuration status="WARN">
  3. <Appenders>
  4. <File name="Dubbo" fileName="dubbo.log">
  5. <PatternLayout>
  6. <Pattern>%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n</Pattern>
  7. </PatternLayout>
  8. </File>
  9. </Appenders>
  10. <Loggers>
  11. <Logger name="org.apache.dubbo" level="info" additivity="false">
  12. <AppenderRef ref="Dubbo"/>
  13. </Logger>
  14. </Loggers>
  15. </Configuration>

Using slf4j-logback for Log Output

Add dependencies:

  1. <!-- SLF4J API -->
  2. <dependency>
  3. <groupId>org.slf4j</groupId>
  4. <artifactId>slf4j-api</artifactId>
  5. <version>1.7.30</version>
  6. </dependency>
  7. <!-- Logback implementation -->
  8. <dependency>
  9. <groupId>ch.qos.logback</groupId>
  10. <artifactId>logback-classic</artifactId>
  11. <version>1.2.3</version>
  12. </dependency>
  13. <dependency>
  14. <groupId>ch.qos.logback</groupId>
  15. <artifactId>logback-core</artifactId>
  16. <version>1.2.3</version>
  17. </dependency>

Add a logback configuration file:

  1. <timestamp key="byDate" datePattern="yyyyMMdd"/>
  2. <!-- dubbo log -->
  3. <appender name="dubboRolling" class="ch.qos.logback.core.rolling.RollingFileAppender">
  4. <Encoding>UTF-8</Encoding>
  5. <file>${LOG_HOME_DUBBO}/MTP-DUBBO.log</file>
  6. <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
  7. <fileNamePattern>${LOG_HOME_DUBBO}/DEMO-%d{yyyy-MM-dd}.%i-DUBBO.zip</fileNamePattern>
  8. <maxHistory>30</maxHistory>
  9. <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
  10. <MaxFileSize>100MB</MaxFileSize>
  11. </TimeBasedFileNamingAndTriggeringPolicy>
  12. </rollingPolicy>
  13. <encoder>
  14. <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
  15. <immediateFlush>true</immediateFlush>
  16. </encoder>
  17. </appender>
  18. <logger name="com.alibaba.dubbo" level="DEBUG">
  19. <appender-ref ref="dubboRolling"/>
  20. </logger>

Using log4j

For Spring Boot users, enable log4j logging by adding the following configuration to application.yaml or application.properties:

  1. dubbo:
  2. application:
  3. logger: log4j

Using log4j2:

  1. dubbo:
  2. application:
  3. logger: log4j2

Access Logs - accesslog

If you want to log detailed information for each request, you can enable access logs like the access logs of apache/tomcat server.

In the application.yaml file, you can enable access logging as follows, and the log content will be output to the currently used log framework (such as log4j, logback, etc.).

  1. dubbo:
  2. provider:
  3. accesslog: true

You can also specify the access log to be output to a specified file:

  1. dubbo:
  2. provider:
  3. accesslog: /home/dubbo/foo/bar.log

Note

Refer to the Traffic Control section for specific instructions on dynamically enabling or disabling access logs.

Dynamically Modify Log Level

Starting from version 3.3, the Dubbo framework supports dynamically modifying log configuration (level, framework, etc.) at runtime through http or telnet commands. Below is an example of usage; for more on telnet commands, refer to the qos Command Guide.

  1. Query Log Configuration Command: loggerInfo

    Example

    1. > telnet 127.0.0.1 22222
    2. > loggerInfo

    Output

    1. Trying 127.0.0.1...
    2. Connected to localhost.
    3. Escape character is '^]'.
    4. ___ __ __ ___ ___ ____
    5. / _ \ / / / // _ ) / _ ) / __ \
    6. / // // /_/ // _ |/ _ |/ /_/ /
    7. /____/ \____//____//____/ \____/
    8. dubbo>loggerInfo
    9. Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: INFO
  2. Modify Log Level Command: switchLogLevel {level}

    level: ALL, TRACE, DEBUG, INFO, WARN, ERROR, OFF

    Example

    1. > telnet 127.0.0.1 22222
    2. > switchLogLevel WARN

    Output

    1. Trying 127.0.0.1...
    2. Connected to localhost.
    3. Escape character is '^]'.
    4. ___ __ __ ___ ___ ____
    5. / _ \ / / / // _ ) / _ ) / __ \
    6. / // // /_/ // _ |/ _ |/ /_/ /
    7. /____/ \____//____//____/ \____/
    8. dubbo>loggerInfo
    9. Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: INFO
    10. dubbo>switchLogLevel WARN
    11. OK
    12. dubbo>loggerInfo
    13. Available logger adapters: [jcl, jdk, log4j, slf4j]. Current Adapter: [log4j]. Log level: WARN
  3. Change Log Output Framework Command: switchLogger {loggerAdapterName}

    loggerAdapterName: slf4j, jcl, log4j, jdk, log4j2

    Example

    1. > telnet 127.0.0.1 22222
    2. > switchLogger slf4j

    Output

    1. Trying 127.0.0.1...
    2. Connected to localhost.
    3. Escape character is '^]'.
    4. ___ __ __ ___ ___ ____
    5. / _ \ / / / // _ ) / _ ) / __ \
    6. / // // /_/ // _ |/ _ |/ /_/ /
    7. /____/ \____//____//____/ \____/
    8. dubbo>loggerInfo
    9. Available logger adapters: [jcl, slf4j, log4j, jdk]. Current Adapter: [log4j]. Log level: INFO
    10. dubbo>switchLogger slf4j
    11. OK
    12. dubbo>loggerInfo
    13. Available logger adapters: [jcl, slf4j, log4j, jdk]. Current Adapter: [slf4j]. Log level: INFO

Working Principle

In the Dubbo framework, all log outputs are obtained through the static factory class LoggerFactory to gain Logger object instances. Additionally, a LoggerAdapter is abstracted to interface with third-party logging frameworks, leading to implementations like JDKLoggerAdapter, Log4jLoggerAdapter, SLF4JLoggerAdapter, etc., which interface with different third-party log implementations. Since Dubbo can support so many logging implementations, what is the priority of these implementations in Dubbo? This priority refers to the situation when no specific logger provider is configured, and the Dubbo framework chooses on its own.

The way Dubbo logs is to adopt a uniform API call and output for different log printing systems, such as:

  1. /**
  2. * ChannelListenerDispatcher
  3. */
  4. public class ChannelHandlerDispatcher implements ChannelHandler {
  5. private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ChannelHandlerDispatcher.class);

The logging output method adopted by Dubbo first obtains the property value from the dubbo.application.logger system variable to determine which logging output method to use; if not set, it loads the corresponding logging output class in the default loading order until successfully loaded:

Order: log4jLogger > slf4jLogger > JclLogger > JdkLogger

The initialization process of the variables in LoggerFactory during class loading:

  1. // search common-used logging frameworks
  2. static {
  3. String logger = System.getProperty("dubbo.application.logger", "");
  4. switch (logger) {
  5. case Slf4jLoggerAdapter.NAME:
  6. setLoggerAdapter(new Slf4jLoggerAdapter());
  7. break;
  8. case JclLoggerAdapter.NAME:
  9. setLoggerAdapter(new JclLoggerAdapter());
  10. break;
  11. case Log4jLoggerAdapter.NAME:
  12. setLoggerAdapter(new Log4jLoggerAdapter());
  13. break;
  14. case JdkLoggerAdapter.NAME:
  15. setLoggerAdapter(new JdkLoggerAdapter());
  16. break;
  17. case Log4j2LoggerAdapter.NAME:
  18. setLoggerAdapter(new Log4j2LoggerAdapter());
  19. break;
  20. default:
  21. List<Class<? extends LoggerAdapter>> candidates = Arrays.asList(
  22. Log4jLoggerAdapter.class,
  23. Slf4jLoggerAdapter.class,
  24. Log4j2LoggerAdapter.class,
  25. JclLoggerAdapter.class,
  26. JdkLoggerAdapter.class
  27. );
  28. boolean found = false;
  29. // try to use the first available adapter
  30. for (Class<? extends LoggerAdapter> clazz : candidates) {
  31. try {
  32. LoggerAdapter loggerAdapter = clazz.getConstructor().newInstance();
  33. loggerAdapter.getLogger(LoggerFactory.class);
  34. if (loggerAdapter.isConfigured()) {
  35. setLoggerAdapter(loggerAdapter);
  36. found = true;
  37. break;
  38. }
  39. } catch (Exception | LinkageError ignored) {
  40. // ignore
  41. }
  42. }
  43. if (found) {
  44. break;
  45. }
  46. System.err.println("Dubbo: Unable to find a proper configured logger to log out.");
  47. for (Class<? extends LoggerAdapter> clazz : candidates) {
  48. try {
  49. LoggerAdapter loggerAdapter = clazz.getConstructor().newInstance();
  50. loggerAdapter.getLogger(LoggerFactory.class);
  51. setLoggerAdapter(loggerAdapter);
  52. found = true;
  53. break;
  54. } catch (Throwable ignored) {
  55. // ignore
  56. }
  57. }
  58. if (found) {
  59. System.err.println("Dubbo: Using default logger: " + loggerAdapter.getClass().getName() + ". " +
  60. "If you cannot see any log, please configure -Ddubbo.application.logger property to your preferred logging framework.");
  61. } else {
  62. System.err.println("Dubbo: Unable to find any available logger adapter to log out. Dubbo logs will be ignored. " +
  63. "Please configure -Ddubbo.application.logger property and add corresponding logging library to classpath.");
  64. }
  65. }
  66. }

The above static block resides in LoggerFactory, indicating that as soon as the LoggerFactory class is loaded, it will select the corresponding log provider. You will notice that the log provider can actually be designated by configuration, as the static block initially fetches dubbo.application.logger from the current JVM environment. This parameter can be specified using java -Ddubbo.application.logger=xxxx, and if deployed in a container, it needs to be configured in the JVM parameters during container startup.

Feedback

Was this page helpful?

Yes No

Last modified September 30, 2024: Update & Translate Overview Docs (#3040) (d37ebceaea7)