I'd like to have an indicator in my log file for which app logs something. This would mean a variable that's the same for the entire app, but different between instances of the app. I tried to use MDC for this, hoping that if I set it directly in the main method, the variable would be taken over by newly spawned threads. This used to work, more or less, using log4j, but it doesn't work at all with logback. I know you can show system variables in the log file, but there might be several instances of the app running on the same machine, so that won't work. So, how should I send this variable to my log file?
问题:
回答1:
I would use a JVM System Property. You can set them per process when the JVM is launched with a flag -Dthings.that.arent.bacon=turkey-bacon
, or programmatically: System.setProperty("no.matter.what.they.tell.you", "turkey bacon is not bacon");
.
It looks like this is already supportted in LogBack if you're using SLF4J/logback: https://logback.qos.ch/manual/layouts.html
回答2:
I think it's impossible to set a MDC variable for the entire app.
What I am doing is extending the appenders I want, setting in a static manner the desired parameters and setting it for for every call to the method protected void append(ILoggingEvent eventObject). This is my example for a socket appender:
package my.package
import org.slf4j.MDC;
import java.util.ResourceBundle;
import ch.qos.logback.classic.net.SocketAppender;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.LoggingEvent;
public class MyLogbackSocketAppenderWithMDCEnabled extends SocketAppender {
/**
* Example parameter calculated
* This is a list of public IPs of the server
*/
private static final String public_ips = MyNetUtility.getPublicIps();
/**
* Example parameter extracted from a .properties
*
**/
private static final String versio;
static {
String versioAux = null;
try {
final ResourceBundle app = ResourceBundle.getBundle("application");
versioAux = app.getString("versio");
} catch (final Exception e) {
; /*If we have problems loading the bundle, versio=null*/
}
versio = versioAux;
}
@Override
protected void append(ILoggingEvent eventObject) {
if (eventObject instanceof LoggingEvent) {
/*Setting of the parameters in the MDC*/
MDC.put("public_ips", public_ips);
if (versio != null) {
MDC.put("versio", versio);
}
final LoggingEvent loggingEvent = ((LoggingEvent) eventObject);
/* This loads the MDC in the event */
loggingEvent.getMDCPropertyMap();
}
super.append(eventObject);
}
}
Then I use it in my logback.xml like the normal SocketAppender with the same config attributes:
<appender name="SOCKET" class="my.package.MyLogbackSocketAppenderWithMDCEnabled">
<remoteHost>${logger.host}</remoteHost>
<port>${logger.port}</port>
<reconnectionDelay>10000</reconnectionDelay>
<includeCallerData>false</includeCallerData>
</appender>
Maybe it's not a clean solution, but it works.
回答3:
Is the definition of a property something you searching for?
You can define a property <property scope="context" name="APP_INSTANCE" value="my-app"/>
and use it in the pattern %-5level property{APP_INSTANCE} [%thread]: %message%n
. See https://logback.qos.ch/manual/layouts.html#property
If you need, you can check if the property exists first:
<if condition='isDefined("APP_INSTANCE")'>
<then>
...
</then>
</if>