--
JoaoCarreira - 15 Dec 2009
XEO Logging Mechanism
General Description
In XEO a logging system was created to create an abstraction over the loggers currently used. In the current XEO version log4j was updated to release 1.2.15 (which is used internally by the XEO). This Logging system is an attempt in normalizing the logging process in XEO Applications.
If no configuration is specified in the
boconfig.xml, the system will use the log4j general parameterization, namely the
log4j.properties file.
Logger Architecture
The logger system consists of two levels. The Logger and the Appender
The loggers are the elements that define which packages should be logged, as also the writing format in the log. For each logger there are appenders, which can be the following:
- console - This appender writes the log messages to the standard Java output
- file - This appender creates log files with a predefined file-size limit.
- email - This appender sends error by email to the configured recipients. This logger does not work in every logging level ( only for error levels superior to WARNING).
There can be loggers with different appenders, if you need to have Java packages logged in different ways.
How to use
Obtain a logger for a class
import netgest.bo.system.Logger;
(...)
private static final Logger logger = Logger.getLogger(MyClass.class);
Write on the log
logger.warn("Something went wrong. Message");
Performance
When logging, you should pay attention to performance. For instance, avoid logging messages if the logger is not active for the current level.
When logging, you should put the code inside an if statement to check if the logger is active for the current level.
Wrong
logger.finest("Entering class " + this.getClass().getName );
Correct
if( logger.isFinestEnabled() )
logger.finest("Entering class %s", this.getClass().getName );
In the "Correct" way, you avoid the string to be concatenated with the class name when the FINEST level is not active.
XEO Logging configuration ( boconfig.xml )
Logging levels and respective use cases:
# |
Level |
Log Text |
Description |
1 |
FINEST |
FINST |
This level should be used to debug behavior. This level should never be active in production environments. |
2 |
FINER |
FINER |
This level should give relevant information to trace errors, ( such as when calling external API's, or reading runtime configuration results. |
3 |
FINE |
FINE |
Extended log level, should give information about background task execution, results of external API calls (like sending emails), web service calls, etc. |
4 |
CONFIG |
CONF |
Information about System configurations, Attention, do not log passwords. |
5 |
WARNING |
WARN |
Information of critical warning, unusual errors, but those the user is notified if they occurred. |
6 |
SEVERE |
SEVER |
Errors that prevent a good system functioning, such as poorly written queries, viewers/objects with definition syntax error. |
Configuration in boconfig.xml
General configuration
logger:
Attribute |
Possible Values |
Description |
active |
true/false |
If the logger is active or not |
for |
String separated by commas |
Java Packages for which this configuration should be used |
level |
FINEST / FINER / FINE / CONFIG / WARNING / SERVERE |
Log level that will be used by this configuration |
pattern |
Writing format for the log of type log4j |
Log writing format |
Appender Configuration
console:
Appender Configuration
file:
Attribute |
Possible Values |
Description |
active |
true/false |
Activate or disable this appender |
logFile |
Name of the log file |
Path relative to the xeoHome or absolute path (with filename) |
maxSize |
nn / nnKB / nnMB |
Maximum log file size. |
backupFiles |
n |
Number of files that should be kept in the history after log limit exceeded |
Appender Configuration (
This Appender only works for logs superior to WARNING)
email:
Attribute |
Possible Values |
Description |
active |
true/false |
Activate or disable this appender |
buffer |
n |
Number of earlier messages in the log that should be sent in the email body |
smtpHost |
hostname |
SMTP Server to use for sending error logs |
from |
email address |
Sender email address |
to |
email address |
Receiver email address |
cc |
email address |
Email CC address |
bcc |
email address |
Email BCC address |
subject |
String |
Email subject text |
Configuration Examples
This logger is configured to do logging in all classes that are in the
pt and
netgest package hierarchy. The log level is FINEST so, the log will be long. Since the email appender is deactivated, the WARNING and SEVERE messages are not sent by email.
<logConfig>
<logger active='true' for='pt,netgest' level='FINEST' pattern='%d %5p [%t] (%F:%L) - %m%n' >
<console active='true' />
<file active='true' logFile='.\log\fileName.log' backupFiles='5' maxSize='50MB' />
<email active='false' buffer='50' smtpHost='mail.itds.pt' from='' to='jp[a]itds.pt' cc='' bcc='' subject='ola' />
</logger>
</logConfig>
The next listing includes different logger and appenders for different Java packages. This configuration makes the log in FINEST mode to the console, file and email of all classes that are in the package
pt (remember, though, that e-mail messages are only sent for SEVERE errors). For the classes in the
netgest package, only the console logger is enabled (for CONFIG level or higher).
<logConfig>
<logger active='true' for='pt' level='FINEST' pattern='%d %5p [%t] (%F:%L) - %m%n' >
<console active='true' />
<file active='true' logFile='.\log\fileName.log' backupFiles='5' maxSize='50MB' />
<email active='true' buffer='50' smtpHost='mail.itds.pt' from='' to='destemail' cc='' bcc='' subject='ola' />
</logger>
<logger active='true' for='netgest' level='CONFIG' pattern='%d %5p [%t] (%F:%L) - %m%n' >
<console active='true' />
</logger>
</logConfig>
Example of a class using logging
package pt.logger;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import netgest.bo.system.Logger;
import netgest.bo.system.boApplication;
public class LoggerDemo {
// Initialize the logger for the class
private static final Logger logger = Logger.getLogger( LoggerDemo.class );
public static void main( String[] args ) {
// Call some sample methods
loggedMethod();
doSomeWork();
}
public static void doSomeWork() {
FileWriter fw;
PrintWriter pw;
File propsFile;
// Log configuration info to the logger
logger.config("xeoHome is [%s]",
boApplication.getApplicationFromStaticContext("XEO")
.getApplicationConfig().getNgtHome()
);
propsFile = new File("c:\\jvmprops.txt");
if( propsFile.exists() ) {
// Warning - the previous file was overwritten
logger.warn("Overwritting file %s ", propsFile.getName() );
}
else {
if( logger.isFineEnabled() )
// Fine - Creating a file
logger.fine("Creating file %s ", propsFile.getName() );
}
try {
fw = new FileWriter( propsFile );
pw = new PrintWriter( fw );
if( logger.isFinestEnabled() ) {
// Finest - Filling a file
logger.finest("Dumping properties to [%s]", propsFile.getAbsolutePath() );
}
for( Object propName : System.getProperties().keySet() ) {
pw.format( "%s : %s \n", propName, System.getProperty( propName.toString() ) );
}
pw.close();
if( logger.isFinestEnabled() ) {
// Finest - Closing the file
logger.finest("Closing file [%s]", propsFile.getAbsolutePath() );
}
fw.close();
} catch (IOException e) {
// Severe - Something goes wrong writing the file
logger.severe( "Error writing to file [%s]" , e, propsFile.getAbsolutePath() );
}
}
public static void loggedMethod() {
// Finest - tracing method call's
logger.finest( "Entering in method: %s", "loggedMethod" );
// Do Work
// (...)
logger.finest( "Exiting in method: %s", "loggedMethod" );
}
}