001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.logger;
018:
019: import java.io.File;
020: import java.io.FileWriter;
021: import java.io.IOException;
022: import java.io.PrintWriter;
023: import java.sql.Timestamp;
024:
025: import org.apache.catalina.LifecycleException;
026: import org.apache.catalina.util.StringManager;
027:
028: /**
029: * Implementation of <b>Logger</b> that appends log messages to a file
030: * named {prefix}.{date}.{suffix} in a configured directory, with an
031: * optional preceding timestamp.
032: *
033: * @author Craig R. McClanahan
034: * @version $Revision: 1.4 $ $Date: 2004/02/27 14:58:44 $
035: */
036:
037: public class FileLogger extends LoggerBase {
038:
039: // ----------------------------------------------------- Instance Variables
040:
041: /**
042: * The as-of date for the currently open log file, or a zero-length
043: * string if there is no open log file.
044: */
045: private String date = "";
046:
047: /**
048: * The directory in which log files are created.
049: */
050: private String directory = "logs";
051:
052: /**
053: * The descriptive information about this implementation.
054: */
055: protected static final String info = "org.apache.catalina.logger.FileLogger/1.0";
056:
057: /**
058: * The prefix that is added to log file filenames.
059: */
060: private String prefix = "catalina.";
061:
062: /**
063: * The string manager for this package.
064: */
065: private StringManager sm = StringManager
066: .getManager(Constants.Package);
067:
068: /**
069: * Has this component been started?
070: */
071: private boolean started = false;
072:
073: /**
074: * The suffix that is added to log file filenames.
075: */
076: private String suffix = ".log";
077:
078: /**
079: * Should logged messages be date/time stamped?
080: */
081: private boolean timestamp = false;
082:
083: /**
084: * The PrintWriter to which we are currently logging, if any.
085: */
086: private PrintWriter writer = null;
087:
088: // ------------------------------------------------------------- Properties
089:
090: /**
091: * Return the directory in which we create log files.
092: */
093: public String getDirectory() {
094:
095: return (directory);
096:
097: }
098:
099: /**
100: * Set the directory in which we create log files.
101: *
102: * @param directory The new log file directory
103: */
104: public void setDirectory(String directory) {
105:
106: String oldDirectory = this .directory;
107: this .directory = directory;
108: support.firePropertyChange("directory", oldDirectory,
109: this .directory);
110:
111: }
112:
113: /**
114: * Return the log file prefix.
115: */
116: public String getPrefix() {
117:
118: return (prefix);
119:
120: }
121:
122: /**
123: * Set the log file prefix.
124: *
125: * @param prefix The new log file prefix
126: */
127: public void setPrefix(String prefix) {
128:
129: String oldPrefix = this .prefix;
130: this .prefix = prefix;
131: support.firePropertyChange("prefix", oldPrefix, this .prefix);
132:
133: }
134:
135: /**
136: * Return the log file suffix.
137: */
138: public String getSuffix() {
139:
140: return (suffix);
141:
142: }
143:
144: /**
145: * Set the log file suffix.
146: *
147: * @param suffix The new log file suffix
148: */
149: public void setSuffix(String suffix) {
150:
151: String oldSuffix = this .suffix;
152: this .suffix = suffix;
153: support.firePropertyChange("suffix", oldSuffix, this .suffix);
154:
155: }
156:
157: /**
158: * Return the timestamp flag.
159: */
160: public boolean getTimestamp() {
161:
162: return (timestamp);
163:
164: }
165:
166: /**
167: * Set the timestamp flag.
168: *
169: * @param timestamp The new timestamp flag
170: */
171: public void setTimestamp(boolean timestamp) {
172:
173: boolean oldTimestamp = this .timestamp;
174: this .timestamp = timestamp;
175: support.firePropertyChange("timestamp", new Boolean(
176: oldTimestamp), new Boolean(this .timestamp));
177:
178: }
179:
180: // --------------------------------------------------------- Public Methods
181:
182: /**
183: * Writes the specified message to a servlet log file, usually an event
184: * log. The name and type of the servlet log is specific to the
185: * servlet container.
186: *
187: * @param msg A <code>String</code> specifying the message to be written
188: * to the log file
189: */
190: public void log(String msg) {
191:
192: // Construct the timestamp we will use, if requested
193: Timestamp ts = new Timestamp(System.currentTimeMillis());
194: String tsString = ts.toString().substring(0, 19);
195: String tsDate = tsString.substring(0, 10);
196:
197: // If the date has changed, switch log files
198: if (!date.equals(tsDate)) {
199: synchronized (this ) {
200: if (!date.equals(tsDate)) {
201: close();
202: date = tsDate;
203: open();
204: }
205: }
206: }
207:
208: // Log this message, timestamped if necessary
209: if (writer != null) {
210: if (timestamp) {
211: writer.println(tsString + " " + msg);
212: } else {
213: writer.println(msg);
214: }
215: }
216:
217: }
218:
219: // -------------------------------------------------------- Private Methods
220:
221: /**
222: * Close the currently open log file (if any)
223: */
224: private void close() {
225:
226: if (writer == null)
227: return;
228: writer.flush();
229: writer.close();
230: writer = null;
231: date = "";
232:
233: }
234:
235: /**
236: * Open the new log file for the date specified by <code>date</code>.
237: */
238: private void open() {
239:
240: // Create the directory if necessary
241: File dir = new File(directory);
242: if (!dir.isAbsolute())
243: dir = new File(System.getProperty("catalina.base"),
244: directory);
245: dir.mkdirs();
246:
247: // Open the current log file
248: try {
249: String pathname = dir.getAbsolutePath() + File.separator
250: + prefix + date + suffix;
251: writer = new PrintWriter(new FileWriter(pathname, true),
252: true);
253: } catch (IOException e) {
254: writer = null;
255: }
256:
257: }
258:
259: // ------------------------------------------------------ Lifecycle Methods
260:
261: /**
262: * Prepare for the beginning of active use of the public methods of this
263: * component. This method should be called after <code>configure()</code>,
264: * and before any of the public methods of the component are utilized.
265: *
266: * @exception LifecycleException if this component detects a fatal error
267: * that prevents this component from being used
268: */
269: public void start() throws LifecycleException {
270:
271: // Validate and update our current component state
272: if (started)
273: throw new LifecycleException(sm
274: .getString("fileLogger.alreadyStarted"));
275: lifecycle.fireLifecycleEvent(START_EVENT, null);
276: started = true;
277:
278: super .start();
279:
280: }
281:
282: /**
283: * Gracefully terminate the active use of the public methods of this
284: * component. This method should be the last one called on a given
285: * instance of this component.
286: *
287: * @exception LifecycleException if this component detects a fatal error
288: * that needs to be reported
289: */
290: public void stop() throws LifecycleException {
291:
292: // Validate and update our current component state
293: if (!started)
294: throw new LifecycleException(sm
295: .getString("fileLogger.notStarted"));
296: lifecycle.fireLifecycleEvent(STOP_EVENT, null);
297: started = false;
298:
299: close();
300:
301: super.stop();
302:
303: }
304:
305: }
|