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-2016 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.core.ServerContext;
029import org.forgerock.opendj.config.ClassPropertyDefinition;
030import org.forgerock.opendj.server.config.meta.DebugLogPublisherCfgDefn;
031import org.forgerock.opendj.server.config.server.DebugLogPublisherCfg;
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  /** The constructor for this class. */
066  private DebugLogger()
067  {
068    super((Class) DebugLogPublisher.class,
069        ERR_CONFIG_LOGGER_INVALID_DEBUG_LOGGER_CLASS);
070  }
071
072  @Override
073  protected ClassPropertyDefinition getJavaClassPropertyDefinition()
074  {
075    return DebugLogPublisherCfgDefn.getInstance()
076        .getJavaClassPropertyDefinition();
077  }
078
079  @Override
080  protected Collection<DebugLogPublisher<DebugLogPublisherCfg>> getLogPublishers()
081  {
082    return loggerStorage.getLogPublishers();
083  }
084
085  /** Update all debug tracers with the settings in the registered publishers. */
086  static void updateTracerSettings()
087  {
088    DebugLogPublisher<DebugLogPublisherCfg>[] publishers =
089        loggerStorage.getLogPublishers().toArray(new DebugLogPublisher[0]);
090
091    for(DebugTracer tracer : classTracers.values())
092    {
093      tracer.updateSettings(publishers);
094    }
095  }
096
097  /**
098   * Indicates if debug logging is enabled.
099   *
100   * @return True if debug logging is enabled. False otherwise.
101   */
102  public static boolean debugEnabled()
103  {
104    return enabled;
105  }
106
107  /**
108   * Retrieve the singleton instance of this class.
109   *
110   * @return The singleton instance of this logger.
111   */
112  public static DebugLogger getInstance()
113  {
114    return instance;
115  }
116
117  /**
118   * Returns the registered Debug Tracer for a traced class.
119   *
120   * @param className The name of the class tracer to retrieve.
121   * @return The tracer for the provided class or null if there are
122   *         no tracers registered.
123   */
124  public static DebugTracer getTracer(final String className)
125  {
126    DebugTracer tracer = classTracers.get(className);
127    if (tracer == null)
128    {
129      tracer =
130          new DebugTracer(className, loggerStorage.getLogPublishers().toArray(
131              new DebugLogPublisher[0]));
132      classTracers.put(tracer.getTracedClassName(), tracer);
133    }
134    return tracer;
135  }
136
137  /**
138   * Adds a text debug log publisher that will print all messages to the
139   * provided writer, based on debug target(s) defined through system
140   * properties.
141   * <p>
142   * It is expected that one or more system properties beginning with
143   * {@code PROPERTY_DEBUG_TARGET} are set to define the properties of the debug
144   * targets used by the publisher, otherwise no publisher is added.
145   *
146   * @param writer
147   *          The text writer where the message will be written to.
148   * @return the publisher. It may be {@code null} if no publisher is added.
149   */
150  @SuppressWarnings({ "unchecked", "rawtypes" })
151  public final TextDebugLogPublisher addPublisherIfRequired(TextWriter writer)
152  {
153    final List<String> debugTargets = getDebugTargetsFromSystemProperties();
154    TextDebugLogPublisher publisher = null;
155    if (!debugTargets.isEmpty())
156    {
157      publisher = TextDebugLogPublisher.getStartupTextDebugPublisher(debugTargets, writer);
158      if (publisher != null) {
159        addLogPublisher((DebugLogPublisher) publisher);
160      }
161    }
162    return publisher;
163  }
164
165  private List<String> getDebugTargetsFromSystemProperties()
166  {
167    final List<String> targets = new ArrayList<>();
168    for (Map.Entry<Object, Object> entry : System.getProperties().entrySet())
169    {
170      if (((String) entry.getKey()).startsWith(PROPERTY_DEBUG_TARGET))
171      {
172        targets.add((String)entry.getValue());
173      }
174    }
175    return targets;
176  }
177
178  @Override
179  public final synchronized void addLogPublisher(final DebugLogPublisher<DebugLogPublisherCfg> publisher)
180  {
181    loggerStorage.addLogPublisher(publisher);
182    updateTracerSettings();
183    enabled = true;
184    adjustJulLevel();
185  }
186
187  @Override
188  public final synchronized boolean removeLogPublisher(final DebugLogPublisher<DebugLogPublisherCfg> publisher)
189  {
190    boolean removed = loggerStorage.removeLogPublisher(publisher);
191    updateTracerSettings();
192    enabled = !loggerStorage.getLogPublishers().isEmpty();
193    adjustJulLevel();
194    return removed;
195  }
196
197  @Override
198  public final synchronized void removeAllLogPublishers()
199  {
200    loggerStorage.removeAllLogPublishers();
201    updateTracerSettings();
202    enabled = false;
203    adjustJulLevel();
204  }
205
206  private void adjustJulLevel()
207  {
208    final ServerContext serverContext = getServerContext();
209    if (serverContext != null)
210    {
211      serverContext.getLoggerConfigManager().adjustJulLevel();
212    }
213  }
214
215  /**
216   * Returns whether there is at least one debug log publisher enabled.
217   * @return whether there is at least one debug log publisher enabled.
218   */
219  public boolean isEnabled()
220  {
221    return enabled;
222  }
223}