KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > util > monolog > wrapper > javaLog > MonologFormatter


1 /**
2  * Copyright (C) 2001-2003 France Telecom R&D
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18 package org.objectweb.util.monolog.wrapper.javaLog;
19
20 import org.objectweb.util.monolog.file.api.Pattern;
21 import org.objectweb.util.monolog.wrapper.common.AbstractFactory;
22
23 import java.util.logging.Formatter JavaDoc;
24 import java.util.logging.LogRecord JavaDoc;
25 import java.util.StringTokenizer JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Calendar JavaDoc;
29 import java.util.Date JavaDoc;
30 import java.io.StringWriter JavaDoc;
31 import java.io.PrintWriter JavaDoc;
32
33 /**
34  * The goal of this class is to format a LogRecord with regard to a pattern.
35  * In order to support support additional logging layer on top monolog, this
36  * class permits to specify package name or class names of its own logging layer.
37  * By default the org.apache.commons.logging package is included. To specify
38  * the list of names you have to assign the system property 'monolog.wrappers'
39  * with a list (separated with commas or white spaces) of your names.
40  *
41  * @author S.Chassande-Barrioz
42  */

43 public class MonologFormatter extends Formatter JavaDoc {
44
45     public final static String JavaDoc WRAPPERS_PROPERTY = "monolog.wrappers";
46
47     /**
48      * Number of items to get back in stack trace to see the caller
49      */

50     private static final int STACK_TRACE_ITEMS = 9;
51
52     private static String JavaDoc[] LOGWRAPPER = {
53         "org.objectweb.util.monolog.wrapper",
54         "org.apache.commons.logging"
55     };
56
57     static {
58         String JavaDoc wrap = System.getProperty(WRAPPERS_PROPERTY);
59         if (wrap != null) {
60             ArrayList JavaDoc ws = new ArrayList JavaDoc(5);
61             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(wrap,",;: /", false);
62             while (st.hasMoreTokens()) {
63                 ws.add(st.nextToken());
64             }
65             String JavaDoc[] wsa = new String JavaDoc[LOGWRAPPER.length + ws.size()];
66             System.arraycopy(LOGWRAPPER, 0, wsa, 0, LOGWRAPPER.length);
67             for(int i=0; i<ws.size(); i++) {
68                 wsa[LOGWRAPPER.length + i] = (String JavaDoc) ws.get(i);
69             }
70             LOGWRAPPER = wsa;
71         }
72     }
73
74     private final static int PATTERN_ID_LEVEL = -100;
75     private final static int PATTERN_ID_TOPIC = -200;
76     private final static int PATTERN_ID_DATE = -300;
77     private final static int PATTERN_ID_THREAD = -400;
78     private final static int PATTERN_ID_MESSAGE = -500;
79     private final static int PATTERN_ID_METHOD = -600;
80     private final static int PATTERN_ID_OBJECT = -700;
81     private final static int PATTERN_ID_LINE_NUMBER = -800;
82     private final static int PATTERN_ID_NEW_LINE = -900;
83     private final static int PATTERN_ID_INTERVAL = 100;
84
85     private final static String JavaDoc TOKENS =
86             "{}"
87             + Pattern.LEVEL
88             + Pattern.TOPIC
89             + Pattern.DATE
90             + Pattern.THREAD
91             + Pattern.MESSAGE
92             + Pattern.METHOD
93             + Pattern.OBJECT
94             + Pattern.LINE_NUMBER
95             + Pattern.PREFIX
96             + Pattern.NEW_LINE;
97
98     private final static String JavaDoc patternIdToString(int id) {
99         switch(id) {
100         case PATTERN_ID_LEVEL: return "" + Pattern.LEVEL;
101         case PATTERN_ID_TOPIC: return "" + Pattern.TOPIC;
102         case PATTERN_ID_DATE: return "" + Pattern.DATE;
103         case PATTERN_ID_THREAD: return "" + Pattern.THREAD;
104         case PATTERN_ID_MESSAGE: return "" + Pattern.MESSAGE;
105         case PATTERN_ID_METHOD: return "" + Pattern.METHOD;
106         case PATTERN_ID_OBJECT: return "" + Pattern.OBJECT;
107         case PATTERN_ID_LINE_NUMBER: return "" + Pattern.LINE_NUMBER;
108         case PATTERN_ID_NEW_LINE: return "" + Pattern.NEW_LINE;
109         default:
110             return null;
111         }
112     }
113
114
115     Calendar JavaDoc calendar;
116
117     private static long previousTime;
118
119     private static char[] previousTimeWithoutMillis = new char[20]; // "YYYY-MM-DD HH:mm:ss."
120

121
122     /**
123      * the pattern in the string format (user value)
124      */

125     String JavaDoc strPattern;
126
127     /**
128      * An array of pattern id representing the user pattern
129      */

130     int[] pattern;
131
132     /**
133      * An array of String used into the pattern
134      */

135     String JavaDoc[] strings;
136
137     public MonologFormatter() {
138         calendar = Calendar.getInstance();
139     }
140
141     public MonologFormatter(String JavaDoc strPattern) {
142         this();
143         setPattern(strPattern);
144     }
145
146
147     public String JavaDoc getPattern() {
148         return strPattern;
149     }
150
151     public void setPattern(String JavaDoc p) {
152         if (AbstractFactory.debug) {
153             AbstractFactory.debug("Pattern=" + p);
154         }
155         this.strPattern = p;
156         if (strPattern == null) {
157             pattern = new int[0];
158         } else {
159             StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(p, TOKENS, true);
160             ArrayList JavaDoc sections = new ArrayList JavaDoc();
161             boolean isPrefix = false;
162             boolean isObject = false;
163             boolean isInSubObject = false;
164             int subObjectNumber = 1;
165             while (st.hasMoreElements()) {
166                 String JavaDoc token = st.nextToken();
167                 if (AbstractFactory.debug) {
168                     AbstractFactory.debug("token=<" + token + ">");
169                 }
170                 if (isObject && token.equals("{")) {
171                     isInSubObject = true;
172                     isObject = false;
173                 }
174                 if (token.length() == 1) {
175                     char c = token.charAt(0);
176                     switch (c) {
177                     case '{':
178                         if (!isInSubObject) {
179                             addSection(sections, token);
180                         }
181                         break;
182                     case '}':
183                         if (isInSubObject) {
184                             int old = ((Integer JavaDoc) sections.get(sections.size() - 1)).intValue();
185                             sections.set(sections.size() - 1,
186                                     new Integer JavaDoc(old - subObjectNumber));
187                             isInSubObject = false;
188                         } else {
189                             addSection(sections, token);
190                         }
191                         break;
192                     case Pattern.PREFIX:
193                         if (isPrefix) {
194                             sections.add(String.valueOf(Pattern.PREFIX));
195                         }
196                         isPrefix = !isPrefix;
197                         break;
198                     case Pattern.LEVEL:
199                         isPrefix = treatPattern(
200                                 sections, token, PATTERN_ID_LEVEL, isPrefix);
201                         break;
202                     case Pattern.TOPIC:
203                         isPrefix = treatPattern(
204                                 sections, token, PATTERN_ID_TOPIC, isPrefix);
205                         break;
206                     case Pattern.DATE:
207                         isPrefix = treatPattern(
208                                 sections, token, PATTERN_ID_DATE, isPrefix);
209                         break;
210                     case Pattern.THREAD:
211                         isPrefix = treatPattern(
212                                 sections, token, PATTERN_ID_THREAD, isPrefix);
213                         break;
214                     case Pattern.MESSAGE:
215                         isPrefix = treatPattern(
216                                 sections, token, PATTERN_ID_MESSAGE, isPrefix);
217                         break;
218                     case Pattern.METHOD:
219                         isPrefix = treatPattern(
220                                 sections, token, PATTERN_ID_METHOD, isPrefix);
221                         break;
222                     case Pattern.OBJECT:
223                         isPrefix = treatPattern(
224                                 sections, token, PATTERN_ID_OBJECT, isPrefix);
225                         isObject = true;
226                         break;
227                     case Pattern.LINE_NUMBER:
228                         isPrefix = treatPattern(
229                                 sections, token, PATTERN_ID_LINE_NUMBER, isPrefix);
230                         break;
231                     case Pattern.NEW_LINE:
232                         isPrefix = treatPattern(
233                                 sections, token, PATTERN_ID_NEW_LINE, isPrefix);
234                         break;
235                     default:
236                         if (isInSubObject) {
237                             subObjectNumber = Integer.parseInt(token);
238                         } else {
239                             addSection(sections, token);
240                         }
241                         break;
242                     }
243                 } else if (isObject) {
244                     //Ignore
245
} else if (isInSubObject) {
246                     subObjectNumber = Integer.parseInt(token);
247                 } else {
248                     addSection(sections, token);
249                 }
250             }
251             pattern = new int[sections.size()];
252             if (AbstractFactory.debug) {
253                 AbstractFactory.debug("building pattern array...");
254                 AbstractFactory.debug("nb of pattern:" + pattern.length);
255             }
256             ArrayList JavaDoc stringList = new ArrayList JavaDoc(sections.size());
257             int cpt = 0;
258             for (int i = 0; i < pattern.length; i++) {
259                 Object JavaDoc o = sections.get(i);
260                 if (o instanceof String JavaDoc) {
261                     if (AbstractFactory.debug) {
262                         AbstractFactory.debug("add current pattern into strings: [" + cpt + ", " + o + "]");
263                     }
264                     stringList.add(o);
265                     pattern[i] = cpt;
266                     cpt++;
267                 } else if (o instanceof Integer JavaDoc) {
268                     if (AbstractFactory.debug) {
269                         AbstractFactory.debug("add current pattern as negative number:" + o);
270                     }
271                     pattern[i] = ((Integer JavaDoc) o).intValue();
272                 }
273             }
274             strings = (String JavaDoc[]) stringList.toArray(new String JavaDoc[cpt]);
275             if (AbstractFactory.debug) {
276                 AbstractFactory.debug("nb of string:" + strings.length);
277             }
278         }
279     }
280
281     private boolean treatPattern(List JavaDoc sections,
282                                  String JavaDoc token,
283                                  int tokenId,
284                                  boolean isPrefix) {
285         if (AbstractFactory.debug) {
286             AbstractFactory.debug("treatPttern(" + tokenId + "):"
287                     + " isPrefix=" + isPrefix
288                     + " token=" + token
289                     + " sections=" + sections
290                 );
291         }
292         if (isPrefix) {
293             sections.add(new Integer JavaDoc(tokenId));
294             return false;
295         } else {
296             addSection(sections, token);
297             return isPrefix;
298         }
299     }
300
301     private void addSection(List JavaDoc sections, String JavaDoc s) {
302         int size = sections.size();
303         if (size == 0) {
304             if (AbstractFactory.debug) {
305                 AbstractFactory.debug("addSection(" + s + ", " + sections + "): first elem");
306             }
307             sections.add(s);
308         } else {
309             Object JavaDoc last = sections.get(size - 1);
310             if (last instanceof String JavaDoc) {
311                 sections.set(size - 1, last + s);
312                 if (AbstractFactory.debug) {
313                     AbstractFactory.debug("addSection(" + s + ", " + sections + "): concat: " + sections.get(size - 1));
314                 }
315             } else {
316                 if (AbstractFactory.debug) {
317                     AbstractFactory.debug("addSection(" + s + ", " + sections + "): new elem");
318                 }
319                 sections.add(s);
320             }
321         }
322     }
323
324     /**
325      * Format the given log record and return the formatted string.
326      * <p>
327      * The resulting formatted String will normally include a
328      * localized and formated version of the LogRecord's message field.
329      * The Formatter.formatMessage convenience method can (optionally)
330      * be used to localize and format the message field.
331      *
332      * @param record the log record to be formatted.
333      * @return the formatted log record
334      */

335     public String JavaDoc format(LogRecord JavaDoc record) {
336         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
337         String JavaDoc[] ctx = null;
338         for (int i = 0; i < pattern.length; i++) {
339             int p = pattern[i];
340             if (AbstractFactory.debug) {
341                 AbstractFactory.debug("format: pattern=" + p + "=" + patternIdToString(p));
342             }
343             switch (p) {
344             case PATTERN_ID_LEVEL:
345                 sb.append(record.getLevel().getName());
346                 break;
347             case PATTERN_ID_TOPIC:
348                 sb.append(record.getLoggerName());
349                 break;
350             case PATTERN_ID_DATE:
351                 format(new Date JavaDoc(record.getMillis()), sb);
352                 break;
353             case PATTERN_ID_THREAD:
354                 sb.append(Thread.currentThread().getName());
355                 break;
356             case PATTERN_ID_MESSAGE:
357                 sb.append(record.getMessage());
358                 break;
359             case PATTERN_ID_METHOD:
360                 if (ctx == null) {
361                     ctx = getContext();
362                 }
363                 sb.append(ctx[1]);
364                 break;
365             case PATTERN_ID_OBJECT:
366                 if (ctx == null) {
367                     ctx = getContext();
368                 }
369                 sb.append(ctx[0]);
370                 break;
371             case PATTERN_ID_LINE_NUMBER:
372                 if (ctx == null) {
373                     ctx = getContext();
374                 }
375                 sb.append(ctx[2]);
376                 break;
377             case PATTERN_ID_NEW_LINE:
378                 sb.append("\n");
379                 break;
380             default:
381                 if (p < 0) {
382                     if (ctx == null) {
383                         ctx = getContext();
384                     }
385                     if (p > (PATTERN_ID_OBJECT - PATTERN_ID_INTERVAL)
386                             && p<PATTERN_ID_OBJECT) {
387                         p = PATTERN_ID_OBJECT - p;
388                         String JavaDoc res = ctx[0];
389                         if (p == 1) {// optimize the usual case
390
int idx = res.lastIndexOf('.');
391                             if (idx != -1) {
392                                 res = res.substring(idx + 1);
393                             }
394                         } else if (p == 0) {
395                             //Nothing to do
396
} else {
397                             int idx = res.lastIndexOf('.');
398                             for(;p>1 && idx != -1;p--) {
399                                 if (idx != -1) {
400                                     idx = res.lastIndexOf('.', idx - 1);
401                                 }
402                             }
403                             if (idx != -1) {
404                                 res = res.substring(idx + 1);
405                             }
406                         }
407                         sb.append(res);
408                     }
409                 } else if (p >= strings.length) {
410                     System.err.println("ERROR: String identifier unknown: " + p);
411                 } else {
412                     sb.append(strings[p]);
413                 }
414             }
415         }
416         if (record.getThrown() != null) {
417             StringWriter JavaDoc sw = new StringWriter JavaDoc();
418             record.getThrown().printStackTrace(new PrintWriter JavaDoc(sw));
419             sb.append(sw.getBuffer());
420         }
421         return sb.toString();
422     }
423
424     /**
425      * Calculate the class name, the method name and the line number of the
426      * logger user.
427      * @return a string array containing 3 String
428      * [ "classname", "method name", "line number"]
429      * ex: ["com.foo.Bar", "myMethod", "512"]
430      */

431     public static String JavaDoc[] getContext() {
432
433         Throwable JavaDoc t = new Throwable JavaDoc().fillInStackTrace();
434         StringWriter JavaDoc sw = new StringWriter JavaDoc();
435         t.printStackTrace(new PrintWriter JavaDoc(sw));
436         String JavaDoc m = sw.getBuffer().toString();
437         int fin = 0;
438         int deb = 0;
439         // remove monolog methods from the stack trace
440
for (int i = 0; i < STACK_TRACE_ITEMS; i++) {
441             deb = m.indexOf("\n", deb) + 1;
442         }
443         boolean isWrapper = true;
444         deb = m.indexOf("at ", deb) + 3;
445         while (isWrapper) {
446             isWrapper = false;
447             for (int i=0; i<LOGWRAPPER.length && !isWrapper; i++) {
448                 isWrapper |= m.startsWith(LOGWRAPPER[i], deb);
449             }
450             if (isWrapper) {
451                 deb = m.indexOf("at ", deb) + 3;
452             }
453         }
454         fin = m.indexOf("\n", deb);
455         m = m.substring(deb, fin);
456
457         //m = %C.%M(Toto.java:%L)
458
deb = m.indexOf("(");
459         fin = m.indexOf(":");
460         String JavaDoc[] res = new String JavaDoc[3];
461         res[2] = (fin == -1 ? "unknown" : m.substring(fin + 1, m.length() - 1));
462         m = m.substring(0, deb);
463
464         //m = %C.%M
465
fin = m.lastIndexOf('.');
466         res[0] = m.substring(0, fin);
467         res[1] = m.substring(fin + 1);
468         return res;
469     }
470
471     /**
472      Appends to <code>sbuf</code> the time in the format
473      "YYYY-MM-DD HH:mm:ss,SSS" for example, "2004-04-28 15:49:37,459"
474
475      @param date the date to format
476      @param sbuf the string buffer to write to
477      */

478     public void format(Date JavaDoc date, StringBuffer JavaDoc sbuf) {
479         long now = date.getTime();
480         int millis = (int) (now % 1000);
481
482         if ((now - millis) != previousTime) {
483             // We reach this point at most once per second
484
// across all threads instead of each time format()
485
// is called. This saves considerable CPU time.
486

487             calendar.setTime(date);
488
489             int start = sbuf.length();
490
491             int year = calendar.get(Calendar.YEAR);
492             sbuf.append(year);
493             sbuf.append('-');
494             int month = calendar.get(Calendar.MONTH);
495             month++;
496             if (month < 10) {
497                 sbuf.append('0');
498             }
499             sbuf.append(month);
500             sbuf.append('-');
501             int day = calendar.get(Calendar.DAY_OF_MONTH);
502             if (day < 10) {
503                 sbuf.append('0');
504             }
505             sbuf.append(day);
506
507             sbuf.append(' ');
508
509             int hour = calendar.get(Calendar.HOUR_OF_DAY);
510             if (hour < 10) {
511                 sbuf.append('0');
512             }
513             sbuf.append(hour);
514             sbuf.append(':');
515
516             int mins = calendar.get(Calendar.MINUTE);
517             if (mins < 10) {
518                 sbuf.append('0');
519             }
520             sbuf.append(mins);
521             sbuf.append(':');
522
523             int secs = calendar.get(Calendar.SECOND);
524             if (secs < 10) {
525                 sbuf.append('0');
526             }
527             sbuf.append(secs);
528             sbuf.append(',');
529
530             // store the time string for next time to avoid recomputation
531
sbuf.getChars(start, sbuf.length(), previousTimeWithoutMillis, 0);
532
533             previousTime = now - millis;
534         } else {
535             sbuf.append(previousTimeWithoutMillis);
536         }
537         if (millis < 100) {
538             sbuf.append('0');
539         }
540         if (millis < 10) {
541             sbuf.append('0');
542         }
543         sbuf.append(millis);
544     }
545
546     public String JavaDoc format(String JavaDoc msg, String JavaDoc levelName, String JavaDoc topic, long time) {
547         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
548         String JavaDoc[] ctx = null;
549         for (int i = 0; i < pattern.length; i++) {
550             int p = pattern[i];
551             if (AbstractFactory.debug) {
552                 AbstractFactory.debug("format: pattern=" + p + "=" + patternIdToString(p));
553             }
554             switch (p) {
555             case PATTERN_ID_LEVEL:
556                 sb.append(levelName);
557                 break;
558             case PATTERN_ID_TOPIC:
559                 sb.append(topic);
560                 break;
561             case PATTERN_ID_DATE:
562                 format(new Date JavaDoc(time), sb);
563                 break;
564             case PATTERN_ID_THREAD:
565                 sb.append(Thread.currentThread().getName());
566                 break;
567             case PATTERN_ID_MESSAGE:
568                 sb.append(msg);
569                 break;
570             case PATTERN_ID_METHOD:
571                 if (ctx == null) {
572                     ctx = getContext();
573                 }
574                 sb.append(ctx[1]);
575                 break;
576             case PATTERN_ID_OBJECT:
577                 if (ctx == null) {
578                     ctx = getContext();
579                 }
580                 sb.append(ctx[0]);
581                 break;
582             case PATTERN_ID_LINE_NUMBER:
583                 if (ctx == null) {
584                     ctx = getContext();
585                 }
586                 sb.append(ctx[2]);
587                 break;
588             case PATTERN_ID_NEW_LINE:
589                 sb.append("\n");
590                 break;
591             default:
592                 if (p < 0) {
593                     if (ctx == null) {
594                         ctx = getContext();
595                     }
596                     if (p > (PATTERN_ID_OBJECT - PATTERN_ID_INTERVAL)
597                             && p<PATTERN_ID_OBJECT) {
598                         p = PATTERN_ID_OBJECT - p;
599                         String JavaDoc res = ctx[0];
600                         if (p == 1) {// optimize the usual case
601
int idx = res.lastIndexOf('.');
602                             if (idx != -1) {
603                                 res = res.substring(idx + 1);
604                             }
605                         } else if (p == 0) {
606                             //Nothing to do
607
} else {
608                             int idx = res.lastIndexOf('.');
609                             for(;p>1 && idx != -1;p--) {
610                                 if (idx != -1) {
611                                     idx = res.lastIndexOf('.', idx - 1);
612                                 }
613                             }
614                             if (idx != -1) {
615                                 res = res.substring(idx + 1);
616                             }
617                         }
618                         sb.append(res);
619                     }
620                 } else if (p >= strings.length) {
621                     System.err.println("ERROR: String identifier unknown: " + p);
622                 } else {
623                     sb.append(strings[p]);
624                 }
625             }
626         }
627         return sb.toString();
628     }
629
630 }
Popular Tags