PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/util/Log.java

#
Java | 496 lines | 315 code | 44 blank | 137 comment | 43 complexity | 85a081bfa92e5a48117e2706fbe78ca1 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * Log.java - A class for logging events
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2003 Slava Pestov
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package org.gjt.sp.util;
  23. import java.io.*;
  24. import java.util.*;
  25. import javax.swing.*;
  26. import javax.swing.event.*;
  27. /**
  28. * This class provides methods for logging events. In terms of functionality,
  29. * it is somewhere in between <code>System.out.println()</code> and
  30. * full-blown logging packages such as log4j.<p>
  31. *
  32. * All events are logged to an in-memory buffer and optionally a stream,
  33. * and those with a high urgency (warnings and errors) are also printed
  34. * to standard output.<p>
  35. *
  36. * Logging of exception tracebacks is supported.<p>
  37. *
  38. * This class can also optionally redirect standard output and error to the log.
  39. *
  40. * @author Slava Pestov
  41. * @version $Id: Log.java 5004 2004-03-28 00:07:27Z spestov $
  42. */
  43. public class Log
  44. {
  45. //{{{ Constants
  46. /**
  47. * The maximum number of log messages that will be kept in memory.
  48. * @since jEdit 2.6pre5
  49. */
  50. public static final int MAXLINES = 500;
  51. /**
  52. * Debugging message urgency. Should be used for messages only
  53. * useful when debugging a problem.
  54. * @since jEdit 2.2pre2
  55. */
  56. public static final int DEBUG = 1;
  57. /**
  58. * Message urgency. Should be used for messages which give more
  59. * detail than notices.
  60. * @since jEdit 2.2pre2
  61. */
  62. public static final int MESSAGE = 3;
  63. /**
  64. * Notice urgency. Should be used for messages that directly
  65. * affect the user.
  66. * @since jEdit 2.2pre2
  67. */
  68. public static final int NOTICE = 5;
  69. /**
  70. * Warning urgency. Should be used for messages that warrant
  71. * attention.
  72. * @since jEdit 2.2pre2
  73. */
  74. public static final int WARNING = 7;
  75. /**
  76. * Error urgency. Should be used for messages that signal a
  77. * failure.
  78. * @since jEdit 2.2pre2
  79. */
  80. public static final int ERROR = 9;
  81. //}}}
  82. //{{{ init() method
  83. /**
  84. * Initializes the log.
  85. * @param stdio If true, standard output and error will be
  86. * sent to the log
  87. * @param level Messages with this log level or higher will
  88. * be printed to the system console
  89. * @since jEdit 3.2pre4
  90. */
  91. public static void init(boolean stdio, int level)
  92. {
  93. if(stdio)
  94. {
  95. if(System.out == realOut && System.err == realErr)
  96. {
  97. System.setOut(createPrintStream(NOTICE,null));
  98. System.setErr(createPrintStream(ERROR,null));
  99. }
  100. }
  101. Log.level = level;
  102. // Log some stuff
  103. log(MESSAGE,Log.class,"When reporting bugs, please"
  104. + " include the following information:");
  105. String[] props = {
  106. "java.version", "java.vm.version", "java.runtime.version",
  107. "java.vendor", "java.compiler", "os.name", "os.version",
  108. "os.arch", "user.home", "java.home",
  109. "java.class.path",
  110. };
  111. for(int i = 0; i < props.length; i++)
  112. {
  113. log(MESSAGE,Log.class,
  114. props[i] + "=" + System.getProperty(props[i]));
  115. }
  116. } //}}}
  117. //{{{ setLogWriter() method
  118. /**
  119. * Writes all currently logged messages to this stream if there was no
  120. * stream set previously, and sets the stream to write future log
  121. * messages to.
  122. * @param stream The writer
  123. * @since jEdit 3.2pre4
  124. */
  125. public static void setLogWriter(Writer stream)
  126. {
  127. if(Log.stream == null && stream != null)
  128. {
  129. try
  130. {
  131. if(wrap)
  132. {
  133. for(int i = logLineCount; i < log.length; i++)
  134. {
  135. stream.write(log[i]);
  136. stream.write(lineSep);
  137. }
  138. }
  139. for(int i = 0; i < logLineCount; i++)
  140. {
  141. stream.write(log[i]);
  142. stream.write(lineSep);
  143. }
  144. stream.flush();
  145. }
  146. catch(Exception e)
  147. {
  148. // do nothing, who cares
  149. }
  150. }
  151. Log.stream = stream;
  152. } //}}}
  153. //{{{ flushStream() method
  154. /**
  155. * Flushes the log stream.
  156. * @since jEdit 2.6pre5
  157. */
  158. public static void flushStream()
  159. {
  160. if(stream != null)
  161. {
  162. try
  163. {
  164. stream.flush();
  165. }
  166. catch(IOException io)
  167. {
  168. io.printStackTrace(realErr);
  169. }
  170. }
  171. } //}}}
  172. //{{{ closeStream() method
  173. /**
  174. * Closes the log stream. Should be done before your program exits.
  175. * @since jEdit 2.6pre5
  176. */
  177. public static void closeStream()
  178. {
  179. if(stream != null)
  180. {
  181. try
  182. {
  183. stream.close();
  184. stream = null;
  185. }
  186. catch(IOException io)
  187. {
  188. io.printStackTrace(realErr);
  189. }
  190. }
  191. } //}}}
  192. //{{{ getLogListModel() method
  193. /**
  194. * Returns the list model for viewing the log contents.
  195. * @since jEdit 4.2pre1
  196. */
  197. public static ListModel getLogListModel()
  198. {
  199. return listModel;
  200. } //}}}
  201. //{{{ log() method
  202. /**
  203. * Logs a message. This method is thread-safe.<p>
  204. *
  205. * The following code sends a typical debugging message to the activity
  206. * log:
  207. * <pre>Log.log(Log.DEBUG,this,"counter = " + counter);</pre>
  208. * The corresponding activity log entry might read as follows:
  209. * <pre>[debug] JavaParser: counter = 15</pre>
  210. *
  211. * @param urgency The urgency; can be one of
  212. * <code>Log.DEBUG</code>, <code>Log.MESSAGE</code>,
  213. * <code>Log.NOTICE</code>, <code>Log.WARNING</code>, or
  214. * <code>Log.ERROR</code>.
  215. * @param source The source of the message, either an object or a
  216. * class instance. When writing log messages from macros, set
  217. * this parameter to <code>BeanShell.class</code> to make macro
  218. * errors easier to spot in the activity log.
  219. * @param message The message. This can either be a string or
  220. * an exception
  221. *
  222. * @since jEdit 2.2pre2
  223. */
  224. public static void log(int urgency, Object source, Object message)
  225. {
  226. String _source;
  227. if(source == null)
  228. {
  229. _source = Thread.currentThread().getName();
  230. if(_source == null)
  231. {
  232. _source = Thread.currentThread().getClass().getName();
  233. }
  234. }
  235. else if(source instanceof Class)
  236. _source = ((Class)source).getName();
  237. else
  238. _source = source.getClass().getName();
  239. int index = _source.lastIndexOf('.');
  240. if(index != -1)
  241. _source = _source.substring(index+1);
  242. if(message instanceof Throwable)
  243. {
  244. _logException(urgency,source,(Throwable)message);
  245. }
  246. else
  247. {
  248. String _message = String.valueOf(message);
  249. // If multiple threads log stuff, we don't want
  250. // the output to get mixed up
  251. synchronized(LOCK)
  252. {
  253. StringTokenizer st = new StringTokenizer(
  254. _message,"\r\n");
  255. int lineCount = 0;
  256. boolean oldWrap = wrap;
  257. while(st.hasMoreTokens())
  258. {
  259. lineCount++;
  260. _log(urgency,_source,st.nextToken()
  261. .replace('\t',' '));
  262. }
  263. listModel.update(lineCount,oldWrap);
  264. }
  265. }
  266. } //}}}
  267. //{{{ Private members
  268. //{{{ Instance variables
  269. private static Object LOCK = new Object();
  270. private static String[] log;
  271. private static int logLineCount;
  272. private static boolean wrap;
  273. private static int level = WARNING;
  274. private static Writer stream;
  275. private static String lineSep;
  276. private static PrintStream realOut;
  277. private static PrintStream realErr;
  278. private static LogListModel listModel;
  279. //}}}
  280. //{{{ Class initializer
  281. static
  282. {
  283. level = WARNING;
  284. realOut = System.out;
  285. realErr = System.err;
  286. log = new String[MAXLINES];
  287. lineSep = System.getProperty("line.separator");
  288. listModel = new LogListModel();
  289. } //}}}
  290. //{{{ createPrintStream() method
  291. private static PrintStream createPrintStream(final int urgency,
  292. final Object source)
  293. {
  294. return new PrintStream(new OutputStream() {
  295. public void write(int b)
  296. {
  297. byte[] barray = { (byte)b };
  298. write(barray,0,1);
  299. }
  300. public void write(byte[] b, int off, int len)
  301. {
  302. String str = new String(b,off,len);
  303. log(urgency,source,str);
  304. }
  305. });
  306. } //}}}
  307. //{{{ _logException() method
  308. private static void _logException(final int urgency,
  309. final Object source,
  310. final Throwable message)
  311. {
  312. PrintStream out = createPrintStream(urgency,source);
  313. synchronized(LOCK)
  314. {
  315. message.printStackTrace(out);
  316. }
  317. } //}}}
  318. //{{{ _log() method
  319. private static void _log(int urgency, String source, String message)
  320. {
  321. String fullMessage = "[" + urgencyToString(urgency) + "] " + source
  322. + ": " + message;
  323. try
  324. {
  325. log[logLineCount] = fullMessage;
  326. if(++logLineCount >= log.length)
  327. {
  328. wrap = true;
  329. logLineCount = 0;
  330. }
  331. if(stream != null)
  332. {
  333. stream.write(fullMessage);
  334. stream.write(lineSep);
  335. }
  336. }
  337. catch(Exception e)
  338. {
  339. e.printStackTrace(realErr);
  340. }
  341. if(urgency >= level)
  342. {
  343. if(urgency == ERROR)
  344. realErr.println(fullMessage);
  345. else
  346. realOut.println(fullMessage);
  347. }
  348. } //}}}
  349. //{{{ urgencyToString() method
  350. private static String urgencyToString(int urgency)
  351. {
  352. switch(urgency)
  353. {
  354. case DEBUG:
  355. return "debug";
  356. case MESSAGE:
  357. return "message";
  358. case NOTICE:
  359. return "notice";
  360. case WARNING:
  361. return "warning";
  362. case ERROR:
  363. return "error";
  364. }
  365. throw new IllegalArgumentException("Invalid urgency: " + urgency);
  366. } //}}}
  367. //}}}
  368. //{{{ LogListModel class
  369. static class LogListModel implements ListModel
  370. {
  371. Vector listeners = new Vector();
  372. private void fireIntervalAdded(int index1, int index2)
  373. {
  374. for(int i = 0; i < listeners.size(); i++)
  375. {
  376. ListDataListener listener = (ListDataListener)
  377. listeners.elementAt(i);
  378. listener.intervalAdded(new ListDataEvent(this,
  379. ListDataEvent.INTERVAL_ADDED,
  380. index1,index2));
  381. }
  382. }
  383. private void fireIntervalRemoved(int index1, int index2)
  384. {
  385. for(int i = 0; i < listeners.size(); i++)
  386. {
  387. ListDataListener listener = (ListDataListener)
  388. listeners.elementAt(i);
  389. listener.intervalRemoved(new ListDataEvent(this,
  390. ListDataEvent.INTERVAL_REMOVED,
  391. index1,index2));
  392. }
  393. }
  394. public void addListDataListener(ListDataListener listener)
  395. {
  396. listeners.addElement(listener);
  397. }
  398. public void removeListDataListener(ListDataListener listener)
  399. {
  400. listeners.removeElement(listener);
  401. }
  402. public Object getElementAt(int index)
  403. {
  404. if(wrap)
  405. {
  406. if(index < MAXLINES - logLineCount)
  407. return log[index + logLineCount];
  408. else
  409. return log[index - MAXLINES + logLineCount];
  410. }
  411. else
  412. return log[index];
  413. }
  414. public int getSize()
  415. {
  416. if(wrap)
  417. return MAXLINES;
  418. else
  419. return logLineCount;
  420. }
  421. void update(final int lineCount, final boolean oldWrap)
  422. {
  423. if(lineCount == 0 || listeners.size() == 0)
  424. return;
  425. SwingUtilities.invokeLater(new Runnable()
  426. {
  427. public void run()
  428. {
  429. if(wrap)
  430. {
  431. if(oldWrap)
  432. fireIntervalRemoved(0,lineCount - 1);
  433. else
  434. {
  435. fireIntervalRemoved(0,
  436. logLineCount);
  437. }
  438. fireIntervalAdded(
  439. MAXLINES - lineCount + 1,
  440. MAXLINES);
  441. }
  442. else
  443. {
  444. fireIntervalAdded(
  445. logLineCount - lineCount + 1,
  446. logLineCount);
  447. }
  448. }
  449. });
  450. }
  451. } //}}}
  452. }