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