1 package net.sf.logdistiller.logtypes;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import java.io.*;
18 import java.text.SimpleDateFormat;
19 import java.text.DateFormat;
20 import java.text.ParseException;
21 import java.util.Date;
22
23 import org.apache.commons.lang.StringUtils;
24
25 import net.sf.logdistiller.LogEvent;
26 import net.sf.logdistiller.LogType;
27 import net.sf.logdistiller.util.LogEventBuilder;
28 import net.sf.logdistiller.util.StringCutter;
29
30
31
32
33
34 public class Log4jXmlLogEvent
35 extends LogEvent
36 implements Comparable<Log4jXmlLogEvent>
37 {
38 public final static String ID = "log4j-XML";
39
40 public final String logger;
41
42 public final String timestamp;
43
44 public final String datetime;
45
46 public final long timestampValue;
47
48 public final String level;
49
50 public final String thread;
51
52 public final String message;
53
54 public final String ndc;
55
56 public final String throwable;
57
58 public final String locationInfoClass;
59
60 public final String locationInfoMethod;
61
62 public final String locationInfoFile;
63
64 public final String locationInfoLine;
65
66 public final static LogType LOGTYPE = new LogType.Basic( ID );
67
68 private final static DateFormat DATE_FORMAT = new SimpleDateFormat( "dd/MM/yyyy HH:mm:ss" );
69
70 private final static String LOGEVENT_START = "<log4j:event logger=\"";
71
72 private final static String[] ATTRIBUTE_NAMES =
73 { "logSource", "datetime", "timestamp", "level", "logger", "thread", "message", "NDC", "throwable",
74 "locationInfo.class", "locationInfo.method", "locationInfo.file", "locationInfo.line" };
75
76 public final static LogType.Description DESCRIPTION = new Description( (LogType.Basic) LOGTYPE, ATTRIBUTE_NAMES );
77
78 public Log4jXmlLogEvent( LogEvent.Factory factory, String rawLog )
79 throws ParseException
80 {
81 super( factory, rawLog );
82 StringCutter cutter = new StringCutter( rawLog );
83 cutter.parseTo( LOGEVENT_START );
84 logger = cutter.parseTo( "\" timestamp=\"" );
85 timestamp = cutter.parseTo( "\" level=\"" );
86 timestampValue = Long.parseLong( timestamp );
87 datetime = DATE_FORMAT.format( new Date( timestampValue ) );
88 level = cutter.parseTo( "\" thread=\"" );
89 thread = cutter.parseTo( "\">" );
90 cutter.parseTo( "<log4j:message><![CDATA[" );
91 message = unescapeCDATA( cutter.parseTo( "]]></log4j:message>" ) );
92
93 String remaining = cutter.getRemaining();
94 if ( remaining.indexOf( "<log4j:NDC>" ) < 0 )
95 {
96 ndc = "";
97 }
98 else
99 {
100 cutter.parseTo( "<log4j:NDC><![CDATA[" );
101 ndc = unescapeCDATA( cutter.parseTo( "]]></log4j:NDC>" ) );
102 remaining = cutter.getRemaining();
103 }
104 if ( remaining.indexOf( "<log4j:throwable>" ) < 0 )
105 {
106 throwable = "";
107 }
108 else
109 {
110 cutter.parseTo( "<log4j:throwable><![CDATA[" );
111 throwable = unescapeCDATA( cutter.parseTo( "]]></log4j:throwable>" ) );
112 remaining = cutter.getRemaining();
113 }
114 if ( remaining.indexOf( "<log4j:locationInfo" ) < 0 )
115 {
116 locationInfoClass = "";
117 locationInfoMethod = "";
118 locationInfoFile = "";
119 locationInfoLine = "";
120 }
121 else
122 {
123 cutter.parseTo( "<log4j:locationInfo class=\"" );
124 locationInfoClass = cutter.parseTo( "\" method=\"" );
125 locationInfoMethod = cutter.parseTo( "\" file=\"" );
126 locationInfoFile = cutter.parseTo( "\" line=\"" );
127 locationInfoLine = cutter.parseTo( "\"/>" );
128 }
129 setAttributes( new String[] { factory.getLogSource(), datetime, timestamp, level, logger, thread, message, ndc,
130 throwable, locationInfoClass, locationInfoMethod, locationInfoFile, locationInfoLine } );
131 }
132
133 public static String unescapeCDATA( String cdata )
134 {
135 return StringUtils.replace( cdata, "]]>]]><![CDATA[", "]]>" );
136 }
137
138 public int compareTo( Log4jXmlLogEvent o )
139 {
140 long diff = timestampValue - o.timestampValue;
141 return ( diff < 0 ) ? -1 : ( diff > 0 ) ? 1 : 0;
142 }
143
144 private static class Description
145 extends LogType.Description
146 {
147 public Description( LogType.Basic logtype, String[] attributeNames )
148 {
149 super( logtype, attributeNames );
150 logtype.setDescription( this );
151 }
152
153 public LogEvent.Factory newFactory( Reader reader, String logSource )
154 throws IOException
155 {
156 return new Factory( this, reader, logSource );
157 }
158
159 public String getDefaultSpecificGroups()
160 {
161 return " <group id=\"warn\">\n"
162 + " <description>WARN events</description>\n"
163 + " <condition>\n"
164 + " <match attribute=\"level\" type=\"equals\">WARN</match>\n"
165 + " </condition>\n"
166 + " <report publisher=\"file\"/>\n"
167 + " <plugin type=\"sampling\">\n"
168 + " <param name=\"attributes\">logger</param>\n"
169 + " </plugin>\n"
170 + " </group>\n"
171 + "\n"
172 + " <group id=\"error\">\n"
173 + " <description>ERROR events</description>\n"
174 + " <condition>\n"
175 + " <match attribute=\"level\" type=\"equals\">ERROR</match>\n"
176 + " </condition>\n"
177 + " <report publisher=\"file\"/>\n"
178 + " <plugin type=\"sampling\">\n"
179 + " <param name=\"attributes\">logger</param>\n"
180 + " </plugin>\n"
181 + " </group>";
182 }
183
184 public String getDefaultSamplingAttributes()
185 {
186 return "level,logger";
187 }
188 }
189
190 private static class Factory
191 extends LogEvent.Factory
192 {
193 private final LineNumberReader reader;
194
195 private String curLine;
196
197 public Factory( Description description, Reader reader, String logSource )
198 throws FileNotFoundException
199 {
200 super( description, logSource );
201 this.reader = new LineNumberReader( reader );
202 }
203
204 protected boolean detectLogEventStart( String line )
205 {
206 return line.startsWith( LOGEVENT_START );
207 }
208
209 protected LogEvent readNextEvent()
210 throws IOException, ParseException
211 {
212 if ( curLine == null )
213 {
214 curLine = reader.readLine();
215 if ( curLine == null )
216 {
217
218 return null;
219 }
220 }
221 if ( !detectLogEventStart( curLine ) )
222 {
223 throw new ParseException(
224 "bad log format, beginnig of line " + reader.getLineNumber() + ": " + curLine,
225 0 );
226 }
227 StringBuffer buffer = new StringBuffer( curLine );
228 int lineNumber = reader.getLineNumber();
229
230 while ( ( ( curLine = reader.readLine() ) != null ) && ( !detectLogEventStart( curLine ) ) )
231 {
232 buffer.append( "\r\n" );
233 buffer.append( curLine );
234 }
235 return BUILDER.buildLogEvent( this, lineNumber, buffer.toString() );
236 }
237
238 private final static LogEventBuilder BUILDER = new LogEventBuilder()
239 {
240 protected LogEvent newEvent( LogEvent.Factory factory, String curLine, Object... objects )
241 throws ParseException
242 {
243 return new Log4jXmlLogEvent( factory, curLine );
244 }
245 };
246 }
247 }