I've extended log42 logger.
The idea: I should pass enum to log method, in order to choose appender in runtime.
My interface:
public interface MyLoggerInterface {
void info(String logMessage, MyLoggerAppenderEnum... appender);
public static MyLoggerInterface getLogger(Class aClass, MyLoggerAppenderEnum... appender) {
return MyLoggerInterfaceImpl.getLogger(aClass, appender);
}
}
implementation:
public class MyLoggerInterfaceImpl extends Logger implements MyLoggerInterface {
private static final String FQCN = MyLoggerInterfaceImpl.class.getName();
protected MyLoggerInterfaceImpl(LoggerContext context, String name, MessageFactory messageFactory) {
super(context, name, messageFactory);
}
public static MyLoggerInterface getLogger(Class aClass, MyLoggerAppenderEnum... appenders) {
return getLogger(aClass.getName(), appenders);
}
private static MyLoggerInterface getLogger(String name, MyLoggerAppenderEnum... appenders) {
return (MyLoggerInterfaceImpl) org.apache.logging.log4j.LogManager.getLogger(name);
}
@Override
public void info(String logMessage, MyLoggerAppenderEnum... appenders) {
this.log(FQCN, Level.INFO, null, new SimpleMessage(logMessage), null, appenders);
}
private void log(String fqcn, Level level, Marker marker, Message message, Throwable throwable, MyLoggerAppenderEnum... appenders) {
Arrays.stream(appenders)
.map(appender -> findAppenderByName(appender))
.collect(Collectors.toList())
.forEach(appender ->
appender.append(
new Log4jLogEvent(this.getName(), marker, fqcn, level, message, new ArrayList<Property>(), throwable)
)
);
}
private Appender findAppenderByName(MyLoggerAppenderEnum appenders) {
return this.getAppenders().get(appenders.name());
}
}
But Note that in log4j 2.X LoggerFactory is removed from 1.X version. So I implement additional classes, in order to avoid ClassCastException (Logger to MyLoggerInterfaceImpl) .
So. MyContext:
public class MyLoggerContext extends LoggerContext {
public MyLoggerContext(String name) {
super(name);
}
@Override
protected Logger newInstance(final LoggerContext ctx, final String name, final MessageFactory messageFactory) {
return new MyLoggerInterfaceImpl(ctx, name, messageFactory);
}
}
Context Selector:
public class MyLoggerContextSelector implements ContextSelector {
private final LoggerContext CONTEXT = new MyLoggerContext("MyLoggerContext");
public LoggerContext getContext(String fqcn, ClassLoader loader, boolean currentContext) {
return CONTEXT;
}
public LoggerContext getContext(String fqcn, ClassLoader loader, boolean currentContext, URI configLocation) {
return CONTEXT;
}
public List<LoggerContext> getLoggerContexts() {
return Arrays.asList(CONTEXT);
}
public void removeContext(LoggerContext context) {
}
}
Context Factory:
public class MyLoggerLog4jContextFactory extends Log4jContextFactory {
public MyLoggerLog4jContextFactory() {
super(new MyLoggerContextSelector(), new DefaultShutdownCallbackRegistry());
}
}
and manager:
public class MyLoggerManager {
public static void initialize(String configURL) {
try {
System.setProperty("log4j2.loggerContextFactory", "ge.test.core.logging.MyLoggerLog4jContextFactory");
System.setProperty("Log4jLogEventFactory", "org.apache.logging.log4j.core.impl.DefaultLogEventFactory");
Configurator.initialize(null, configURL);
} catch (Exception ex ) {
System.err.println("Cannot initialize Log4J using configuration url:" + configURL);
}
}
}
Cool! Everything works fine!!! and usage:
MyLoggerManager.initialize("Log4j2.xml");
MyLoggerInterface logger = MyLoggerInterface.getLogger(AppLauncher.class);
logger.info("test", MyLoggerAppenderEnum.Console);
BUT problem is that If I use extend custom logger, I can't log method name and line. Layout is correct! If I dont use extended custom logger, mehtod name and line is logged too!
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} %method:%line - %msg%n"/>
</Console>
...
</Appenders>
<Loggers>
...
<Logger name="Console" level="trace" additivity="false">
<appender-ref ref="Console" level="trace"/>
</Logger>
...
<Root level="error">
...
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
Question: I want to log method name and line too. but it does not work after I extend my logger class (layout syntaxt is correct!)
I found the extended logger example here
and my code in here in gitlab
I use log4j 2.9.1