log4j hierarchy between different packages - java

I am new in log4j. As I read on internet, child logger inherit parent logger settings. Usually examples are given are for two classes in same package. But what if the classes will be in different packages? For example
import com.foo.Bar;
public class MyApp{
static Logger logger = Logger.getLogger(MyApp.class);
public static void main(String[] args) {
BasicConfigurator.configure(); // default logging level is debug
Bar bar = new Bar();
bar.doIt();
}
}
and the second class in different package
package mypackage;
import org.apache.log4j.Logger;
public class Bar {
static Logger logger = Logger.getLogger(Bar.class);
public void doIt() {
logger.debug("Did it again!");
}
}
So what will be the level of logger in class Bar?

MyApp is in default package. Note that it is not recommended to use default package as has been answered in this question.
I think it is impossible to define a custom <logger> for the default package, so it must be <root> applied.
Unless you define a custom <logger> for mypackage.Bar, <root>also applies for that class.
Apart from the fact that they both may be ruled by <root>, MyApp and Bar are unrelated when it comes to log configuration.

Related

How to automatically add code to every class I create

In Eclipse (Java), how do I automatically add code to every class I create. Suppose I create a class called Foo, I want this code to automatically go in the preamble/state:
private final Logger log = LoggerFactory.getLogger(this.getClass());
and the appropriate slf4j import to be automatically imported. Similarly, I would like the constructor to automatically show up. Full example of what I would like to see after I click the create button:
package test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Foo {
private final Logger log = LoggerFactory.getLogger(this.getClass());
public Foo() {
}
}
This should help. You can modify whichever template suits your purpose.
You could change the New Java Files and Class body templates to get what you want.
In the Preferences, under Java-> Code Style -> Code Templates, there is New Java Files where you would add the imports, at the appropriate place.
Change the Class body template like this
private final Logger log = LoggerFactory.getLogger(this.getClass());
public void ${type_name}() {
}
to add the logger and a default, public constructor.
Making those 2 changes will automatically add what you want when you create a new Java class file with Eclipse.

How to remove log calls in J2SE/J2EE application (not Android)

I know that removing logger calls with Proguard works for Android applications.
How can one accomplish this in standard Java application?
import java.util.logging.Logger;
public class Clazz {
private static final Logger LOGGER = Logger.getLogger(Clazz.class.getName());
public void foo() {
LOGGER.info("bar");
}
}
in my Proguard configuration I have the following:
-assumenosideeffects class java.util.logging.Logger { *; }
-whyareyoukeeping class java.util.logging.Logger
which gives the following output when running:
[proguard] java.util.logging.Logger
[proguard] is a library class.
I understand that it's a library but I want to strip all calls to it anyway. Is this possible with Proguard? If not, why? How come this works so conveniently for Android, does the logger field or lack of it have something to do with this?
You should be able to remove logging calls like this, assuming you haven't disabled optimization -- it's the optimization step that removes unnecessary and unwanted calls. ProGuard can't remove the Logger class itself, since it is a run-time library class, as you've seen.
You mustn't use a wildcard for matching the methods though, since this includes essential methods like wait() and finalize() (affecting all classes). You'll have to enumerate the methods that you want to remove. For instance:
-assumenosideeffects class java.util.logging.Logger {
void info(java.lang.String);
}

Spring AOP - why do i need aspectjweaver?

i wrote a very simple Aspect with Spring AOP. It works, but i have some problems understanding what is really going on. I don't understand why i have to add the aspectjweaver.jar? The Spring-AOP documentation clearly states that i don't need aspectj compiler or weaver as long as i just use Spring-AOP:
The AOP runtime is still pure Spring AOP though, and there is no dependency on the AspectJ compiler or weaver.
My configuration looks like this:
<aop:aspectj-autoproxy />
#Aspect
#Service
public class RemoteInvocationAspect {
#Before("execution(* at.test.mypackage.*.*(..))")
public void test() {
System.out.println("test");
}
...
I also tried XML configuration, didn't change anything though. Maybe i could just let it go, but i really would like to understand why aspectj-weaver is used? If i don't add the dependency in maven i get java.lang.ClassNotFoundException: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException
Spring AOP implementation I think is reusing some classes from the aspectj-weaver. It still uses dynamic proxies - doesn't do byte code modification.
The following comment from the spring forum might clarify.
Spring isn't using the AspectJ weaver in this case. It is simply
reusing some of the classes from aspectjweaver.jar.
-Ramnivas
You are using AspectJ style pointcut-expression #Aspect and #Before are part of AspectJ. Check this link.
Regarding the AspectJ-weaver, its actually a bytecode weaver which weaves aspects into classes at load time.
I recently had a similar question Why does spring throw an aspectj error if it does not depend on aspectj?
To use Spring AoP without an AspectJ dependency it must be done in xml. The annotations are a part of AspectJ.
Also, the really cool expression language is only supported by AspectJ. So you have to define explicit point-cuts. See Section 6.3.2. Declaring a pointcut:
http://static.springsource.org/spring/docs/2.0.x/reference/aop.html section
I'm still having trouble finding any elaborate documentation on this technique.
You need the aspectjtools or the aspectjweaver dependencies when you use the AspectJ pointcut expression language.
Please see the following classes:
Foo.java
public interface Foo {
void foo();
void baz();
}
FooImpl.java
public class FooImpl implements Foo {
#Override
public void foo() {
System.out.println("Foo!");
}
#Override
public void baz() {
System.out.println("Baz!");
}
}
MethodBeforeAdviceBarImpl.java
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class MethodBeforeAdviceBarImpl implements MethodBeforeAdvice {
#Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("Bar!");
}
}
And please see App.java version - 1
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.NameMatchMethodPointcutAdvisor;
public class App {
public static void main(String[] args) {
final MethodBeforeAdvice advice = new MethodBeforeAdviceBarImpl();
final NameMatchMethodPointcutAdvisor nameMatchMethodPointcutAdvisor = new NameMatchMethodPointcutAdvisor();
nameMatchMethodPointcutAdvisor.setMappedName("foo");
nameMatchMethodPointcutAdvisor.setAdvice(advice);
final ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addAdvisor(nameMatchMethodPointcutAdvisor);
final Foo foo = new FooImpl();
proxyFactory.setTarget(foo);
final Foo fooProxy = (Foo) proxyFactory.getProxy();
fooProxy.foo();
fooProxy.baz();
}
}
The output of running this example will be:
Bar!
Foo!
Baz!
I only need the org.springframework:spring-context.jar in my classpath. Now instead of a NameMatchMethodPointcutAdvisor, lets use AspectJExpressionPointcutAdvisor:
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.aop.framework.ProxyFactory;
public class App {
public static void main(String[] args) {
final MethodBeforeAdvice advice = new MethodBeforeAdviceBarImpl();
final AspectJExpressionPointcutAdvisor aspectJExpressionPointcutAdvisor = new AspectJExpressionPointcutAdvisor();
aspectJExpressionPointcutAdvisor.setAdvice(advice);
aspectJExpressionPointcutAdvisor.setExpression("execution(void biz.tugay.spashe.Foo.foo())");
final ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addAdvisor(aspectJExpressionPointcutAdvisor);
final Foo foo = new FooImpl();
proxyFactory.setTarget(foo);
final Foo fooProxy = (Foo) proxyFactory.getProxy();
fooProxy.foo();
fooProxy.baz();
}
}
Again, if I only have the spring-context.jar in my classpath, I will get:
An exception occured while executing the Java class. null: InvocationTargetException: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException
When you investigate the AspectJExpressionPointcutAdvisor class, you will see that it extends AbstractGenericPointcutAdvisor and which delegates the work to an instance of AspectJExpressionPointcut. And you can see that AspectJExpressionPointcut has the following import statements:
import org.aspectj.weaver.patterns.NamePattern;
import org.aspectj.weaver.reflect.ReflectionWorld.ReflectionWorldException;
import org.aspectj.weaver.reflect.ShadowMatchImpl;
import org.aspectj.weaver.tools.ContextBasedMatcher;
import org.aspectj.weaver.tools.FuzzyBoolean;
import org.aspectj.weaver.tools.JoinPointMatch;
import org.aspectj.weaver.tools.MatchingContext;
import org.aspectj.weaver.tools.PointcutDesignatorHandler;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParameter;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;
import org.aspectj.weaver.tools.ShadowMatch;
You will need the aspectjtools dependency in your classpath in runtime so AspectJExpressionPointcut can load the classes it needs.
You can browse spring website and find the answer on page of docs.spring.io
The #AspectJ support can be enabled with XML or Java style configuration. In either case you will also need to ensure that AspectJ’s aspectjweaver.jar library is on the classpath of your application (version 1.6.8 or later). This library is available in the 'lib' directory of an AspectJ distribution or via the Maven Central repository.

how to generate the instance for logger?

Here is my code
package com.my;
import org.apache.log4j.spi.LoggerFactory;
import java.io.*;
import java.util.logging.*;
public class Log {
public static void main(String[] args) {
try{
FileHandler hand = new FileHandler("vk.log");
Logger log = Logger.getLogger("log_file");
log.addHandler(hand);
log.warning("Doing carefully!");
log.info("Doing something ...");
log.severe("Doing strictily ");
System.out.println(log.getName());
}
catch(IOException e){
System.out.println(e)
}
}
}
Your code should work if you delete the superfluous log.getLogger(""); statement and fix the imports.
A couple of comments:
If you have multiple loggers you can selectively turn them on and off. It is conventional to create multiple loggers based on class or package names; e.g.
Logger log = Logger.getLogger(this.getClass());
or
Logger log = Logger.getLogger(SomeClass.class);
You are instantiating and associating the handler programmatically. It is a better idea to put the logging configurations into an XML or properties file, and use one of the configurers to load it and wire up the logging handlers. This allows you ... or the user ... to adjust the logging without modifying your code.
You should probably READ the log4j introduction document that explains the above and other things about using log4j.
The above assumes that you were trying to use log4j. Is you are really trying to use java.util.logging, some details are not exactly right. (And, IMO, you would be better off with using log4j or one of its offspring.)
Your code is more or less fine (check the imports) and should work correctly if you remove the line:
log.getLogger("");
A working implementation of your class would then be:
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
public class test {
public static void main(String[] args) {
try {
FileHandler hand = new FileHandler("vk.log");
Logger log = Logger.getLogger("log_file");
log.addHandler(hand);
log.warning("Doing carefully!");
log.info("Doing something ...");
log.severe("Doing strictily ");
System.out.println(log.getName());
} catch (IOException e) {
// Handle error.
}
}
}
Can you explain further your problem?
Here are a couple suggestions.
Watch your imports, you are mixing
Log4j or java.util.logging imports
no need to call getLogger() twice
Do something with your exceptions,
even if that means using a
System.out.println() e.printStackTrace() in this test
case. If there were problems thrown,
you were hiding them.

Is it possible to change the log4j level in my packages but not change the levels in api's im using e.g spring

So I have this code:
public class LoggingManager {
Logger root = Logger.getRootLogger();
public void setLogger(String fullClassName, String level) {
LogManager.getLogger(fullClassName).setLevel(Level.toLevel(level));
}
public void logLevelAll(String level) {
root.setLevel(Level.toLevel(level));
}
}
My problem is this. The first method takes in values: p1: com.domain.data.Object and p2: DEBUG and will change that classes log level to debug. The second class will change every logger in the project including libraries referenced like spring.
I want to create a method that only changes the logging level of my packages. So changes com.domain.* if you like.
Can this be done?
Simply set the log level for com.domain. By default each logger will inherit the log level from its parent logger.
Just realised that. Here is the full answer I got for others:
Log4j provides a default root logger that all user-defined loggers inherit from. Root logger is at the top of the logger hierarchy; in other words, root logger is either parent or ancestor of all logger objects created.
For example: A class 'MyClass' in com.domain.sampleapp application package can have a logger named com.domain.sampleapp.MyClass you can use my method above to set the class:
LogManager.getLogger("com.domain.sampleapp.MyClass").setLevel(Level.toLevel("DEBUG"));
But you can also set the package log level like so:
LogManager.getLogger("com.domain.sampleapp").setLevel(Level.toLevel("DEBUG"));
And finally you could set a whole group of packages (i.e ur whole project) by using:
LogManager.getLogger("com.domain").setLevel(Level.toLevel("DEBUG"));

Categories

Resources