Recent Blogs
Ambimorphic, Mobile Configurations for Lamport Clocks After years of technical research into Smalltalk, with close cooperation with MIT Computer Science and Artificial Intelligence Laboratory (CSAIL) and its SCIgen, we have been able to show the construction of link-level acknowledgements. As a result, we propose an analysis of A* search, which we call Volt. 10/02/2008
Restlets and HTTP Sessions (Recipe 9) This recipe discusses some options in available to Web site developers using Restlet API to emulate traditional HttpSession's 07/31/2008
Restlet Cookbook - Delving into handleGet() and handlePost() (Recipe 8) This posting provides related examples that illustrate at least some simple things you may do with several handleX() methods where X may stand for various types of calls. 07/30/2008
Restlet Cookbook - How to enable SSL (Recipe 7) How to enable SSL on Restlet Web sites wihtout knowing too much keys, encryption, SSL and such. 07/29/2008
Restlet Cookbook - Using Filters in Restlet Applications (Recipe 6) This recipe contains code snippets illustrating the use of Filters in Restlet applications 03/09/2008
Restlet Cookbook - How to Create Virtual Hosts in Restlet Applications (Recipe 5) This recipe contains a code snippet for creating virtual hosts 02/24/2008
Popular HTML Escape Codes Here is a table of HTML escape codes for most frequently used symbols. If you use HTML, sooner or later you will find this table useful. 12/29/2007
Restlet Cookbook - Access Log (Recipe 4) This recipe describes access Logging using Restlet framework 11/09/2007
Restlet Cookbook - Form Submission and Processing (Recipe 3) This recipe describes a typical form submission using Restlet framework 10/15/2007
Restlet Cookbook - Site Application (Recipe 2) This recipe describes a possible way to code a Restlet Web site application 10/04/2007
more...
Restlet Cookbook - Access Log (Recipe 4)
Posted: 11/09/2007 by Serge IlynCoding and configuring access logging using Restlet framework is as easy as everything else with Restlets. However, if you are not familiar with Logging API in Java (used as a default logging mechanism in Restlets), dealing with logging may be confusing. Unfortunately, Restlet documentation is very laconic and provides few insights on how to use access logging. This recipe contains practical recommendations on most of things you need to do to setup Restlet access logging.
Defining the Problem
Actually, if you do nothing, you will get some king of logging "out of the box" - but, most likely, that would not be the logging you want. First, logging messages will be printed on the console only. Second, the output format will look something like
Nov 10, 2007 2:42:59 PM com.noelios.restlet.LogFilter afterHandle INFO: 2007-11-10 14:42:59 127.0.0.1 .... ..... ......
with two lines per one request. The second line will be in the W3C Extended Log File Format format (which is OK); however, you probably will not be happy with the first line of the log message (in most cases absolutely useless). Thus, most changes to logging setup will consist of two tasks:
- How to output to a file, and
- How to tune up the output format.
General Considerations
Restlet entry point to control access logging is through the
org.restlet.Component class (you create a new Component very soon
after you start your Restlet application). The Component's
getLogService() method will return an instance of the
org.restlet.service.LogService class. Restlet LogService class
provides access to logging service.
Component component = new Component();
LogService logService = component.getLogService();
One of the things you can do with LogService is to disable it:
logService.setEnabled(false);
By the way, even if it does not relate directly to the topic of this recipe (which is access logging), I would like to mention how to get rid of this type of very annoying messages that appear contrary to your will on the console output:
INFO: Converted target URI: file:///c:/navirest2/html/images/bg/footer.jpg Jun 16, 2009 9:44:57 AM com.noelios.restlet.local.DirectoryResource getVariants
The API mentioned above: logService.setEnabled(false); or
something like
component.getContext().getLogger().getLogger("com.naviquan.Naviquan").setL
evel(Level.WARNING); will not have any effect on the output. What may
help is the following method public Logger getLogger() available
in Restlet class (hence, in all its subclasses). Accordingly, you can do this
(use any Level value you want)
Directory directory = new Directory(...);
directory.getLogger().setLevel(Level.WARNING);
and this vexatious output will disappear.
Now, let's get back to the original topic - access logging. If you want to
configure it the way you want, your most important step is to obtain "a link"
(for the lack of better terminology) between Restlet LogService and an instance
of the java.util.logging.Logger class (that belongs to the Java
Logging API). You do this by giving a name to the LogService instance, like
this:
logService.setLoggerName("com.naviquan");
To get an instance of Logger, use the following API:
Logger logger = Logger.getLogger("com.naviquan");
It can be a static member of your application, and you can instantiate it as such:
private static Logger logger = Logger.getLogger("com.naviquan");
To continue configuration of your custom logging, you need to know that the way
to configure many things in Java Logging is to manipulate parameters in the
logging.config properties file located by default in the
java.util.logging.config.file System property. The same can be
done programmatically using the following API:
System.setProperty("java.util.logging.config.file",
"/your/path/logging.config");
It is also possible to ignore at least some of logging.config parameters by setting/modifying them programmatically (this is the reason we do not worry about logging.config file in this recipe).
Outputting to File
Previously, I mentioned that one of the problems you may want to solve is to redirect your logging output to a file (and possibly disabling completely or changing console output). How do we accomplish this? By creating an instance of java.util.logging.FileHandler and adding it to the Logger instance:
FileHandler fh = new FileHandler("c:/navi%g.log", true);
logger.addHandler(fileHandler);
To disable console logging, we can use this approach:
logger.setUseParentHandlers(false);
Note that all three lines of coding above use the Java Logging API. In the FileHandler constructor, we specify the file name and a boolean parameter. If the latter is true, messages are appended to file. Our file name contains a pattern %g - it instructs Java Logging to insert generation number (for log rotation). If you use this pattern, keep in mind that rotation is controlled by two FileHandler parameters: limit and count. The first parameter, limit, sets the max file size that, when reached, will result in creation of a new log output file. The second parameter, count, defines the number of files that can be created before the file name rotates to the first one (created with count of 0 - in our example, navi0.log). Both parameters can be set either using a FileHandler constructor (that's why there are several of them) or can be set in the logging.config file. There are other patterns that can be used in specifying log file names. You can consult Java Logging API javadoc for all the details.
Several comments regarding disabling console output. To understand the
respective line in the example above, you need to know that by default the root
handler created by Java logging mechanism is an instance of the
java.util.logging.ConsoleHandler class. Thus, it's always there,
unless you disable it like we did above.
Changing Log Format
Our second problem to deal with was the output formatting. It is controlled by
an instance of java.util.logging.Formatter. This is an abstract
class from Java Logging API which also offers two subclasses:
SimpleFormatter and XMLFormatter. If you are not
happy with either one, you need to implement your own Formatter or
extend the existing subclasses (depending on what exactly you want). For the
purposes of our recipe we will extend SimpleFormatter - all you
need to do is to override public String format(LogRecord record)
method
public class NaviquanLogFormatter extends SimpleFormatter {
public String format(LogRecord record) {
return Naviquan.sdf.format(new Date()) + " - " + record.getMessage() + "\n";
}
}
where sdf is an instance of
java.text.SimpleDateFormat defined in the Naviquan class as:
public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd 'at'
HH:mm:ss");
Once a Formatter is crafted, you need to let your FileHandler know
about it. You can do this in the logging.config file, or use API:
fileHandler.setFormatter(new NaviquanLogFormatter());
We are almost done with the formatting issue, but one of its pieces is still
missing. If you look at my implementation of the NaviquanLogFormatter and, in
particular, its format(LogRecord record) method, you will see that
it relies on the record.getMessage() call. Accordingly, the result
will be formatted following rules enabled for this 'message'. So, what is the
'message' in the java.util.logging.LogRecord class and how to
control it?
Make no mistake - this 'message' comes from your application, and the
java.util.logging.LogRecord class is nothing more than a utility
to perform some (very unexciting) operations (for example, localization) with
messages coming from elsewhere. If this is true, the question is - where does
actual formatting come from? As I mentioned above, the
org.restlet.service.LogService provides some default formatting.
But it also has API that allows for specifying any format you want. Here it is:
logService.setLogFormat("{cia} {m} {S} {rp} AGENT:{cig} REF:{fp}");
The setLogFormat(String format) method takes as its argument a String that
describes the exact log message format using {name} syntax through the internal
Restlet mechanism based on org.restlet.util.Template class. In the
example above the following names are used:
cia | - | request.clientInfo.address |
m | - | request.method |
S | - | response.status |
rp | - | request.resourceRef, path |
cig | - | request.clientInfo.agent |
fp | - | request.referrerRef, path |
The above formatting string will result in the output similar to the following (as one line):
2007.11.10 at 14:02:24 - 127.0.0.1 GET 200 /pages/Money AGENT:Mozilla/5.0 (Windows; U; ...... ) REF:/pages/Tech
For the full list of available {name}s, you need to consult Restlet API javadoc
for the org.restlet.util.Template class
That's it. The example below summarizes in a concise form everything that has been done.
Complete Example of Setting Restlet Access Logging
public class Naviquan extends Application {
...
private static Logger logger = Logger.getLogger("com.naviquan");
public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd 'at'
HH:mm:ss");
public static void main(String ...args) throws Exception {
Component component = new Component();
// start logging
LogService logService = component.getLogService();
logService.setEnabled(true);
logService.setLoggerName("com.naviquan");
logService.setLogFormat("{cia} {m} {S} {rp} AGENT:{cig} REF:{fp}");
FileHandler fileHandler = new FileHandler("c:/navi%g.log", true);
fileHandler.setFormatter(new NaviquanLogFormatter());
logger.setUseParentHandlers(false);
logger.addHandler(fileHandler);
// end logging
...
}
...
}
public class NaviquanLogFormatter extends SimpleFormatter {
public String format(LogRecord record) {
return Naviquan.sdf.format(new Date()) + " - " + record.getMessage() +
"\n"; }
}