2727
2828import java .io .PrintStream ;
2929import java .math .BigInteger ;
30+ import java .time .Instant ;
31+ import java .time .ZoneId ;
32+ import java .time .format .DateTimeFormatter ;
3033import java .util .HexFormat ;
3134import java .util .regex .Pattern ;
3235import java .util .regex .Matcher ;
4144public class Debug {
4245
4346 private String prefix ;
47+ private boolean printDateTime ;
48+ private boolean printThreadDetails ;
4449
4550 private static String args ;
51+ private static boolean threadInfoAll ;
52+ private static boolean timeStampInfoAll ;
53+ private static final String TIMESTAMP_OPTION = "+timestamp" ;
54+ private static final String THREAD_OPTION = "+thread" ;
4655
4756 static {
4857 args = GetPropertyAction .privilegedGetProperty ("java.security.debug" );
@@ -61,12 +70,21 @@ public class Debug {
6170 args = marshal (args );
6271 if (args .equals ("help" )) {
6372 Help ();
73+ } else if (args .contains ("all" )) {
74+ // "all" option has special handling for decorator options
75+ // If the thread or timestamp decorator option is detected
76+ // with the "all" option, then it impacts decorator options
77+ // for other categories
78+ int beginIndex = args .lastIndexOf ("all" ) + "all" .length ();
79+ int commaIndex = args .indexOf (',' , beginIndex );
80+ if (commaIndex == -1 ) commaIndex = args .length ();
81+ threadInfoAll = args .substring (beginIndex , commaIndex ).contains (THREAD_OPTION );
82+ timeStampInfoAll = args .substring (beginIndex , commaIndex ).contains (TIMESTAMP_OPTION );
6483 }
6584 }
6685 }
6786
68- public static void Help ()
69- {
87+ public static void Help () {
7088 System .err .println ();
7189 System .err .println ("all turn on all debugging" );
7290 System .err .println ("access print all checkPermission results" );
@@ -95,6 +113,11 @@ public static void Help()
95113 System .err .println ("ts timestamping" );
96114 System .err .println ("x509 X.509 certificate debugging" );
97115 System .err .println ();
116+ System .err .println ("+timestamp can be appended to any of above options to print" );
117+ System .err .println (" a timestamp for that debug option" );
118+ System .err .println ("+thread can be appended to any of above options to print" );
119+ System .err .println (" thread and caller information for that debug option" );
120+ System .err .println ();
98121 System .err .println ("The following can be used with access:" );
99122 System .err .println ();
100123 System .err .println ("stack include stack trace" );
@@ -139,26 +162,60 @@ public static void Help()
139162 * option is set. Set the prefix to be the same as option.
140163 */
141164
142- public static Debug getInstance (String option )
143- {
165+ public static Debug getInstance (String option ) {
144166 return getInstance (option , option );
145167 }
146168
147169 /**
148170 * Get a Debug object corresponding to whether or not the given
149171 * option is set. Set the prefix to prefix.
150172 */
151- public static Debug getInstance (String option , String prefix )
152- {
173+ public static Debug getInstance (String option , String prefix ) {
153174 if (isOn (option )) {
154175 Debug d = new Debug ();
155176 d .prefix = prefix ;
177+ d .configureExtras (option );
156178 return d ;
157179 } else {
158180 return null ;
159181 }
160182 }
161183
184+ private static String formatCaller () {
185+ return StackWalker .getInstance ().walk (s ->
186+ s .dropWhile (f ->
187+ f .getClassName ().startsWith ("sun.security.util.Debug" ))
188+ .map (f -> f .getFileName () + ":" + f .getLineNumber ())
189+ .findFirst ().orElse ("unknown caller" ));
190+ }
191+
192+ // parse an option string to determine if extra details,
193+ // like thread and timestamp, should be printed
194+ private void configureExtras (String option ) {
195+ // treat "all" as special case, only used for java.security.debug property
196+ this .printDateTime = timeStampInfoAll ;
197+ this .printThreadDetails = threadInfoAll ;
198+
199+ if (printDateTime && printThreadDetails ) {
200+ // nothing left to configure
201+ return ;
202+ }
203+
204+ // args is converted to lower case for the most part via marshal method
205+ int optionIndex = args .lastIndexOf (option );
206+ if (optionIndex == -1 ) {
207+ // option not in args list. Only here since "all" was present
208+ // in debug property argument. "all" option already parsed
209+ return ;
210+ }
211+ int beginIndex = optionIndex + option .length ();
212+ int commaIndex = args .indexOf (',' , beginIndex );
213+ if (commaIndex == -1 ) commaIndex = args .length ();
214+ String subOpt = args .substring (beginIndex , commaIndex );
215+ printDateTime = printDateTime || subOpt .contains (TIMESTAMP_OPTION );
216+ printThreadDetails = printThreadDetails || subOpt .contains (THREAD_OPTION );
217+ }
218+
162219 /**
163220 * Get a Debug object corresponding to the given option on the given
164221 * property value.
@@ -173,14 +230,22 @@ public static Debug getInstance(String option, String prefix)
173230 * String property = settings.get("login");
174231 * Debug debug = Debug.of("login", property);
175232 * }
176- * @param option the debug option name
233+ *
234+ * +timestamp string can be appended to property value
235+ * to print timestamp information. (e.g. true+timestamp)
236+ * +thread string can be appended to property value
237+ * to print thread and caller information. (e.g. true+thread)
238+ *
239+ * @param prefix the debug option name
177240 * @param property debug setting for this option
178241 * @return a new Debug object if the property is true
179242 */
180- public static Debug of (String option , String property ) {
181- if ("true" . equalsIgnoreCase ( property )) {
243+ public static Debug of (String prefix , String property ) {
244+ if (property != null && property . toLowerCase ( Locale . ROOT ). startsWith ( "true" )) {
182245 Debug d = new Debug ();
183- d .prefix = option ;
246+ d .prefix = prefix ;
247+ d .printThreadDetails = property .contains (THREAD_OPTION );
248+ d .printDateTime = property .contains (TIMESTAMP_OPTION );
184249 return d ;
185250 }
186251 return null ;
@@ -190,8 +255,7 @@ public static Debug of(String option, String property) {
190255 * True if the system property "security.debug" contains the
191256 * string "option".
192257 */
193- public static boolean isOn (String option )
194- {
258+ public static boolean isOn (String option ) {
195259 if (args == null )
196260 return false ;
197261 else {
@@ -214,37 +278,53 @@ public static boolean isVerbose() {
214278 * created from the call to getInstance.
215279 */
216280
217- public void println (String message )
218- {
219- System .err .println (prefix + ": " +message );
281+ public void println (String message ) {
282+ System .err .println (prefix + extraInfo () + ": " + message );
220283 }
221284
222285 /**
223286 * print a message to stderr that is prefixed with the prefix
224287 * created from the call to getInstance and obj.
225288 */
226- public void println (Object obj , String message )
227- {
228- System .err .println (prefix + " [" + obj .getClass ().getSimpleName () +
289+ public void println (Object obj , String message ) {
290+ System .err .println (prefix + extraInfo () + " [" + obj .getClass ().getSimpleName () +
229291 "@" + System .identityHashCode (obj ) + "]: " +message );
230292 }
231293
232294 /**
233295 * print a blank line to stderr that is prefixed with the prefix.
234296 */
235297
236- public void println ()
237- {
238- System .err .println (prefix + ":" );
298+ public void println () {
299+ System .err .println (prefix + extraInfo () + ":" );
239300 }
240301
241302 /**
242303 * print a message to stderr that is prefixed with the prefix.
243304 */
244305
245- public static void println (String prefix , String message )
246- {
247- System .err .println (prefix + ": " +message );
306+ public void println (String prefix , String message ) {
307+ System .err .println (prefix + extraInfo () + ": " + message );
308+ }
309+
310+ /**
311+ * If thread debug option enabled, include information containing
312+ * hex value of threadId and the current thread name
313+ * If timestamp debug option enabled, include timestamp string
314+ * @return extra info if debug option enabled.
315+ */
316+ private String extraInfo () {
317+ String retString = "" ;
318+ if (printThreadDetails ) {
319+ retString = "0x" + Long .toHexString (
320+ Thread .currentThread ().threadId ()).toUpperCase (Locale .ROOT ) +
321+ "|" + Thread .currentThread ().getName () + "|" + formatCaller ();
322+ }
323+ if (printDateTime ) {
324+ retString += (retString .isEmpty () ? "" : "|" )
325+ + FormatHolder .DATE_TIME_FORMATTER .format (Instant .now ());
326+ }
327+ return retString .isEmpty () ? "" : "[" + retString + "]" ;
248328 }
249329
250330 /**
@@ -364,4 +444,11 @@ public static String toString(BigInteger b) {
364444 return toString (b .toByteArray ());
365445 }
366446
447+ // Holder class to break cyclic dependency seen during build
448+ private static class FormatHolder {
449+ private static final String PATTERN = "yyyy-MM-dd kk:mm:ss.SSS" ;
450+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter
451+ .ofPattern (PATTERN , Locale .ENGLISH )
452+ .withZone (ZoneId .systemDefault ());
453+ }
367454}
0 commit comments