Display thread id instead thread name in log

后端 未结 10 574
南笙
南笙 2020-12-31 00:34

I have a Struts application with log4j to display information about application.

The pattern to format log\'s output is as follows:

log4j.appender.RA         


        
相关标签:
10条回答
  • 2020-12-31 01:14

    Extend PatternLayout as below, and then specify MyPatternLayout with $X{threadId} in the format string.

    This implementation uses ThreadLocal to minimize the performance impact of calculating the Thread ID:

        MyPatternLayout extends PatternLayout {
    
            private final ThreadLocal<String> threadId = new ThreadLocal<String>() {
    
                @Override
                protected String initialValue() {
                    String t = Long.toString(Thread.currentThread().getId());
                    MDC.put("threadId", t);
                    return t;
                }
            };
    
            @Override
            public String format(LoggingEvent event) {
    
                this.threadId.get();
                return super.format(event);
            }
        }
    
    0 讨论(0)
  • 2020-12-31 01:15

    Another elegant solution with log4j2 is to use org.apache.logging.log4j.core.pattern.LogEventPatternConverter.

    You can write a class like this

    @Plugin(name = "ThreadIdConverter", category = "Converter")
    @ConverterKeys({ "tid" })
    public class ThreadIdConverter extends LogEventPatternConverter {
    
        protected ThreadIdConverter(String name, String style) {
            super(name, style);
        }
    
        @Override
        public void format(LogEvent event, StringBuilder toAppendTo) {
            toAppendTo.append(getThreadId());
        }
    
        protected String getThreadId() {
            long id = Thread.currentThread().getId();
            return Long.toHexString(id);
        }
    
        public static ThreadIdConverter newInstance(String[] options) {
            return new ThreadIdConverter("tid", "tid");
        }
    }
    

    In this way you are creating a new pattern tid and you can use it when you define your appender's layout

    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout>
                <Pattern>%d{dd-MMM HH:mm:ss.SSS} %-7level [%5tid] %logger - %message%n</Pattern>
            </PatternLayout>
        </Console>
    </Appenders>
    

    The last important thing to remember is how to activate your log4j2 plugin. To do it you have to add the package that contains your plugins in the log4j2 configuration file using the package attribute on Configuration node

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE Configuration>
    <Configuration status="warn"
        packages="my.package.logging.plugins">
        <Appenders>
            <Console name="console" target="SYSTEM_OUT">
                <PatternLayout>
                    <Pattern>%d{dd-MMM HH:mm:ss.SSS} %-7level [%5tid] %logger - %message%n</Pattern>
                </PatternLayout>
            </Console>
        </Appenders>
        <Loggers>
            <Root level="warn">
                <AppenderRef ref="console" />
            </Root>
            <Logger name="my.package" level="trace" />
        </Loggers>
    </Configuration>
    
    0 讨论(0)
  • 2020-12-31 01:19

    I implemented thread ID and thread priority for the upcoming 2.6. Tracking here: https://issues.apache.org/jira/browse/LOG4J2-1299

    You can pick up a 2.6-SNAPSHOT build from the Apache snapshots repository: https://repository.apache.org/content/repositories/snapshots/

    0 讨论(0)
  • 2020-12-31 01:20

    One possible solution is to create your own class which sits between your code and Log4J and appends the thread ID to every log message:

    public class ThreadLogger
    {
        // Constructor declared private to prevent instantiation.  Use static methods instead.
        private ThreadLogger() {}
    
        private static enum LogLevel
        {
            TRACE,
            DEBUG,
            INFO,
            WARN,
            ERROR
        }
    
        public static void trace(String message)
        {
            logMessage(message, LogLevel.ERROR);
        }
    
        public static void debug(String message)
        {
            logMessage(message, LogLevel.ERROR);
        }
    
        public static void info(String message)
        {
            logMessage(message, LogLevel.ERROR);
        }
    
        public static void warn(String message)
        {
            logMessage(message, LogLevel.WARN);
        }
    
        public static void error(String message)
        {
            logMessage(message, LogLevel.ERROR);
        }
    
        private static void logMessage(String message, LogLevel logLevel)
        {
            // Get the Log4J logger for the class that originally wanted to log the message
            String callingClassName = Thread.currentThread().getStackTrace()[3].getClassName();
            Class callingClass;
            try
            {
                callingClass = Class.forName(callingClassName);
            }
            catch(ClassNotFoundException e)
            {
                String errorMessage = String.format("Could not reference class [%s].  Unable to log call!", callingClassName);
                throw new RuntimeException(errorMessage);
            }
            Logger logger = Logger.getLogger(callingClass);
    
            // Get the thread ID and place it in front of the logged message
            long threadId = Thread.currentThread().getId();
            String formattedMessage = String.format("[%s] %s", threadId, message);
    
            // Log the message
            switch(logLevel)
            {
                case TRACE:
                    logger.trace(formattedMessage);
                    break;
                case DEBUG:
                    logger.debug(formattedMessage);
                    break;
                case INFO:
                    logger.info(formattedMessage);
                    break;
                case WARN:
                    logger.warn(formattedMessage);
                    break;
                case ERROR:
                    logger.error(formattedMessage);
                    break;
            }
        }
    }
    

    Downsides:

    • Performance? This adds a few extra steps to every log statement.
    • Stability? This adds a potential point of failure (the Class.forName call).
    • You have to replace all of your existing log statements with calls to the new class.
    • The thread ID won't appear until after the regular Log4J formatting. IE:

    1234 [main] INFO com.foo.bar.Baz - [1] Hello world on thread #1!
    1234 [main] INFO com.foo.bar.Baz - [2] Hello world on thread #2!

    0 讨论(0)
提交回复
热议问题