001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2004 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: Log.java 8416 2006-06-02 07:22:42Z pelletib $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas.common;
025:
026: import java.io.File;
027: import java.io.FileInputStream;
028: import java.io.FileNotFoundException;
029: import java.io.InputStream;
030: import java.io.PrintWriter;
031: import java.text.SimpleDateFormat;
032: import java.util.Date;
033: import java.util.Enumeration;
034: import java.util.Properties;
035:
036: import org.objectweb.jonas_timer.TraceTimer;
037:
038: import org.objectweb.common.TraceCore;
039:
040: import org.objectweb.jonas_ejb.container.TraceEjb;
041:
042: import org.objectweb.jonas_jms.TraceJms;
043:
044: import org.objectweb.util.monolog.Monolog;
045: import org.objectweb.util.monolog.api.BasicLevel;
046: import org.objectweb.util.monolog.api.HandlerFactory;
047: import org.objectweb.util.monolog.api.LevelFactory;
048: import org.objectweb.util.monolog.api.Logger;
049: import org.objectweb.util.monolog.api.LoggerFactory;
050: import org.objectweb.util.monolog.api.MonologFactory;
051: import org.objectweb.util.monolog.file.DottedStringTools;
052: import org.objectweb.util.monolog.file.monolog.PropertiesConfAccess;
053: import org.objectweb.util.monolog.wrapper.p6spy.P6SpyLogger;
054: import org.objectweb.util.monolog.wrapper.printwriter.PrintWriterImpl;
055:
056: /**
057: * This class provides utility method for using Monolog
058: * @author Philippe Coq.
059: * @author Sebastien Chassande-Barrioz sebastien.chassande@inrialpes.fr
060: * @author Philippe Durieux
061: * @author Florent Benoit & Ludovic Bert
062: * @author Adriana Danes : change MBean implementation model from inheritance to delegation
063: */
064: public class Log {
065:
066: // name of the config file - initialized by the configure method
067: private static String configFile = "trace";
068:
069: /**
070: * This class is actually a wrapper on the unique loggerFactory
071: */
072: private static LoggerFactory lf = null;
073:
074: /**
075: * Properties used for Logging system
076: * Kept here mainly for debugging
077: */
078: private static Properties props = null;
079:
080: // List of topic used inside JOnAS
081: // This list may be not exhaustive since many topics can be added for
082: // different purposes or to refine debugging.
083: // To get the complete list, use "jonas admin -t"
084:
085: public static final String JONAS_ADMIN_PREFIX = "org.objectweb.jonas.admin";
086:
087: public static final String JONAS_DBM_PREFIX = "org.objectweb.jonas.dbm";
088:
089: public static final String JONAS_JCA_PREFIX = "org.objectweb.jonas.jca";
090:
091: public static final String JONAS_CLIENT_PREFIX = "org.objectweb.jonas.client";
092:
093: public static final String JONAS_NAMING_PREFIX = "org.objectweb.jonas.naming";
094:
095: public static final String JONAS_PROPCTX_PREFIX = "org.objectweb.jonas.propagation";
096:
097: public static final String JONAS_REGISTRY_PREFIX = "org.objectweb.jonas.registry";
098:
099: public static final String JONAS_SECURITY_PREFIX = "org.objectweb.jonas.security";
100:
101: public static final String JONAS_CLIENTSTUBGEN_PREFIX = "org.objectweb.jonas_lib.genclientstub";
102:
103: public static final String JONAS_GENBASE_PREFIX = "org.objectweb.jonas_lib.genbase";
104:
105: public static final String JONAS_JACC_SECURITY_PREFIX = "org.objectweb.jonas.security.jacc";
106:
107: public static final String JONAS_WS_SECURITY_PREFIX = "org.objectweb.jonas.security.ws";
108:
109: public static final String JONAS_CSIV2_SECURITY_PREFIX = "org.objectweb.jonas.security.csiv2";
110:
111: public static final String JONAS_CSIV2_DETAILS_SECURITY_PREFIX = "org.objectweb.jonas.security.csiv2_details";
112:
113: public static final String JONAS_SERVER_PREFIX = "org.objectweb.jonas.server";
114:
115: public static final String JONAS_WEB_PREFIX = "org.objectweb.jonas.web";
116:
117: public static final String JONAS_EAR_PREFIX = "org.objectweb.jonas.ear";
118:
119: public static final String JONAS_MAIL_PREFIX = "org.objectweb.jonas.mail";
120:
121: public static final String JONAS_TESTS_PREFIX = "org.objectweb.jonas_tests";
122:
123: public static final String JONAS_LOADER_PREFIX = "org.objectweb.jonas.loader";
124:
125: public static final String JONAS_GENIC_PREFIX = "org.objectweb.jonas.genic";
126:
127: public static final String JONAS_GENIC_VELOCITY_PREFIX = "org.objectweb.jonas.genic.velocity";
128:
129: public static final String JONAS_WSGEN_PREFIX = "org.objectweb.jonas_ws.wsgen";
130:
131: public static final String JONAS_WSGEN_EWS_PREFIX = "org.objectweb.jonas_ws.wsgen.ews";
132:
133: public static final String JONAS_WS_PREFIX = "org.objectweb.jonas.ws";
134:
135: public static final String JONAS_WS_EJBPROVIDER_PREFIX = "org.objectweb.jonas.ws.ejbprovider";
136:
137: public static final String JONAS_PUBLISH_PREFIX = "org.objectweb.jonas.publication";
138:
139: public static final String JONAS_JMX_PREFIX = "org.objectweb.jonas.jmx";
140:
141: public static final String JONAS_MANAGEMENT_PREFIX = "org.objectweb.jonas.management";
142:
143: public static final String JONAS_DOMAIN_MANAGEMENT_PREFIX = "org.objectweb.jonas.domain.management";
144:
145: public static final String JONAS_MANAGEMENT_EVENT_PREFIX = "org.objectweb.jonas.management.event";
146:
147: public static final String JONAS_MEJB = "org.objectweb.jonas.mejb";
148:
149: public static final String JONAS_DISCOVERY_PREFIX = "org.objectweb.jonas.discovery";
150:
151: public static final String SPY_LOGGER_NAME = "org.objectweb.jonas.jdbc.sql";
152:
153: public static final String JONAS_DEPLOY_WORK_PREFIX = "org.objectweb.jonas_lib.deployment.work";
154:
155: public static final String JONAS_JAXR_PREFIX = "org.objectweb.jonas.jaxr";
156:
157: public static final String JONAS_WORK_MGR_PREFIX = "org.objectweb.jonas_lib.work";
158:
159: public static final String JONAS_CLUSTER_DAEMON = "org.objectweb.jonas.cluster.daemon";
160:
161: /**
162: * Logger for Naming
163: */
164: private static boolean isDebugNaming = false;
165:
166: /**
167: * Prefix for DB service (for example hsqldb service)
168: */
169: public static final String JONAS_DB_PREFIX = "org.objectweb.jonas.db";
170:
171: /**
172: * Output tag for the hamdler
173: */
174: private static final String HANDLER_OUTPUT_ATTRIBUTE = "output";
175:
176: /**
177: * Output tag which must be replaced by JOnAS
178: */
179: private static final String AUTOMATIC_CONFIG = "automatic";
180:
181: /**
182: * Directory for the logs $JONAS_BASE/logs
183: */
184: private static final String LOG_DIRECTORY = "logs";
185:
186: /**
187: * Format of a timestamp log.
188: */
189: private static final String TIMESTAMP_FORMAT = "-yyyy-MM-dd";
190:
191: /**
192: * Suffix of a log file.
193: */
194: private static final String SUFFIX_LOGFILE = "log";
195:
196: /**
197: * Default logger factory
198: */
199: private static final String DEFAULT_LOGGERFACTORY = "org.objectweb.util.monolog.wrapper.javaLog.LoggerFactory";
200:
201: private static boolean clientcontainer = false;
202:
203: /**
204: * JProp fully qualified Classname
205: */
206: private static final String JPROP_CLASSNAME = "org.objectweb.jonas.common.JProp";
207:
208: /**
209: * Configure Logger
210: * @param file The configuration file for monolog (usually: trace.properties)
211: */
212: public static void configure(String file) {
213: configFile = file;
214: getLoggerFactory();
215: if (!clientcontainer) {
216: P6SpyLogger.logger = lf.getLogger(SPY_LOGGER_NAME);
217: TraceTimer.configure(lf);
218: TraceCore.configure(lf);
219: // Comment out call until JONAS uses Log4j
220: // TraceTm.configure(lf);
221: }
222:
223: TraceEjb.configure(lf);
224: TraceJms.configure(lf);
225:
226: }
227:
228: /**
229: * It returns the unique LoggerFactory used in JOnAS.
230: * initialize it if not already done.
231: */
232: public static synchronized LoggerFactory getLoggerFactory() {
233: if (lf == null) {
234: try {
235: // Detect client case = no JONAS_BASE
236: if (isClient()) {
237: clientcontainer = true;
238: InputStream is = null;
239:
240: // Is there a specific file to use instead the default name
241: String traceClient = System
242: .getProperty("jonas.client.trace.file");
243: if (traceClient != null) {
244: try {
245: is = new FileInputStream(new File(
246: traceClient));
247: } catch (FileNotFoundException fne) {
248: System.err
249: .println("Can not init logger with the supplied file '"
250: + traceClient
251: + "', this file doesn't exist. Init with default values.");
252:
253: }
254: } else {
255: //Client
256: //Is there a trace properties file in the classpath ?
257: is = Thread.currentThread()
258: .getContextClassLoader()
259: .getResourceAsStream(
260: "traceclient.properties");
261: }
262: if (is == null) {
263: // no traceclient.properties found
264: // using a default configuration
265: props = new Properties();
266: props.put("log.config.classname",
267: DEFAULT_LOGGERFACTORY);
268: props.put("logger.root.level", "INFO");
269: } else {
270: // use the configuration of the properties file.
271: props = new Properties();
272: props.load(is);
273: }
274: lf = Monolog.getMonologFactory(props);
275: return lf;
276: }
277: // server case
278: // get jonas configuration properties
279: Object jProp = null;
280: try {
281: jProp = JProp.getInstance();
282: // Run jonas
283: // Create a JProp object for the configFile
284: JProp.getInstance(configFile);
285: } catch (Exception e) {
286: System.err
287: .println("Can't read jonas.properties. Check that you have defined a $JONAS_BASE variable");
288: }
289:
290: // load properties from config file
291: props = JProp.getInstance(configFile)
292: .getConfigFileEnv();
293: String jonasBase = null;
294: String nameOfServer = null;
295: if (jProp != null) {
296: jonasBase = JProp.getJonasBase();
297: nameOfServer = ((JProp) jProp).getValue(
298: "jonas.name", "jonas");
299: } else {
300: // Set default
301: jonasBase = ".";
302: nameOfServer = "jonas";
303: }
304:
305: // Before sending props, replace AUTOMATIC pattern by a file in $JONAS_BASE/logs/
306: // File are named <JOnAS_server_name>TIMESTAMP_FORMAT.SUFFIX_LOGFILE
307: File logFirFile = new File(jonasBase + File.separator
308: + LOG_DIRECTORY);
309:
310: // Properties sent may be updated if AUTOMATIC_CONFIG is used
311: // Updated properties are in
312: Properties updatedProps = null;
313:
314: //Create a date format
315: SimpleDateFormat sdf = new SimpleDateFormat(
316: TIMESTAMP_FORMAT);
317: String date = sdf.format(new Date());
318: // How many AUTOMATIC field have been replaced
319: int nbAut = 0;
320:
321: File logFile = null;
322: for (Enumeration keys = props.keys(); keys
323: .hasMoreElements();) {
324: String key = (String) keys.nextElement();
325: if (key == null) {
326: continue;
327: }
328:
329: if (key
330: .startsWith(PropertiesConfAccess.HANDLER_FIELD)) {
331: String temp = DottedStringTools.getFirst(key);
332:
333: if (temp == null) {
334: continue;
335: }
336:
337: temp = DottedStringTools.getEnd(key);
338: if (temp == null) {
339: continue;
340: }
341:
342: String handlerName = DottedStringTools
343: .getBegin(temp);
344:
345: String stringType = props
346: .getProperty(
347: PropertiesConfAccess.HANDLER_FIELD
348: + PropertiesConfAccess.DOT
349: + handlerName
350: + PropertiesConfAccess.DOT
351: + PropertiesConfAccess.HANDLER_TYPE_ATTRIBUTE,
352: null);
353: String stringOutput = props.getProperty(
354: PropertiesConfAccess.HANDLER_FIELD
355: + PropertiesConfAccess.DOT
356: + handlerName
357: + PropertiesConfAccess.DOT
358: + HANDLER_OUTPUT_ATTRIBUTE,
359: null);
360: // Got the type and the output
361: // --> Compare with the pattern AUTOMATIC_CONFIG for the FILE type.
362: if ((stringType != null)
363: && (stringOutput != null)) {
364: if (PropertiesConfAccess.HANDLER_TYPE_ATTRIBUTE_FILE_VALUE
365: .equalsIgnoreCase(stringType)
366: || (PropertiesConfAccess.HANDLER_TYPE_ATTRIBUTE_ROLLING_FILE_VALUE
367: .equalsIgnoreCase(stringType))) {
368: if (stringOutput
369: .equalsIgnoreCase(AUTOMATIC_CONFIG)) {
370: // OK, it's match
371: String fileName = null;
372:
373: if (nbAut > 0) {
374: // Add an unique entry by adding nbAut value.
375: fileName = nameOfServer
376: + date
377: + PropertiesConfAccess.DOT
378: + nbAut
379: + PropertiesConfAccess.DOT
380: + SUFFIX_LOGFILE;
381: } else {
382: // this is the first occurence of AUTOMATIC_CONFIG, create updatedProps
383: updatedProps = (Properties) props
384: .clone();
385: fileName = nameOfServer
386: + date
387: + PropertiesConfAccess.DOT
388: + SUFFIX_LOGFILE;
389: }
390:
391: // Log directory exists ?
392: if (logFirFile.exists()) {
393: logFile = new File(logFirFile,
394: fileName);
395: } else {
396: // No $JONAS_BASE/logs directory, try current directory
397: logFile = new File(fileName);
398: }
399:
400: updatedProps
401: .setProperty(
402: PropertiesConfAccess.HANDLER_FIELD
403: + PropertiesConfAccess.DOT
404: + handlerName
405: + PropertiesConfAccess.DOT
406: + HANDLER_OUTPUT_ATTRIBUTE,
407: logFile.getPath());
408: nbAut++;
409:
410: } else {
411: // not automatic -- change relative file name to be relative to JONAS_BASE/logs
412: logFile = new File(stringOutput);
413: if (!logFile.isAbsolute()) {
414: // file name is relative so try to create in JONAS_BASE/logs
415: if (logFirFile.exists()) { // Log directory exists ?
416: logFile = new File(
417: logFirFile,
418: stringOutput);
419: } else { // No $JONAS_BASE/logs directory, try current directory
420: logFile = new File(
421: stringOutput);
422: }
423: if (nbAut == 0) {
424: updatedProps = (Properties) props
425: .clone();
426: nbAut++;
427: }
428: if (stringOutput
429: .endsWith(".automatic")
430: || stringOutput
431: .endsWith(".auto")) {
432: nbAut++;
433: String autoStr = logFile
434: .getPath()
435: .substring(
436: 0,
437: logFile
438: .getPath()
439: .lastIndexOf(
440: '.'))
441: + date
442: + PropertiesConfAccess.DOT
443: + nbAut
444: + PropertiesConfAccess.DOT
445: + SUFFIX_LOGFILE;
446: logFile = new File(autoStr);
447: }
448: updatedProps
449: .setProperty(
450: PropertiesConfAccess.HANDLER_FIELD
451: + PropertiesConfAccess.DOT
452: + handlerName
453: + PropertiesConfAccess.DOT
454: + HANDLER_OUTPUT_ATTRIBUTE,
455: logFile
456: .getPath());
457: }
458: }
459: }
460: }
461: }
462: }
463:
464: // Instanciate the LoggerFactory
465: String b = props.getProperty("log.config.classname",
466: null);
467: if (b == null) {
468: System.err
469: .println("Malformed configuration log file: log.config.classname not available");
470: return null;
471: }
472: lf = (LoggerFactory) Class.forName(b).newInstance();
473: // Configure the LoggerFactory with the updated properties or the initial ones
474: if (updatedProps == null) {
475: PropertiesConfAccess.load(props, lf,
476: (HandlerFactory) lf, (LevelFactory) lf);
477: } else {
478: PropertiesConfAccess.load(updatedProps, lf,
479: (HandlerFactory) lf, (LevelFactory) lf);
480: }
481: //Register the monolog factory in Monolog
482: Monolog.monologFactory = (MonologFactory) lf;
483: } catch (Exception e) {
484: System.err.println("Cannot get LoggerFactory:" + e);
485: e.printStackTrace();
486: }
487: }
488: return lf;
489: }
490:
491: /**
492: * @return Returns true if we are in a client context
493: */
494: private static boolean isClient() {
495: boolean hasJonasBase = System.getProperty("jonas.base") != null;
496: boolean hasJonasRoot = System.getProperty("install.root") != null;
497: boolean hasJProp = true;
498: try {
499: Thread.currentThread().getContextClassLoader().loadClass(
500: JPROP_CLASSNAME);
501: } catch (ClassNotFoundException cnfe) {
502: hasJProp = false;
503: }
504: // a server has the 3 params, all other case are clients case
505: return !(hasJProp && hasJonasBase && hasJonasRoot);
506: }
507:
508: /**
509: * Reset logger factory
510: */
511: public static void reset() {
512: lf = null;
513: }
514:
515: /**
516: * Returns the standard PrintWriter associated to the logger defined by
517: * its topic.
518: * This is mainly used for DBM and Connectors.
519: */
520: public static PrintWriter getLogWriter(String topic) {
521: // TODO : should not create a new object at each call
522: return new PrintWriterImpl(getLogger(topic), getLoggerFactory());
523: }
524:
525: /**
526: * Shortcut that returns the LevelFactory
527: */
528: public static LevelFactory getLevelFactory() {
529: return (LevelFactory) getLoggerFactory();
530: }
531:
532: /**
533: * Shortcut to get the Logger by its topic name.
534: * @param topic the topic of the returned logger
535: * @return always a logger instance (never null value).
536: */
537: public static Logger getLogger(String topic) {
538: return getLoggerFactory().getLogger(topic);
539: }
540:
541: public static Properties getProperties() {
542: return props;
543: }
544:
545: public static final boolean isDebugNaming() {
546: return isDebugNaming;
547: }
548:
549: /**
550: * Sets booleans which enable debugging (debug level or Warn)
551: */
552: public static void syncLevels() {
553: // debug
554: isDebugNaming = getLogger(JONAS_NAMING_PREFIX).isLoggable(
555: BasicLevel.DEBUG);
556: }
557: }
|