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