View Javadoc

1   // ========================================================================
2   // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses.
12  // ========================================================================
13  
14  package org.eclipse.jetty.util.log;
15  
16  import java.security.AccessControlException;
17  import java.util.concurrent.ConcurrentHashMap;
18  import java.util.concurrent.ConcurrentMap;
19  
20  import org.eclipse.jetty.util.DateCache;
21  
22  /**
23   * StdErr Logging. This implementation of the Logging facade sends all logs to
24   * StdErr with minimal formatting.
25   * <p>
26   * If the system property "org.eclipse.jetty.util.log.DEBUG" is set, then debug
27   * logs are printed if stderr is being used. For named debuggers, the system 
28   * property name+".DEBUG" is checked. If it is not not set, then 
29   * "org.eclipse.jetty.util.log.DEBUG" is used as the default.
30   * <p>
31   * If the system property "org.eclipse.jetty.util.log.SOURCE" is set, then the
32   * source method/file of a log is logged. For named debuggers, the system 
33   * property name+".SOURCE" is checked. If it is not not set, then 
34   * "org.eclipse.jetty.util.log.SOURCE" is used as the default.
35   * 
36   */
37  public class StdErrLog implements Logger
38  {
39      private static DateCache _dateCache;
40  
41      private final static boolean __debug = Boolean.parseBoolean(
42              System.getProperty("org.eclipse.jetty.util.log.DEBUG",
43                      System.getProperty("org.eclipse.jetty.util.log.stderr.DEBUG", "false")));
44      private final static boolean __source = Boolean.parseBoolean(
45              System.getProperty("org.eclipse.jetty.util.log.SOURCE",
46                      System.getProperty("org.eclipse.jetty.util.log.stderr.SOURCE", "false")));
47  
48      private final static ConcurrentMap<String,StdErrLog> __loggers = new ConcurrentHashMap<String, StdErrLog>();
49      
50      static
51      {
52          try
53          {
54              _dateCache = new DateCache("yyyy-MM-dd HH:mm:ss");
55          }
56          catch (Exception x)
57          {
58              x.printStackTrace();
59          }
60      }
61  
62      private boolean _debug = __debug;
63      private boolean _source = __source;
64      private final String _name;
65      private boolean _hideStacks = false;
66  
67      public StdErrLog()
68      {
69          this(null);
70      }
71  
72      public StdErrLog(String name)
73      {
74          this._name = name == null ? "" : name;
75  
76          try
77          {
78              _debug = Boolean.parseBoolean(System.getProperty(_name + ".DEBUG", Boolean.toString(_debug)));
79          }
80          catch (AccessControlException ace)
81          {
82              _debug = __debug;
83          }
84          
85          try
86          {
87              _source = Boolean.parseBoolean(System.getProperty(_name + ".SOURCE", Boolean.toString(_source)));
88          }
89          catch (AccessControlException ace)
90          {
91              _source = __source;
92          }
93      }
94  
95      public String getName()
96      {
97          return _name;
98      }
99  
100     public boolean isHideStacks()
101     {
102         return _hideStacks;
103     }
104 
105     public void setHideStacks(boolean hideStacks)
106     {
107         _hideStacks = hideStacks;
108     }
109 
110     /* ------------------------------------------------------------ */
111     /** Is the source of a log, logged
112      * @return true if the class, method, file and line number of a log is logged.
113      */
114     public boolean isSource()
115     {
116         return _source;
117     }
118 
119     /* ------------------------------------------------------------ */
120     /** Set if a log source is logged.
121      * @param source true if the class, method, file and line number of a log is logged.
122      */
123     public void setSource(boolean source)
124     {
125         _source = source;
126     }
127 
128     public void warn(String msg, Object... args)
129     {
130         StringBuilder buffer = new StringBuilder(64);
131         format(buffer, ":WARN:", msg, args);
132         System.err.println(buffer);
133     }
134 
135     public void warn(Throwable thrown)
136     {
137         warn("", thrown);
138     }
139 
140     public void warn(String msg, Throwable thrown)
141     {
142         StringBuilder buffer = new StringBuilder(64);
143         format(buffer, ":WARN:", msg, thrown);
144         System.err.println(buffer);
145     }
146 
147     public void info(String msg, Object... args)
148     {
149         StringBuilder buffer = new StringBuilder(64);
150         format(buffer, ":INFO:", msg, args);
151         System.err.println(buffer);
152     }
153 
154     public void info(Throwable thrown)
155     {
156         info("", thrown);
157     }
158 
159     public void info(String msg, Throwable thrown)
160     {
161         StringBuilder buffer = new StringBuilder(64);
162         format(buffer, ":INFO:", msg, thrown);
163         System.err.println(buffer);
164     }
165 
166     public boolean isDebugEnabled()
167     {
168         return _debug;
169     }
170 
171     public void setDebugEnabled(boolean enabled)
172     {
173         _debug = enabled;
174     }
175 
176     public void debug(String msg, Object... args)
177     {
178         if (!_debug)
179             return;
180         StringBuilder buffer = new StringBuilder(64);
181         format(buffer, ":DBUG:", msg, args);
182         System.err.println(buffer);
183     }
184 
185     public void debug(Throwable thrown)
186     {
187         debug("", thrown);
188     }
189 
190     public void debug(String msg, Throwable thrown)
191     {
192         if (!_debug)
193             return;
194         StringBuilder buffer = new StringBuilder(64);
195         format(buffer, ":DBUG:", msg, thrown);
196         System.err.println(buffer);
197     }
198 
199     private void format(StringBuilder buffer, String level, String msg, Object... args)
200     {
201         String d = _dateCache.now();
202         int ms = _dateCache.lastMs();
203         tag(buffer, d, ms, level);
204         format(buffer, msg, args);
205     }
206 
207     private void format(StringBuilder buffer, String level, String msg, Throwable thrown)
208     {
209         format(buffer, level, msg);
210         if (isHideStacks())
211             format(buffer, String.valueOf(thrown));
212         else
213             format(buffer, thrown);
214     }
215 
216     private void tag(StringBuilder buffer, String d, int ms, String tag)
217     {
218         buffer.setLength(0);
219         buffer.append(d);
220         if (ms > 99)
221             buffer.append('.');
222         else if (ms > 9)
223             buffer.append(".0");
224         else
225             buffer.append(".00");
226         buffer.append(ms).append(tag).append(_name).append(':');
227         if (_source)
228         {
229             Throwable source = new Throwable();
230             StackTraceElement[] frames =  source.getStackTrace();
231             for (int i=0;i<frames.length;i++)
232             {
233                 final StackTraceElement frame = frames[i];
234                 String clazz = frame.getClassName();
235                 if (clazz.equals(StdErrLog.class.getName())|| clazz.equals(Log.class.getName()))
236                     continue;
237                 if (clazz.startsWith("org.eclipse.jetty."))
238                     buffer.append("o.e.j.").append(clazz,18,clazz.length());
239                 else
240                     buffer.append(clazz);
241                 buffer.append('#').append(frame.getMethodName());
242                 if (frame.getFileName()!=null)
243                     buffer.append('(').append(frame.getFileName()).append(':').append(frame.getLineNumber()).append(')');
244                 buffer.append(':');
245                 break;
246             }
247         }
248     }
249 
250     private void format(StringBuilder builder, String msg, Object... args)
251     {
252         msg = String.valueOf(msg); // Avoids NPE
253         String braces = "{}";
254         int start = 0;
255         for (Object arg : args)
256         {
257             int bracesIndex = msg.indexOf(braces, start);
258             if (bracesIndex < 0)
259             {
260                 escape(builder, msg.substring(start));
261                 builder.append(" ");
262                 builder.append(arg);
263                 start = msg.length();
264             }
265             else
266             {
267                 escape(builder, msg.substring(start, bracesIndex));
268                 builder.append(String.valueOf(arg));
269                 start = bracesIndex + braces.length();
270             }
271         }
272         escape(builder, msg.substring(start));
273     }
274 
275     private void escape(StringBuilder builder, String string)
276     {
277         for (int i = 0; i < string.length(); ++i)
278         {
279             char c = string.charAt(i);
280             if (Character.isISOControl(c))
281             {
282                 if (c == '\n')
283                     builder.append('|');
284                 else if (c == '\r')
285                     builder.append('<');
286                 else
287                     builder.append('?');
288             }
289             else
290                 builder.append(c);
291         }
292     }
293 
294     private void format(StringBuilder buffer, Throwable thrown)
295     {
296         if (thrown == null)
297         {
298             buffer.append("null");
299         }
300         else
301         {
302             buffer.append('\n');
303             format(buffer, thrown.toString());
304             StackTraceElement[] elements = thrown.getStackTrace();
305             for (int i = 0; elements != null && i < elements.length; i++)
306             {
307                 buffer.append("\n\tat ");
308                 format(buffer, elements[i].toString());
309             }
310             
311             Throwable cause = thrown.getCause();
312             if (cause!=null && cause!=thrown)
313             {
314                 buffer.append("\nCaused by: ");
315                 format(buffer,cause);
316             }
317         }
318     }
319 
320     public Logger getLogger(String name)
321     {
322         String fullname=_name == null || _name.length() == 0?name:_name + "." + name;
323         
324         if ((name == null && this._name == null) || fullname.equals(_name))
325             return this;
326         
327         StdErrLog logger = __loggers.get(name);
328         if (logger==null)
329         {
330             StdErrLog sel=new StdErrLog(fullname);
331             logger=__loggers.putIfAbsent(fullname,sel);
332             if (logger==null)
333                 logger=sel;
334         }
335         
336         return logger;
337     }
338 
339     @Override
340     public String toString()
341     {
342         return "StdErrLog:" + _name + ":DEBUG=" + _debug;
343     }
344 
345     public void ignore(Throwable ignored)
346     {
347         if (Log.isIgnored())
348         {
349             warn(Log.IGNORED, ignored);
350         }
351     }
352 }