How to get logger Hierarchy in Log4j2 ? I am migrating from Log4j1 to log4j2. Earlier we were using the Hierarchy Class to get the Hierarchy - log4j

Earlier we were doing like below :
This is code we had used to get the logger hierarchy and loggers. but now in log4j2 the Hierarchy class does not exist.
What is the alternative to achieve below in log4j2 ?
public class ReportHierarchy extends Hierarchy
{
public ReportHierarchy(Logger root)
{
super(root);
}
public Logger getLogger(String name)
{
return getLogger(name, defaultFactory);
}
private LoggerFactory defaultFactory = new ReportFactory();
}
We are using the ReportHierarchy class like below :
static
{
ReportHierarchy h = new ReportHierarchy(new RootLogger(Level.DEBUG));
LogManager.setRepositorySelector(new DefaultRepositorySelector(h), "nuova");
LogManager.resetConfiguration();
NuRollingFileAppender.initializeCleanupTimer();
}

This part of architecture has not changed between Log4j 1.x and Log4j2, but the names changed. So you have:
a ContextSelector instead of a RepositorySelector,
a LoggerContext instead of Hierarchy.
You don't need to set the ContextSelector in code any more, just set the log4j2.contextSelector Log4j2 system property to the fully qualified class name of your selector. You can do it e.g. in a log4j2.component.properties file.

Related

Changing class loader for flow assembly

I am using Spring Web flow 2.4.8.RELEASE with Spring version 4.3.11. There are certain classes being used in the flow file that are not part of standard class loader. They are being loaded using application specific class loader.
How can I change change the class loader used by FlowModelFlowBuilder?
java.lang.IllegalArgumentException: Unable to load class '<CLASS TO LOAD USING DIFFERENT CLASS LOADER>'
at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.toClass(FlowModelFlowBuilder.java:977)
at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.parseFlowVariable(FlowModelFlowBuilder.java:402)
at org.springframework.webflow.engine.builder.model.FlowModelFlowBuilder.buildVariables(FlowModelFlowBuilder.java:181)
at org.springframework.webflow.engine.builder.FlowAssembler.directAssembly(FlowAssembler.java:103)
at org.springframework.webflow.engine.builder.FlowAssembler.assembleFlow(FlowAssembler.java:91)
at org.springframework.webflow.engine.builder.DefaultFlowHolder.assembleFlow(DefaultFlowHolder.java:109)
at org.springframework.webflow.engine.builder.DefaultFlowHolder.getFlowDefinition(DefaultFlowHolder.java:84)
at org.springframework.webflow.definition.registry.FlowDefinitionRegistryImpl.getFlowDefinition(FlowDefinitionRegistryImpl.java:60)
at org.springframework.webflow.executor.FlowExecutorImpl.launchExecution(FlowExecutorImpl.java:138)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:263)
at org.springframework.faces.webflow.JsfFlowHandlerAdapter.handle(JsfFlowHandlerAdapter.java:57)
FlowModelFlowBuilder calls getLocalContext().getApplicationContext().getClassLoader() to get the class loader. It return instance of ParallelWebappClassLoader.
I am looking for a way to let FlowModelFlowBuilder to specify custom class loader. Is it possible to customize FlowModelFlowBuilder?
Found another way. Instead of trying to find way to customize the Flow specifics, used ContextRefreshedEvent Listener and changed the class loader. As the beans are loaded after the context refreshed, following approach worked
public class WebflowApplicationContextListener implements ApplicationListener<ContextRefreshedEvent> {
#Override
public void onApplicationEvent( final ContextRefreshedEvent p_event ) {
ApplicationContext l_appContext = p_event.getApplicationContext();
if ( l_appContext instanceof GenericWebApplicationContext ) {
( (GenericWebApplicationContext) l_appContext ).setClassLoader( getSpecificContextClassLoader() );
}
}
}

Log4Net appender filter for specific exception type?

I'm trying to filter my appender based on the type of exception being logged. Is this possible in log4net?
log4net does not support this directly. You can however quite easily implement your own filter by deriving either from the IFilter interface or the FilterSkeleton class (both in log4net.Filter namespace).
Something like this should do the trick:
public class ExceptionTypeFilter : FilterSkeleton
{
override public FilterDecision Decide(LoggingEvent loggingEvent)
{
var ex = loggingEvent.ExceptionObject as YourExceptionType;
return (ex != null) ? FilterDecision.Accept : FilterDecision.Deny;
}
}
This filter you can then use like a regular filter. For further reference you may look at the source code of the standard log4net filters.

How to add multiple outlets for generated XText DSL

By default the generated XText artifacts generate code from my DSL to the default outlet (which defaults to src-gen folder). I know that you can explicitly pass the outlet configuration name in fsa.generateFile("myfile.txt", "MY_OUTLET_NAME", "Some file content").
I it because I want to generate code with my XText DSL and want to use the generation gap pattern and generate code in a folder called "src-once".
I'am using XText 2.2.1.
My questions:
1) Where and how do I define my outlets like "MY_OUTLET_NAME"?
2) Is there a way to prevent overwriting existing files in a specific outlet?
The hint form Christian Dietrich pointed me in the right direction. Below is the code that I ended up with.
I have created a new class MyOutputConfigurationProvider that implements IOutputConfigurationProvider. The getOutputConfigurations method returns two output configurations, the default src-gen and a custom src-gen-once with the correct settings for generating sources only once.
package com.my.dsl;
import static com.google.common.collect.Sets.newHashSet;
import java.util.Set;
import org.eclipse.xtext.generator.IFileSystemAccess;
import org.eclipse.xtext.generator.IOutputConfigurationProvider;
import org.eclipse.xtext.generator.OutputConfiguration;
public class MyOutputConfigurationProvider implements
IOutputConfigurationProvider {
public final static String DEFAULT_OUTPUT_ONCE = "DEFAULT_OUTPUT_ONCE";
/**
* #return a set of {#link OutputConfiguration} available for the generator
*/
public Set<OutputConfiguration> getOutputConfigurations() {
OutputConfiguration defaultOutput = new OutputConfiguration(IFileSystemAccess.DEFAULT_OUTPUT);
defaultOutput.setDescription("Output Folder");
defaultOutput.setOutputDirectory("./src-gen");
defaultOutput.setOverrideExistingResources(true);
defaultOutput.setCreateOutputDirectory(true);
defaultOutput.setCleanUpDerivedResources(true);
defaultOutput.setSetDerivedProperty(true);
OutputConfiguration onceOutput = new OutputConfiguration(DEFAULT_OUTPUT_ONCE);
onceOutput.setDescription("Output Folder (once)");
onceOutput.setOutputDirectory("./src-gen-once");
onceOutput.setOverrideExistingResources(false);
onceOutput.setCreateOutputDirectory(true);
onceOutput.setCleanUpDerivedResources(false);
onceOutput.setSetDerivedProperty(true);
return newHashSet(defaultOutput, onceOutput);
}
}
To use the MyOutputConfigurationProvider implementation add a configure method to your module class:
/**
* Use this class to register components to be used within the IDE.
*/
public class MyDslUiModule extends com.my.dsl.ui.AbstractMyDslUiModule {
public MyDslUiModule(AbstractUIPlugin plugin) {
super(plugin);
}
#Override
public void configure(Binder binder) {
super.configure(binder);
binder.bind(IOutputConfigurationProvider.class).to(MyOutputConfigurationProvider.class).in(Singleton.class);
}
}
implement a custom IOutputConfigurationProvider should do the trick

How to initialize slf4j (using log4j) logger properly in abstract classes / for inheritance

In my project I've got a top-level abstract class FrameProducer. I added a slf4j logger at this level, so that every inheriting class already has it. Here the code:
public abstract class FrameProducer extends Observable {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
protected BufferedImage frame;
public BufferedImage getFrame() {
return frame;
}
public void fireEvent() {
logger.debug("Firing event. Implementing class: {}", this.getClass());
setChanged();
notifyObservers();
}
}
There are also two inheriting classes: CameraFrameGrabber and GrayscaleFilter. Yet, when the method fireEvent() is being called from CameraFrameGrabber or GrayscaleFilter the message is being logged at FrameProducer level. Here the log, for clarity:
FrameProducer.fireEvent - Firing event. Implementing class: class com.ofj.frameaccess.CameraFrameGrabber
FrameProducer.fireEvent - Firing event. Implementing class: class com.ofj.frameaccess.GrayscaleFilter
Is it possible to initialize the logger in FrameProducer in a way that everything gets logged at the most-specialized level in my class hierarchy?
Thanks for any help.
Edit: My log4j.properties looks like this:
log4j.rootCategory=TRACE, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%C{1}.%M - %m%n
Logging in abstract classes is considered an anti-pattern by some because it introduces a potentially unexpected dependency. However if you are sure that all the stuff you are dealing with is your own that that's no problem I guess.
If you want to get the log message to show the concrete implementation rather than the abstract class name (which makes sense) then change your logging initialization statement in the abstract class to:
private final Logger logger = LoggerFactory.getLogger(getClass());
instead of something like:
private static final Logger logger = LoggerFactory.getLogger(MyAbstractClass.class);
i.e.
no static because it could be cast to something else.
getClass() instead of the specific class
Thanks for pointing out the right direction to look for possible corrections skaffman. I eventually changed my log4j.properties to (as one of the examples in the PatternLayout documentation says):
log4j.rootCategory=TRACE, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%-6r [%15.15t] %-5p %30.30c %x - %m%n
...and everything gets logged right.

Log4j: How filter out messages from a specific class?

I want to configure my log4j logging to not log messages that are 1) coming from a specific class and 2) of a specific severity i.e. WARN.
Can someone provide sample configuration/code on how to do this?
The information below solves the problem for standart java.util.logging package:
For filtering classes you should implement Filter inteface and use it by calling setFilter method of Logger class:
public class ClassFilter implements Filter {
public boolean isLoggable(LogRecord lr) {
return (lr.getSourceClassName() == "SpecificClassName");
}
}
...
Logger l = Logger.getLogger("mypackage.log");
l.setFilter(new ClassFilter());
For filtering severity use setLevel() method of Logger class.

Resources