1   // ========================================================================
2   // Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
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   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14  
15  package org.mortbay.log;
16  import java.lang.reflect.Method;
17  
18  import org.mortbay.util.Loader;
19  
20  
21  
22  /*-----------------------------------------------------------------------*/
23  /** Logging.
24   * This class provides a static logging interface.  If an instance of the 
25   * org.slf4j.Logger class is found on the classpath, the static log methods
26   * are directed to a slf4j logger for "org.mortbay.log".   Otherwise the logs
27   * are directed to stderr.
28   * 
29   * If the system property VERBOSE is set, then ignored exceptions are logged in detail.
30   * 
31   */
32  public class Log 
33  {    
34      private static final String[] __nestedEx =
35          {"getTargetException","getTargetError","getException","getRootCause"};
36      /*-------------------------------------------------------------------*/
37      private static final Class[] __noArgs=new Class[0];
38      public final static String EXCEPTION= "EXCEPTION ";
39      public final static String IGNORED= "IGNORED";
40      public final static String IGNORED_FMT= "IGNORED: {}";
41      public final static String NOT_IMPLEMENTED= "NOT IMPLEMENTED ";
42      
43      private static String __logClass=System.getProperty("org.mortbay.log.class","org.mortbay.log.Slf4jLog");
44      private static boolean __verbose = System.getProperty("VERBOSE",null)!=null;
45      private static boolean __ignored = System.getProperty("IGNORED",null)!=null;
46      private static Logger __log;
47     
48      private static boolean _initialized;
49      
50      public static boolean initialized()
51      {
52          if (__log!=null)
53              return true;
54          
55          synchronized (Log.class)
56          {
57              if (_initialized)
58                  return __log!=null;
59              _initialized=true;
60          }
61          
62          Class log_class=null;
63          try
64          {
65              log_class=Loader.loadClass(Log.class, __logClass);
66              if (__log==null || !__log.getClass().equals(log_class))
67              {
68                  __log=(Logger) log_class.newInstance();
69                  __log.info("Logging to {} via {}",__log,log_class.getName());
70              }
71          }
72          catch(Exception e)
73          {
74              if (__log==null)
75              {
76                  log_class=StdErrLog.class;
77                  __log=new StdErrLog();
78                  __log.info("Logging to {} via {}",__log,log_class.getName());
79                  if(__verbose)
80                      e.printStackTrace();
81              }
82          }
83  
84          return __log!=null;
85      }
86      
87      public static void setLog(Logger log)
88      {
89          Log.__log=log;
90      }
91      
92      public static Logger getLog()
93      {
94          initialized();
95          return __log;
96      }
97  
98      
99      /**
100      * Set Log to parent Logger.
101      * <p>
102      * If there is a different Log class available from a parent classloader,
103      * call {@link #getLogger(String)} on it and construct a {@link LoggerLog} instance
104      * as this Log's Logger, so that logging is delegated to the parent Log.
105      * <p>
106      * This should be used if a webapp is using Log, but wishes the logging to be 
107      * directed to the containers log.
108      * <p>
109      * If there is not parent Log, then this call is equivalent to<pre>
110      *   Log.setLog(Log.getLogger(name));
111      * </pre> 
112      * @param name Logger name
113      */
114     public static void setLogToParent(String name)
115     {
116         ClassLoader loader = Log.class.getClassLoader();
117         if (loader.getParent()!=null)
118         {
119             try
120             {
121                 Class<?> uberlog = loader.getParent().loadClass("org.mortbay.log.Log");
122                 Method getLogger=uberlog.getMethod("getLogger",new Class[]{String.class});
123                 Object logger = getLogger.invoke(null,name);
124                 setLog(new LoggerLog(logger));
125                 return;
126             }
127             catch (Exception e)
128             {
129                 e.printStackTrace();
130             }     
131         }
132             
133         setLog(getLogger(name));
134     }
135     
136     public static void debug(Throwable th)
137     {        
138         if (!isDebugEnabled())
139             return;
140         __log.debug(EXCEPTION,th);
141         unwind(th);
142     }
143 
144     public static void debug(String msg)
145     {
146         if (!initialized())
147             return;
148         
149         __log.debug(msg,null,null);
150     }
151     
152     public static void debug(String msg,Object arg)
153     {
154         if (!initialized())
155             return;
156         __log.debug(msg,arg,null);
157     }
158     
159     public static void debug(String msg,Object arg0, Object arg1)
160     {
161         if (!initialized())
162             return;
163         __log.debug(msg,arg0,arg1);
164     }
165     
166     /* ------------------------------------------------------------ */
167     /**
168      * Ignore an exception unless trace is enabled.
169      * This works around the problem that log4j does not support the trace level.
170      */
171     public static void ignore(Throwable th)
172     {
173         if (!initialized())
174             return;
175         if (__ignored)
176         {
177             __log.warn(IGNORED,th);
178             unwind(th);
179         }
180         else if (__verbose)
181         {
182             __log.warn(IGNORED,th);
183             unwind(th);
184         }
185     }
186     
187     public static void info(String msg)
188     {
189         if (!initialized())
190             return;
191         __log.info(msg,null,null);
192     }
193     
194     public static void info(String msg,Object arg)
195     {
196         if (!initialized())
197             return;
198         __log.info(msg,arg,null);
199     }
200     
201     public static void info(String msg,Object arg0, Object arg1)
202     {
203         if (!initialized())
204             return;
205         __log.info(msg,arg0,arg1);
206     }
207     
208     public static boolean isDebugEnabled()
209     {
210         if (!initialized())
211             return false;
212         return __log.isDebugEnabled();
213     }
214     
215     public static void warn(String msg)
216     {
217         if (!initialized())
218             return;
219         __log.warn(msg,null,null);
220     }
221     
222     public static void warn(String msg,Object arg)
223     {
224         if (!initialized())
225             return;
226         __log.warn(msg,arg,null);        
227     }
228     
229     public static void warn(String msg,Object arg0, Object arg1)
230     {
231         if (!initialized())
232             return;
233         __log.warn(msg,arg0,arg1);        
234     }
235     
236     public static void warn(String msg, Throwable th)
237     {
238         if (!initialized())
239             return;
240         __log.warn(msg,th);
241         unwind(th);
242     }
243 
244     public static void warn(Throwable th)
245     {
246         if (!initialized())
247             return;
248         __log.warn(EXCEPTION,th);
249         unwind(th);
250     }
251 
252     /** Obtain a named Logger.
253      * Obtain a named Logger or the default Logger if null is passed.
254      */
255     public static Logger getLogger(String name)
256     {
257         if (!initialized())
258             return null;
259         
260         if (name==null)
261           return __log;
262         return __log.getLogger(name);
263     }
264 
265     private static void unwind(Throwable th)
266     {
267         if (th==null)
268             return;
269         for (int i=0;i<__nestedEx.length;i++)
270         {
271             try
272             {
273                 Method get_target = th.getClass().getMethod(__nestedEx[i],__noArgs);
274                 Throwable th2=(Throwable)get_target.invoke(th,(Object[])null);
275                 if (th2!=null && th2!=th)
276                     warn("Nested in "+th+":",th2);
277             }
278             catch(Exception ignore){}
279         }
280     }
281     
282 
283 }
284