001: /*
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 1999 The Apache Software Foundation. All rights
005: * reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The end-user documentation included with the redistribution, if
020: * any, must include the following acknowlegement:
021: * "This product includes software developed by the
022: * Apache Software Foundation (http://www.apache.org/)."
023: * Alternately, this acknowlegement may appear in the software itself,
024: * if and wherever such third-party acknowlegements normally appear.
025: *
026: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
027: * Foundation" must not be used to endorse or promote products derived
028: * from this software without prior written permission. For written
029: * permission, please contact apache@apache.org.
030: *
031: * 5. Products derived from this software may not be called "Apache"
032: * nor may "Apache" appear in their names without prior written
033: * permission of the Apache Group.
034: *
035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: *
049: * This software consists of voluntary contributions made by many
050: * individuals on behalf of the Apache Software Foundation. For more
051: * information on the Apache Software Foundation, please see
052: * <http://www.apache.org/>.
053: *
054: */
055: package com.sun.portal.providers.jsp.jasper3.tomcat.logging;
056:
057: import java.io.Writer;
058: import java.io.PrintWriter;
059: import java.io.FileWriter;
060: import java.io.File;
061: import java.io.IOException;
062:
063: import java.util.*;
064: import java.text.DateFormat;
065: import java.text.SimpleDateFormat;
066:
067: /**
068: * Interface for a logging object. A logging object provides mechanism
069: * for logging errors and messages that are of interest to someone who
070: * is trying to monitor the system.
071: *
072: * @author Anil Vijendran (akv@eng.sun.com)
073: * @since Tomcat 3.1
074: */
075: public abstract class Logger {
076:
077: /**
078: * Is this Log usable?
079: */
080: public boolean isOpen() {
081: return this .sink != null;
082: }
083:
084: /**
085: * Prints the log message on a specified logger.
086: *
087: * @param name the name of the logger.
088: * @param message the message to log.
089: * @param verbosityLevel what type of message is this?
090: * (WARNING/DEBUG/INFO etc)
091: */
092: public static void log(String logName, String message,
093: int verbosityLevel) {
094: Logger logger = getLogger(logName);
095: if (logger != null)
096: logger.log(message, verbosityLevel);
097: }
098:
099: /**
100: * Prints the log message on a specified logger at the "default"
101: * log leve: INFORMATION
102: *
103: * @param name the name of the logger.
104: * @param message the message to log.
105: */
106: public static void log(String logName, String message) {
107: Logger logger = getLogger(logName);
108: if (logger != null)
109: logger.log(message);
110: }
111:
112: /**
113: * Prints the log message.
114: *
115: * @param message the message to log.
116: * @param verbosityLevel what type of message is this?
117: * (WARNING/DEBUG/INFO etc)
118: */
119: public final void log(String message, int verbosityLevel) {
120: if (matchVerbosityLevel(verbosityLevel))
121: realLog(message);
122: }
123:
124: /**
125: * Prints the log message at the "default" log level: INFORMATION
126: *
127: * @param message the message to log.
128: */
129: public final void log(String message) {
130: log(message, Logger.INFORMATION);
131: }
132:
133: /**
134: * Prints log message and stack trace.
135: *
136: * @param message the message to log.
137: * @param t the exception that was thrown.
138: * @param verbosityLevel what type of message is this?
139: * (WARNING/DEBUG/INFO etc)
140: */
141: public final void log(String message, Throwable t,
142: int verbosityLevel) {
143: if (matchVerbosityLevel(verbosityLevel))
144: realLog(message, t);
145: }
146:
147: public boolean matchVerbosityLevel(int verbosityLevel) {
148: return verbosityLevel <= getVerbosityLevel();
149: }
150:
151: /**
152: * Subclasses implement these methods which are called by the
153: * log(..) methods internally.
154: *
155: * @param message the message to log.
156: */
157: protected abstract void realLog(String message);
158:
159: /**
160: * Subclasses implement these methods which are called by the
161: * log(..) methods internally.
162: *
163: * @param message the message to log.
164: * @param t the exception that was thrown.
165: */
166: protected abstract void realLog(String message, Throwable t);
167:
168: /**
169: * Flush the log.
170: */
171: public abstract void flush();
172:
173: /**
174: * Close the log.
175: */
176: public synchronized void close() {
177: this .sink = null;
178: loggers.remove(getName());
179: }
180:
181: /**
182: * Get name of this log channel.
183: */
184: public String getName() {
185: return this .name;
186: }
187:
188: /**
189: * Set name of this log channel.
190: *
191: * @param name Name of this logger.
192: */
193: public void setName(String name) {
194: this .name = name;
195:
196: // Once the name of this logger is set, we add it to the list
197: // of loggers...
198: putLogger(this );
199: }
200:
201: /**
202: * Set the path name for the log output file.
203: *
204: * @param path The path to the log file.
205: */
206: public void setPath(String path) {
207: if (File.separatorChar == '/')
208: this .path = path.replace('\\', '/');
209: else if (File.separatorChar == '\\')
210: this .path = path.replace('/', '\\');
211: }
212:
213: public String getPath() {
214: return path;
215: }
216:
217: /** Open the log - will create the log file and all the parent directories.
218: * You must open the logger before use, or it will write to System.err
219: */
220: public void open() {
221: if (path == null)
222: return;
223: // use default sink == System.err
224: try {
225: File file = new File(path);
226:
227: if (!file.exists())
228: new File(file.getParent()).mkdirs();
229:
230: this .sink = new FileWriter(path);
231: } catch (IOException ex) {
232: System.err.print("Unable to open log file: " + path + "! ");
233: System.err.println(" Using stderr as the default.");
234: this .sink = defaultSink;
235: }
236: }
237:
238: /**
239: * Verbosity level codes.
240: */
241: public static final int FATAL = Integer.MIN_VALUE;
242: public static final int ERROR = 1;
243: public static final int WARNING = 2;
244: public static final int INFORMATION = 3;
245: public static final int DEBUG = 4;
246:
247: /**
248: * Set the verbosity level for this logger. This controls how the
249: * logs will be filtered.
250: *
251: * @param level one of the verbosity level strings.
252: */
253: public void setVerbosityLevel(String level) {
254: if ("warning".equalsIgnoreCase(level))
255: this .level = WARNING;
256: else if ("fatal".equalsIgnoreCase(level))
257: this .level = FATAL;
258: else if ("error".equalsIgnoreCase(level))
259: this .level = ERROR;
260: else if ("information".equalsIgnoreCase(level))
261: this .level = INFORMATION;
262: else if ("debug".equalsIgnoreCase(level))
263: this .level = DEBUG;
264: }
265:
266: /**
267: * Set the verbosity level for this logger. This controls how the
268: * logs will be filtered.
269: *
270: * @param level one of the verbosity level codes.
271: */
272: public void setVerbosityLevel(int level) {
273: this .level = level;
274: }
275:
276: /**
277: * Get the current verbosity level.
278: */
279: public int getVerbosityLevel() {
280: return this .level;
281: }
282:
283: /**
284: * Do we need to time stamp this or not?
285: *
286: * @param value "yes/no" or "true/false"
287: */
288: public void setTimestamp(String value) {
289: if ("true".equalsIgnoreCase(value)
290: || "yes".equalsIgnoreCase(value))
291: timestamp = true;
292: else if ("false".equalsIgnoreCase(value)
293: || "no".equalsIgnoreCase(value))
294: timestamp = false;
295: }
296:
297: public boolean isTimestamp() {
298: return timestamp;
299: }
300:
301: /**
302: * If we are timestamping at all, what format do we use to print
303: * the timestamp? See java.text.SimpleDateFormat.
304: *
305: * Default = "yyyy-MM-dd hh:mm:ss". Special case: "msec" => raw
306: * number of msec since epoch, very efficient but not
307: * user-friendly
308: **/
309: public void setTimestampFormat(String value) {
310: if (value.equalsIgnoreCase("msec"))
311: timestampRaw = true;
312: else {
313: timestampRaw = false;
314: timestampFormat = value;
315: timestampFormatter = new SimpleDateFormat(timestampFormat);
316: }
317: }
318:
319: public String getTimestampFormat() {
320: if (timestampRaw)
321: return "msec";
322: else
323: return timestampFormat;
324: }
325:
326: /**
327: * Set the default output stream that is used by all logging
328: * channels.
329: *
330: * @param w the default output stream.
331: */
332: public static void setDefaultSink(Writer w) {
333: defaultSink = w;
334: }
335:
336: public static Logger getLogger(String name) {
337: return (Logger) loggers.get(name);
338: }
339:
340: public static Enumeration getLoggerNames() {
341: return loggers.keys();
342: }
343:
344: public static void putLogger(Logger logger) {
345: loggers.put(logger.getName(), logger);
346: }
347:
348: public static void removeLogger(Logger logger) {
349: loggers.remove(logger.getName());
350: }
351:
352: public void setCustomOutput(String value) {
353: if ("true".equalsIgnoreCase(value)
354: || "yes".equalsIgnoreCase(value))
355: custom = true;
356: else if ("false".equalsIgnoreCase(value)
357: || "no".equalsIgnoreCase(value))
358: custom = false;
359: }
360:
361: protected String formatTimestamp(long msec) {
362: StringBuffer buf = new StringBuffer();
363: formatTimestamp(msec, buf);
364: return buf.toString();
365: }
366:
367: // dummy variable to make SimpleDateFormat work right
368: static java.text.FieldPosition position = new java.text.FieldPosition(
369: DateFormat.YEAR_FIELD);
370:
371: protected void formatTimestamp(long msec, StringBuffer buf) {
372: if (timestamp == false)
373: return;
374: else if (timestampRaw) {
375: buf.append(Long.toString(msec));
376: return;
377: } else {
378: Date d = new Date(msec);
379: timestampFormatter.format(d, buf, position);
380: return;
381: }
382: }
383:
384: protected boolean custom = true;
385: protected Writer sink = defaultSink;
386: String path;
387: protected String name;
388:
389: protected static Writer defaultSink = new PrintWriter(System.err);
390: protected static Hashtable loggers = new Hashtable(5);
391:
392: private int level = WARNING;
393:
394: /**
395: * Should we timestamp this log at all?
396: **/
397: protected boolean timestamp = true;
398:
399: /**
400: * true = The timestamp format is raw msec-since-epoch <br>
401: * false = The timestamp format is a custom string to pass to SimpleDateFormat
402: **/
403: protected boolean timestampRaw = false;
404:
405: /**
406: * The timestamp format string, default is "yyyy-MM-dd HH:mm:ss"
407: **/
408: protected String timestampFormat = "yyyy-MM-dd HH:mm:ss";
409:
410: protected SimpleDateFormat timestampFormatter = new SimpleDateFormat(
411: timestampFormat);
412: }
|