001: /*
002: TomcatMonologFileLogger.java
003: An Extension of a Logger that channels the logging trough Monolog instead
004: of Tomcat's default FileLogger.
005: */
006:
007: //package org.enhydra.logging;
008: package org.apache.catalina.logger;
009:
010: import java.io.File;
011: import java.io.FileInputStream;
012: import java.io.FileWriter;
013: import java.io.IOException;
014: import java.io.PrintWriter;
015: import java.sql.Timestamp;
016: import java.util.Enumeration;
017: import java.util.Iterator;
018: import java.util.Locale;
019: import java.util.Properties;
020: import java.util.ResourceBundle;
021: import java.util.Set;
022:
023: import javax.management.MBeanServerConnection;
024: import javax.management.ObjectName;
025: import javax.management.remote.JMXConnector;
026: import javax.management.remote.JMXConnectorFactory;
027: import javax.management.remote.JMXServiceURL;
028:
029: import org.apache.catalina.LifecycleException;
030: import org.apache.catalina.util.StringManager;
031: import org.objectweb.util.monolog.Monolog;
032: import org.objectweb.util.monolog.api.BasicLevel;
033: import org.objectweb.util.monolog.api.Level;
034: import org.objectweb.util.monolog.api.LoggerFactory;
035: import org.objectweb.util.monolog.wrapper.common.Configurable;
036:
037: import com.lutris.util.Config;
038: import com.lutris.util.ConfigException;
039:
040: /**
041: * Implementation of <b>Logger</b> that appends log messages to a file
042: * named {prefix}.{date}.{suffix} in a configured directory, with an
043: * optional preceding timestamp.
044: *
045: * @author Igor Smirnov
046: * @version $Revision: v1.0
047: */
048:
049: public class TomcatMonologFileLogger extends LoggerBase {
050: // private String _options;
051: // private transient boolean _started;
052: private org.objectweb.util.monolog.api.LoggerFactory lf;
053: private org.objectweb.util.monolog.api.Logger logger = null;
054: // private String path, jonas, fileName;
055: private static ResourceBundle rb = null;
056: public static String PROPERTY_FILE;
057: static ObjectName objectName;
058:
059: //LifecycleSupport lifecycle = new LifecycleSupport(LoggerBase.class);
060:
061: public TomcatMonologFileLogger() throws ConfigException {
062:
063: try {
064: configure();
065: this .logger = lf.getLogger("TomcatMonologFileLogger");
066:
067: } catch (ConfigException ex) {
068: throw new ConfigException(
069: "TomcatMonologFileLogger:Cannot configure logger. Logger not initialized.");
070: }
071:
072: }
073:
074: private String date = "";
075:
076: /**
077: * The directory in which log files are created.
078: */
079: private String directory = "logs";
080:
081: /**
082: * The descriptive information about this implementation.
083: */
084: protected static final String info = "org.apache.catalina.logger.FileLogger/1.0";
085:
086: /**
087: * The prefix that is added to log file filenames.
088: */
089: private String prefix = "catalina.";
090:
091: /**
092: * The string manager for this package.
093: */
094: /*private StringManager sm =
095: StringManager.getManager(Constants.Package);*/
096:
097: /**
098: * Has this component been started?
099: */
100: // private boolean started = false;
101:
102: /**
103: * The suffix that is added to log file filenames.
104: */
105: private String suffix = ".log";
106:
107: /**
108: * Should logged messages be date/time stamped?
109: */
110: // private boolean timestamp = false;
111:
112: /**
113: * The PrintWriter to which we are currently logging, if any.
114: */
115: private PrintWriter writer = null;
116:
117: // --------------------------------------------------------- Public Methods
118:
119: /**
120: * Writes the specified message to a servlet log file, usually an event
121: * log. The name and type of the servlet log is specific to the
122: * servlet container.
123: *
124: * @param msg A <code>String</code> specifying the message to be written
125: * to the log file
126: */
127: public void log(String msg) {
128:
129: // Construct the timestamp we will use, if requested
130:
131: // Timestamp ts = new Timestamp(System.currentTimeMillis());
132: // String tsString = ts.toString().substring(0, 19);
133: // String tsDate = tsString.substring(0, 10);
134: // String logString = "";
135:
136: // If the date has changed, switch log files
137: /*if (!date.equals(tsDate)) {
138: synchronized (this) {
139: if (!date.equals(tsDate)) {
140: close();
141: date = tsDate;
142: open();
143: }
144: }
145: }*/
146:
147: // Log this message, timestamped if necessary
148: /*
149: if (timestamp) {
150: logString = tsString + " " + msg;
151: } else {
152: logString = msg;
153: }
154: */
155:
156: Level priority = BasicLevel.LEVEL_INFO;
157:
158: /*if (Log.DEBUG.equals(tag))
159: priority=BasicLevel.LEVEL_DEBUG;
160: else if (Log.WARN.equals(tag) || Log.ASSERT.equals(tag))
161: priority=BasicLevel.LEVEL_ERROR;
162: else if (Log.FAIL.equals(tag))
163: priority=BasicLevel.LEVEL_FATAL; */
164:
165: //if (!logger.isLoggable(priority))
166: // return;
167: logger.log(priority, "", "" + msg, null);
168:
169: }
170:
171: public synchronized void configure(String monologConfFile)
172: throws ConfigException {
173:
174: if (monologConfFile == null || monologConfFile.length() == 0) {
175: throw new ConfigException(
176: "impossible to configure monolog without configuration file");
177: }
178: // Load the configuration in a Properties object
179: String b = null;
180: Properties p = new Properties();
181: FileInputStream fis = null;
182: try {
183: fis = new FileInputStream(monologConfFile);
184: p.load(fis);
185: // Search the class name of the LoggerFactory which must be instanciated
186: b = p.getProperty("log.config.classname", null);
187:
188: if (b == null) {
189: throw new ConfigException(
190: "Malformed configuration log file:"
191: + " log.config.classname not available");
192: }
193:
194: // Instanciate the LoggerFactory
195: lf = (LoggerFactory) Class.forName(b).newInstance();
196: // Configure with the properties
197: p.put(Configurable.LOG_CONFIGURATION_TYPE,
198: Configurable.PROPERTY);
199: p.put(Configurable.LOG_CONFIGURATION_FILE, monologConfFile);
200: // p.put(Configurable.LOG_CONFIGURATION_FILE_USE_CLASSPATH, "true");
201:
202: ((Configurable) lf).configure(p);
203:
204: fis.close();
205: // PropertiesConfAccess.load(p, lf, (HandlerFactory) lf, (LevelFactory) lf);
206: } catch (Exception e) {
207: try {
208: fis.close();
209: } catch (IOException e1) {
210: e1.printStackTrace();
211: }
212: throw new ConfigException(
213: "Malformed configuration log file:"
214: + " log.config.classname not available");
215: }
216: }
217:
218: public synchronized void configure() throws ConfigException {
219: String b = null;
220: String propkey;
221: String propvalue;
222: Properties props = new Properties();
223:
224: // Search the classpath for the logger configuration file
225:
226: try {
227: findObjectName();
228: if (objectName != null)
229: PROPERTY_FILE = objectName.getKeyProperty("fname");
230: rb = ResourceBundle.getBundle(PROPERTY_FILE, new Locale(
231: "en", "US"), ClassLoader.getSystemClassLoader());
232:
233: Enumeration enumeration = rb.getKeys();
234:
235: while (enumeration.hasMoreElements()) {
236:
237: propkey = (String) enumeration.nextElement();
238: propvalue = rb.getString(propkey);
239: props.setProperty(propkey, propvalue);
240: }
241:
242: } catch (Exception e) {
243: throw new ConfigException(
244: "Logger configuration file could not be found: logger could not be initialized!");
245: }
246:
247: try {
248:
249: // Search the class name of the LoggerFactory which must be instanciated
250: b = props.getProperty("log.config.classname", null);
251: if (b == null) {
252: throw new ConfigException(
253: "Malformed configuration log file:"
254: + " log.config.classname not available");
255: }
256:
257: // Instanciate the LoggerFactory
258:
259: props.put(Configurable.LOG_CONFIGURATION_TYPE,
260: Configurable.PROPERTY);
261: lf = Monolog.getMonologFactory(b);
262:
263: // PropertiesConfAccess.load(p, lf, (HandlerFactory) lf, (LevelFactory) lf);
264: } catch (Exception e) {
265: throw new ConfigException(
266: "Malformed configuration log file:"
267: + " log.config.classname not available");
268: }
269:
270: }
271:
272: /**
273: * Configure Logger with given config section
274: *
275: * @param logConfig containing parameters for configuring logger
276: */
277: public void configure(Config logConfig) throws ConfigException {
278: String fileName = null;
279:
280: if (logConfig.containsKey("Monolog")) {
281: fileName = logConfig.getString("Monolog");
282: try {
283: configure(fileName);
284: } catch (Exception ex) {
285: try {
286: configure();
287: } catch (ConfigException cex) {
288: throw new ConfigException(
289: "Cannot configure logger. Config file is null.");
290: }
291: }
292:
293: } else {
294: try {
295: configure();
296: } catch (ConfigException ex) {
297: throw new ConfigException(
298: "Cannot configure logger. Logger not initialized.");
299: }
300: }
301: }
302:
303: /**
304: * finds the ObjectName which correspondes to the MBean of the jonas logger
305: */
306: private void findObjectName() throws Exception {
307: JMXConnector connector = null;
308: try {
309:
310: String serviceName = "jonas";
311:
312: // The name of the started jonas server (service name)
313: serviceName = System.getProperty("jonas.name");
314: if (serviceName == null) {
315: serviceName = "jonas";
316: }
317:
318: // The address of the connector server
319: JMXServiceURL url = new JMXServiceURL(
320: "service:jmx:rmi://localhost/jndi/jrmpconnector_"
321: + serviceName);
322:
323: // Connect a JSR 160 JMXConnector to the server side
324: connector = JMXConnectorFactory.connect(url);
325:
326: // Retrieve an MBeanServerConnection that represent the MBeanServer the remote
327: // connector server is bound to
328: MBeanServerConnection connection = connector
329: .getMBeanServerConnection();
330:
331: objectName = new ObjectName(serviceName
332: + ":type=service,name=log,*");
333:
334: Set mBeans = connection.queryNames(objectName, null);
335: int l = mBeans.size();
336: if ((l) > 1) {
337: throw new Exception("MBean set size not equal 1: " + l);
338: } else if (l == 0) {
339: objectName = null;
340: if (connector != null) {
341: try {
342: connector.close();
343: } catch (Exception exept) {
344: }
345: }
346: return;
347: }
348: Iterator i = mBeans.iterator();
349: objectName = (ObjectName) i.next();
350: } catch (Exception e) {
351: throw new Exception(e);
352: } finally {
353: if (connector != null) {
354: try {
355: connector.close();
356: } catch (Exception exept) {
357: }
358: }
359: }
360: return;
361: }
362:
363: private void close() {
364:
365: if (writer == null)
366: return;
367: writer.flush();
368: writer.close();
369: writer = null;
370: date = "";
371:
372: }
373:
374: /**
375: * Open the new log file for the date specified by <code>date</code>.
376: */
377: private void open() {
378:
379: // Create the directory if necessary
380: File dir = new File(directory);
381: if (!dir.isAbsolute())
382: dir = new File(System.getProperty("catalina.base"),
383: directory);
384: dir.mkdirs();
385:
386: // Open the current log file
387: try {
388: String pathname = dir.getAbsolutePath() + File.separator
389: + prefix + date + suffix;
390: writer = new PrintWriter(new FileWriter(pathname, true),
391: true);
392: } catch (IOException e) {
393: writer = null;
394: }
395:
396: }
397:
398: public void start() throws LifecycleException {
399: }
400:
401: /**
402: * Gracefully terminate the active use of the public methods of this
403: * component. This method should be the last one called on a given
404: * instance of this component.
405: *
406: * @exception LifecycleException if this component detects a fatal error
407: * that needs to be reported
408: */
409: public void stop() throws LifecycleException {
410: }
411:
412: }
|