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