001: /*
002: * <copyright>
003: *
004: * Copyright 2001-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026:
027: package org.cougaar.util.log.log4j;
028:
029: import org.apache.log4j.Category;
030: import org.apache.log4j.ConsoleAppender;
031: import org.apache.log4j.Level;
032: import org.apache.log4j.Logger;
033: import org.cougaar.bootstrap.SystemProperties;
034: import org.cougaar.util.StackElements;
035: import org.cougaar.util.log.LoggerAdapter;
036: import org.cougaar.util.log.Logging;
037:
038: import java.text.SimpleDateFormat;
039: import java.util.Date;
040: import java.util.Enumeration;
041: import java.util.HashSet;
042:
043: /**
044: * Package-private log4j implementation of logger.
045: * <p/>
046: * This is an log4j based implementation of Logger. One
047: * important note is that when this instance is created it
048: * creates a log4j Logger based on the class passed in. If
049: * subclasses use the same LoggerImpl as the superclass
050: * they will have the same log4j Logger. This may possibly
051: * cause confusion. To avoid this each object can get its own
052: * instance or use its own "classname:method" name.
053: *
054: * @property org.cougaar.util.log.checkwrappers
055: * Debugging check to ensure that every call to the logger is wrapped with an <code>isEnabled</code> check.
056: * @see org.cougaar.util.log.LoggerFactory
057: */
058: class LoggerImpl extends LoggerAdapter {
059: private static final int MAXDOTS = 50;
060: private static int ndots = 0;
061: private static Object dotsLock = new Object();
062: private static SimpleDateFormat dateFormat = new SimpleDateFormat(
063: "yyyy-MM-dd hh:mm:ss,SSS");
064:
065: // log4j logger, which does the real work...
066: private final Logger cat;
067:
068: private boolean checkDots = false;
069:
070: private static boolean checkForWrappers = SystemProperties
071: .getBoolean("org.cougaar.util.log.checkwrappers");
072:
073: private static final HashSet throwables = new HashSet();
074:
075: private static boolean hasConsoleAppender(Category cat) {
076: for (Enumeration e = cat.getAllAppenders(); e.hasMoreElements();) {
077: Object o = e.nextElement();
078: if (o instanceof ConsoleAppender) {
079: return true;
080: }
081: }
082: if (cat.getAdditivity()) {
083: Category parent = cat.getParent();
084: if (parent != null)
085: return hasConsoleAppender(parent);
086: }
087: return false;
088: }
089:
090: /**
091: * Constructor which uses the specified name to form a
092: * log4j Logger.
093: *
094: * @param obj requestor Object requesting this service.
095: */
096: public LoggerImpl(Object obj) {
097: String s = Logging.getKey(obj);
098: cat = Logger.getLogger(s);
099: checkDots = hasConsoleAppender(cat);
100: }
101:
102: /**
103: * @see Logger.isEnabledFor see interface for notes
104: */
105: public boolean isEnabledFor(int level) {
106: if (level > WARN) {
107: return true;
108: } else {
109: Level p = Util.convertIntToLevel(level);
110: return cat.isEnabledFor(p);
111: }
112: }
113:
114: public void log(int level, String message, Throwable t) {
115: Level p = Util.convertIntToLevel(level);
116: if (checkForWrappers && !cat.isEnabledFor(p)) {
117: Throwable th = new Throwable();
118: StackElements st = new StackElements(th);
119: boolean res;
120: synchronized (throwables) {
121: res = throwables.add(st);
122: }
123:
124: if (res) {
125: cat.error("Call to Logger is missing wrapper: ", th);
126: }
127: }
128: if (checkDots && cat.isEnabledFor(p)) {
129: // synchronize to prevent any dots between dumpDots and logging.
130: synchronized (dotsLock) {
131: dumpDots();
132: cat.log(p, message, t);
133: }
134: } else {
135: cat.log(p, message, t);
136: }
137: }
138:
139: // Must be called in a synchronized(dotsLock)
140: private static void dumpDots() {
141: if (ndots > 0) {
142: System.out.println();
143: ndots = 0;
144: }
145: }
146:
147: /**
148: * Print a dot or other string to System.out such that it is nicely
149: * interleaved with log output to any ConsoleAppenders to
150: * System.out. Such output is always preceded with a standard format
151: * time of the first such output and terminated with a eol before
152: * any logging output or if such output exceeds a certain length. In
153: * theory, we could pipe any output to stderr or stdout through (a
154: * static version of) this method and thereby interleave such
155: * spontaneous output with logging output, but doing so would
156: * require adjusting all ConsoleAppenders to use the original
157: * stdout/stderr to avoid.
158: */
159:
160: public void printDot(String dot) {
161: synchronized (dotsLock) {
162: if (ndots == 0) {
163: System.out.print(dateFormat.format(new Date())
164: + " SHOUT [DOTS] - ");
165: }
166: System.out.print(dot);
167: ndots += dot.length();
168: if (ndots >= MAXDOTS) {
169: dumpDots();
170: }
171: }
172: }
173:
174: public String toString() {
175: return "logger \""
176: + cat.getName()
177: + "\" at "
178: + (isDetailEnabled() ? "detail"
179: : isDebugEnabled() ? "debug"
180: : isInfoEnabled() ? "info"
181: : isWarnEnabled() ? "warn"
182: : isErrorEnabled() ? "error"
183: : isShoutEnabled() ? "shout"
184: : isFatalEnabled() ? "fatal"
185: : "none");
186: }
187: }
|