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 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 028 package org.opends.server.loggers.debug; 029 import org.opends.messages.Message; 030 031 import org.opends.server.types.DebugLogLevel; 032 import org.opends.server.types.DebugLogCategory; 033 import org.opends.server.types.ConfigChangeResult; 034 import org.opends.server.types.ResultCode; 035 import org.opends.server.loggers.LogLevel; 036 import org.opends.server.loggers.LogCategory; 037 import org.opends.server.admin.server.ConfigurationChangeListener; 038 import org.opends.server.admin.std.meta.DebugTargetCfgDefn; 039 import org.opends.server.admin.std.server.DebugTargetCfg; 040 041 042 import java.util.Set; 043 import java.util.HashSet; 044 import java.util.ArrayList; 045 import java.util.List; 046 047 /** 048 * This class encapsulates the trace settings in effect at a given traceing 049 * scope. 050 */ 051 public class TraceSettings 052 implements ConfigurationChangeListener<DebugTargetCfg> 053 { 054 /** A TraceSettings object representing a fully disabled trace state. */ 055 public static final TraceSettings DISABLED = 056 new TraceSettings(DebugLogLevel.DISABLED); 057 058 private static final String STACK_DUMP_KEYWORD = "stack"; 059 private static final String INCLUDE_CAUSE_KEYWORD = "cause"; 060 private static final String SUPPRESS_ARG_KEYWORD = "noargs"; 061 private static final String SUPPRESS_RETVAL_KEYWORD = "noretval"; 062 private static final String INCLUDE_CATEGORY_KEYWORD = "category"; 063 private static final String LEVEL_KEYWORD = "level"; 064 065 /** 066 * The log level of this setting. 067 */ 068 LogLevel level; 069 070 /** 071 * The log categories for this setting. 072 */ 073 Set<LogCategory> includeCategories; 074 075 /** 076 * Indicates if method arguments should be logged. 077 */ 078 boolean noArgs; 079 080 /** 081 * Indicates if method return values should be logged. 082 */ 083 boolean noRetVal; 084 085 /** 086 * The level of stack frames to include. 087 */ 088 int stackDepth; 089 090 /** 091 * Indicates if the cause exception is included in exception messages. 092 */ 093 boolean includeCause; 094 095 private DebugTargetCfg currentConfig; 096 097 /** 098 * Construct new trace settings at the specified log level. 099 * 100 * @param level the log level for this setting. 101 */ 102 public TraceSettings(LogLevel level) 103 { 104 this(level, null, false, false, 0, false); 105 106 } 107 108 /** 109 * Construct new trace settings at the specified log level and including 110 * the categories. 111 * 112 * @param level the log level for this setting. 113 * @param includeCategories the categories to include in this setting. 114 */ 115 public TraceSettings(LogLevel level, Set<LogCategory> includeCategories) 116 { 117 this(level, includeCategories, false, false, 0, false); 118 119 } 120 121 /** 122 * Construct new trace settings at the specified log level and including 123 * the categories. Optionally turn off arguments and return value in entry 124 * and exit messages. 125 * 126 * @param level the log level for this setting. 127 * @param includeCategories the categories to include in this setting. 128 * @param noArgs whether to include arguments in the log messages. 129 * @param noRetVal whether to include return values in the log messages. 130 */ 131 public TraceSettings(LogLevel level, Set<LogCategory> includeCategories, 132 boolean noArgs, boolean noRetVal) 133 { 134 this(level, includeCategories, noArgs, noRetVal, 0, false); 135 } 136 137 /** 138 * Construct new trace settings at the specified log level and including 139 * the categories. Optionally turn off arguments, return value in entry 140 * and exit messages, and specifying the depth of stack traces and whether 141 * to include the cause of exceptions. 142 * 143 * @param level the log level for this setting. 144 * @param includeCategories the categories to include in this setting. 145 * @param noArgs whether to include arguments in the log messages. 146 * @param noRetVal whether to include return values in the log messages. 147 * @param stackDepth the stack depth to display in log messages. 148 * @param includeCause whether to include the cause of exceptions. 149 */ 150 public TraceSettings(LogLevel level, Set<LogCategory> includeCategories, 151 boolean noArgs, boolean noRetVal, int stackDepth, 152 boolean includeCause) 153 { 154 this.level = level; 155 this.includeCategories = includeCategories; 156 this.noArgs = noArgs; 157 this.noRetVal = noRetVal; 158 this.stackDepth = stackDepth; 159 this.includeCause = includeCause; 160 } 161 162 /** 163 * Construct a new trace settings from the provided configuration. 164 * 165 * @param config The debug target configuration that contains the information 166 * to use to initialize this trace setting. 167 */ 168 public TraceSettings(DebugTargetCfg config) 169 { 170 this.level = 171 DebugLogLevel.parse(config.getDebugLevel().toString()); 172 173 Set<LogCategory> logCategories = null; 174 if(!config.getDebugCategory().isEmpty()) 175 { 176 logCategories = 177 new HashSet<LogCategory>(config.getDebugCategory().size()); 178 for(DebugTargetCfgDefn.DebugCategory category : 179 config.getDebugCategory()) 180 { 181 logCategories.add(DebugLogCategory.parse(category.toString())); 182 } 183 } 184 185 this.includeCategories = logCategories; 186 this.noArgs = config.isOmitMethodEntryArguments(); 187 this.noRetVal = config.isOmitMethodReturnValue(); 188 this.stackDepth = config.getThrowableStackFrames(); 189 this.includeCause = config.isIncludeThrowableCause(); 190 191 currentConfig = config; 192 config.addChangeListener(this); 193 } 194 195 /** 196 * {@inheritDoc} 197 */ 198 public boolean isConfigurationChangeAcceptable( 199 DebugTargetCfg config, 200 List<Message> unacceptableReasons) 201 { 202 // This should alwas be acceptable. We are assuing that the scope for this 203 // trace setting is the same sine its part of the DN. 204 return true; 205 } 206 207 /** 208 * {@inheritDoc} 209 */ 210 public ConfigChangeResult applyConfigurationChange(DebugTargetCfg config) 211 { 212 // Default result code. 213 ResultCode resultCode = ResultCode.SUCCESS; 214 boolean adminActionRequired = false; 215 ArrayList<Message> messages = new ArrayList<Message>(); 216 217 // We can assume that the target scope did not change since its the 218 // naming attribute. Changing it would result in a modify DN. 219 220 this.level = 221 DebugLogLevel.parse(config.getDebugLevel().toString()); 222 223 Set<LogCategory> logCategories = null; 224 if(!config.getDebugCategory().isEmpty()) 225 { 226 logCategories = 227 new HashSet<LogCategory>(config.getDebugCategory().size()); 228 for(DebugTargetCfgDefn.DebugCategory category : 229 config.getDebugCategory()) 230 { 231 logCategories.add(DebugLogCategory.parse(category.toString())); 232 } 233 } 234 235 this.includeCategories = logCategories; 236 this.noArgs = config.isOmitMethodEntryArguments(); 237 this.noRetVal = config.isOmitMethodReturnValue(); 238 this.stackDepth = config.getThrowableStackFrames(); 239 this.includeCause = config.isIncludeThrowableCause(); 240 241 this.currentConfig = config; 242 243 return new ConfigChangeResult(resultCode, adminActionRequired, messages); 244 } 245 246 /** 247 * Parse trace settings from the string representation. 248 * 249 * @param value the trace settings string to be parsed. 250 * @return the trace settings parsed from the string. 251 */ 252 protected static TraceSettings parseTraceSettings(String value) 253 { 254 TraceSettings settings = null; 255 if(value != null) 256 { 257 //Touch DebugLogLevel and DebugLogCategory so they are statically 258 //initialized or parse will not see all the levels/categories. 259 LogLevel level = DebugLogLevel.ERROR; 260 LogCategory categoryStub = DebugLogCategory.MESSAGE; 261 262 Set<LogCategory> includeCategories = null; 263 boolean noArgs = false; 264 boolean noRetVal = false; 265 int stackDepth = 0; 266 boolean includeCause = false; 267 268 String[] keywords = value.split(","); 269 270 for(String keyword : keywords) 271 { 272 //See if stack dump keyword is included 273 if(keyword.startsWith(STACK_DUMP_KEYWORD)) 274 { 275 //See if a stack depth is included 276 if(keyword.length() == STACK_DUMP_KEYWORD.length()) 277 { 278 stackDepth = DebugStackTraceFormatter.COMPLETE_STACK; 279 } 280 else 281 { 282 int depthStart= keyword.indexOf("=", STACK_DUMP_KEYWORD.length()); 283 if (depthStart == STACK_DUMP_KEYWORD.length()) 284 { 285 try 286 { 287 stackDepth = Integer.valueOf(keyword.substring(depthStart+1)); 288 } 289 catch(NumberFormatException nfe) 290 { // TODO: i18n 291 System.err.println("The keyword " + STACK_DUMP_KEYWORD + 292 " contains an invalid depth value. The complete stack " + 293 "will be included."); 294 } 295 } 296 } 297 } 298 //See if to include cause in exception messages. 299 else if(keyword.equals(INCLUDE_CAUSE_KEYWORD)) 300 { 301 includeCause = true; 302 } 303 //See if to supress method arguments. 304 else if(keyword.equals(SUPPRESS_ARG_KEYWORD)) 305 { 306 noArgs = true; 307 } 308 //See if to supress return values. 309 else if(keyword.equals(SUPPRESS_RETVAL_KEYWORD)) 310 { 311 noRetVal = true; 312 } 313 else if(keyword.startsWith(INCLUDE_CATEGORY_KEYWORD)) 314 { 315 int categoryStart = 316 keyword.indexOf("=", INCLUDE_CATEGORY_KEYWORD.length()); 317 318 if(keyword.length() == INCLUDE_CATEGORY_KEYWORD.length() || 319 categoryStart != INCLUDE_CATEGORY_KEYWORD.length()) 320 { // TODO: i18n 321 System.err.println("The keyword " + INCLUDE_CATEGORY_KEYWORD + 322 " does not contain an equal sign to define the set of " + 323 "categories to include. All categories will be included."); 324 } 325 else 326 { 327 String[] categories = 328 keyword.substring(categoryStart+1).split("[|]"); 329 includeCategories = new HashSet<LogCategory>(); 330 for(String category : categories) 331 { 332 try 333 { 334 includeCategories.add(DebugLogCategory.parse(category)); 335 } 336 catch(IllegalArgumentException iae) 337 { // TODO: i18n 338 System.err.println("The keyword " + INCLUDE_CATEGORY_KEYWORD + 339 " contains an invalid debug log category: " + 340 iae.toString() + ". It will be ignored."); 341 } 342 } 343 344 } 345 } 346 else if(keyword.startsWith(LEVEL_KEYWORD)) 347 { 348 int levelStart = 349 keyword.indexOf("=", LEVEL_KEYWORD.length()); 350 351 if(keyword.length() == LEVEL_KEYWORD.length() || 352 levelStart != LEVEL_KEYWORD.length()) 353 { // TODO: i18n 354 System.err.println("The keyword " + LEVEL_KEYWORD + 355 " does not contain an equal sign to specify the log level. " + 356 "Default level of " + level.toString() + " will be used."); 357 } 358 else 359 { 360 try 361 { 362 level = LogLevel.parse(keyword.substring(levelStart+1)); 363 } 364 catch(IllegalArgumentException iae) 365 { // TODO: i18n 366 System.err.println("The keyword " + LEVEL_KEYWORD + 367 " contains an invalid debug log level: " + 368 iae.toString() + ". Default level of " + level.toString() + 369 " will be used."); 370 } 371 } 372 } 373 374 } 375 settings = new TraceSettings(level, includeCategories, noArgs, noRetVal, 376 stackDepth, includeCause); 377 } 378 379 return settings; 380 } 381 }