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 2006-2009 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027 028package org.opends.server.loggers; 029 030import java.util.List; 031 032import org.forgerock.i18n.LocalizableMessage; 033import org.opends.server.admin.server.ConfigurationChangeListener; 034import org.opends.server.admin.std.server.DebugTargetCfg; 035import org.forgerock.opendj.config.server.ConfigChangeResult; 036 037/** 038 * This class encapsulates the trace settings in effect at a given tracing scope. 039 */ 040public class TraceSettings implements 041 ConfigurationChangeListener<DebugTargetCfg> 042{ 043 /** A TraceSettings object representing a fully disabled trace state. */ 044 public static final TraceSettings DISABLED = 045 new TraceSettings(Level.DISABLED); 046 047 private static final String STACK_DUMP_KEYWORD = "stack"; 048 private static final String INCLUDE_CAUSE_KEYWORD = "cause"; 049 private static final String SUPPRESS_ARG_KEYWORD = "noargs"; 050 private static final String SUPPRESS_RETVAL_KEYWORD = "noretval"; 051 private static final String ENABLED_KEYWORD = "enabled"; 052 private static final String EXCEPTIONS_ONLY_KEYWORD = "exceptionsonly"; 053 054 /** 055 * Represents the level of trace. 056 */ 057 enum Level 058 { 059 /** Log nothing. **/ 060 DISABLED, 061 062 /** Log only exceptions. **/ 063 EXCEPTIONS_ONLY, 064 065 /** Log everything. */ 066 ALL; 067 068 /** 069 * Returns the level corresponding to provided options. 070 * 071 * @param isEnabled 072 * Indicates if tracer is enabled. 073 * @param isDebugExceptionsOnly 074 * Indicates if tracer should log only exceptions. 075 * @return the level corresponding to options 076 */ 077 static Level getLevel(boolean isEnabled, boolean isDebugExceptionsOnly) 078 { 079 if (isEnabled) 080 { 081 if (isDebugExceptionsOnly) 082 { 083 return Level.EXCEPTIONS_ONLY; 084 } 085 else 086 { 087 return Level.ALL; 088 } 089 } 090 return Level.DISABLED; 091 } 092 093 } 094 095 /** 096 * The level of this setting. 097 */ 098 private Level level; 099 100 /** 101 * Indicates if method arguments should be logged. 102 */ 103 private boolean noArgs; 104 105 /** 106 * Indicates if method return values should be logged. 107 */ 108 private boolean noRetVal; 109 110 /** 111 * The level of stack frames to include. 112 */ 113 private int stackDepth; 114 115 /** 116 * Indicates if the cause exception is included in exception messages. 117 */ 118 private boolean includeCause; 119 120 private DebugTargetCfg currentConfig; 121 122 /** 123 * Construct new trace settings with default values. 124 */ 125 public TraceSettings() 126 { 127 this(Level.ALL, false, false, 0, false); 128 129 } 130 131 /** 132 * Construct new trace settings at provided level. 133 * 134 * @param level 135 * Level for this settings. 136 */ 137 private TraceSettings(Level level) 138 { 139 this(level, false, false, 0, false); 140 141 } 142 143 /** 144 * Construct new trace settings at the specified level. Optionally turn off 145 * arguments, return value in entry and exit messages, and specifying the 146 * depth of stack traces and whether to include the cause of exceptions. 147 * 148 * @param level 149 * the level for this setting. 150 * @param noArgs 151 * whether to include arguments in the log messages. 152 * @param noRetVal 153 * whether to include return values in the log messages. 154 * @param stackDepth 155 * the stack depth to display in log messages. 156 * @param includeCause 157 * whether to include the cause of exceptions. 158 */ 159 TraceSettings(Level level, boolean noArgs, 160 boolean noRetVal, int stackDepth, boolean includeCause) 161 { 162 this.level = level; 163 this.noArgs = noArgs; 164 this.noRetVal = noRetVal; 165 this.stackDepth = stackDepth; 166 this.includeCause = includeCause; 167 } 168 169 /** 170 * Construct a new trace settings from the provided configuration. 171 * 172 * @param config 173 * The debug target configuration that contains the information to 174 * use to initialize this trace setting. 175 */ 176 TraceSettings(DebugTargetCfg config) 177 { 178 this.level = 179 Level.getLevel(config.isEnabled(), config.isDebugExceptionsOnly()); 180 this.noArgs = config.isOmitMethodEntryArguments(); 181 this.noRetVal = config.isOmitMethodReturnValue(); 182 this.stackDepth = config.getThrowableStackFrames(); 183 this.includeCause = config.isIncludeThrowableCause(); 184 185 currentConfig = config; 186 config.addChangeListener(this); 187 } 188 189 /** {@inheritDoc} */ 190 public boolean isConfigurationChangeAcceptable(DebugTargetCfg config, 191 List<LocalizableMessage> unacceptableReasons) 192 { 193 // This should alwas be acceptable. We are assuing that the scope for this 194 // trace setting is the same sine its part of the DN. 195 return true; 196 } 197 198 /** {@inheritDoc} */ 199 public ConfigChangeResult applyConfigurationChange(DebugTargetCfg config) 200 { 201 final ConfigChangeResult ccr = new ConfigChangeResult(); 202 203 // We can assume that the target scope did not change since its the 204 // naming attribute. Changing it would result in a modify DN. 205 206 this.level = 207 Level.getLevel(config.isEnabled(), config.isDebugExceptionsOnly()); 208 this.noArgs = config.isOmitMethodEntryArguments(); 209 this.noRetVal = config.isOmitMethodReturnValue(); 210 this.stackDepth = config.getThrowableStackFrames(); 211 this.includeCause = config.isIncludeThrowableCause(); 212 213 this.currentConfig = config; 214 215 return ccr; 216 } 217 218 /** 219 * Parse trace settings from the string representation. 220 * 221 * @param value 222 * the trace settings string to be parsed. 223 * @return the trace settings parsed from the string. 224 */ 225 protected static TraceSettings parseTraceSettings(String value) 226 { 227 TraceSettings settings = null; 228 if (value != null) 229 { 230 boolean enabled = false; 231 boolean exceptionsOnly = false; 232 boolean noArgs = false; 233 boolean noRetVal = false; 234 int stackDepth = 0; 235 boolean includeCause = false; 236 237 String[] keywords = value.split(","); 238 239 for (String keyword : keywords) 240 { 241 //See if stack dump keyword is included 242 if (keyword.startsWith(STACK_DUMP_KEYWORD)) 243 { 244 //See if a stack depth is included 245 if (keyword.length() == STACK_DUMP_KEYWORD.length()) 246 { 247 stackDepth = DebugStackTraceFormatter.COMPLETE_STACK; 248 } 249 else 250 { 251 int depthStart = keyword.indexOf("=", STACK_DUMP_KEYWORD.length()); 252 if (depthStart == STACK_DUMP_KEYWORD.length()) 253 { 254 try 255 { 256 stackDepth = Integer.valueOf(keyword.substring(depthStart + 1)); 257 } 258 catch (NumberFormatException nfe) 259 { // TODO: i18n 260 System.err.println("The keyword " + STACK_DUMP_KEYWORD 261 + " contains an invalid depth value. The complete stack " 262 + "will be included."); 263 } 264 } 265 } 266 } 267 //See if to include cause in exception messages. 268 else if (keyword.equals(INCLUDE_CAUSE_KEYWORD)) 269 { 270 includeCause = true; 271 } 272 //See if to supress method arguments. 273 else if (keyword.equals(SUPPRESS_ARG_KEYWORD)) 274 { 275 noArgs = true; 276 } 277 //See if to supress return values. 278 else if (keyword.equals(SUPPRESS_RETVAL_KEYWORD)) 279 { 280 noRetVal = true; 281 } 282 else if (keyword.equals(ENABLED_KEYWORD)) 283 { 284 enabled = true; 285 } 286 else if (keyword.equals(EXCEPTIONS_ONLY_KEYWORD)) 287 { 288 exceptionsOnly = true; 289 } 290 } 291 settings = 292 new TraceSettings(Level.getLevel(enabled, exceptionsOnly), 293 noArgs, noRetVal, stackDepth, includeCause); 294 } 295 296 return settings; 297 } 298 299 /** 300 * Get the level of this setting. 301 * 302 * @return the level of this setting. 303 */ 304 public Level getLevel() 305 { 306 return level; 307 } 308 309 /** 310 * Get whether method arguments should be logged. 311 * 312 * @return if method arguments should be logged. 313 */ 314 public boolean isNoArgs() 315 { 316 return noArgs; 317 } 318 319 /** 320 * Get whether method return values should be logged. 321 * 322 * @return if method return values should be logged. 323 */ 324 public boolean isNoRetVal() 325 { 326 return noRetVal; 327 } 328 329 /** 330 * Get the level of stack frames to include. 331 * 332 * @return the level of stack frames to include. 333 */ 334 public int getStackDepth() 335 { 336 return stackDepth; 337 } 338 339 /** 340 * Get whether the cause exception is included in exception messages. 341 * 342 * @return if the cause exception is included in exception messages. 343 */ 344 public boolean isIncludeCause() 345 { 346 return includeCause; 347 } 348}