001: /*
002: * Log.java
003: *
004: * Copyright (C) 1998-2003 Peter Graves
005: * $Id: Log.java,v 1.2 2003/06/29 00:19:34 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: import java.io.IOException;
025: import java.io.PrintWriter;
026: import java.io.StringWriter;
027: import java.text.SimpleDateFormat;
028: import java.util.Date;
029:
030: public final class Log {
031: // Levels.
032: private static final int DEBUG = 1;
033: private static final int INFO = 2;
034: private static final int WARN = 3;
035: private static final int ERROR = 4;
036: private static final int FATAL = 5;
037:
038: // Synchronization.
039: private static final Object lock = new Object();
040:
041: private static final SimpleDateFormat dateFormat = new SimpleDateFormat(
042: "MMM dd HH:mm:ss.SSS ");
043: private static final int lineSeparatorLength = System.getProperty(
044: "line.separator").length();
045:
046: // Configuration.
047: private static boolean logEnabled;
048: private static long maxFileSize;
049: private static int maxBackupIndex;
050: private static int minLevel;
051:
052: private static PrintWriter logWriter;
053: private static long fileSize;
054: private static boolean rollOverEnabled;
055:
056: private static final void setRollOverEnabled(boolean b) {
057: rollOverEnabled = b;
058: }
059:
060: public static final int getLevel() {
061: return minLevel;
062: }
063:
064: public static final void setLevel(int level) {
065: minLevel = level;
066: }
067:
068: public static final void debug(String s) {
069: log(DEBUG, s);
070: }
071:
072: public static final void debug(Throwable t) {
073: log(DEBUG, t);
074: }
075:
076: public static final void info(String s) {
077: log(INFO, s);
078: }
079:
080: public static final void warn(String s) {
081: log(WARN, s);
082: }
083:
084: public static final void warn(Throwable t) {
085: log(WARN, t);
086: }
087:
088: public static final void error(String s) {
089: log(ERROR, s);
090: }
091:
092: public static final void error(Throwable t) {
093: log(ERROR, t);
094: }
095:
096: public static final void fatal(String s) {
097: log(FATAL, s);
098: }
099:
100: private static final void log(int level, String s) {
101: if (Editor.isDebugEnabled())
102: System.err.println(s);
103: if (logEnabled && level >= minLevel)
104: writeLog(level, s);
105: }
106:
107: private static final void forceLog(int level, String s) {
108: if (Editor.isDebugEnabled())
109: System.err.println(s);
110: writeLog(level, s);
111: }
112:
113: private static final void writeLog(int level, String s) {
114: synchronized (lock) {
115: if (logWriter != null) {
116: String dt = getDateTimeString();
117: logWriter.print(dt);
118: logWriter.print(levelToString(level));
119: logWriter.println(s);
120: fileSize += dt.length() + 6 + s.length()
121: + lineSeparatorLength;
122: if (rollOverEnabled && fileSize > maxFileSize)
123: rollOver();
124: }
125: }
126: }
127:
128: private static final void log(int level, Throwable t) {
129: if (Editor.isDebugEnabled())
130: t.printStackTrace();
131: if (logEnabled && level >= minLevel) {
132: synchronized (lock) {
133: if (logWriter != null) {
134: String dt = getDateTimeString();
135: logWriter.print(dt);
136: logWriter.print(levelToString(level));
137: StringWriter sw = new StringWriter();
138: PrintWriter pw = new PrintWriter(sw);
139: t.printStackTrace(pw);
140: String s = sw.toString();
141: logWriter.println(s);
142: fileSize += dt.length() + 6 + s.length()
143: + lineSeparatorLength;
144: if (rollOverEnabled && fileSize > maxFileSize)
145: rollOver();
146: }
147: }
148: }
149: }
150:
151: // Called only from synchronized methods.
152: private static final void rollOver() {
153: if (!rollOverEnabled)
154: Debug.bug();
155: setRollOverEnabled(false);
156: long start = System.currentTimeMillis();
157: Log.debug("rotating log files...");
158: for (int i = maxBackupIndex - 1; i >= 0; i--) {
159: File source = getBackupLogFile(i);
160: File destination = getBackupLogFile(i + 1);
161: if (destination.exists())
162: destination.delete();
163: if (source.isFile())
164: source.renameTo(destination);
165: }
166: File destination = getBackupLogFile(0);
167: File logFile = getLogFile();
168: logWriter.flush();
169: logWriter.close();
170: if (destination.exists())
171: destination.delete();
172: if (logFile.isFile())
173: logFile.renameTo(destination);
174: logWriter = null;
175: fileSize = 0;
176: try {
177: logWriter = new PrintWriter(logFile.getOutputStream(), true);
178: int oldLevel = getLevel();
179: setLevel(INFO);
180: setRollOverEnabled(false);
181: logSystemInformation();
182: logUptime();
183: setRollOverEnabled(true);
184: setLevel(oldLevel);
185: } catch (IOException e) {
186: logEnabled = false;
187: e.printStackTrace();
188: }
189: long elapsed = System.currentTimeMillis() - start;
190: Log.debug("rollOver " + elapsed + " ms");
191: setRollOverEnabled(true);
192: }
193:
194: private static final File getLogFile() {
195: return File
196: .getInstance(Directories.getEditorDirectory(), "log");
197: }
198:
199: private static final File getBackupLogFile(int index) {
200: return File.getInstance(Directories.getEditorDirectory(),
201: "log.".concat(String.valueOf(index)));
202: }
203:
204: public static final void initialize() {
205: synchronized (lock) {
206: Preferences preferences = Editor.preferences();
207: if (preferences != null) {
208: preferences
209: .addPreferencesChangeListener(preferencesChangeListener);
210: loadPreferences();
211: if (logEnabled) {
212: initializeLogWriter();
213: if (logWriter != null) {
214: setLevel(INFO);
215: info("Starting j...");
216: logSystemInformation();
217: if (Editor.isDebugEnabled())
218: setLevel(DEBUG);
219: setRollOverEnabled(true);
220: }
221: }
222: }
223: }
224: }
225:
226: private static final void initializeLogWriter() {
227: Debug.assertTrue(logWriter == null);
228: File logFile = getLogFile();
229: if (logFile.isFile())
230: fileSize = logFile.length();
231: try {
232: // Append to file, flush automatically.
233: logWriter = new PrintWriter(logFile.getOutputStream(true),
234: true);
235: } catch (Exception e) {
236: logEnabled = false;
237: e.printStackTrace();
238: }
239: }
240:
241: private static final void logSystemInformation() {
242: info(Version.getLongVersionString());
243: String snapshotInformation = Version.getSnapshotInformation();
244: if (snapshotInformation != null)
245: info(snapshotInformation);
246: FastStringBuffer sb = new FastStringBuffer("Java ");
247: sb.append(System.getProperty("java.version"));
248: sb.append(' ');
249: sb.append(System.getProperty("java.vendor"));
250: info(sb.toString());
251: String fullversion = System.getProperty("java.fullversion");
252: if (fullversion != null)
253: info(fullversion);
254: String vm = System.getProperty("java.vm.name");
255: if (vm != null)
256: info(vm);
257: sb.setText(System.getProperty("os.name"));
258: sb.append(' ');
259: sb.append(System.getProperty("os.version"));
260: info(sb.toString());
261: }
262:
263: private static final void logUptime() {
264: info("up since ".concat(getDateTimeString(Editor
265: .getStartTimeMillis())));
266: }
267:
268: private static final String getDateTimeString() {
269: return getDateTimeString(System.currentTimeMillis());
270: }
271:
272: private static final String getDateTimeString(long millis) {
273: return dateFormat.format(new Date(millis));
274: }
275:
276: // String returned is always 6 characters long and ends with a space.
277: private static final String levelToString(int level) {
278: switch (level) {
279: case DEBUG:
280: return "DEBUG ";
281: case INFO:
282: return " INFO ";
283: case WARN:
284: return " WARN ";
285: case ERROR:
286: return "ERROR ";
287: case FATAL:
288: return "FATAL ";
289: }
290: // Shouldn't happen.
291: return "????? ";
292: }
293:
294: private static final void loadPreferences() {
295: synchronized (lock) {
296: Preferences preferences = Editor.preferences();
297: logEnabled = preferences
298: .getBooleanProperty(Property.LOG_ENABLED);
299: maxFileSize = preferences
300: .getIntegerProperty(Property.LOG_MAX_FILE_SIZE);
301: if (maxFileSize < 10000)
302: maxFileSize = 10000; // Minimum is 10 KB.
303: else if (maxFileSize > 1000000)
304: maxFileSize = 1000000; // Maximum is 1 MB.
305: maxBackupIndex = preferences
306: .getIntegerProperty(Property.LOG_MAX_BACKUP_INDEX);
307: if (maxBackupIndex < 0)
308: maxBackupIndex = 0; // Minimum is one backup.
309: }
310: }
311:
312: private static final PreferencesChangeListener preferencesChangeListener = new PreferencesChangeListener() {
313: public void preferencesChanged() {
314: boolean logWasEnabled = logEnabled;
315: loadPreferences();
316: forceLog(DEBUG, "preferencesChanged logEnabled = "
317: + logEnabled);
318: forceLog(DEBUG, "preferencesChanged maxFileSize = "
319: + maxFileSize);
320: forceLog(DEBUG, "preferencesChanged maxBackupIndex = "
321: + maxBackupIndex);
322: if (logEnabled && !logWasEnabled) {
323: // Start logging.
324: initializeLogWriter();
325: if (logWriter != null) {
326: setLevel(INFO);
327: info("Logging enabled");
328: logSystemInformation();
329: logUptime();
330: if (Editor.isDebugEnabled())
331: setLevel(DEBUG);
332: setRollOverEnabled(true);
333: }
334: } else if (logWasEnabled && !logEnabled) {
335: // Stop logging.
336: if (logWriter != null) {
337: forceLog(INFO, "Logging disabled");
338: logWriter.flush();
339: logWriter.close();
340: logWriter = null;
341: }
342: } else if (logEnabled) {
343: if (Editor.preferences().getBooleanProperty(
344: Property.DEBUG))
345: setLevel(DEBUG);
346: else
347: setLevel(INFO);
348: }
349: }
350: };
351: }
|