I am using general java.util.logging.Logger with the following initialization line:
private static final Logger _log = Logger.getLogger(Login.class.getName());
Then I use it like this (just an example):
_log.log(Level.FINE, "Session id: {0}.", session.getId());
In the log sometimes I can see the following:
24-Nov-2014 17:26:13.692 FINE [http-nio-80-exec-1] null.null Session id: 18BD6989930169F77565EA2D001A5759.
Most of the times times however it shows me the calling class and function correctly. That happens in other classes and members too. I cannot figure out why does this happen? Is it a bug in the Loggger?
The output looks like it is from the 'org.apache.juli.OneLineFormatter' and the 'null.null' is the source class and source method names. From the LogRecord.getSourceMethodName documentation:
May be null if no information could be obtained.
It is possible it can't be determined or has been forced to null.
Looking at the source code for 'org.apache.juli.AsyncFileHandler' there is a bug where that code is not capturing the original callsite.
You can create and install a filter on the AsynchFileHandler to force compute the method and class names before a the thread hand off. Here is an example of such a filter:
public class InferCallerFilter implements Filter {
public boolean isLoggable(LogRecord record) {
record.getSourceMethodName(); //Infer caller.
return true;
}
}
Even the MemoryHandler included with the JDK gets this wrong. Per the LogRecord documentation:
Therefore, if a logging Handler wants to pass off a LogRecord to another thread, or to transmit it over RMI, and if it wishes to subsequently obtain method name or class name information it should call one of getSourceClassName or getSourceMethodName to force the values to be filled in.
I "solved" this by changing my custom LogFormatter to get the source class name and source method name at the very beginning of the format method.
The return values of these methods seem to have an "expiration date"...
#Override
public String format(LogRecord record)
{
String sourceClassName = record.getSourceClassName();
String sourceMethodName = record.getSourceMethodName();
...
}
So far, after that change I have not observed any null.null entries anymore, when before I had lots of them.
Related
Hi folksSuppose I have a hypothetical class that has nothing to do with neither a database nor a message queue. Is there any way to make the methods of this class transaction aware? To explain my point, suppose I have a class that can be used to write given info on a file. For example something like below
public class WriterToFileSystem
{
private fileName="current_file_name";
public void addToFile(String textToAppendToFile)
{
//---add $textToAppendToFile to already opened file byte by byte
}
}
and there is another class that uses objects of this class like so:
public class Appender
{
private WriterToFileSystem writer;
#Transactionl // making it transactional so that when exception happens all changes get discarded
public void append(String someLongText)
{
writer.addToFile()
}
}
Suppose that file system has file size limit 200 Bytes and currently we have written 100 Bytes to it. calling addToFile method will be causeing an exception to be raised for the last byte of given string with size of 101 bytes. Is there any way to make first class transaction aware (perhaps by implementing a certain interface) so that by decorating second class's method with #Transactional annotation ,transaction manager can role back all the data that has been added to the file after last call.
Please keep in mind that this is a hypothetical scenario, I'm aware that there are some tools that can provide similar functionalities for files. Its a general question.
Thanks in advance.
Is there a way to detect usages of java method reference (double colon) operator inside the code?
I need to discover all instance/static method references used in a given class in order to be able to detect some errors (must verify that the target method has a particular annotation - #Good in the below example) during build time. As by convention a method reference should be used only to some of the methods when it is passed to a constructor of some helper class (Info in the below example).
class X {
Info init() {
return new Info(X::beta); // good code: target method has #Good annotation
return new Info(X::alpha); // bad code: target method has no #Good annotation
}
void alpha() {
}
#Good
void beta() {
}
}
The intention is to be able to click on the method reference as this makes it easy to follow as otherwise if just passing Method instance or just method name it would lack this ability.
(The example is not very good but I'm now allowed to share more details, sorry about that!)
I can see IntelliJ IDEA "knows" about them - when you ctrl+click on them it navigates to the target method so there should be some form of a static analysis used there.
I'm already using ObjectWeb ASM to detect invocations to certain methods but it seems it lacks the ability to detect method references (::)
EDIT:
Just a note that you can also pass new Info(x -> x.alpha()) as #Thomas below mentioned in the comments but this would not pass our review process but I guess the additional ability to detect it would not hurt.
EDIT2: What exactly are you trying to achieve with these checks? What makes beta worthy of receiving the annotation?
Answer:
When the init() method is called we obtain the Info instance and from it obtain the lambda which must be a method reference. Then we use javassist ProxyFactory and create a sub-class of class X then instantiate it and intercept all its methods via setting a method handler. So now it is safe to execute the lambda without allowing it to make any side effects - the method body is skipped and the only thing we do is to capture which is the X method that the lambda actually is calling - in the example this will lead to a java.lang.Method instance pointing to X.beta or X.alpha method. Then we can check if it has the #Good annotation and proceed accordingly - which is to call the lambda without any proxying, but that call might happen later, like a millisecond later or an hour later. If there is no #Good annotation we cannot proceed - it is a bug.
So the problem is that this will happen at runtime later and there might be a bug not caught early enough and that is the reason I would like to inspect the X class at build time and catch all the bugs :)
This is a bit of a shot in the dark, as I'm neither very proficient with ASM nor sure if this approach addresses your problem. Having said that, I found that, in a similar setting, asm.MethodVisitor calls MethodVisitor.visitInvokeDynamicInsn(...) for (some? all?) method references.
E.g., if I compile this variant of your class X along with an Info:
class Info {
public Info(Runnable alpha) {}
}
class X {
Info init() { return new Info(this::alpha); }
void alpha() {}
}
... and I then feed the resulting X.class into a mini ClassVisitor + printing MethodVisitor (Groovy for brevity):
class MyMethodVisitor extends MethodVisitor {
MyMethodVisitor(MethodVisitor parent) { super(Opcodes.ASM8, parent) }
#Override
void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
println "visitInvokeDynamicInsn($name, $descriptor, $bootstrapMethodHandle, $bootstrapMethodArguments)"
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments)
}
}
class MyClassVisitor extends ClassVisitor {
MyClassVisitor() { super(Opcodes.ASM8) }
#Override
MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
println "Starting method '$name'"
new MyMethodVisitor(super.visitMethod(access, name, descriptor, signature, exceptions))
}
}
def clr = new ClassReader(new File("./X.class").bytes)
clr.accept(new MyClassVisitor(), ClassReader.SKIP_FRAMES)
Then the method visitor prints, amongst other details, a call to visitInvokeDynamicInsn from within the method visitation of X::init with the desired X::alpha among the arguments (the xyz being my local package):
Visiting method '<init>'
Visiting method 'init'
visitInvokeDynamicInsn(run, (xyz/X;)Ljava/lang/Runnable;,
java/lang/invoke/LambdaMetafactory.metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; (6),
[()V, xyz/X.alpha()V (5), ()V])
Visiting method 'alpha'
So it would seem possible to peel the method out of those arguments. I am not sure if this reliable (e.g., whether this bytecode is guaranteed by specification, or whether it can depend on compilation/optimization details).
Is there a specific way to accomplish this? I tried to find a solution on here but couldn't find what I need. I have a Spring Boot application that will be accepting multiple arguments from the command line. The argument in question is the queue name (i.e. the destination). It can be one of several of our many queues. The JmsListener is in the form
#JmsListener(destination="dest_goes_here")
public void processOrder(Message message){. . .}
I have a class that basically looks like this
public class Arguments {
private static queue
private static antoherArg
:
:
getters and setters
}
And what I would like to say is destination = Arguments.getQueue(), but it seems destination can only be a static final variable? I assume this because the error presents a little tooltip that alludes to that.
I also tested it, as I have yet another class called Constants, that obvioulsy contains constants, and if I hard code the queue name as public static final String QUEUE = "MyQ"; then say destination = Constants.QUEUE it is ok with that.
So then I assumed I could do something like this in my listener class private static final String QUEUE = Arguments.getQueue(); But it doesn't like that either. Alas, I am stumped.
So really two questions here if anyone is willing to knowledge share. Why is the #JmsListener ok with having destination set to my second solution, but not the first and the last?
And then the main question (that I'd prefer you answer over the first) is, what strategies can I make use of to set destination to a variable that originates from the command line (i.e. be dynamic)?
Edit: To clarify, I cannot keep the value in my Constants class, as the value will be coming from the command line and needs to be passed to the JmsListener class to be used as the destination.
That's how Java works, destination must be a compile-time constant expression and a function invocation isn't considered one. Take a look at the official language specification for more details. EDIT: you can also look at this answer.
As far as your second (and more important) question goes, I have several suggestions for you.
First, you can read the queue name from a configuration property, like so: destination="${jms.queue.name1}" where jms.queue.name1 is your configuration property. Then, since you are using Spring Boot, you can use command-line arguments to override your configuration properties (see externalized configuration documentation for more details). That way, you'll be able to specify the queue name at runtime by passing it as a command-line argument like so --jms.queue.name1=foo.
Second, you can use programmatic listener registration, like so:
#Configuration
#EnableJms
public class AppConfig implements JmsListenerConfigurer {
#Override
public void configureJmsListeners(JmsListenerEndpointRegistrar registrar) {
SimpleJmsListenerEndpoint endpoint = new SimpleJmsListenerEndpoint();
endpoint.setId("myJmsEndpoint");
endpoint.setDestination(Arguments.getQueue());
endpoint.setMessageListener(message -> {
// processing
});
registrar.registerEndpoint(endpoint);
}
}
I just started to use Java Logger. I tried to use its entering() and exiting() methods with hard coded string for class name and method. They both didn't work for me. Just no log entry for them. But other log statements within that methods were logged properly. My logger level is set to CONFIG. I have tried to set to ALL but still cannot see log entry from them.
I found for each entry, there already has a line with class name and method being logged. It seems these two methods are not necessary. But I am still want to know how to make them work for me.
EDIT:
My code followed: these entering() and exiting() are not create an entry in the log file
//class variables
private final static Logger logger = Logger.getLogger(MyClass.class.getName());
private static FileHandler logFileHandler = null;
//within the main() method
Logger thisLogger = Logger.getLogger("");
logFileHandler = new FileHandler(logFileNameStr, false);
logFileHandler.setFormatter(new SimpleFormatter());
thisLogger.addHandler(logFileHandler);
thisLogger.setLevel(Level.CONFIG);
logger.log(Level.INFO, "Logfile Directory = " + logFileNameStr);
//within a constructor of MyClass
logger.entering("MyClass", "MyClass()");
....
logger.info(initMsg);
....
logger.exiting(this.getClass().getSimpleName(), "MyClass()");
Entering, exiting, and throwing are logged at level FINER. You'll have to set your logger to FINER or lower and set your FileHandler to FINER or lower.
thisLogger.addHandler(logFileHandler);
thisLogger.setLevel(Level.FINER);
logFileHandler.setLevel(Level.ALL);
As far as style goes, you should try creating a static final for class name because you'll use it as the name of the logger and reference it for entering, exiting, throwing, and log precise tracing:
private static final String CLASS_NAME = MyClass.class.getName();
You always want to use a class literal to fetch the name (as above) because getClass().getName() can return a subclass name which can falsify your tracing.
For method names don't include () in the name, just use the entering/exiting method that matches the number of arguments.
For constructor method names use "<init>" and for static init blocks use "<clinit>" as the method name since that is what would show up in a stacktrace.
As #jmehrens said, these "convenience" methods are logged at finer and your Logger and Handler objects are likely configured at a much higher level by default.
Here are more convenient entering and exiting replacements for use within the logged method and which you can simply change the level on:
logger.finer("ENTRY"); // compare to .entering(MyClass.class.getName(),"MyMethodName")
...
logger.finer("RETURN"); // less typing than .exiting(CLASS_NAME,"MyMethodName")
Same output as entering and exiting as long as you're providing the real class and method name. Simple enough to change .finer to .info.
To handle the parameterized versions use .log:
logger.log(Level.FINER,"ENTRY {0}", param1);
...
logger.log(Level.FINER,"RETURN {0}", result);
I think the only place entering/exiting makes sense is when you're logging from the caller's side:
logger.entering(thing.getClass().getName(),"DoStuff");
thing.DoStuff();
logger.exiting(thing.getClass().getName(),"DoStuff");
You could do the same with logp have control over what level it logs at, but it is more verbose:
logger.logp(Level.FINER,thing.getClass().getName(),"DoStuff","ENTRY");
thing.DoStuff();
logger.logp(Level.FINER,thing.getClass().getName(),"DoStuff","RETURN");
In Java, it is possible to get the class and method that called the current method (the method in which you get the StackTrace).
Can I get the arguments that were passed to the method that called this method?
I need this for debugging purposes.
Eg:
baseClass {
initialFunc(input) {
var modifiedInput = input + " I modified you";
otherClass.doSomething(modifiedInput);
}
}
otherClass {
doSomething(input) {
//GET THE ARGUMENTS PASSED TO THE METHOD OF THE CLASS THAT CALLED THIS METHOD
}
}
Can one get this information from the stacktrace, or are there other means?
(Note that I need to be able to do this in runtime and cannot actually change the source of baseClass, this is going to be a feature of my debugging class that does not know the source beforehand)
I don't believe this is possible using the standard Java API.
What you could do is to use AspectJ, place a point-cut at the calling method, save the arguments, place a point-cut at the called method and pass on the arguments.
Another option (slightly more advanced) is to use a custom, bytecode-rewriting, class loader that saves the original arguments, and passes them on as extra arguments to the next method. This would probably take a day or two to implement. Suitable frameworks are BCEL or ASM.
I think this could be possible, because input is out of scope but isn't yet accessible for garbage collection, so the value still exists, but unfortunately I don't believe there is an default API way to access it. This could be maybe possible with a custom implemented NDC (nested diagnostic context) for the logging approach.
I'm not sure why you'd ever want to do this in Java?
The only way I can think of is to create a custom wrapper object for the passed string, thus sending the reference to the wrapper instead of a new string each time.
I'd advice against it, though, since it clutters your original code, and makes it even more error prone.
Might this problem not be solved using a debugger, like the one built into eclipse, to inspect your state?
In my case, I needed to get a parameter value has been passed to a method in a certain stack frame to be used later within the execution flow
I used ThreadLocal to store it and when I needed it I was able to retrieve it at any point in code as I declared it as public static
here is a skeleton example
public static final ThreadLocal<SomeType> IMPORTANT_THREAD_LOCAL_FOR_BLA = ThreadLocal.withInitial(whatever);
methodWithImportantParam(SomeType importantValue){
// save it in the static threadLocal Field
this.IMPORTANT_THREAD_LOCAL_FOR_BLA.get()=importantValue;// code to set the value
// continue method logic
}
and somewhere in code where you need that value
YourClass.IMPORTANT_THREAD_LOCAL_FOR_BLA.get()
but make sure the execution flow that you set the value then you retrieve it
hope my answer add something valuable to this question
You can get name of caller method and its class, but you have to add some code in current method:
public static void main(String[] args) throws Exception {
call();
}
private static void call() {
Exception exception = new Exception();
for(StackTraceElement trace : exception.getStackTrace()){
System.out.println(trace.getMethodName());
}
}
This will print "call" and "main", methods name in called order (reverse).
This is possible using Reflection API !
public class StackTrace {
public static void main(String args[]) {
StackTrace st = new StackTrace();
st.func();
}
public void func() {
OtherClass os =new OtherClass();
os.getStackTrace(this);
}
}
class OtherClass {
void getStackTrace(Object obj) {
System.out.println(obj.getClass());
}
}