Can the log that is automatically completed by AI be printed normally?

Original link: https://mazhuang.org/2023/05/10/can-this-log-print-work/

I have recently used GitHub Copilot, and its capabilities have amazed me from time to time, so more and more tab-oriented programming, the loss of mechanical keyboards is much smaller:-p

Today, it automatically generated a log printing code like this for me:

 try { // ... } catch ( Exception e ) { log . error ( "Xxx 操作出错,订单号{},操作人{}" , orderNumber , operatorName , e ); }

I stared at this line of familiar and unfamiliar code—yes, I usually write this way myself, but at this time, there was a trace of uncertainty. It can really print out this sentence first, and then complete it according to the expected effect. print exception stack?

If you have doubts, ask them to the bottom of it.

Why do you wonder?

After asking myself this question, I thought back, probably because I’ve come across this before:

If the last parameter is not of Throwable type, IDEA will give a warning:

 More arguments provided (3) than placeholders specified (2)

Then why the last extra parameter is Throwable, and the IDE thinks it is normal? This is the question to be explored in this paper.

dispel doubts

In case of indecision, command + click. You can see that the method definition looks like this:

 public void error ( String format , Object ... arguments );

It’s a pity that when I want to see the specific implementation, I find that there are too many implementation classes, so I simply write a test case to debug and follow it, and enter with F7 all the way (the log framework used here is log4j2):

 org.apache.logging.slf4j.Log4jLogger#error(java.lang.String, java.lang.Object...) org.apache.logging.log4j.spi.AbstractLogger#logIfEnabled(java.lang.String, org.apache.logging.log4j.Level, org.apache.logging.log4j.Marker, java.lang.String, java.lang.Object...) org.apache.logging.log4j.spi.AbstractLogger#logMessage(java.lang.String, org.apache.logging.log4j.Level, org.apache.logging.log4j.Marker, java.lang.String, java.lang.Object...) org.apache.logging.log4j.message.ParameterizedMessageFactory#newMessage(java.lang.String, java.lang.Object...) org.apache.logging.log4j.message.ParameterizedMessage#ParameterizedMessage(java.lang.String, java.lang.Object...) org.apache.logging.log4j.message.ParameterizedMessage#init

The secret is here:

 // org.apache.logging.log4j.message.ParameterizedMessage private void init ( final String messagePattern ) { this . messagePattern = messagePattern ; final int len = Math . max ( 1 , messagePattern == null ? 0 : messagePattern . length () >> 1 ); // divide by 2 this . indices = new int [ len ]; // LOG4J2-1542 ensure non-zero array length // 计算占位符个数final int placeholders = ParameterFormatter . countArgumentPlaceholders2 ( messagePattern , indices ); initThrowable ( argArray , placeholders ); this . usedCount = Math . min ( placeholders , argArray == null ? 0 : argArray . length ); } private void initThrowable ( final Object [] params , final int usedParams ) { if ( params != null ) { final int argCount = params . length ; // 如果占位符个数比参数个数少,且最后一个参数是throwable 类型, // 则将最后一个参数赋值给Message 的成员if ( usedParams < argCount && this . throwable == null && params [ argCount - 1 ] instanceof Throwable ) { this . throwable = ( Throwable ) params [ argCount - 1 ]; } } }

Then a few steps back in the call stack there is:

 // org.apache.logging.log4j.spi.AbstractLogger protected void logMessage ( final String fqcn , final Level level , final Marker marker , final String message , final Object ... params ) { final Message msg = messageFactory . newMessage ( message , params ); logMessageSafely ( fqcn , level , marker , msg , msg . getThrowable ()); }

So far it is basically clear.

in conclusion

After analysis and actual operation verification:

  • The code generated by AI can be printed as expected;
  • If there are more non-Throwable type parameters than placeholders, they will be ignored.

This article is transferred from: https://mazhuang.org/2023/05/10/can-this-log-print-work/
This site is only for collection, and the copyright belongs to the original author.