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" );
@@ -92,6 +110,11 @@ public static void Help()
92110 System .err .println ("securerandom SecureRandom" );
93111 System .err .println ("ts timestamping" );
94112 System .err .println ();
113+ System .err .println ("+timestamp can be appended to any of above options to print" );
114+ System .err .println (" a timestamp for that debug option" );
115+ System .err .println ("+thread can be appended to any of above options to print" );
116+ System .err .println (" thread and caller information for that debug option" );
117+ System .err .println ();
95118 System .err .println ("The following can be used with access:" );
96119 System .err .println ();
97120 System .err .println ("stack include stack trace" );
@@ -132,32 +155,65 @@ public static void Help()
132155 * option is set. Set the prefix to be the same as option.
133156 */
134157
135- public static Debug getInstance (String option )
136- {
158+ public static Debug getInstance (String option ) {
137159 return getInstance (option , option );
138160 }
139161
140162 /**
141163 * Get a Debug object corresponding to whether or not the given
142164 * option is set. Set the prefix to be prefix.
143165 */
144- public static Debug getInstance (String option , String prefix )
145- {
166+ public static Debug getInstance (String option , String prefix ) {
146167 if (isOn (option )) {
147168 Debug d = new Debug ();
148169 d .prefix = prefix ;
170+ d .configureExtras (option );
149171 return d ;
150172 } else {
151173 return null ;
152174 }
153175 }
154176
177+ private static String formatCaller () {
178+ return StackWalker .getInstance ().walk (s ->
179+ s .dropWhile (f ->
180+ f .getClassName ().startsWith ("sun.security.util.Debug" ))
181+ .map (f -> f .getFileName () + ":" + f .getLineNumber ())
182+ .findFirst ().orElse ("unknown caller" ));
183+ }
184+
185+ // parse an option string to determine if extra details,
186+ // like thread and timestamp, should be printed
187+ private void configureExtras (String option ) {
188+ // treat "all" as special case, only used for java.security.debug property
189+ this .printDateTime = timeStampInfoAll ;
190+ this .printThreadDetails = threadInfoAll ;
191+
192+ if (printDateTime && printThreadDetails ) {
193+ // nothing left to configure
194+ return ;
195+ }
196+
197+ // args is converted to lower case for the most part via marshal method
198+ int optionIndex = args .lastIndexOf (option );
199+ if (optionIndex == -1 ) {
200+ // option not in args list. Only here since "all" was present
201+ // in debug property argument. "all" option already parsed
202+ return ;
203+ }
204+ int beginIndex = optionIndex + option .length ();
205+ int commaIndex = args .indexOf (',' , beginIndex );
206+ if (commaIndex == -1 ) commaIndex = args .length ();
207+ String subOpt = args .substring (beginIndex , commaIndex );
208+ printDateTime = printDateTime || subOpt .contains (TIMESTAMP_OPTION );
209+ printThreadDetails = printThreadDetails || subOpt .contains (THREAD_OPTION );
210+ }
211+
155212 /**
156213 * True if the system property "security.debug" contains the
157214 * string "option".
158215 */
159- public static boolean isOn (String option )
160- {
216+ public static boolean isOn (String option ) {
161217 if (args == null )
162218 return false ;
163219 else {
@@ -180,37 +236,53 @@ public static boolean isVerbose() {
180236 * created from the call to getInstance.
181237 */
182238
183- public void println (String message )
184- {
185- System .err .println (prefix + ": " +message );
239+ public void println (String message ) {
240+ System .err .println (prefix + extraInfo () + ": " + message );
186241 }
187242
188243 /**
189244 * print a message to stderr that is prefixed with the prefix
190245 * created from the call to getInstance and obj.
191246 */
192- public void println (Object obj , String message )
193- {
194- System .err .println (prefix + " [" + obj .getClass ().getSimpleName () +
247+ public void println (Object obj , String message ) {
248+ System .err .println (prefix + extraInfo () + " [" + obj .getClass ().getSimpleName () +
195249 "@" + System .identityHashCode (obj ) + "]: " +message );
196250 }
197251
198252 /**
199253 * print a blank line to stderr that is prefixed with the prefix.
200254 */
201255
202- public void println ()
203- {
204- System .err .println (prefix + ":" );
256+ public void println () {
257+ System .err .println (prefix + extraInfo () + ":" );
205258 }
206259
207260 /**
208261 * print a message to stderr that is prefixed with the prefix.
209262 */
210263
211- public static void println (String prefix , String message )
212- {
213- System .err .println (prefix + ": " +message );
264+ public void println (String prefix , String message ) {
265+ System .err .println (prefix + extraInfo () + ": " + message );
266+ }
267+
268+ /**
269+ * If thread debug option enabled, include information containing
270+ * hex value of threadId and the current thread name
271+ * If timestamp debug option enabled, include timestamp string
272+ * @return extra info if debug option enabled.
273+ */
274+ private String extraInfo () {
275+ String retString = "" ;
276+ if (printThreadDetails ) {
277+ retString = "0x" + Long .toHexString (
278+ Thread .currentThread ().getId ()).toUpperCase (Locale .ROOT ) +
279+ "|" + Thread .currentThread ().getName () + "|" + formatCaller ();
280+ }
281+ if (printDateTime ) {
282+ retString += (retString .isEmpty () ? "" : "|" )
283+ + FormatHolder .DATE_TIME_FORMATTER .format (Instant .now ());
284+ }
285+ return retString .isEmpty () ? "" : "[" + retString + "]" ;
214286 }
215287
216288 /**
@@ -326,4 +398,11 @@ public static String toString(byte[] b) {
326398 return HexFormat .ofDelimiter (":" ).formatHex (b );
327399 }
328400
401+ // Holder class to break cyclic dependency seen during build
402+ private static class FormatHolder {
403+ private static final String PATTERN = "yyyy-MM-dd kk:mm:ss.SSS" ;
404+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter
405+ .ofPattern (PATTERN , Locale .ENGLISH )
406+ .withZone (ZoneId .systemDefault ());
407+ }
329408}
0 commit comments