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