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 }