001 //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/tags/2.1/src/org/deegree/framework/log/LoggerService.java $ 002 /*---------------- FILE HEADER ------------------------------------------ 003 004 This file is part of deegree. 005 Copyright (C) 2001-2006 by: 006 EXSE, Department of Geography, University of Bonn 007 http://www.giub.uni-bonn.de/deegree/ 008 lat/lon GmbH 009 http://www.lat-lon.de 010 011 This library is free software; you can redistribute it and/or 012 modify it under the terms of the GNU Lesser General Public 013 License as published by the Free Software Foundation; either 014 version 2.1 of the License, or (at your option) any later version. 015 016 This library is distributed in the hope that it will be useful, 017 but WITHOUT ANY WARRANTY; without even the implied warranty of 018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 Lesser General Public License for more details. 020 021 You should have received a copy of the GNU Lesser General Public 022 License along with this library; if not, write to the Free Software 023 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 024 025 Contact: 026 027 Andreas Poth 028 lat/lon GmbH 029 Aennchenstr. 19 030 53115 Bonn 031 Germany 032 E-Mail: poth@lat-lon.de 033 034 Prof. Dr. Klaus Greve 035 Department of Geography 036 University of Bonn 037 Meckenheimer Allee 166 038 53115 Bonn 039 Germany 040 E-Mail: greve@giub.uni-bonn.de 041 042 043 ---------------------------------------------------------------------------*/ 044 package org.deegree.framework.log; 045 046 // J2EE 1.3 047 import java.io.BufferedOutputStream; 048 import java.io.BufferedWriter; 049 import java.io.File; 050 import java.io.FileOutputStream; 051 import java.io.FileWriter; 052 import java.io.IOException; 053 import java.net.InetAddress; 054 import java.net.UnknownHostException; 055 import java.text.DateFormat; 056 import java.text.MessageFormat; 057 import java.util.Date; 058 import java.util.Enumeration; 059 import java.util.Map; 060 import java.util.Properties; 061 062 import javax.mail.Session; 063 064 import org.deegree.framework.jndi.JndiUtils; 065 import org.deegree.framework.mail.EMailMessage; 066 import org.deegree.framework.mail.MailHelper; 067 import org.deegree.framework.mail.MailMessage; 068 import org.deegree.framework.util.BootLogger; 069 import org.deegree.framework.version.Version; 070 import org.deegree.framework.xml.XMLFragment; 071 072 /** 073 * The Logger is used to log messages to files. This service will use a logging service provided by the application 074 * server or a 3rd party logging service such as Apache Log4J to enable asychronous call of the method log(). The log 075 * server is configured by a set of Properties which are provided to the class init. 076 * <p> 077 * There are some global properties as well: <BR> 078 * <UL> 079 * <LI><B>log.class </B>: the logging class. 080 * <LI><B>log.active </B>: to enable or disabel the logging service 081 * <LI><B>log.mail.active </B>: to activate the email notification 082 * <LI><B>log.mail.to </B>: the mail address 083 * <LI><B>log.mail.session </B>: the mail session used to send mail 084 * </UL> 085 * <P> 086 * Messages are logged using log(). If an error occurs during creation or logging, the message will be written to the 087 * server BootLogger. 088 * 089 * @author <a href="mailto:tfr@users.sourceforge.net">Torsten Friebe </A> 090 * 091 * @author last edited by: UID=$Author: mschneider $ 092 * 093 * @version $Revision: 7597 $, $Date: 2007-06-19 15:29:49 +0200 (Di, 19 Jun 2007) $ 094 * 095 * @see LoggerFactory 096 * @see org.deegree.framework.util.BootLogger 097 */ 098 abstract class LoggerService implements ILogger { 099 100 protected static String defaultChannelName; 101 102 private static String hostAddress; 103 104 private static String hostName; 105 106 private static String mailNotificationAddress; 107 108 private static String mailSessionName; 109 110 private static Session mailSession; 111 112 private static String mailHostName; 113 114 private static boolean sendMailIsActive; 115 116 private static DateFormat df; 117 118 private static final String ENTERING_METHOD = "-> {1}#{0}() with arguments {2}"; 119 120 private static final String EXITING_METHOD = "<- {1}#{0}()"; 121 122 public void init( Properties props ) { 123 124 df = DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT ); 125 126 try { 127 128 // fetch all configuration parameters 129 LoggerService.defaultChannelName = props.getProperty( "log.channel.name" ); 130 LoggerService.mailNotificationAddress = props.getProperty( "log.mail.to" ); 131 String mailerActive = props.getProperty( "log.mail.active" ); 132 LoggerService.mailSessionName = props.getProperty( "log.mail.session" ); 133 LoggerService.mailHostName = props.getProperty( "log.mail.smtphost" ); 134 135 // set defaults if not set 136 if ( mailerActive == null || mailerActive.equalsIgnoreCase( "false" ) ) { 137 LoggerService.sendMailIsActive = false; 138 } 139 if ( defaultChannelName == null ) { 140 LoggerService.defaultChannelName = LoggerService.class.getName(); 141 } 142 if ( mailNotificationAddress == null ) { 143 LoggerService.mailNotificationAddress = "UNKNOWN@" + LoggerService.mailHostName; 144 } 145 146 hostAddress = InetAddress.getLocalHost().getHostAddress(); 147 hostName = InetAddress.getLocalHost().getHostName(); 148 149 } catch ( UnknownHostException ex ) { 150 BootLogger.log( "Unable to determine host: " + ex.getMessage() ); 151 } catch ( Exception ex ) { 152 ex.printStackTrace(); 153 BootLogger.log( "Error while initializing " + LoggerService.class.getName() + " : " + ex.getMessage() ); 154 } finally { 155 BootLogger.log( "Using: defaultChannelName=" + defaultChannelName + ", mailNotificationAddress=" 156 + mailNotificationAddress + ", mailSessionName=" + mailSessionName + ", log.mail.active=" 157 + LoggerService.sendMailIsActive ); 158 } 159 } 160 161 /** 162 * Create logger instance 163 * 164 */ 165 protected LoggerService() { 166 // only callable for the package. 167 } 168 169 /** 170 * Log error with exception 171 * 172 * @param message 173 * the log message 174 * @param e 175 * the exception to be logged 176 * @param properties 177 * a given Property file in which specific email notification possibilities are saved. 178 */ 179 public final void logError( String message, Throwable e, Map properties ) { 180 this.logError( message, e ); 181 if ( sendMailIsActive ) { 182 this.sendMail( message, e, properties ); 183 } 184 } 185 186 /** 187 * Log warning message 188 * 189 * @param message 190 * the log message 191 */ 192 public abstract void logWarning( String message ); 193 194 /** 195 * Log warning message with exception 196 * 197 * @param message 198 * the log message 199 * @param e 200 * the exception to be logged 201 */ 202 public abstract void logWarning( String message, Throwable e ); 203 204 /** 205 * Log info message 206 * 207 * @param message 208 * the log message 209 */ 210 public abstract void logInfo( String message ); 211 212 /** 213 * Log info message 214 * 215 * @param message 216 * the log message 217 * @param e 218 * the exception to be logged 219 */ 220 public abstract void logInfo( String message, Throwable e ); 221 222 /** 223 * Log debug message 224 * 225 * @param message 226 * the log message 227 */ 228 public abstract void logDebug( String message ); 229 230 /** 231 * Log debug message. 232 * 233 * @param message 234 * the log message 235 * @param e 236 * the exception to be logged 237 */ 238 public abstract void logDebug( String message, Throwable e ); 239 240 /** 241 * Logs the given text to the specified file if log level is set to <code>LOG_DEBUG</code>. 242 * 243 * @param file 244 * file to log to 245 * @param content 246 * text to be logged 247 */ 248 public void logDebugFile( File file, String content ) { 249 if ( getLevel() == LOG_DEBUG ) { 250 logDebug( "Writing debug file '" + file.getAbsolutePath() + "'." ); 251 BufferedWriter writer = null; 252 try { 253 writer = new BufferedWriter( new FileWriter( file ) ); 254 writer.write( content ); 255 } catch ( IOException e ) { 256 String msg = "Could not write to debug file '" + file.getAbsolutePath() + "'."; 257 logError( msg, e ); 258 } finally { 259 if ( writer != null ) { 260 try { 261 writer.close(); 262 } catch ( IOException e ) { 263 String msg = "Error closing debug file '" + file.getAbsolutePath() + "'."; 264 logError( msg, e ); 265 } 266 } 267 } 268 } 269 } 270 271 /** 272 * Logs the given text to a temporary file (created from specified prefix and suffix) if log level is set to 273 * <code>LOG_DEBUG</code>. 274 * 275 * @see File#createTempFile(String, String) 276 * @param filePrefix 277 * prefix for the temp file name 278 * @param fileSuffix 279 * suffix for the temp file name, can be null (then ".tmp" is used) 280 * @param content 281 * text to be logged 282 */ 283 public void logDebugFile( String filePrefix, String fileSuffix, String content ) { 284 if ( getLevel() == LOG_DEBUG ) { 285 try { 286 File tmpFile = File.createTempFile( filePrefix, fileSuffix ); 287 logDebugFile( tmpFile, content ); 288 } catch ( IOException e ) { 289 String msg = "Cannot create debug file for prefix '" + filePrefix + "' and suffix '" + fileSuffix + "."; 290 logError( msg, e ); 291 } 292 } 293 } 294 295 /** 296 * Logs the given {@link XMLFragment} to a temporary file (created from specified prefix and suffix ".xml") if log 297 * level is set to <code>LOG_DEBUG</code>. 298 * 299 * @param filePrefix 300 * prefix for the temp file name 301 * @param fragment 302 * XMLFragment to be logged (will be pretty-printed) 303 */ 304 public void logDebugXMLFile( String filePrefix, XMLFragment fragment ) { 305 if ( getLevel() == LOG_DEBUG ) { 306 logDebugFile( filePrefix, ".xml", fragment.getAsPrettyString() ); 307 } 308 } 309 310 /** 311 * Logs the given binary data to the specified file if log level is set to <code>LOG_DEBUG</code>. 312 * 313 * @param file 314 * file to log to 315 * @param data 316 * binary data to be logged 317 */ 318 public void logDebugBinaryFile( File file, byte[] data ) { 319 if ( getLevel() == LOG_DEBUG ) { 320 logDebug( "Writing binary debug file '" + file.getAbsolutePath() + "'." ); 321 BufferedOutputStream out = null; 322 try { 323 out = new BufferedOutputStream( new FileOutputStream( file ) ); 324 out.write( data ); 325 } catch ( IOException e ) { 326 String msg = "Could not write to debug file '" + file.getAbsolutePath() + "'."; 327 logError( msg, e ); 328 } finally { 329 if ( out != null ) { 330 try { 331 out.close(); 332 } catch ( IOException e ) { 333 String msg = "Error closing debug file '" + file.getAbsolutePath() + "'."; 334 logError( msg, e ); 335 } 336 } 337 } 338 } 339 } 340 341 /** 342 * Logs the given binary data to a temporary file (created from specified prefix and suffix) if log level is set to 343 * <code>LOG_DEBUG</code>. 344 * 345 * @see File#createTempFile(String, String) 346 * @param filePrefix 347 * prefix for the temp file name 348 * @param fileSuffix 349 * suffix for the temp file name, can be null (then ".tmp" is used) 350 * @param data 351 * binary data to be logged 352 */ 353 public void logDebugBinaryFile( String filePrefix, String fileSuffix, byte[] data ) { 354 if ( getLevel() == LOG_DEBUG ) { 355 try { 356 File tmpFile = File.createTempFile( filePrefix, fileSuffix ); 357 logDebugBinaryFile( tmpFile, data ); 358 } catch ( IOException e ) { 359 String msg = "Cannot create debug file for prefix '" + filePrefix + "' and suffix '" + fileSuffix + "."; 360 logError( msg, e ); 361 } 362 } 363 } 364 365 /** 366 * {@inheritDoc} 367 */ 368 public void entering() { 369 StackTraceElement[] stack = new Exception().getStackTrace(); 370 StackTraceElement element = null; 371 if ( stack.length > 2 ) { 372 element = stack[1]; 373 this.entering( element.getClassName(), element.getMethodName() ); 374 } 375 } 376 377 /** 378 * {@inheritDoc} 379 */ 380 public void entering( String sourceClass, String sourceMethod, Object[] arguments ) { 381 this.logDebug( this.produceMessage( ENTERING_METHOD, new Object[] { sourceMethod, sourceClass, arguments } ) ); 382 } 383 384 /** 385 * 386 * 387 * 388 */ 389 public void entering( String sourceClass, String sourceMethod ) { 390 this.entering( sourceClass, sourceMethod, null ); 391 } 392 393 /* 394 * (non-Javadoc) 395 * 396 * @see org.deegree_impl.log.ILogger#exiting(java.lang.String, java.lang.String, java.lang.Object[]) 397 */ 398 public void exiting( String sourceClass, String sourceMethod, Object[] arguments ) { 399 this.logDebug( this.produceMessage( EXITING_METHOD, new Object[] { sourceMethod, sourceClass } ) ); 400 } 401 402 /** 403 * {@inheritDoc} 404 */ 405 public void exiting() { 406 StackTraceElement[] stack = new Exception().getStackTrace(); 407 StackTraceElement element = null; 408 if ( stack.length > 2 ) { 409 element = stack[1]; 410 this.exiting( element.getClassName(), element.getMethodName() ); 411 } 412 } 413 414 /** 415 * {@inheritDoc} 416 */ 417 public void exiting( String sourceClass, String sourceMethod ) { 418 this.exiting( sourceClass, sourceMethod, null ); 419 } 420 421 /** 422 * Formats the provided string and the args array into a String using MessageFormat. 423 */ 424 private String produceMessage( String pattern, Object[] args ) { 425 return new MessageFormat( pattern ).format( args ); 426 } 427 428 /** 429 * Sends email with exception string. If mail session or mail notification address is null no email is send. 430 * 431 * @param message 432 * message is in mail subject 433 * @param ex 434 * full exception is displayed in body 435 * @param properties 436 * list of properties listed in body 437 */ 438 protected void sendMail( String message, Throwable ex, Map properties ) { 439 if ( sendMailIsActive && mailSessionName != null && mailNotificationAddress != null ) { 440 this.sendMailNotification( message, ex, properties ); 441 } 442 } 443 444 private void sendMailNotification( String message, Throwable ex, Map properties ) { 445 MailMessage mail; 446 StringBuffer emailBody = new StringBuffer(); 447 448 emailBody.append( "A critical error occured in " + Version.getVersion() ); 449 emailBody.append( " running on " + hostName + "/" + hostAddress ); 450 emailBody.append( " on " + df.format( new Date( System.currentTimeMillis() ) ) ); 451 emailBody.append( "\n\n" ); 452 if ( message != null ) { 453 emailBody.append( "\n\nThe error message: " + message ); 454 } 455 if ( properties != null ) { 456 emailBody.append( "\n\nRequest data:\n--------------\n" + properties.toString() ); 457 } 458 if ( ex != null ) { 459 emailBody.append( "\n\nException:\n---------\n" + ex.getMessage() ); 460 emailBody.append( "\n\nStack Trace:\n------------\n\n" + ex.toString() ); 461 } 462 emailBody.append( "\n\nSystem Info:\n--------------\n" + getSystemInfo() ); 463 464 String subject = "Critical Error:" + Version.getVersion() + " on " + hostName + "/" + hostAddress; 465 466 mail = new EMailMessage( "DO_NOT_REPLY@" + hostName, mailNotificationAddress, subject, emailBody.toString() ); 467 try { 468 if ( mailSession == null ) { 469 mailSession = this.getMailSession(); 470 } 471 new MailHelper().createAndSendMail( mail, mailSession ); 472 } catch ( Exception e ) { 473 BootLogger.logError( "Can't send email notification: " + mail.getHeader(), e ); 474 } 475 } 476 477 /** 478 * Return system information (memory and properties) as string. 479 * 480 * @return system information (memory and properties) as string. 481 */ 482 private String getSystemInfo() { 483 StringBuffer buf = new StringBuffer(); 484 buf.append( "Total Memory: " + Runtime.getRuntime().totalMemory() / 1024 + " Kilobyte\n" ); 485 buf.append( "Free Memory: " + Runtime.getRuntime().freeMemory() / 1024 + " Kilobyte\n" ); 486 java.util.Properties sysprops = System.getProperties(); 487 for ( Enumeration e = sysprops.keys(); e.hasMoreElements(); ) { 488 String key = e.nextElement().toString(); 489 String value = sysprops.getProperty( key ); 490 buf.append( key + " : " + value + "\n" ); 491 } 492 return buf.toString(); 493 } 494 495 /** 496 * 497 */ 498 private Session getMailSession() { 499 Session session = null; 500 try { 501 session = (Session) JndiUtils.lookup( mailSessionName, Session.class ); 502 } catch ( Exception ex ) { 503 BootLogger.logError( "Error while initializing " + LoggerService.class.getName() + " : " + ex.getMessage(), 504 ex ); 505 } finally { 506 if ( session == null ) { 507 Properties p = System.getProperties(); 508 p.put( "mail.smtp.host", LoggerService.mailHostName ); 509 session = Session.getDefaultInstance( p, null ); 510 } 511 } 512 return session; 513 } 514 515 }