Home arrow static arrow Java Programming [Archive] - Enabling method parameters logging in Java logging
Warning: Creating default object from empty value in /www/htdocs/w008deb8/wiki/components/com_staticxt/staticxt.php on line 51
Java Programming [Archive] - Enabling method parameters logging in Java logging
This topic has 11 replies on 1 page.

Posts:13
Registered: 8/8/04
Enabling method parameters logging in Java logging  
Aug 10, 2004 12:39 AM



 
I know that it is possible to log some information without access to the source code of the classes just by running java with

java -Djava.util.logging.config.file=myLoggingConfigFilePath

However, I can't configure that config file to log the entry parameters and/or return values. If I hard code in the method like below:

public int dodaj(float p1, float p2){
// Log entry
Logger logger = Logger.getLogger("sorter");
if (logger.isLoggable(Level.FINER)) {
logger.entering(this.getClass().getName(), "dodaj",
new Object[]{new Float(p1), new Float(p2)});
}

if (logger.isLoggable(Level.FINER)) {
logger.exiting(this.getClass().getName(), "dodaj",
new Integer( (int) (p1+ p2)));
}
return (int)(p1 + p2);
}

this works. However, I would like not to put lines:

if (logger.isLoggable(Level.FINER)) {
logger.entering(this.getClass().getName(), "dodaj",
new Object[]{new Float(p1), new Float(p2)});
}

if (logger.isLoggable(Level.FINER)) {
logger.exiting(this.getClass().getName(), "dodaj",
new Integer( (int) (p1+ p2)));
}

into the source code of method 'dodaj'. I would like to have the source of my method 'dodaj' like that:

public int dodaj(float p1, float p2){
return (int)(p1 + p2);
}

And I would like to write in my 'myLoggingConfigFilePath' write something:

.level=ALL

or .level=ENTRY
or .level=RETURN

But I don't know what should I put in my config file exactly and where. I can't deduce from the documentation if it possible to enable logging method and parameters method and returned results by the config file (properties).

Thank you for any help...
 

Posts:18,384
Registered: 21.03.00
Re: Enabling method parameters logging in Java logging  
Aug 10, 2004 12:49 AM (reply 1 of 11)



 
Eh, what?

You can't enable logging on a class/method that doesn't use logging. So you have to sprinkle your code with logging statements, or you could look into aspect programming.

/Kaj
 

Posts:18,384
Registered: 21.03.00
Re: Enabling method parameters logging in Java logging  
Aug 10, 2004 12:50 AM (reply 2 of 11)



 
And here is a link that shows how to use aspects for logging:
http://www-106.ibm.com/developerworks/java/library/j-aspectj/?loc=j

/Kaj
 

Posts:13
Registered: 8/8/04
Re: Enabling method parameters logging in Java logging  
Aug 10, 2004 2:55 AM (reply 3 of 11)



 
Yes, I can log some information at

//------------ Generator.java
package sorter;

import java.util.Vector;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Generator extends Remote{
public Vector generate(int num) throws RemoteException;
}
//


end Generator.java

//
start GeneratorImpl.java
package sorter;

import java.rmi.*;
import java.util.Vector;
import java.util.Random;
import java.rmi.server.UnicastRemoteObject;

public class GeneratorImpl
extends UnicastRemoteObject implements Generator{

public GeneratorImpl() throws RemoteException{
}

public Vector generate(int num)
throws RemoteException{

Random r = new Random(
java.util.Calendar.getInstance().getTime().getTime());

Vector vec = new Vector();

for(int i = 0; i < num; i ++){
vec.add(i, new Integer(r.nextInt() % 100) );
}

return vec;
}
}
//
end GeneratorImpl.java

//
start Servers.java
package sorter;

import java.rmi.RMISecurityManager;
import java.rmi.Naming;

import java.util.logging.*;

public class Servers {

public static void main(String args[]) {

// Create and install a security manager
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
try {
// run generator
GeneratorImpl gen = new GeneratorImpl();

// Bind this object instance to the name "HelloServer"
Naming.rebind("//localhost/GeneratorServer", gen);

} catch (Exception e) {
System.out.println("Servers err: " + e.getMessage());
e.printStackTrace();
}
}
}

//
Client.java
package sorter;

import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
import java.util.Date;
import java.util.Vector;

import java.util.logging.*;

public class Client{

public static void main(String[] argv) {
String serverName = "";
Generator gen = null;
Vector vec = null;

System.setSecurityManager(new RMISecurityManager());
if (argv.length != 1) {
try {
serverName = java.net.InetAddress.getLocalHost().getHostName();
}
catch(Exception e) {
e.printStackTrace();
}
}

try {
//bind server object to object in client
gen = (Generator) Naming.lookup("//" + serverName + "/GeneratorServer");
//Print success message
System.out.println("RMI connection to GeneratorServer successful...");

//Call method on server and put result into String message
vec = gen.generate(11);

//Print message on server
System.out.println("Value " + vec);
}
catch(Exception e) {
System.out.println("Exception occurred: " + e);
System.exit(0);
}
}
}
//
end Client.java

//
clientlog.props
handlers=java.util.logging.FileHandler
.level=ALL
sorter.level=ALL
sorter.Client.level=ALL

java.util.logging.FileHandler.pattern=/tmp/log/client%u.log
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
//
end clientlog.props

//
start serverlog.props
handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler
.level=ALL
sorter.level=ALL

java.util.logging.ConsoleHandler.level=SEVERE
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

java.util.logging.FileHandler.level=ALL
java.util.logging.FileHandler.pattern=/tmp/log/server%u.log
java.util.logging.FileHandler.limit=50000
java.util.logging.FileHandler.count=1
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
//
end severlog.props

//
start rmi.policy
grant {
// Allow everything for now
permission java.net.SocketPermission "*:1024-65535", "accept, connect, listen";
permission java.security.AllPermission;
permission java.io.FilePermission "/tmp/log/*", "write, read";
permission java.util.logging.LoggingPermission "control";
};
//
end rmi.policy

I wrote a very simple RMI program I showed above that generates random vector of integer numbers and ran it with command:

$rmiregistry
$java -Djava.security.policy=file:/jbproject/sorter/rmi.policy -Djava.util.logging.config.file=/jbproject/sorter/serverlog.props sorter.Servers
$java -Djava.security.policy=file:/jbproject/sorter/rmi.policy -Djava.util.logging.config.file=/jbproject/sorter/clientlog.props sorter.Client

And I got the following log output in /tmp/log:
///----------------- client0.log
..........................
2004-08-10 11:12:53 sun.rmi.server.UnicastRef invoke
FINER: main: method: public abstract java.util.Vector sorter.Generator.generate(int) throws java.rmi.RemoteException
2004-08-10 11:12:53 sun.rmi.server.UnicastRef logClientCall
FINER: main: outbound call: [endpoint:[192.168.0.1:36424](remote),objID:[19ee1ac:fe47f89fa9:-8000, 0]] : sorter.GeneratorImpl_Stub[19ee1ac:fe47f89fa9:-8000, 0]: public abstract java.util.Vector sorter.Generator.generate(int) throws java.rmi.RemoteException
2004-08-10 11:12:53 sun.rmi.transport.tcp.TCPChannel newConnection
FINE: main: reuse connection
2004-08-10 11:12:53 sun.rmi.server.UnicastRef invoke
FINER: main: opnum = 7324764122476237606
2004-08-10 11:12:53 sun.rmi.transport.StreamRemoteCall <init>
FINER: main: write remote call header...
................
//
end client0.log

//
server0.log
.....................
2004-08-10 11:12:49 sun.rmi.transport.ObjectTable putTarget
FINER: main: add object [0]
2004-08-10 11:12:49 sun.rmi.server.UnicastServerRef computeMethodHash
FINER: main: string used for method hash: "generate(I)Ljava/util/Vector;"
2004-08-10 11:12:49 sun.rmi.server.UnicastRef newCall
FINE: main: get connection
2004-08-10 11:12:49 sun.rmi.transport.tcp.TCPChannel createConnection
FINE: main: create connection
........................
//
end server0.log

You can see that sorter.Generator.generate(int) is invoked. And please notice that there is no single line in the source code with Logger, or log() apart from config files.

As far as I can understand logging mechanisms is embedded in JDK so I only need to enable it and configure. Of course I can put log() statements in the soruce code if I wish. But I can get some information about execution without any additional instruction put into my source code. Please notice, that this is the FINER level and you can read in documentation that entering() and exiting() also log information at FINER level (as I remember). So if I configure to log ALL actions why I cannot enable also logging method invocation with parameter values without additional instrumentation of my source code.

However, thank you 'kajbj'.
 

Posts:18,384
Registered: 21.03.00
Re: Enabling method parameters logging in Java logging  
Aug 10, 2004 3:56 AM (reply 4 of 11)



 
Hi,

Sorry to say, but look at the logging statements. They are all logged by sun classes. Look at the documentation, and learn how to read the log. The statement:
2004-08-10 11:12:53 sun.rmi.server.UnicastRef invoke
FINER: main: method: public abstract java.util.Vector sorter.Generator.generate(int) throws java.rmi.RemoteException

Is logged by the class sun.rmi.server.UnicastRef. I.e. sun has logging statements in their code, and that is what you have turned on. So your code hasn't written, or caused anything to be written to the log.

I'm pretty sure that you can't log without adding logging to your code (which an aspect can do)
/Kaj
 

Posts:13
Registered: 8/8/04
Re: Enabling method parameters logging in Java logging  
Aug 10, 2004 5:52 AM (reply 5 of 11)



 
Hi Kaj,

I am just looking around the matter since I am not familiar with logging facility (I have been just learning it since Sunday) - I try log4j but it seems not so powerful as JDK 1.4 logging (by the way it looks as JDK incorporated main concepts from log4j).

It helps me a lot since it means that I need to write a proxy object and instrument code at the proxy level or it means that I should instrument the rmi stubs in order to log parameters or returned values.

Currently I am reading and exercising the AspectJ as you suggested. However, I am not pretty sure if I can use it for RMI applications since AspectJ uses its own compiler. Do you know anything if RMI works fine with AspectJ?

Thanks.
 

Posts:21,718
Registered: 98-02-20
Re: Enabling method parameters logging in Java logging  
Aug 10, 2004 6:03 AM (reply 6 of 11)



 
I am just looking around the matter since I am not familiar with logging facility (I have been just
learning it since Sunday) -

Then you still have a lot to learn.

I try log4j but it seems not so powerful as JDK 1.4 logging (by the way it
looks as JDK incorporated main concepts from log4j).

Yes, indeed, log4j is older, and the JDK for logging did borrow liberally from log4j. (Some folks would take offence at your statement that log4j isn't as powerful. They'd argue that the JDK logging facility watered down log4j.)

It helps me a lot since it means that I need to write
a proxy object and instrument code at the proxy level
or it means that I should instrument the rmi stubs in
order to log parameters or returned values.

If the Sun classes are putting out logging info, then Sun put the logging statements in there to do it. You can see them at any time by looking at the source code you downloaded with your JDK.

Currently I am reading and exercising the AspectJ as
you suggested. However, I am not pretty sure if I can
use it for RMI applications since AspectJ uses its own
compiler. Do you know anything if RMI works fine with
AspectJ?

Since you're writing the RMI classes, I'd say that it'd be easy for you to add logging to your stuff. I'd be surprised if you needed more than that.

My advice would be to learn logging without AspectJ for now. Aspects might be very important someday, but you can solve your fundamental logging problem without it today.

%
 

Posts:18,384
Registered: 21.03.00
Re: Enabling method parameters logging in Java logging  
Aug 10, 2004 6:07 AM (reply 7 of 11)



 
My advice would be to learn logging without AspectJ
for now. Aspects might be very important someday, but
you can solve your fundamental logging problem without
it today.

I totally agree with duffymo, you probably don't want to use Aspects, it's just an interesting concept. It's better if you add logging statements to your code.

/Kaj
 

Posts:21,718
Registered: 98-02-20
Re: Enabling method parameters logging in Java logging  
Aug 10, 2004 6:10 AM (reply 8 of 11)



 
However, I can't configure that config file to log the entry parameters and/or return values. If I hard code
in the method like below:

It's possible to do what you want. You just need to study the logging docs some more.

It's not necessary to write lines of code like this. All you have to do is have the logger.entering() call. The level is set in the file external to your program.

And I would like to write in my 'myLoggingConfigFilePath' write something:>
.level=ALL

or .level=ENTRY
or .level=RETURN

Yes, you can turn on logging at a class level if you wish.

You need to set the following JVM arg when you run your Java app:

-Djava.util.logging.config.file=<path-to-your-logging-config-file>


And here's what the logging config should look like to write to a file:

# Global defaults.level      = ALLhandlers    = java.util.logging.FileHandler java.util.logging.FileHandler.level         = ALLjava.util.logging.FileHandler.pattern       = /path/to/LogTester-%g.logjava.util.logging.FileHandler.limit         = 100000java.util.logging.FileHandler.formatter     = java.util.logging.SimpleFormatterjava.util.logging.FileHandler.append        = false     # Turn on class-specific logging levels herecom.foo.bar.LogTester.level    = ALLcom.foo.bar.LogClass1.level    = FINESTcom.foo.bar.LogClass2.level    = INFO


%
 

Posts:21,718
Registered: 98-02-20
Re: Enabling method parameters logging in Java logging  
Aug 10, 2004 6:12 AM (reply 9 of 11)



 
The ONLY time you might need stuff like

if (logger.isLoggable(Level.FINEST)){}


would be if you were concatenating some strings to create a logging message. This can be an expensive operation, especially if your code is peppered with them. Surrounding those cases with this IF test gives the Hotspot compiler a chance to eliminate the operation.

%
 

Posts:13
Registered: 8/8/04
Re: Enabling method parameters logging in Java logging  
Aug 10, 2004 6:33 AM (reply 10 of 11)



 
Thanks Guys,

'duffymo': Yes, I can do that but I need as Kaj and you say first to log something i.e. put lines with logger.entering() and logger.exiting(). And I would like not to instrument the source code and I would like to have a log. It means that:

1. I should have an instrumented JVM (but it would be probably much more slower). However, I should do it on my own.

2. I should put log instructions somewhere (to stubs, source code, or proxies, etc.) and then use logging facility supported by JDK 1.4.

As Kaj has said: it is not possible to log without logging.

Concerning log4j, I think that I will be politically correct if I say that log4j is so good that it has been incorporated into official JDK 1.4 release. Make peace not war.

Thanks again Guys. I reward Kaj since (s)he was first who interested in this subject.
 

Posts:21,718
Registered: 98-02-20
Re: Enabling method parameters logging in Java logging  
Aug 10, 2004 6:36 AM (reply 11 of 11)



 
'duffymo': Yes, I can do that but I need as Kaj and
you say first to log something i.e. put lines with
logger.entering() and logger.exiting(). And I would
like not to instrument the source code and I would
like to have a log. It means that:

You have no choice. You have to instrument the source code. Can't have logging without it. Even AspectJ isn't magic that way. You have to tell the JVM where to do it somewhere. All AspectJ does is move it out of your code and into deployment descriptors.

Rod Johnson says that writing a class means instrumenting it for logging. I take that advice to heart. That's what I do from now on.

1. I should have an instrumented JVM (but it would be
probably much more slower). However, I should do it
on my own.

But you don't.

2. I should put log instructions somewhere (to stubs,
source code, or proxies, etc.) and then use logging
facility supported by JDK 1.4.

Right.

As Kaj has said: it is not possible to log without logging.

Indeed.

Concerning log4j, I think that I will be politically
correct if I say that log4j is so good that it has
been incorporated into official JDK 1.4 release. Make
peace not war.

Fine with me. I'm not one of those folks who's upset about log4j. They all work at IBM. ;) I'm just pointing out the history.

%
 
This topic has 11 replies on 1 page.