PageRenderTime 77ms CodeModel.GetById 53ms app.highlight 20ms RepoModel.GetById 0ms app.codeStats 1ms

/jEdit/tags/jedit-4-1-pre5/org/gjt/sp/util/Log.java

#
Java | 356 lines | 219 code | 36 blank | 101 comment | 29 complexity | 79ef69ab4e8baf70cc836d715d601caa MD5 | raw file
  1/*
  2 * Log.java - A class for logging events
  3 * Copyright (C) 1999, 2000 Slava Pestov
  4 *
  5 * This program is free software; you can redistribute it and/or
  6 * modify it under the terms of the GNU General Public License
  7 * as published by the Free Software Foundation; either version 2
  8 * of the License, or any later version.
  9 *
 10 * This program is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13 * GNU General Public License for more details.
 14 *
 15 * You should have received a copy of the GNU General Public License
 16 * along with this program; if not, write to the Free Software
 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 18 */
 19
 20package org.gjt.sp.util;
 21
 22import javax.swing.text.*;
 23import java.io.*;
 24import java.util.StringTokenizer;
 25
 26/**
 27 * This class provides methods for logging events. It has the same
 28 * purpose as System.out.println() and such, but more powerful.
 29 * All events are logged to a Swing document and optionally a stream,
 30 * and those with a high urgency (warnings and errors) are also printed
 31 * to the standard error stream. This class can also optionally redirect
 32 * standard output and error to the log.
 33 * @author Slava Pestov
 34 * @version $Id: Log.java 3945 2001-12-25 03:06:50Z spestov $
 35 */
 36public class Log
 37{
 38	/**
 39	 * The maximum number of log messages that will be kept in memory.
 40	 * @since jEdit 2.6pre5
 41	 */
 42	public static final int MAXLINES = 500;
 43
 44	/**
 45	 * Debugging message urgency. Should be used for messages only
 46	 * useful when debugging a problem.
 47	 * @since jEdit 2.2pre2
 48	 */
 49	public static final int DEBUG = 1;
 50
 51	/**
 52	 * Message urgency. Should be used for messages which give more
 53	 * detail than notices.
 54	 * @since jEdit 2.2pre2
 55	 */
 56	public static final int MESSAGE = 3;
 57
 58	/**
 59	 * Notice urgency. Should be used for messages that directly
 60	 * affect the user.
 61	 * @since jEdit 2.2pre2
 62	 */
 63	public static final int NOTICE = 5;
 64
 65	/**
 66	 * Warning urgency. Should be used for messages that warrant
 67	 * attention.
 68	 * @since jEdit 2.2pre2
 69	 */
 70	public static final int WARNING = 7;
 71
 72	/**
 73	 * Error urgency. Should be used for messages that signal a
 74	 * failure.
 75	 * @since jEdit 2.2pre2
 76	 */
 77	public static final int ERROR = 9;
 78
 79	/**
 80	 * Initializes the log.
 81	 * @param stdio If true, standard output and error will be
 82	 * sent to the log
 83	 * @param level Messages with this log level or higher will
 84	 * be printed to the system console
 85	 * @param stream The stream to save log data to
 86	 * @since jEdit 3.2pre4
 87	 */
 88	public static void init(boolean stdio, int level)
 89	{
 90		if(stdio)
 91		{
 92			if(System.out == realOut && System.err == realErr)
 93			{
 94				System.setOut(createPrintStream(NOTICE,null));
 95				System.setErr(createPrintStream(ERROR,null));
 96			}
 97		}
 98
 99		Log.level = level;
100
101		// Log some stuff
102		log(MESSAGE,Log.class,"When reporting bugs, please"
103			+ " include the following information:");
104		String[] props = {
105			"java.version", "java.vm.version", "java.runtime.version",
106			"java.vendor", "java.compiler", "os.name", "os.version",
107			"os.arch", "user.home", "java.home",
108			"java.class.path",
109			};
110		for(int i = 0; i < props.length; i++)
111		{
112			log(MESSAGE,Log.class,
113				props[i] + "=" + System.getProperty(props[i]));
114		}
115	}
116
117	/**
118	 * Writes all currently logged messages to this stream if there was no
119	 * stream set previously, and sets the stream to write future log
120	 * messages to.
121	 * @param stream The writer
122	 * @since jEdit 3.2pre4
123	 */
124	public static void setLogWriter(Writer stream)
125	{
126		if(Log.stream == null && stream != null)
127		{
128			try
129			{
130				stream.write(logDocument.getText(0,
131					logDocument.getLength()));
132
133				stream.flush();
134			}
135			catch(Exception e)
136			{
137				// do nothing, who cares
138			}
139		}
140
141		Log.stream = stream;
142	}
143
144	/**
145	 * Returns the document where the most recent messages are stored.
146	 * The document of a Swing text area can be set to this to graphically
147	 * view log messages.
148	 * @since jEdit 2.2pre2
149	 */
150	public static Document getLogDocument()
151	{
152		return logDocument;
153	}
154
155	/**
156	 * Flushes the log stream.
157	 * @since jEdit 2.6pre5
158	 */
159	public static void flushStream()
160	{
161		if(stream != null)
162		{
163			try
164			{
165				stream.flush();
166			}
167			catch(IOException io)
168			{
169				io.printStackTrace(realErr);
170			}
171		}
172	}
173
174	/**
175	 * Closes the log stream. Should be done before your program exits.
176	 * @since jEdit 2.6pre5
177	 */
178	public static void closeStream()
179	{
180		if(stream != null)
181		{
182			try
183			{
184				stream.close();
185				stream = null;
186			}
187			catch(IOException io)
188			{
189				io.printStackTrace(realErr);
190			}
191		}
192	}
193
194	/**
195	 * Logs a message. This method is threadsafe.
196	 * @param urgency The urgency
197	 * @param source The object that logged this message.
198	 * @param message The message. This can either be a string or
199	 * an exception
200	 *
201	 * @since jEdit 2.2pre2
202	 */
203	public static void log(int urgency, Object source, Object message)
204	{
205		String _source;
206		if(source == null)
207		{
208			_source = Thread.currentThread().getName();
209			if(_source == null)
210			{
211				_source = Thread.currentThread().getClass().getName();
212			}
213		}
214		else if(source instanceof Class)
215			_source = ((Class)source).getName();
216		else
217			_source = source.getClass().getName();
218		int index = _source.lastIndexOf('.');
219		if(index != -1)
220			_source = _source.substring(index+1);
221
222		if(message instanceof Throwable)
223		{
224			_logException(urgency,source,(Throwable)message);
225		}
226		else
227		{
228			String _message = String.valueOf(message);
229			// If multiple threads log stuff, we don't want
230			// the output to get mixed up
231			synchronized(LOCK)
232			{
233				StringTokenizer st = new StringTokenizer(
234					_message,"\r\n");
235				while(st.hasMoreTokens())
236				{
237					_log(urgency,_source,st.nextToken());
238				}
239			}
240		}
241	}
242
243	// private members
244	private static Object LOCK = new Object();
245	private static Document logDocument;
246	private static int level = WARNING;
247	private static Writer stream;
248	private static String lineSep;
249	private static PrintStream realOut;
250	private static PrintStream realErr;
251
252	static
253	{
254		level = WARNING;
255
256		realOut = System.out;
257		realErr = System.err;
258
259		logDocument = new PlainDocument();
260		lineSep = System.getProperty("line.separator");
261	}
262
263	private static PrintStream createPrintStream(final int urgency,
264		final Object source)
265	{
266		return new PrintStream(new OutputStream() {
267			public void write(int b)
268			{
269				byte[] barray = { (byte)b };
270				write(barray,0,1);
271			}
272
273			public void write(byte[] b, int off, int len)
274			{
275				String str = new String(b,off,len);
276				log(urgency,source,str);
277			}
278		});
279	}
280
281	private static void _logException(final int urgency,
282		final Object source,
283		final Throwable message)
284	{
285		PrintStream out = createPrintStream(urgency,source);
286
287		synchronized(LOCK)
288		{
289			message.printStackTrace(out);
290		}
291	}
292
293	private static void _log(int urgency, String source, String message)
294	{
295		String urgencyString = "[" + urgencyToString(urgency) + "] ";
296
297		String fullMessage = urgencyString + source + ": " + message;
298
299		try
300		{
301			logDocument.insertString(logDocument.getLength(),
302				fullMessage,null);
303			logDocument.insertString(logDocument.getLength(),
304				"\n",null);
305
306			Element map = logDocument.getDefaultRootElement();
307			int lines = map.getElementCount();
308			if(lines > MAXLINES)
309			{
310				Element first = map.getElement(0);
311				Element last = map.getElement(lines - MAXLINES);
312				logDocument.remove(first.getStartOffset(),
313					last.getEndOffset());
314			}
315
316			if(stream != null)
317			{
318				stream.write(fullMessage);
319				stream.write(lineSep);
320			}
321		}
322		catch(Exception e)
323		{
324			e.printStackTrace(realErr);
325		}
326
327		message = urgencyString +  message + '\n';
328
329		if(urgency >= level)
330		{
331			if(urgency == ERROR)
332				realErr.print(message);
333			else
334				realOut.print(message);
335		}
336	}
337
338	private static String urgencyToString(int urgency)
339	{
340		switch(urgency)
341		{
342		case DEBUG:
343			return "debug";
344		case MESSAGE:
345			return "message";
346		case NOTICE:
347			return "notice";
348		case WARNING:
349			return "warning";
350		case ERROR:
351			return "error";
352		}
353
354		throw new IllegalArgumentException("Invalid urgency: " + urgency);
355	}
356}