/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.loggers.debug; import org.opends.server.loggers.*; import org.opends.server.util.DynamicConstants; import org.opends.server.types.DebugLogLevel; import static org.opends.server.util.ServerConstants.PROPERTY_DEBUG_ENABLED; import static org.opends.server.util.ServerConstants.PROPERTY_DEBUG_TARGET; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.TreeMap; /** * A LoggingConfiguration for the debug logging system. */ public class DebugConfiguration extends LoggerConfiguration { private static final String GLOBAL= "_global"; private Map classTraceSettings; private Map> methodTraceSettings; /** * Error handler for tracing. Tracing will be disabled * if too many errors occur. */ private class DebugErrorHandler implements LoggerErrorHandler { private static final int ERROR_THRESHOLD= 10; private int _loggingErrors= 0; /** * Error handler for tracing. Tracing will be disabled * if too many errors occur. * * @param record the log record that caused the error to occur. * @param ex the exception thrown. */ public synchronized void handleError(LogRecord record, Throwable ex) { _loggingErrors++; DebugLogFormatter formatter = new DebugLogFormatter(); System.err.println("Error publishing record: " + formatter.format(record) + ex); // If we've had too many write errors, just turn off // tracing to prevent an overflow of messages. if (_loggingErrors >= ERROR_THRESHOLD) { System.err.println("TOO MANY ERRORS FROM DEBUG LOGGER. SHUTTING DOWN"); enabled = false; } } } /** * Construct a default configuration where the logger is disabled and the * global scope will only log at the ERROR level. */ public DebugConfiguration() { super(null); this.setErrorHandler(new DebugErrorHandler()); classTraceSettings = null; methodTraceSettings = null; //Set the global settings so that only errors are logged. addTraceSettings(null, new TraceSettings(DebugLogLevel.ERROR)); } /** * Gets the method trace levels for a specified class. * @param className - a fully qualified class name to get method trace * levels for * @return an unmodifiable map of trace levels keyed by method name. If * no method level tracing is configured for the scope, null is * returned. */ public Map getMethodSettings(String className) { Map levels = null; if (enabled && methodTraceSettings != null) { // Method levels are always at leaves in the // hierarchy, so don't bother searching up. Map value= methodTraceSettings.get(className); if (value != null ) { levels= value; } } return levels != null ? Collections.unmodifiableMap(levels) : null; } /** * Get the trace settings for a specified class. * @param className - a fully qualified class name to get the * trace level for * @return the current trace settings for the class. */ public TraceSettings getTraceSettings(String className) { TraceSettings settings = TraceSettings.DISABLED; // If we're not enabled, trace level is DISABLED. if (enabled && classTraceSettings != null) { // Find most specific trace setting which covers this // fully qualified class name // Search up the hierarchy for a match. String searchName= className; Object value= null; value= classTraceSettings.get(searchName); while (value == null && searchName != null) { int clipPoint= searchName.lastIndexOf('$'); if (clipPoint == -1) clipPoint= searchName.lastIndexOf('.'); if (clipPoint != -1) { searchName= searchName.substring(0, clipPoint); value= classTraceSettings.get(searchName); } else { searchName= null; } } // Use global settings, if nothing more specific was found. if (value == null) value= classTraceSettings.get(GLOBAL); if (value != null) { settings= (TraceSettings)value; } } return settings; } /** * Adds a trace settings to the current set for a specified scope. If a * scope is not specified, the settings will be set for the global scope. * The global scope settings are used when no other scope matches. * * @param scope - the scope to set trace settings for; this is a fully * qualified class name or null to set the trace settings for the global * scope. * @param settings - the trace settings for the scope */ public void addTraceSettings(String scope, TraceSettings settings) { if (scope == null) { setClassSettings(GLOBAL, settings); } else { int methodPt= scope.lastIndexOf('#'); if (methodPt != -1) { String methodName= scope.substring(methodPt+1); scope= scope.substring(0, methodPt); setMethodSettings(scope, methodName, settings); } else { setClassSettings(scope, settings); } } } private synchronized void setClassSettings(String className, TraceSettings settings) { if(classTraceSettings == null) classTraceSettings = new HashMap(); classTraceSettings.put(className, settings); } private synchronized void setMethodSettings(String className, String methodName, TraceSettings settings) { if (methodTraceSettings == null) methodTraceSettings = new HashMap>(); Map methodLevels= methodTraceSettings.get(className); if (methodLevels == null) { methodLevels= new TreeMap(); methodTraceSettings.put(className, methodLevels); } methodLevels.put(methodName, settings); } /** * Retrieve the initial configuration to use on debug logger startup. Settings * are read from system properties. * If this is not a debug build of OpenDS, the resulting configuration is * always disabled. * * @return the initial configuration to use for the debug logger. */ public static DebugConfiguration getStartupConfiguration() { String enabledProp = System.getProperty(PROPERTY_DEBUG_ENABLED); if(DynamicConstants.WEAVE_ENABLED && (enabledProp != null && (enabledProp.startsWith("T") || enabledProp.startsWith("t") || enabledProp.startsWith("Y") || enabledProp.startsWith("y")))) { DebugConfiguration config = new DebugConfiguration(); config.setEnabled(true); TextLogPublisher consolePublisher = new TextLogPublisher(TextWriter.STDOUT, new DebugLogFormatter()); config.addPublisher(consolePublisher); Set> propertyEntries = System.getProperties().entrySet(); for(Map.Entry entry : propertyEntries) { if(((String)entry.getKey()).startsWith(PROPERTY_DEBUG_TARGET)) { String value = (String)entry.getValue(); int settingsStart= value.indexOf(":"); //See if the scope and settings exists if(settingsStart > 0) { String scope = value.substring(0, settingsStart); TraceSettings settings = TraceSettings.parseTraceSettings( value.substring(settingsStart+1)); if(settings != null) { config.addTraceSettings(scope, settings); } } } } return config; } else { //If it is not enabled or not a debug build, just return the default //off config. return new DebugConfiguration(); } } }