001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2007-2009 Sun Microsystems, Inc.
015 * Portions Copyright 2013-2015 ForgeRock AS.
016 */
017package org.opends.server.loggers;
018
019import static org.opends.messages.ConfigMessages.*;
020import static org.opends.server.util.ServerConstants.*;
021
022import java.util.ArrayList;
023import java.util.Collection;
024import java.util.List;
025import java.util.Map;
026import java.util.concurrent.ConcurrentHashMap;
027
028import org.opends.server.admin.ClassPropertyDefinition;
029import org.opends.server.admin.std.meta.DebugLogPublisherCfgDefn;
030import org.opends.server.admin.std.server.DebugLogPublisherCfg;
031import org.opends.server.core.ServerContext;
032
033/**
034 * A logger for debug and trace logging. DebugLogger provides a debugging
035 * management access point. It is used to configure the Tracers, as well as
036 * to register a per-class tracer.
037 *
038 * Various stub debug methods are provided to log different types of debug
039 * messages. However, these methods do not contain any actual implementation.
040 * Tracer aspects are later weaved to catch alls to these stub methods and
041 * do the work of logging the message.
042 *
043 * DebugLogger is self-initializing.
044 */
045public class DebugLogger extends AbstractLogger
046    <DebugLogPublisher<DebugLogPublisherCfg>, DebugLogPublisherCfg>
047{
048
049  /** The set of all DebugTracer instances. */
050  private static Map<String, DebugTracer> classTracers = new ConcurrentHashMap<>();
051
052  /**
053   * Trace methods will use this static boolean to determine if debug is enabled
054   * so to not incur the cost of calling debugPublishers.isEmpty().
055   */
056  private static boolean enabled;
057
058  private static final LoggerStorage
059      <DebugLogPublisher<DebugLogPublisherCfg>, DebugLogPublisherCfg>
060      loggerStorage = new LoggerStorage<>();
061
062  /** The singleton instance of this class. */
063  static final DebugLogger instance = new DebugLogger();
064
065  /**
066   * The constructor for this class.
067   */
068  private DebugLogger()
069  {
070    super((Class) DebugLogPublisher.class,
071        ERR_CONFIG_LOGGER_INVALID_DEBUG_LOGGER_CLASS);
072  }
073
074  /** {@inheritDoc} */
075  @Override
076  protected ClassPropertyDefinition getJavaClassPropertyDefinition()
077  {
078    return DebugLogPublisherCfgDefn.getInstance()
079        .getJavaClassPropertyDefinition();
080  }
081
082  /** {@inheritDoc} */
083  @Override
084  protected Collection<DebugLogPublisher<DebugLogPublisherCfg>> getLogPublishers()
085  {
086    return loggerStorage.getLogPublishers();
087  }
088
089  /**
090   * Update all debug tracers with the settings in the registered
091   * publishers.
092   */
093  static void updateTracerSettings()
094  {
095    DebugLogPublisher<DebugLogPublisherCfg>[] publishers =
096        loggerStorage.getLogPublishers().toArray(new DebugLogPublisher[0]);
097
098    for(DebugTracer tracer : classTracers.values())
099    {
100      tracer.updateSettings(publishers);
101    }
102  }
103
104  /**
105   * Indicates if debug logging is enabled.
106   *
107   * @return True if debug logging is enabled. False otherwise.
108   */
109  public static boolean debugEnabled()
110  {
111    return enabled;
112  }
113
114  /**
115   * Retrieve the singleton instance of this class.
116   *
117   * @return The singleton instance of this logger.
118   */
119  public static DebugLogger getInstance()
120  {
121    return instance;
122  }
123
124  /**
125   * Returns the registered Debug Tracer for a traced class.
126   *
127   * @param className The name of the class tracer to retrieve.
128   * @return The tracer for the provided class or null if there are
129   *         no tracers registered.
130   */
131  public static DebugTracer getTracer(final String className)
132  {
133    DebugTracer tracer = classTracers.get(className);
134    if (tracer == null)
135    {
136      tracer =
137          new DebugTracer(className, loggerStorage.getLogPublishers().toArray(
138              new DebugLogPublisher[0]));
139      classTracers.put(tracer.getTracedClassName(), tracer);
140    }
141    return tracer;
142  }
143
144  /**
145   * Adds a text debug log publisher that will print all messages to the
146   * provided writer, based on debug target(s) defined through system
147   * properties.
148   * <p>
149   * It is expected that one or more system properties beginning with
150   * {@code PROPERTY_DEBUG_TARGET} are set to define the properties of the debug
151   * targets used by the publisher, otherwise no publisher is added.
152   *
153   * @param writer
154   *          The text writer where the message will be written to.
155   * @return the publisher. It may be {@code null} if no publisher is added.
156   */
157  @SuppressWarnings({ "unchecked", "rawtypes" })
158  public final TextDebugLogPublisher addPublisherIfRequired(TextWriter writer)
159  {
160    final List<String> debugTargets = getDebugTargetsFromSystemProperties();
161    TextDebugLogPublisher publisher = null;
162    if (!debugTargets.isEmpty())
163    {
164      publisher = TextDebugLogPublisher.getStartupTextDebugPublisher(debugTargets, writer);
165      if (publisher != null) {
166        addLogPublisher((DebugLogPublisher) publisher);
167      }
168    }
169    return publisher;
170  }
171
172  private List<String> getDebugTargetsFromSystemProperties()
173  {
174    final List<String> targets = new ArrayList<>();
175    for (Map.Entry<Object, Object> entry : System.getProperties().entrySet())
176    {
177      if (((String) entry.getKey()).startsWith(PROPERTY_DEBUG_TARGET))
178      {
179        targets.add((String)entry.getValue());
180      }
181    }
182    return targets;
183  }
184
185  @Override
186  public final synchronized void addLogPublisher(final DebugLogPublisher<DebugLogPublisherCfg> publisher)
187  {
188    loggerStorage.addLogPublisher(publisher);
189    updateTracerSettings();
190    enabled = true;
191    adjustJulLevel();
192  }
193
194  @Override
195  public final synchronized boolean removeLogPublisher(final DebugLogPublisher<DebugLogPublisherCfg> publisher)
196  {
197    boolean removed = loggerStorage.removeLogPublisher(publisher);
198    updateTracerSettings();
199    enabled = !loggerStorage.getLogPublishers().isEmpty();
200    adjustJulLevel();
201    return removed;
202  }
203
204  @Override
205  public final synchronized void removeAllLogPublishers()
206  {
207    loggerStorage.removeAllLogPublishers();
208    updateTracerSettings();
209    enabled = false;
210    adjustJulLevel();
211  }
212
213  private void adjustJulLevel()
214  {
215    final ServerContext serverContext = getServerContext();
216    if (serverContext != null)
217    {
218      serverContext.getLoggerConfigManager().adjustJulLevel();
219    }
220  }
221
222  /**
223   * Returns whether there is at least one debug log publisher enabled.
224   * @return whether there is at least one debug log publisher enabled.
225   */
226  public boolean isEnabled()
227  {
228    return enabled;
229  }
230}