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 2009 Sun Microsystems, Inc. 015 * Portions Copyright 2012-2016 ForgeRock AS. 016 */ 017package org.opends.server.loggers; 018 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.TreeMap; 023 024import org.forgerock.i18n.LocalizableMessage; 025import org.forgerock.opendj.server.config.server.DebugLogPublisherCfg; 026 027/** 028 * This class defines the set of methods and structures that must be 029 * implemented for a Directory Server debug log publisher. 030 * 031 * @param <T> The type of debug log publisher configuration handled 032 * by this log publisher implementation. 033 */ 034@org.opends.server.types.PublicAPI( 035 stability=org.opends.server.types.StabilityLevel.VOLATILE, 036 mayInstantiate=false, 037 mayExtend=true, 038 mayInvoke=false) 039public abstract class DebugLogPublisher<T extends DebugLogPublisherCfg> 040 implements LogPublisher<T> 041{ 042 /** The default global settings key. */ 043 private static final String GLOBAL= "_global"; 044 045 /** The map of class names to their trace settings. */ 046 private Map<String,TraceSettings> classTraceSettings; 047 048 /** The map of class names to their method trace settings. */ 049 private Map<String,Map<String,TraceSettings>> methodTraceSettings; 050 051 052 053 /** Construct a default configuration where the global scope will only log at the ERROR level. */ 054 protected DebugLogPublisher() 055 { 056 classTraceSettings = null; 057 methodTraceSettings = null; 058 059 //Set the global settings so that nothing is logged. 060 addTraceSettings(null, TraceSettings.DISABLED); 061 } 062 063 064 065 @Override 066 public boolean isConfigurationAcceptable(T configuration, 067 List<LocalizableMessage> unacceptableReasons) 068 { 069 // This default implementation does not perform any special 070 // validation. It should be overridden by debug log publisher 071 // implementations that wish to perform more detailed validation. 072 return true; 073 } 074 075 076 077 /** 078 * Gets the method trace levels for a specified class. 079 * 080 * @param className The fully-qualified name of the class for 081 * which to get the trace levels. 082 * 083 *@return An unmodifiable map of trace levels keyed by method name, 084 * or {@code null} if no method-level tracing is configured 085 * for the scope. 086 */ 087 final Map<String,TraceSettings> getMethodSettings( 088 String className) 089 { 090 if(methodTraceSettings == null) 091 { 092 return null; 093 } 094 else 095 { 096 return methodTraceSettings.get(className); 097 } 098 } 099 100 101 102 /** 103 * Get the trace settings for a specified class. 104 * 105 * @param className 106 * The fully-qualified name of the class for which to get the trace 107 * levels. 108 * @return The current trace settings for the class. 109 */ 110 final TraceSettings getClassSettings(String className) 111 { 112 TraceSettings settings = null; 113 if (classTraceSettings != null) 114 { 115 // Find most specific trace setting 116 // which covers this fully qualified class name 117 // Search up the hierarchy for a match. 118 String searchName = className; 119 settings = classTraceSettings.get(searchName); 120 while (settings == null && searchName != null) 121 { 122 int clipPoint = searchName.lastIndexOf('$'); 123 if (clipPoint == -1) 124 { 125 clipPoint = searchName.lastIndexOf('.'); 126 } 127 if (clipPoint != -1) 128 { 129 searchName = searchName.substring(0, clipPoint); 130 settings = classTraceSettings.get(searchName); 131 } 132 else 133 { 134 searchName = null; 135 } 136 } 137 // Try global settings 138 // only if no specific target is defined 139 if (settings == null && classTraceSettings.size()==1) { 140 settings = classTraceSettings.get(GLOBAL); 141 } 142 } 143 return settings == null ? TraceSettings.DISABLED : settings; 144 } 145 146 147 148 /** 149 * Adds a trace settings to the current set for a specified scope. 150 * If a scope is not specified, the settings will be set for the 151 * global scope. The global scope settings are used when no other 152 * scope matches. 153 * 154 * @param scope The scope for which to set the trace settings. 155 * This should be a fully-qualified class name, or 156 * {@code null} to set the trace settings for the 157 * global scope. 158 * @param settings The trace settings for the specified scope. 159 */ 160 public final void addTraceSettings(String scope, TraceSettings settings) 161 { 162 if (scope == null) { 163 setClassSettings(GLOBAL, settings); 164 } 165 else { 166 int methodPt= scope.lastIndexOf('#'); 167 if (methodPt != -1) { 168 String methodName= scope.substring(methodPt+1); 169 scope= scope.substring(0, methodPt); 170 setMethodSettings(scope, methodName, settings); 171 } 172 else { 173 setClassSettings(scope, settings); 174 } 175 } 176 } 177 178 /** 179 * Determine whether a trace setting is already defined for a particular 180 * scope. 181 * 182 * @param scope 183 * The scope for which to make the determination. This should be a 184 * fully-qualified class name. 185 * @return {@code true} if a trace settings is defined for the specified 186 * scope, {@code false} otherwise. 187 */ 188 final boolean hasTraceSettings(String scope) 189 { 190 int methodPt = scope.lastIndexOf('#'); 191 if (methodPt != -1) 192 { 193 String methodName = scope.substring(methodPt + 1); 194 scope = scope.substring(0, methodPt); 195 if (methodTraceSettings != null) 196 { 197 Map<String, TraceSettings> methodLevels = 198 methodTraceSettings.get(scope); 199 if (methodLevels != null) 200 { 201 return methodLevels.containsKey(methodName); 202 } 203 } 204 } 205 else if (classTraceSettings != null) 206 { 207 return classTraceSettings.containsKey(scope); 208 } 209 return false; 210 } 211 212 213 214 /** 215 * Remove a trace setting by scope. 216 * 217 * @param scope The scope for which to remove the trace setting. 218 * This should be a fully-qualified class name, or 219 * {@code null} to remove the trace setting for the 220 * global scope. 221 * 222 * @return The trace settings for the specified scope, or 223 * {@code null} if no trace setting is defined for that 224 * scope. 225 */ 226 final TraceSettings removeTraceSettings(String scope) 227 { 228 TraceSettings removedSettings = null; 229 if (scope == null) { 230 if(classTraceSettings != null) 231 { 232 removedSettings = classTraceSettings.remove(GLOBAL); 233 } 234 } 235 else { 236 int methodPt= scope.lastIndexOf('#'); 237 if (methodPt != -1) { 238 String methodName= scope.substring(methodPt+1); 239 scope= scope.substring(0, methodPt); 240 if(methodTraceSettings != null) 241 { 242 Map<String, TraceSettings> methodLevels = 243 methodTraceSettings.get(scope); 244 if(methodLevels != null) 245 { 246 removedSettings = methodLevels.remove(methodName); 247 if(methodLevels.isEmpty()) 248 { 249 methodTraceSettings.remove(scope); 250 } 251 } 252 } 253 } 254 else { 255 if(classTraceSettings != null) 256 { 257 removedSettings = classTraceSettings.remove(scope); 258 } 259 } 260 } 261 262 return removedSettings; 263 } 264 265 /** 266 * Set the trace settings for a class. 267 * 268 * @param className The class name. 269 * @param settings The trace settings for the class. 270 */ 271 private final synchronized void setClassSettings(String className, TraceSettings settings) 272 { 273 if (classTraceSettings == null) 274 { 275 classTraceSettings = new HashMap<>(); 276 } 277 classTraceSettings.put(className, settings); 278 } 279 280 281 282 /** 283 * Set the method settings for a particular method in a class. 284 * 285 * @param className The class name. 286 * @param methodName The method name. 287 * @param settings The trace settings for the method. 288 */ 289 private final synchronized void setMethodSettings(String className, 290 String methodName, TraceSettings settings) 291 { 292 if (methodTraceSettings == null) { 293 methodTraceSettings = new HashMap<>(); 294 } 295 Map<String, TraceSettings> methodLevels = methodTraceSettings.get(className); 296 if (methodLevels == null) 297 { 298 methodLevels = new TreeMap<>(); 299 methodTraceSettings.put(className, methodLevels); 300 } 301 methodLevels.put(methodName, settings); 302 } 303 304 305 306 /** 307 * Log an arbitrary event in a method. 308 * @param settings The current trace settings in effect. 309 * @param signature The method signature. 310 * @param sourceLocation The location of the method in the source. 311 * @param msg The message to be logged. 312 * @param stackTrace The stack trace at the time the message 313 * is logged or null if its not available. 314 */ 315 public abstract void trace(TraceSettings settings, String signature, 316 String sourceLocation, String msg, StackTraceElement[] stackTrace); 317 318 319 320 /** 321 * Log a caught exception in a method. 322 * @param settings The current trace settings in effect. 323 * @param signature The method signature. 324 * @param sourceLocation The location of the method in the source. 325 * @param msg The message to be logged. 326 * @param ex The exception that was caught. 327 * @param stackTrace The stack trace at the time the exception 328 * is caught or null if its not available. 329 */ 330 public abstract void traceException(TraceSettings settings, String signature, 331 String sourceLocation, String msg, Throwable ex, 332 StackTraceElement[] stackTrace); 333 334}