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,32 +162,65 @@ 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 * True if the system property "security.debug" contains the
164221 * string "option".
165222 */
166- public static boolean isOn (String option )
167- {
223+ public static boolean isOn (String option ) {
168224 if (args == null )
169225 return false ;
170226 else {
@@ -187,37 +243,53 @@ public static boolean isVerbose() {
187243 * created from the call to getInstance.
188244 */
189245
190- public void println (String message )
191- {
192- System .err .println (prefix + ": " +message );
246+ public void println (String message ) {
247+ System .err .println (prefix + extraInfo () + ": " + message );
193248 }
194249
195250 /**
196251 * print a message to stderr that is prefixed with the prefix
197252 * created from the call to getInstance and obj.
198253 */
199- public void println (Object obj , String message )
200- {
201- System .err .println (prefix + " [" + obj .getClass ().getSimpleName () +
254+ public void println (Object obj , String message ) {
255+ System .err .println (prefix + extraInfo () + " [" + obj .getClass ().getSimpleName () +
202256 "@" + System .identityHashCode (obj ) + "]: " +message );
203257 }
204258
205259 /**
206260 * print a blank line to stderr that is prefixed with the prefix.
207261 */
208262
209- public void println ()
210- {
211- System .err .println (prefix + ":" );
263+ public void println () {
264+ System .err .println (prefix + extraInfo () + ":" );
212265 }
213266
214267 /**
215268 * print a message to stderr that is prefixed with the prefix.
216269 */
217270
218- public static void println (String prefix , String message )
219- {
220- System .err .println (prefix + ": " +message );
271+ public void println (String prefix , String message ) {
272+ System .err .println (prefix + extraInfo () + ": " + message );
273+ }
274+
275+ /**
276+ * If thread debug option enabled, include information containing
277+ * hex value of threadId and the current thread name
278+ * If timestamp debug option enabled, include timestamp string
279+ * @return extra info if debug option enabled.
280+ */
281+ private String extraInfo () {
282+ String retString = "" ;
283+ if (printThreadDetails ) {
284+ retString = "0x" + Long .toHexString (
285+ Thread .currentThread ().threadId ()).toUpperCase (Locale .ROOT ) +
286+ "|" + Thread .currentThread ().getName () + "|" + formatCaller ();
287+ }
288+ if (printDateTime ) {
289+ retString += (retString .isEmpty () ? "" : "|" )
290+ + FormatHolder .DATE_TIME_FORMATTER .format (Instant .now ());
291+ }
292+ return retString .isEmpty () ? "" : "[" + retString + "]" ;
221293 }
222294
223295 /**
@@ -333,4 +405,11 @@ public static String toString(byte[] b) {
333405 return HexFormat .ofDelimiter (":" ).formatHex (b );
334406 }
335407
408+ // Holder class to break cyclic dependency seen during build
409+ private static class FormatHolder {
410+ private static final String PATTERN = "yyyy-MM-dd kk:mm:ss.SSS" ;
411+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter
412+ .ofPattern (PATTERN , Locale .ENGLISH )
413+ .withZone (ZoneId .systemDefault ());
414+ }
336415}
0 commit comments