View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.log4j.lf5.util;
18  
19  import java.io.BufferedInputStream;
20  import java.io.File;
21  import java.io.FileInputStream;
22  import java.io.FileNotFoundException;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.text.ParseException;
26  import java.text.SimpleDateFormat;
27  import java.util.Date;
28  
29  import javax.swing.SwingUtilities;
30  
31  import org.apache.log4j.lf5.Log4JLogRecord;
32  import org.apache.log4j.lf5.LogLevel;
33  import org.apache.log4j.lf5.LogLevelFormatException;
34  import org.apache.log4j.lf5.LogRecord;
35  import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
36  import org.apache.log4j.lf5.viewer.LogFactor5ErrorDialog;
37  import org.apache.log4j.lf5.viewer.LogFactor5LoadingDialog;
38  
39  /**
40   * Provides utility methods for input and output streams.
41   *
42   * @author Brad Marlborough
43   * @author Richard Hurst
44   */
45  
46  // Contributed by ThoughtWorks Inc.
47  
48  public class LogFileParser implements Runnable {
49    //--------------------------------------------------------------------------
50    //   Constants:
51    //--------------------------------------------------------------------------
52    public static final String RECORD_DELIMITER = "[slf5s.start]";
53    public static final String ATTRIBUTE_DELIMITER = "[slf5s.";
54    public static final String DATE_DELIMITER = ATTRIBUTE_DELIMITER + "DATE]";
55    public static final String THREAD_DELIMITER = ATTRIBUTE_DELIMITER + "THREAD]";
56    public static final String CATEGORY_DELIMITER = ATTRIBUTE_DELIMITER + "CATEGORY]";
57    public static final String LOCATION_DELIMITER = ATTRIBUTE_DELIMITER + "LOCATION]";
58    public static final String MESSAGE_DELIMITER = ATTRIBUTE_DELIMITER + "MESSAGE]";
59    public static final String PRIORITY_DELIMITER = ATTRIBUTE_DELIMITER + "PRIORITY]";
60    public static final String NDC_DELIMITER = ATTRIBUTE_DELIMITER + "NDC]";
61  
62    //--------------------------------------------------------------------------
63    //   Protected Variables:
64    //--------------------------------------------------------------------------
65  
66    //--------------------------------------------------------------------------
67    //   Private Variables:
68    //--------------------------------------------------------------------------
69    private static SimpleDateFormat _sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss,S");
70    private LogBrokerMonitor _monitor;
71    LogFactor5LoadingDialog _loadDialog;
72    private InputStream _in = null;
73  
74    //--------------------------------------------------------------------------
75    //   Constructors:
76    //--------------------------------------------------------------------------
77    public LogFileParser(File file) throws IOException,
78        FileNotFoundException {
79      this(new FileInputStream(file));
80    }
81  
82    public LogFileParser(InputStream stream) throws IOException {
83      _in = stream;
84    }
85    //--------------------------------------------------------------------------
86    //   Public Methods:
87    //--------------------------------------------------------------------------
88  
89    /**
90     * Starts a new thread to parse the log file and create a LogRecord.
91     * See run().
92     * @param monitor LogBrokerMonitor
93     */
94    public void parse(LogBrokerMonitor monitor) throws RuntimeException {
95      _monitor = monitor;
96      Thread t = new Thread(this);
97      t.start();
98    }
99  
100   /**
101    * Parses the file and creates new log records and adds the record
102    * to the monitor.
103    */
104   public void run() {
105 
106     int index = 0;
107     int counter = 0;
108     LogRecord temp;
109     boolean isLogFile = false;
110 
111     _loadDialog = new LogFactor5LoadingDialog(
112         _monitor.getBaseFrame(), "Loading file...");
113 
114 
115     try {
116       String logRecords = loadLogFile(_in);
117 
118       while ((counter = logRecords.indexOf(RECORD_DELIMITER, index)) != -1) {
119         temp = createLogRecord(logRecords.substring(index, counter));
120         isLogFile = true;
121 
122         if (temp != null) {
123           _monitor.addMessage(temp);
124         }
125 
126         index = counter + RECORD_DELIMITER.length();
127       }
128 
129       if (index < logRecords.length() && isLogFile) {
130         temp = createLogRecord(logRecords.substring(index));
131 
132         if (temp != null) {
133           _monitor.addMessage(temp);
134         }
135       }
136 
137       if (isLogFile == false) {
138         throw new RuntimeException("Invalid log file format");
139       }
140       SwingUtilities.invokeLater(new Runnable() {
141         public void run() {
142           destroyDialog();
143         }
144       });
145 
146     } catch (RuntimeException e) {
147       destroyDialog();
148       displayError("Error - Invalid log file format.\nPlease see documentation"
149           + " on how to load log files.");
150     } catch (IOException e) {
151       destroyDialog();
152       displayError("Error - Unable to load log file!");
153     }
154 
155     _in = null;
156   }
157 
158   //--------------------------------------------------------------------------
159   //   Protected Methods:
160   //--------------------------------------------------------------------------
161   protected void displayError(String message) {
162     LogFactor5ErrorDialog error = new LogFactor5ErrorDialog(
163         _monitor.getBaseFrame(), message);
164 
165   }
166 
167   //--------------------------------------------------------------------------
168   //   Private Methods:
169   //--------------------------------------------------------------------------
170   private void destroyDialog() {
171     _loadDialog.hide();
172     _loadDialog.dispose();
173   }
174 
175   /**
176    * Loads a log file from a web server into the LogFactor5 GUI.
177    */
178   private String loadLogFile(InputStream stream) throws IOException {
179     BufferedInputStream br = new BufferedInputStream(stream);
180 
181     int count = 0;
182     int size = br.available();
183 
184     StringBuffer sb = null;
185     if (size > 0) {
186       sb = new StringBuffer(size);
187     } else {
188       sb = new StringBuffer(1024);
189     }
190 
191     while ((count = br.read()) != -1) {
192       sb.append((char) count);
193     }
194 
195     br.close();
196     br = null;
197     return sb.toString();
198 
199   }
200 
201   private String parseAttribute(String name, String record) {
202 
203     int index = record.indexOf(name);
204 
205     if (index == -1) {
206       return null;
207     }
208 
209     return getAttribute(index, record);
210   }
211 
212   private long parseDate(String record) {
213     try {
214       String s = parseAttribute(DATE_DELIMITER, record);
215 
216       if (s == null) {
217         return 0;
218       }
219 
220       Date d = _sdf.parse(s);
221 
222       return d.getTime();
223     } catch (ParseException e) {
224       return 0;
225     }
226   }
227 
228   private LogLevel parsePriority(String record) {
229     String temp = parseAttribute(PRIORITY_DELIMITER, record);
230 
231     if (temp != null) {
232       try {
233         return LogLevel.valueOf(temp);
234       } catch (LogLevelFormatException e) {
235         return LogLevel.DEBUG;
236       }
237 
238     }
239 
240     return LogLevel.DEBUG;
241   }
242 
243   private String parseThread(String record) {
244     return parseAttribute(THREAD_DELIMITER, record);
245   }
246 
247   private String parseCategory(String record) {
248     return parseAttribute(CATEGORY_DELIMITER, record);
249   }
250 
251   private String parseLocation(String record) {
252     return parseAttribute(LOCATION_DELIMITER, record);
253   }
254 
255   private String parseMessage(String record) {
256     return parseAttribute(MESSAGE_DELIMITER, record);
257   }
258 
259   private String parseNDC(String record) {
260     return parseAttribute(NDC_DELIMITER, record);
261   }
262 
263   private String parseThrowable(String record) {
264     return getAttribute(record.length(), record);
265   }
266 
267   private LogRecord createLogRecord(String record) {
268     if (record == null || record.trim().length() == 0) {
269       return null;
270     }
271 
272     LogRecord lr = new Log4JLogRecord();
273     lr.setMillis(parseDate(record));
274     lr.setLevel(parsePriority(record));
275     lr.setCategory(parseCategory(record));
276     lr.setLocation(parseLocation(record));
277     lr.setThreadDescription(parseThread(record));
278     lr.setNDC(parseNDC(record));
279     lr.setMessage(parseMessage(record));
280     lr.setThrownStackTrace(parseThrowable(record));
281 
282     return lr;
283   }
284 
285 
286   private String getAttribute(int index, String record) {
287     int start = record.lastIndexOf(ATTRIBUTE_DELIMITER, index - 1);
288 
289     if (start == -1) {
290       return record.substring(0, index);
291     }
292 
293     start = record.indexOf("]", start);
294 
295     return record.substring(start + 1, index).trim();
296   }
297   //--------------------------------------------------------------------------
298   //   Nested Top-Level Classes or Interfaces
299   //--------------------------------------------------------------------------
300 
301 }