< prev index next >

src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java

Print this page
*** 62,17 ***
       * Generate a thread dump in plain text format to a file or byte array, UTF-8 encoded.
       * This method is invoked by the VM for the Thread.dump_to_file diagnostic command.
       *
       * @param file the file path to the file, null or "-" to return a byte array
       * @param okayToOverwrite true to overwrite an existing file
       * @return the UTF-8 encoded thread dump or message to return to the tool user
       */
!     public static byte[] dumpThreads(String file, boolean okayToOverwrite) {
          if (file == null || file.equals("-")) {
!             return dumpThreadsToByteArray(false, MAX_BYTE_ARRAY_SIZE);
          } else {
!             return dumpThreadsToFile(file, okayToOverwrite, false);
          }
      }
  
      /**
       * Generate a thread dump in JSON format to a file or byte array, UTF-8 encoded.
--- 62,18 ---
       * Generate a thread dump in plain text format to a file or byte array, UTF-8 encoded.
       * This method is invoked by the VM for the Thread.dump_to_file diagnostic command.
       *
       * @param file the file path to the file, null or "-" to return a byte array
       * @param okayToOverwrite true to overwrite an existing file
+      * @param ignore not used
       * @return the UTF-8 encoded thread dump or message to return to the tool user
       */
!     public static byte[] dumpThreads(String file, boolean okayToOverwrite, boolean ignore) {
          if (file == null || file.equals("-")) {
!             return dumpThreadsToByteArray(false, false, MAX_BYTE_ARRAY_SIZE);
          } else {
!             return dumpThreadsToFile(file, okayToOverwrite, false, false);
          }
      }
  
      /**
       * Generate a thread dump in JSON format to a file or byte array, UTF-8 encoded.

*** 80,29 ***
       *
       * @param file the file path to the file, null or "-" to return a byte array
       * @param okayToOverwrite true to overwrite an existing file
       * @return the UTF-8 encoded thread dump or message to return to the tool user
       */
!     public static byte[] dumpThreadsToJson(String file, boolean okayToOverwrite) {
          if (file == null || file.equals("-")) {
!             return dumpThreadsToByteArray(true, MAX_BYTE_ARRAY_SIZE);
          } else {
!             return dumpThreadsToFile(file, okayToOverwrite, true);
          }
      }
  
      /**
       * Generate a thread dump in plain text or JSON format to a byte array, UTF-8 encoded.
       * This method is the implementation of the Thread.dump_to_file diagnostic command
       * when a file path is not specified. It returns the thread dump and/or message to
       * send to the tool user.
       */
!     private static byte[] dumpThreadsToByteArray(boolean json, int maxSize) {
          var out = new BoundedByteArrayOutputStream(maxSize);
          try (out; var writer = new TextWriter(out)) {
              if (json) {
!                 dumpThreadsToJson(writer);
              } else {
                  dumpThreads(writer);
              }
          } catch (Exception ex) {
              if (ex instanceof UncheckedIOException ioe) {
--- 81,29 ---
       *
       * @param file the file path to the file, null or "-" to return a byte array
       * @param okayToOverwrite true to overwrite an existing file
       * @return the UTF-8 encoded thread dump or message to return to the tool user
       */
!     public static byte[] dumpThreadsToJson(String file, boolean okayToOverwrite, boolean prettyPrint) {
          if (file == null || file.equals("-")) {
!             return dumpThreadsToByteArray(true, prettyPrint, MAX_BYTE_ARRAY_SIZE);
          } else {
!             return dumpThreadsToFile(file, okayToOverwrite, true, prettyPrint);
          }
      }
  
      /**
       * Generate a thread dump in plain text or JSON format to a byte array, UTF-8 encoded.
       * This method is the implementation of the Thread.dump_to_file diagnostic command
       * when a file path is not specified. It returns the thread dump and/or message to
       * send to the tool user.
       */
!     private static byte[] dumpThreadsToByteArray(boolean json, boolean prettyPrint, int maxSize) {
          var out = new BoundedByteArrayOutputStream(maxSize);
          try (out; var writer = new TextWriter(out)) {
              if (json) {
!                 dumpThreadsToJson(writer, prettyPrint);
              } else {
                  dumpThreads(writer);
              }
          } catch (Exception ex) {
              if (ex instanceof UncheckedIOException ioe) {

*** 117,20 ***
      /**
       * Generate a thread dump in plain text or JSON format to the given file, UTF-8 encoded.
       * This method is the implementation of the Thread.dump_to_file diagnostic command.
       * It returns the thread dump and/or message to send to the tool user.
       */
!     private static byte[] dumpThreadsToFile(String file, boolean okayToOverwrite, boolean json) {
          Path path = Path.of(file).toAbsolutePath();
          OpenOption[] options = (okayToOverwrite)
                  ? new OpenOption[0]
                  : new OpenOption[] { StandardOpenOption.CREATE_NEW };
          String reply;
          try (OutputStream out = Files.newOutputStream(path, options)) {
              try (var writer = new TextWriter(out)) {
                  if (json) {
!                     dumpThreadsToJson(writer);
                  } else {
                      dumpThreads(writer);
                  }
                  reply = String.format("Created %s%n", path);
              } catch (UncheckedIOException e) {
--- 118,23 ---
      /**
       * Generate a thread dump in plain text or JSON format to the given file, UTF-8 encoded.
       * This method is the implementation of the Thread.dump_to_file diagnostic command.
       * It returns the thread dump and/or message to send to the tool user.
       */
!     private static byte[] dumpThreadsToFile(String file,
+                                             boolean okayToOverwrite,
+                                             boolean json,
+                                             boolean prettyPrint) {
          Path path = Path.of(file).toAbsolutePath();
          OpenOption[] options = (okayToOverwrite)
                  ? new OpenOption[0]
                  : new OpenOption[] { StandardOpenOption.CREATE_NEW };
          String reply;
          try (OutputStream out = Files.newOutputStream(path, options)) {
              try (var writer = new TextWriter(out)) {
                  if (json) {
!                     dumpThreadsToJson(writer, prettyPrint);
                  } else {
                      dumpThreads(writer);
                  }
                  reply = String.format("Created %s%n", path);
              } catch (UncheckedIOException e) {

*** 178,11 ***
      }
  
      private static boolean dumpThread(Thread thread, TextWriter writer) {
          ThreadSnapshot snapshot = ThreadSnapshot.of(thread);
          if (snapshot == null) {
!             return false; // thread terminated
          }
          Instant now = Instant.now();
          Thread.State state = snapshot.threadState();
          writer.println("#" + thread.threadId() + " \"" + snapshot.threadName()
                  + "\" " + (thread.isVirtual() ? "virtual " : "") + state + " " + now);
--- 182,11 ---
      }
  
      private static boolean dumpThread(Thread thread, TextWriter writer) {
          ThreadSnapshot snapshot = ThreadSnapshot.of(thread);
          if (snapshot == null) {
!             return false; // thread not alive
          }
          Instant now = Instant.now();
          Thread.State state = snapshot.threadState();
          writer.println("#" + thread.threadId() + " \"" + snapshot.threadName()
                  + "\" " + (thread.isVirtual() ? "virtual " : "") + state + " " + now);

*** 240,11 ***
       * @throws IOException if an I/O error occurs
       */
      public static void dumpThreadsToJson(OutputStream out) throws IOException {
          var writer = new TextWriter(out);
          try {
!             dumpThreadsToJson(writer);
              writer.flush();
          } catch (UncheckedIOException e) {
              IOException ioe = e.getCause();
              throw ioe;
          }
--- 244,11 ---
       * @throws IOException if an I/O error occurs
       */
      public static void dumpThreadsToJson(OutputStream out) throws IOException {
          var writer = new TextWriter(out);
          try {
!             dumpThreadsToJson(writer, /*prettyPrint*/true);
              writer.flush();
          } catch (UncheckedIOException e) {
              IOException ioe = e.getCause();
              throw ioe;
          }

*** 275,13 ***
  
      /**
       * Generate a thread dump to the given text stream in JSON format.
       * @throws UncheckedIOException if an I/O error occurs
       */
!     private static void dumpThreadsToJson(TextWriter textWriter) {
          int format = JsonFormat.formatVersion();
!         var jsonWriter = new JsonWriter(textWriter, (format == JsonFormat.JSON_FORMAT_V1));
          jsonWriter.startObject();  // top-level object
          jsonWriter.startObject("threadDump");
          if (format > JsonFormat.JSON_FORMAT_V1) {
              jsonWriter.writeProperty("formatVersion", format);
          }
--- 279,14 ---
  
      /**
       * Generate a thread dump to the given text stream in JSON format.
       * @throws UncheckedIOException if an I/O error occurs
       */
!     private static void dumpThreadsToJson(TextWriter textWriter, boolean prettyPrint) {
          int format = JsonFormat.formatVersion();
!         boolean generateLongsAsString = (format == JsonFormat.JSON_FORMAT_V1);
+         var jsonWriter = new JsonWriter(textWriter, prettyPrint, generateLongsAsString);
          jsonWriter.startObject();  // top-level object
          jsonWriter.startObject("threadDump");
          if (format > JsonFormat.JSON_FORMAT_V1) {
              jsonWriter.writeProperty("formatVersion", format);
          }

*** 345,11 ***
       */
      private static boolean dumpThread(Thread thread, JsonWriter jsonWriter) {
          Instant now = Instant.now();
          ThreadSnapshot snapshot = ThreadSnapshot.of(thread);
          if (snapshot == null) {
!             return false; // thread terminated
          }
          Thread.State state = snapshot.threadState();
          StackTraceElement[] stackTrace = snapshot.stackTrace();
  
          jsonWriter.startObject();
--- 350,11 ---
       */
      private static boolean dumpThread(Thread thread, JsonWriter jsonWriter) {
          Instant now = Instant.now();
          ThreadSnapshot snapshot = ThreadSnapshot.of(thread);
          if (snapshot == null) {
!             return false; // thread not alive
          }
          Thread.State state = snapshot.threadState();
          StackTraceElement[] stackTrace = snapshot.stackTrace();
  
          jsonWriter.startObject();

*** 438,38 ***
                  propertyCount++;
                  return old;
              }
          }
          private final Deque<Node> stack = new ArrayDeque<>();
-         private final boolean generateLongsAsString;
          private final TextWriter writer;
  
!         JsonWriter(TextWriter writer, boolean generateLongsAsString) {
              this.writer = writer;
              this.generateLongsAsString = generateLongsAsString;
          }
  
          private void indent() {
!             int indent = stack.size() * 2;
!             writer.print(" ".repeat(indent));
          }
  
          /**
           * Start of object or array.
           */
          private void startObject(String name, boolean isArray) {
              if (!stack.isEmpty()) {
                  Node node = stack.peek();
                  if (node.getAndIncrementPropertyCount() > 0) {
!                     writer.println(",");
                  }
              }
              indent();
              if (name != null) {
!                 writer.print("\"" + name + "\": ");
              }
!             writer.println(isArray ? "[" : "{");
              stack.push(new Node(isArray));
          }
  
          /**
           * End of object or array.
--- 443,61 ---
                  propertyCount++;
                  return old;
              }
          }
          private final Deque<Node> stack = new ArrayDeque<>();
          private final TextWriter writer;
+         private final boolean prettyPrint;  // pretty print or minify
+         private final boolean generateLongsAsString;
  
!         JsonWriter(TextWriter writer, boolean prettyPrint, boolean generateLongsAsString) {
              this.writer = writer;
+             this.prettyPrint = prettyPrint;
              this.generateLongsAsString = generateLongsAsString;
          }
  
+         private void print(Object obj) {
+             writer.print(obj);
+         }
+ 
+         private void println(Object obj) {
+             if (prettyPrint) {
+                 writer.println(obj);
+             } else {
+                 writer.print(obj);
+             }
+         }
+ 
+         private void println() {
+             if (prettyPrint) {
+                 writer.println();
+             }
+         }
+ 
          private void indent() {
!             if (prettyPrint) {
!                 int indent = stack.size() * 2;
+                 writer.print(" ".repeat(indent));
+             }
          }
  
          /**
           * Start of object or array.
           */
          private void startObject(String name, boolean isArray) {
              if (!stack.isEmpty()) {
                  Node node = stack.peek();
                  if (node.getAndIncrementPropertyCount() > 0) {
!                     println(",");
                  }
              }
              indent();
              if (name != null) {
!                 String gap = prettyPrint ? " " : "";
+                 print("\"" + name + "\":" + gap);
              }
!             println(isArray ? "[" : "{");
              stack.push(new Node(isArray));
          }
  
          /**
           * End of object or array.

*** 477,14 ***
          private void endObject(boolean isArray) {
              Node node = stack.pop();
              if (node.isArray() != isArray)
                  throw new IllegalStateException();
              if (node.propertyCount() > 0) {
!                 writer.println();
              }
              indent();
!             writer.print(isArray ? "]" : "}");
          }
  
          /**
           * Write a property.
           * @param name the property name, null for an unnamed property
--- 505,14 ---
          private void endObject(boolean isArray) {
              Node node = stack.pop();
              if (node.isArray() != isArray)
                  throw new IllegalStateException();
              if (node.propertyCount() > 0) {
!                 println();
              }
              indent();
!             print(isArray ? "]" : "}");
          }
  
          /**
           * Write a property.
           * @param name the property name, null for an unnamed property

*** 492,21 ***
           */
          void writeProperty(String name, Object obj) {
              Node node = stack.peek();
              assert node != null;
              if (node.getAndIncrementPropertyCount() > 0) {
!                 writer.println(",");
              }
              indent();
              if (name != null) {
!                 writer.print("\"" + name + "\": ");
              }
              switch (obj) {
!                 case Number _  -> writer.print(obj);
!                 case Boolean _ -> writer.print(obj);
!                 case null      -> writer.print("null");
!                 default        -> writer.print("\"" + escape(obj.toString()) + "\"");
              }
          }
  
          /**
           * Write a property with a long value. If the value is outside the "interop"
--- 520,21 ---
           */
          void writeProperty(String name, Object obj) {
              Node node = stack.peek();
              assert node != null;
              if (node.getAndIncrementPropertyCount() > 0) {
!                 println(",");
              }
              indent();
              if (name != null) {
!                 print("\"" + name + "\": ");
              }
              switch (obj) {
!                 case Number _  -> print(obj);
!                 case Boolean _ -> print(obj);
!                 case null      -> print("null");
!                 default        -> print("\"" + escape(obj.toString()) + "\"");
              }
          }
  
          /**
           * Write a property with a long value. If the value is outside the "interop"
< prev index next >