1/*
2 * Copyright 2001-2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18package org.apache.commons.logging.impl;
19
20import java.io.InputStream;
21import java.io.Serializable;
22import java.lang.reflect.InvocationTargetException;
23import java.lang.reflect.Method;
24import java.security.AccessController;
25import java.security.PrivilegedAction;
26import java.text.DateFormat;
27import java.text.SimpleDateFormat;
28import java.util.Date;
29import java.util.Properties;
30
31import org.apache.commons.logging.Log;
32import org.apache.commons.logging.LogConfigurationException;
33
34/**
35 * <p>Simple implementation of Log that sends all enabled log messages,
36 * for all defined loggers, to System.err.  The following system properties
37 * are supported to configure the behavior of this logger:</p>
38 * <ul>
39 * <li><code>org.apache.commons.logging.simplelog.defaultlog</code> -
40 *     Default logging detail level for all instances of SimpleLog.
41 *     Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
42 *     If not specified, defaults to "info". </li>
43 * <li><code>org.apache.commons.logging.simplelog.log.xxxxx</code> -
44 *     Logging detail level for a SimpleLog instance named "xxxxx".
45 *     Must be one of ("trace", "debug", "info", "warn", "error", or "fatal").
46 *     If not specified, the default logging detail level is used.</li>
47 * <li><code>org.apache.commons.logging.simplelog.showlogname</code> -
48 *     Set to <code>true</code> if you want the Log instance name to be
49 *     included in output messages. Defaults to <code>false</code>.</li>
50 * <li><code>org.apache.commons.logging.simplelog.showShortLogname</code> -
51 *     Set to <code>true</code> if you want the last component of the name to be
52 *     included in output messages. Defaults to <code>true</code>.</li>
53 * <li><code>org.apache.commons.logging.simplelog.showdatetime</code> -
54 *     Set to <code>true</code> if you want the current date and time
55 *     to be included in output messages. Default is <code>false</code>.</li>
56 * <li><code>org.apache.commons.logging.simplelog.dateTimeFormat</code> -
57 *     The date and time format to be used in the output messages.
58 *     The pattern describing the date and time format is the same that is
59 *     used in <code>java.text.SimpleDateFormat</code>. If the format is not
60 *     specified or is invalid, the default format is used.
61 *     The default format is <code>yyyy/MM/dd HH:mm:ss:SSS zzz</code>.</li>
62 * </ul>
63 *
64 * <p>In addition to looking for system properties with the names specified
65 * above, this implementation also checks for a class loader resource named
66 * <code>"simplelog.properties"</code>, and includes any matching definitions
67 * from this resource (if it exists).</p>
68 *
69 * @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
70 * @author Rod Waldhoff
71 * @author Robert Burrell Donkin
72 *
73 * @version $Id: SimpleLog.java 399221 2006-05-03 09:20:24Z dennisl $
74 *
75 * @deprecated Please use {@link java.net.URL#openConnection} instead.
76 *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
77 *     for further details.
78 */
79@Deprecated
80public class SimpleLog implements Log, Serializable {
81
82
83    // ------------------------------------------------------- Class Attributes
84
85    /** All system properties used by <code>SimpleLog</code> start with this */
86    static protected final String systemPrefix =
87        "org.apache.commons.logging.simplelog.";
88
89    /** Properties loaded from simplelog.properties */
90    static protected final Properties simpleLogProps = new Properties();
91
92    /** The default format to use when formating dates */
93    static protected final String DEFAULT_DATE_TIME_FORMAT =
94        "yyyy/MM/dd HH:mm:ss:SSS zzz";
95
96    /** Include the instance name in the log message? */
97    static protected boolean showLogName = false;
98    /** Include the short name ( last component ) of the logger in the log
99     *  message. Defaults to true - otherwise we'll be lost in a flood of
100     *  messages without knowing who sends them.
101     */
102    static protected boolean showShortName = true;
103    /** Include the current time in the log message */
104    static protected boolean showDateTime = false;
105    /** The date and time format to use in the log message */
106    static protected String dateTimeFormat = DEFAULT_DATE_TIME_FORMAT;
107    /** Used to format times */
108    static protected DateFormat dateFormatter = null;
109
110    // ---------------------------------------------------- Log Level Constants
111
112
113    /** "Trace" level logging. */
114    public static final int LOG_LEVEL_TRACE  = 1;
115    /** "Debug" level logging. */
116    public static final int LOG_LEVEL_DEBUG  = 2;
117    /** "Info" level logging. */
118    public static final int LOG_LEVEL_INFO   = 3;
119    /** "Warn" level logging. */
120    public static final int LOG_LEVEL_WARN   = 4;
121    /** "Error" level logging. */
122    public static final int LOG_LEVEL_ERROR  = 5;
123    /** "Fatal" level logging. */
124    public static final int LOG_LEVEL_FATAL  = 6;
125
126    /** Enable all logging levels */
127    public static final int LOG_LEVEL_ALL    = (LOG_LEVEL_TRACE - 1);
128
129    /** Enable no logging levels */
130    public static final int LOG_LEVEL_OFF    = (LOG_LEVEL_FATAL + 1);
131
132    // ------------------------------------------------------------ Initializer
133
134    private static String getStringProperty(String name) {
135        String prop = null;
136	try {
137	    prop = System.getProperty(name);
138	} catch (SecurityException e) {
139	    ; // Ignore
140	}
141        return (prop == null) ? simpleLogProps.getProperty(name) : prop;
142    }
143
144    private static String getStringProperty(String name, String dephault) {
145        String prop = getStringProperty(name);
146        return (prop == null) ? dephault : prop;
147    }
148
149    private static boolean getBooleanProperty(String name, boolean dephault) {
150        String prop = getStringProperty(name);
151        return (prop == null) ? dephault : "true".equalsIgnoreCase(prop);
152    }
153
154    // Initialize class attributes.
155    // Load properties file, if found.
156    // Override with system properties.
157    static {
158        // Add props from the resource simplelog.properties
159        InputStream in = getResourceAsStream("simplelog.properties");
160        if(null != in) {
161            try {
162                simpleLogProps.load(in);
163                in.close();
164            } catch(java.io.IOException e) {
165                // ignored
166            }
167        }
168
169        showLogName = getBooleanProperty( systemPrefix + "showlogname", showLogName);
170        showShortName = getBooleanProperty( systemPrefix + "showShortLogname", showShortName);
171        showDateTime = getBooleanProperty( systemPrefix + "showdatetime", showDateTime);
172
173        if(showDateTime) {
174            dateTimeFormat = getStringProperty(systemPrefix + "dateTimeFormat",
175                                               dateTimeFormat);
176            try {
177                dateFormatter = new SimpleDateFormat(dateTimeFormat);
178            } catch(IllegalArgumentException e) {
179                // If the format pattern is invalid - use the default format
180                dateTimeFormat = DEFAULT_DATE_TIME_FORMAT;
181                dateFormatter = new SimpleDateFormat(dateTimeFormat);
182            }
183        }
184    }
185
186
187    // ------------------------------------------------------------- Attributes
188
189    /** The name of this simple log instance */
190    protected String logName = null;
191    /** The current log level */
192    protected int currentLogLevel;
193    /** The short name of this simple log instance */
194    private String shortLogName = null;
195
196
197    // ------------------------------------------------------------ Constructor
198
199    /**
200     * Construct a simple log with given name.
201     *
202     * @param name log name
203     */
204    public SimpleLog(String name) {
205
206        logName = name;
207
208        // Set initial log level
209        // Used to be: set default log level to ERROR
210        // IMHO it should be lower, but at least info ( costin ).
211        setLevel(SimpleLog.LOG_LEVEL_INFO);
212
213        // Set log level from properties
214        String lvl = getStringProperty(systemPrefix + "log." + logName);
215        int i = String.valueOf(name).lastIndexOf(".");
216        while(null == lvl && i > -1) {
217            name = name.substring(0,i);
218            lvl = getStringProperty(systemPrefix + "log." + name);
219            i = String.valueOf(name).lastIndexOf(".");
220        }
221
222        if(null == lvl) {
223            lvl =  getStringProperty(systemPrefix + "defaultlog");
224        }
225
226        if("all".equalsIgnoreCase(lvl)) {
227            setLevel(SimpleLog.LOG_LEVEL_ALL);
228        } else if("trace".equalsIgnoreCase(lvl)) {
229            setLevel(SimpleLog.LOG_LEVEL_TRACE);
230        } else if("debug".equalsIgnoreCase(lvl)) {
231            setLevel(SimpleLog.LOG_LEVEL_DEBUG);
232        } else if("info".equalsIgnoreCase(lvl)) {
233            setLevel(SimpleLog.LOG_LEVEL_INFO);
234        } else if("warn".equalsIgnoreCase(lvl)) {
235            setLevel(SimpleLog.LOG_LEVEL_WARN);
236        } else if("error".equalsIgnoreCase(lvl)) {
237            setLevel(SimpleLog.LOG_LEVEL_ERROR);
238        } else if("fatal".equalsIgnoreCase(lvl)) {
239            setLevel(SimpleLog.LOG_LEVEL_FATAL);
240        } else if("off".equalsIgnoreCase(lvl)) {
241            setLevel(SimpleLog.LOG_LEVEL_OFF);
242        }
243
244    }
245
246
247    // -------------------------------------------------------- Properties
248
249    /**
250     * <p> Set logging level. </p>
251     *
252     * @param currentLogLevel new logging level
253     */
254    public void setLevel(int currentLogLevel) {
255
256        this.currentLogLevel = currentLogLevel;
257
258    }
259
260
261    /**
262     * <p> Get logging level. </p>
263     */
264    public int getLevel() {
265
266        return currentLogLevel;
267    }
268
269
270    // -------------------------------------------------------- Logging Methods
271
272
273    /**
274     * <p> Do the actual logging.
275     * This method assembles the message
276     * and then calls <code>write()</code> to cause it to be written.</p>
277     *
278     * @param type One of the LOG_LEVEL_XXX constants defining the log level
279     * @param message The message itself (typically a String)
280     * @param t The exception whose stack trace should be logged
281     */
282    protected void log(int type, Object message, Throwable t) {
283        // Use a string buffer for better performance
284        StringBuffer buf = new StringBuffer();
285
286        // Append date-time if so configured
287        if(showDateTime) {
288            buf.append(dateFormatter.format(new Date()));
289            buf.append(" ");
290        }
291
292        // Append a readable representation of the log level
293        switch(type) {
294            case SimpleLog.LOG_LEVEL_TRACE: buf.append("[TRACE] "); break;
295            case SimpleLog.LOG_LEVEL_DEBUG: buf.append("[DEBUG] "); break;
296            case SimpleLog.LOG_LEVEL_INFO:  buf.append("[INFO] ");  break;
297            case SimpleLog.LOG_LEVEL_WARN:  buf.append("[WARN] ");  break;
298            case SimpleLog.LOG_LEVEL_ERROR: buf.append("[ERROR] "); break;
299            case SimpleLog.LOG_LEVEL_FATAL: buf.append("[FATAL] "); break;
300        }
301
302        // Append the name of the log instance if so configured
303 	if( showShortName) {
304            if( shortLogName==null ) {
305                // Cut all but the last component of the name for both styles
306                shortLogName = logName.substring(logName.lastIndexOf(".") + 1);
307                shortLogName =
308                    shortLogName.substring(shortLogName.lastIndexOf("/") + 1);
309            }
310            buf.append(String.valueOf(shortLogName)).append(" - ");
311        } else if(showLogName) {
312            buf.append(String.valueOf(logName)).append(" - ");
313        }
314
315        // Append the message
316        buf.append(String.valueOf(message));
317
318        // Append stack trace if not null
319        if(t != null) {
320            buf.append(" <");
321            buf.append(t.toString());
322            buf.append(">");
323
324            java.io.StringWriter sw= new java.io.StringWriter(1024);
325            java.io.PrintWriter pw= new java.io.PrintWriter(sw);
326            t.printStackTrace(pw);
327            pw.close();
328            buf.append(sw.toString());
329        }
330
331        // Print to the appropriate destination
332        write(buf);
333
334    }
335
336
337    /**
338     * <p>Write the content of the message accumulated in the specified
339     * <code>StringBuffer</code> to the appropriate output destination.  The
340     * default implementation writes to <code>System.err</code>.</p>
341     *
342     * @param buffer A <code>StringBuffer</code> containing the accumulated
343     *  text to be logged
344     */
345    protected void write(StringBuffer buffer) {
346
347        System.err.println(buffer.toString());
348
349    }
350
351
352    /**
353     * Is the given log level currently enabled?
354     *
355     * @param logLevel is this level enabled?
356     */
357    protected boolean isLevelEnabled(int logLevel) {
358        // log level are numerically ordered so can use simple numeric
359        // comparison
360        return (logLevel >= currentLogLevel);
361    }
362
363
364    // -------------------------------------------------------- Log Implementation
365
366
367    /**
368     * Logs a message with
369     * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG</code>.
370     *
371     * @param message to log
372     * @see org.apache.commons.logging.Log#debug(Object)
373     */
374    public final void debug(Object message) {
375
376        if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
377            log(SimpleLog.LOG_LEVEL_DEBUG, message, null);
378        }
379    }
380
381
382    /**
383     * Logs a message with
384     * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_DEBUG</code>.
385     *
386     * @param message to log
387     * @param t log this cause
388     * @see org.apache.commons.logging.Log#debug(Object, Throwable)
389     */
390    public final void debug(Object message, Throwable t) {
391
392        if (isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG)) {
393            log(SimpleLog.LOG_LEVEL_DEBUG, message, t);
394        }
395    }
396
397
398    /**
399     * Logs a message with
400     * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE</code>.
401     *
402     * @param message to log
403     * @see org.apache.commons.logging.Log#trace(Object)
404     */
405    public final void trace(Object message) {
406
407        if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
408            log(SimpleLog.LOG_LEVEL_TRACE, message, null);
409        }
410    }
411
412
413    /**
414     * Logs a message with
415     * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_TRACE</code>.
416     *
417     * @param message to log
418     * @param t log this cause
419     * @see org.apache.commons.logging.Log#trace(Object, Throwable)
420     */
421    public final void trace(Object message, Throwable t) {
422
423        if (isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE)) {
424            log(SimpleLog.LOG_LEVEL_TRACE, message, t);
425        }
426    }
427
428
429    /**
430     * Logs a message with
431     * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO</code>.
432     *
433     * @param message to log
434     * @see org.apache.commons.logging.Log#info(Object)
435     */
436    public final void info(Object message) {
437
438        if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
439            log(SimpleLog.LOG_LEVEL_INFO,message,null);
440        }
441    }
442
443
444    /**
445     * Logs a message with
446     * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_INFO</code>.
447     *
448     * @param message to log
449     * @param t log this cause
450     * @see org.apache.commons.logging.Log#info(Object, Throwable)
451     */
452    public final void info(Object message, Throwable t) {
453
454        if (isLevelEnabled(SimpleLog.LOG_LEVEL_INFO)) {
455            log(SimpleLog.LOG_LEVEL_INFO, message, t);
456        }
457    }
458
459
460    /**
461     * Logs a message with
462     * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN</code>.
463     *
464     * @param message to log
465     * @see org.apache.commons.logging.Log#warn(Object)
466     */
467    public final void warn(Object message) {
468
469        if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
470            log(SimpleLog.LOG_LEVEL_WARN, message, null);
471        }
472    }
473
474
475    /**
476     * Logs a message with
477     * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_WARN</code>.
478     *
479     * @param message to log
480     * @param t log this cause
481     * @see org.apache.commons.logging.Log#warn(Object, Throwable)
482     */
483    public final void warn(Object message, Throwable t) {
484
485        if (isLevelEnabled(SimpleLog.LOG_LEVEL_WARN)) {
486            log(SimpleLog.LOG_LEVEL_WARN, message, t);
487        }
488    }
489
490
491    /**
492     * Logs a message with
493     * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR</code>.
494     *
495     * @param message to log
496     * @see org.apache.commons.logging.Log#error(Object)
497     */
498    public final void error(Object message) {
499
500        if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
501            log(SimpleLog.LOG_LEVEL_ERROR, message, null);
502        }
503    }
504
505
506    /**
507     * Logs a message with
508     * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_ERROR</code>.
509     *
510     * @param message to log
511     * @param t log this cause
512     * @see org.apache.commons.logging.Log#error(Object, Throwable)
513     */
514    public final void error(Object message, Throwable t) {
515
516        if (isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR)) {
517            log(SimpleLog.LOG_LEVEL_ERROR, message, t);
518        }
519    }
520
521
522    /**
523     * Log a message with
524     * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL</code>.
525     *
526     * @param message to log
527     * @see org.apache.commons.logging.Log#fatal(Object)
528     */
529    public final void fatal(Object message) {
530
531        if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
532            log(SimpleLog.LOG_LEVEL_FATAL, message, null);
533        }
534    }
535
536
537    /**
538     * Logs a message with
539     * <code>org.apache.commons.logging.impl.SimpleLog.LOG_LEVEL_FATAL</code>.
540     *
541     * @param message to log
542     * @param t log this cause
543     * @see org.apache.commons.logging.Log#fatal(Object, Throwable)
544     */
545    public final void fatal(Object message, Throwable t) {
546
547        if (isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL)) {
548            log(SimpleLog.LOG_LEVEL_FATAL, message, t);
549        }
550    }
551
552
553    /**
554     * <p> Are debug messages currently enabled? </p>
555     *
556     * <p> This allows expensive operations such as <code>String</code>
557     * concatenation to be avoided when the message will be ignored by the
558     * logger. </p>
559     */
560    public final boolean isDebugEnabled() {
561
562        return isLevelEnabled(SimpleLog.LOG_LEVEL_DEBUG);
563    }
564
565
566    /**
567     * <p> Are error messages currently enabled? </p>
568     *
569     * <p> This allows expensive operations such as <code>String</code>
570     * concatenation to be avoided when the message will be ignored by the
571     * logger. </p>
572     */
573    public final boolean isErrorEnabled() {
574
575        return isLevelEnabled(SimpleLog.LOG_LEVEL_ERROR);
576    }
577
578
579    /**
580     * <p> Are fatal messages currently enabled? </p>
581     *
582     * <p> This allows expensive operations such as <code>String</code>
583     * concatenation to be avoided when the message will be ignored by the
584     * logger. </p>
585     */
586    public final boolean isFatalEnabled() {
587
588        return isLevelEnabled(SimpleLog.LOG_LEVEL_FATAL);
589    }
590
591
592    /**
593     * <p> Are info messages currently enabled? </p>
594     *
595     * <p> This allows expensive operations such as <code>String</code>
596     * concatenation to be avoided when the message will be ignored by the
597     * logger. </p>
598     */
599    public final boolean isInfoEnabled() {
600
601        return isLevelEnabled(SimpleLog.LOG_LEVEL_INFO);
602    }
603
604
605    /**
606     * <p> Are trace messages currently enabled? </p>
607     *
608     * <p> This allows expensive operations such as <code>String</code>
609     * concatenation to be avoided when the message will be ignored by the
610     * logger. </p>
611     */
612    public final boolean isTraceEnabled() {
613
614        return isLevelEnabled(SimpleLog.LOG_LEVEL_TRACE);
615    }
616
617
618    /**
619     * <p> Are warn messages currently enabled? </p>
620     *
621     * <p> This allows expensive operations such as <code>String</code>
622     * concatenation to be avoided when the message will be ignored by the
623     * logger. </p>
624     */
625    public final boolean isWarnEnabled() {
626
627        return isLevelEnabled(SimpleLog.LOG_LEVEL_WARN);
628    }
629
630
631    /**
632     * Return the thread context class loader if available.
633     * Otherwise return null.
634     *
635     * The thread context class loader is available for JDK 1.2
636     * or later, if certain security conditions are met.
637     *
638     * @exception LogConfigurationException if a suitable class loader
639     * cannot be identified.
640     */
641    private static ClassLoader getContextClassLoader()
642    {
643        ClassLoader classLoader = null;
644
645        if (classLoader == null) {
646            try {
647                // Are we running on a JDK 1.2 or later system?
648                Method method = Thread.class.getMethod("getContextClassLoader",
649                        (Class[]) null);
650
651                // Get the thread context class loader (if there is one)
652                try {
653                    classLoader = (ClassLoader)method.invoke(Thread.currentThread(),
654                            (Object[]) null);
655
656                } catch (IllegalAccessException e) {
657                    ;  // ignore
658                } catch (InvocationTargetException e) {
659                    /**
660                     * InvocationTargetException is thrown by 'invoke' when
661                     * the method being invoked (getContextClassLoader) throws
662                     * an exception.
663                     *
664                     * getContextClassLoader() throws SecurityException when
665                     * the context class loader isn't an ancestor of the
666                     * calling class's class loader, or if security
667                     * permissions are restricted.
668                     *
669                     * In the first case (not related), we want to ignore and
670                     * keep going.  We cannot help but also ignore the second
671                     * with the logic below, but other calls elsewhere (to
672                     * obtain a class loader) will trigger this exception where
673                     * we can make a distinction.
674                     */
675                    if (e.getTargetException() instanceof SecurityException) {
676                        ;  // ignore
677                    } else {
678                        // Capture 'e.getTargetException()' exception for details
679                        // alternate: log 'e.getTargetException()', and pass back 'e'.
680                        throw new LogConfigurationException
681                            ("Unexpected InvocationTargetException", e.getTargetException());
682                    }
683                }
684            } catch (NoSuchMethodException e) {
685                // Assume we are running on JDK 1.1
686                ;  // ignore
687            }
688        }
689
690        if (classLoader == null) {
691            classLoader = SimpleLog.class.getClassLoader();
692        }
693
694        // Return the selected class loader
695        return classLoader;
696    }
697
698    private static InputStream getResourceAsStream(final String name)
699    {
700        return (InputStream)AccessController.doPrivileged(
701            new PrivilegedAction() {
702                public Object run() {
703                    ClassLoader threadCL = getContextClassLoader();
704
705                    if (threadCL != null) {
706                        return threadCL.getResourceAsStream(name);
707                    } else {
708                        return ClassLoader.getSystemResourceAsStream(name);
709                    }
710                }
711            });
712    }
713}
714
715