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