001: /*
002: * LogMgr.java
003: *
004: * This file is part of SQL Workbench/J, http://www.sql-workbench.net
005: *
006: * Copyright 2002-2008, Thomas Kellerer
007: * No part of this code maybe reused without the permission of the author
008: *
009: * To contact the author please send an email to: support@sql-workbench.net
010: *
011: */
012: package workbench.log;
013:
014: import java.io.File;
015: import java.io.FileOutputStream;
016: import java.io.PrintStream;
017: import java.io.PrintWriter;
018: import java.io.StringWriter;
019: import java.sql.SQLException;
020: import java.text.SimpleDateFormat;
021: import java.util.ArrayList;
022: import java.util.Date;
023: import java.util.List;
024: import java.util.regex.Matcher;
025: import java.util.regex.Pattern;
026:
027: import workbench.util.ExceptionUtil;
028: import workbench.util.StrBuffer;
029: import workbench.util.StringUtil;
030:
031: /**
032: * @author support@sql-workbench.net
033: */
034: public class LogMgr {
035:
036: public static final String ERROR = "ERROR";
037: public static final String WARNING = "WARN";
038: public static final String INFO = "INFO";
039: public static final String DEBUG = "DEBUG";
040:
041: private static final String WARNING_DISPLAY = "WARN ";
042: private static final String INFO_DISPLAY = "INFO ";
043:
044: public static final List<String> LEVELS;
045: static {
046: LEVELS = new ArrayList<String>(4);
047: LEVELS.add(ERROR);
048: LEVELS.add(WARNING);
049: LEVELS.add(INFO);
050: LEVELS.add(DEBUG);
051: }
052:
053: private static PrintStream logOut = null;
054: private static final Date theDate = new Date();
055: private static boolean logSystemErr = false;
056:
057: private static int typeIndex = -1;
058: private static int timeIndex = -1;
059: private static int sourceIndex = -1;
060: private static int messageIndex = 0;
061: private static int exceptionMsgIndex = 1;
062: private static boolean showStackTrace = false;
063: private static final int NUM_ELEMENTS = 5;
064: private static String[] MSG_ELEMENTS = new String[NUM_ELEMENTS];
065:
066: private static SimpleDateFormat formatter = new SimpleDateFormat(
067: "dd.MM.yyyy HH:mm:ss");
068:
069: private static int loglevel = 3;
070:
071: private static int levelDebug;
072: private static int levelWarning;
073: private static int levelInfo;
074: private static int levelError;
075: private static boolean debugEnabled;
076: private static boolean infoEnabled;
077: private static File currentFile;
078:
079: public static void setMessageFormat(String aFormat) {
080: if (aFormat == null)
081: return;
082: Pattern p = Pattern.compile("\\{[a-zA-Z]+\\}");
083: Matcher m = p.matcher(aFormat);
084:
085: typeIndex = -1;
086: timeIndex = -1;
087: sourceIndex = -1;
088: messageIndex = -1;
089: exceptionMsgIndex = -1;
090: showStackTrace = false;
091:
092: int currentIndex = 0;
093: while (m.find()) {
094: int start = m.start();
095: int end = m.end();
096: String key = aFormat.substring(start, end).toLowerCase();
097: if ("{type}".equals(key)) {
098: typeIndex = currentIndex;
099: currentIndex++;
100: } else if ("{timestamp}".equals(key)) {
101: timeIndex = currentIndex;
102: currentIndex++;
103: } else if ("{source}".equals(key)) {
104: sourceIndex = currentIndex;
105: currentIndex++;
106: } else if ("{message}".equals(key)) {
107: messageIndex = currentIndex;
108: currentIndex++;
109: } else if ("{error}".equals(key)) {
110: exceptionMsgIndex = currentIndex;
111: currentIndex++;
112: } else if ("{stacktrace}".equals(key)) {
113: showStackTrace = true;
114: }
115: }
116: }
117:
118: public static void logErrors() {
119: setLevel(ERROR);
120: }
121:
122: public static void logWarnings() {
123: setLevel(WARNING);
124: }
125:
126: public static void logInfo() {
127: setLevel(INFO);
128: }
129:
130: public static void logDebug() {
131: setLevel(DEBUG);
132: }
133:
134: public static void logAll() {
135: logDebug();
136: }
137:
138: public static void logToSystemError(boolean flag) {
139: logSystemErr = flag;
140: }
141:
142: public static String getLevel() {
143: if (loglevel == levelDebug)
144: return "DEBUG";
145: if (loglevel == levelWarning)
146: return "WARNING";
147: if (loglevel == levelError)
148: return "ERROR";
149: if (loglevel == levelInfo)
150: return "INFO";
151: return "ERROR";
152: }
153:
154: public static void setLevel(String aType) {
155: if (aType == null)
156: aType = "INFO";
157: if ("warning".equalsIgnoreCase(aType))
158: aType = "WARN";
159: else
160: aType = aType.toUpperCase();
161:
162: levelDebug = LEVELS.indexOf(DEBUG);
163: levelWarning = LEVELS.indexOf(WARNING);
164: levelInfo = LEVELS.indexOf(INFO);
165: levelError = LEVELS.indexOf(ERROR);
166:
167: if (LEVELS.contains(aType)) {
168: loglevel = LEVELS.indexOf(aType);
169: } else {
170: logErrors();
171: logError("LogMgr.setLevel()", "Requested level " + aType
172: + " not found! Setting level " + ERROR, null);
173: }
174: debugEnabled = (loglevel == levelDebug);
175: infoEnabled = (loglevel == levelInfo || debugEnabled);
176: }
177:
178: public static void shutdown() {
179: if (logOut != null) {
180: logInfo(null,
181: "=================== Log stopped ===================");
182: logOut.close();
183: }
184: }
185:
186: public static void setOutputFile(File logfile, int maxFilesize) {
187: if (logfile == null)
188: return;
189: if (logfile.equals(currentFile))
190: return;
191:
192: try {
193: if (logOut != null) {
194: logOut.close();
195: logOut = null;
196: }
197:
198: if (logfile.exists() && logfile.length() > maxFilesize) {
199: File last = new File(logfile.getAbsolutePath()
200: + ".last");
201: if (last.exists())
202: last.delete();
203: logfile.renameTo(last);
204: }
205: logOut = new PrintStream(
206: new FileOutputStream(logfile, true));
207: currentFile = logfile;
208: logInfo(null,
209: "=================== Log started ===================");
210: } catch (Throwable th) {
211: logOut = null;
212: logSystemErr = true;
213: logError("LogMgr.checkOutput()",
214: "Error when opening logfile="
215: + logfile.getAbsolutePath(), th);
216: }
217: }
218:
219: public static boolean isInfoEnabled() {
220: return infoEnabled;
221: }
222:
223: public static boolean isDebugEnabled() {
224: return debugEnabled;
225: }
226:
227: public static void logDebug(Object aCaller, String aMsg) {
228: if (levelDebug > loglevel)
229: return;
230: logMessage(DEBUG, aCaller, aMsg, null);
231: }
232:
233: public static void logSqlError(Object caller, String sql,
234: Throwable th) {
235: if (th instanceof SQLException) {
236: logDebug(caller, "Error executing statement: " + sql, th);
237: } else {
238: logError(caller, "Error executing statement: " + sql, th);
239: }
240: }
241:
242: public static void logDebug(Object aCaller, String aMsg,
243: Throwable th) {
244: if (levelDebug > loglevel)
245: return;
246: logMessage(DEBUG, aCaller, aMsg, th);
247: }
248:
249: public static void logInfo(Object aCaller, String aMsg) {
250: if (levelInfo > loglevel)
251: return;
252: logMessage(INFO_DISPLAY, aCaller, aMsg, null);
253: }
254:
255: public static void logInfo(Object aCaller, String aMsg, Throwable th) {
256: if (levelInfo > loglevel)
257: return;
258: logMessage(INFO_DISPLAY, aCaller, aMsg, th);
259: }
260:
261: public static void logWarning(Object aCaller, String aMsg) {
262: if (levelWarning > loglevel)
263: return;
264: logMessage(WARNING_DISPLAY, aCaller, aMsg, null);
265: }
266:
267: public static void logWarning(Object aCaller, String aMsg,
268: Throwable th) {
269: if (levelWarning > loglevel)
270: return;
271: logMessage(WARNING_DISPLAY, aCaller, aMsg, th);
272: }
273:
274: public static void logError(Object aCaller, String aMsg,
275: Throwable th) {
276: if (levelError > loglevel)
277: return;
278: logMessage(ERROR, aCaller, aMsg, th);
279: }
280:
281: public static void logError(Object aCaller, String aMsg,
282: SQLException se) {
283: if (levelError > loglevel)
284: return;
285:
286: logMessage(ERROR, aCaller, aMsg, se);
287: if (se != null) {
288: SQLException next = se.getNextException();
289: while (next != null) {
290: logMessage(ERROR, "Chained exception", ExceptionUtil
291: .getDisplay(next), null);
292: next = next.getNextException();
293: }
294: }
295: }
296:
297: private synchronized static void logMessage(String aType,
298: Object aCaller, String aMsg, Throwable th) {
299: StrBuffer s = formatMessage(aType, aCaller, aMsg, th);
300: if (logOut != null) {
301: s.writeTo(logOut);
302: logOut.flush();
303: }
304: if (logSystemErr) {
305: s.writeTo(System.err);
306: }
307: }
308:
309: private static StrBuffer formatMessage(String aType,
310: Object aCaller, String aMsg, Throwable th) {
311: StrBuffer buff = new StrBuffer(100);
312:
313: for (int i = 0; i < NUM_ELEMENTS; i++)
314: MSG_ELEMENTS[i] = null;
315:
316: if (timeIndex > -1) {
317: MSG_ELEMENTS[timeIndex] = getTimeString();
318: }
319:
320: if (typeIndex > -1) {
321: MSG_ELEMENTS[typeIndex] = aType;
322: }
323:
324: if (sourceIndex > -1) {
325: if (aCaller != null) {
326: if (aCaller instanceof String)
327: MSG_ELEMENTS[sourceIndex] = (String) aCaller;
328: else
329: MSG_ELEMENTS[sourceIndex] = aCaller.getClass()
330: .getName();
331: }
332: }
333:
334: if (messageIndex > -1) {
335: MSG_ELEMENTS[messageIndex] = aMsg;
336: }
337:
338: boolean hasException = false;
339: if (exceptionMsgIndex > -1 && th != null) {
340: MSG_ELEMENTS[exceptionMsgIndex] = ExceptionUtil
341: .getDisplay(th);
342: hasException = true;
343: }
344:
345: boolean first = true;
346:
347: for (int i = 0; i < NUM_ELEMENTS; i++) {
348:
349: if (MSG_ELEMENTS[i] != null) {
350: if (!first)
351: buff.append(" ");
352: else
353: first = false;
354: buff.append(MSG_ELEMENTS[i]);
355: if (i == sourceIndex)
356: buff.append(" -");
357: if (i == messageIndex && hasException)
358: buff.append(":");
359: }
360: }
361: buff.append(StringUtil.LINE_TERMINATOR);
362:
363: // always display the stacktrace in debug level
364: if (th != null
365: && (showStackTrace || loglevel == levelDebug || th instanceof NullPointerException)) {
366: buff.append(getStackTrace(th));
367: buff.append(StringUtil.LINE_TERMINATOR);
368: }
369:
370: return buff;
371: }
372:
373: public static String getStackTrace(Throwable th) {
374: if (th == null)
375: return StringUtil.EMPTY_STRING;
376: try {
377: StringWriter sw = new StringWriter(2000);
378: PrintWriter pw = new PrintWriter(sw);
379: pw.println();
380: th.printStackTrace(pw);
381: pw.close();
382: return sw.toString();
383: } catch (Exception ex) {
384: }
385: return StringUtil.EMPTY_STRING;
386: }
387:
388: private static String getTimeString() {
389: theDate.setTime(System.currentTimeMillis());
390: return formatter.format(theDate);
391: }
392:
393: }
|