content: package btools.util;
  
  import java.io.BufferedWriter;
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.OutputStreamWriter;
  import java.text.DateFormat;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.Locale;
  import java.util.Map;
  import java.util.Random;
  
  public class StackSampler extends Thread {
    private DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS", new Locale.Builder().setLanguage("en").setRegion("US").build());
    private BufferedWriter bw;
    private Random rand = new Random();
  
    private int interval;
    private int flushCnt = 0;
  
    private volatile boolean stopped;
  
    public StackSampler(File logfile, int interval) {
      this.interval = interval;
      try {
        bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(logfile, true)));
      } catch (Exception e) {
        printError("StackSampler: " + e.getMessage());
      }
    }
  
    protected void printError(String msg) {
      System.out.println(msg);
    }
  
    @Override
    public void run() {
      while (!stopped) {
        dumpThreads();
      }
      if (bw != null) {
        try {
          bw.close();
        } catch (Exception e) {
        }
      }
    }
  
    @SuppressWarnings({"deprecation", "RedundantSuppression"}) // Android
    public void dumpThreads() {
      try {
        int wait1 = rand.nextInt(interval);
        int wait2 = interval - wait1;
        sleep(wait1);
        StringBuilder sb = new StringBuilder(df.format(new Date()) + " THREADDUMP\n");
        Map<Thread, StackTraceElement[]> allThreads = getAllStackTraces();
        for (Map.Entry<Thread, StackTraceElement[]> e : allThreads.entrySet()) {
          Thread t = e.getKey();
          if (t == currentThread()) {
            continue; // not me
          }
  
          StackTraceElement[] stack = e.getValue();
          if (!matchesFilter(stack)) {
            continue;
          }
  
          sb.append(" (ID=").append(t.getId()).append(" \"").append(t.getName()).append("\" ").append(t.getState()).append("\n");
          for (StackTraceElement line : stack) {
            sb.append("    ").append(line.toString()).append("\n");
          }
          sb.append("\n");
        }
        bw.write(sb.toString());
        if (flushCnt++ >= 0) {
          flushCnt = 0;
          bw.flush();
        }
        sleep(wait2);
      } catch (Exception e) {
        // ignore
      }
    }
  
    public void close() {
      stopped = true;
      interrupt();
    }
  
    private boolean matchesFilter(StackTraceElement[] stack) {
      boolean positiveMatch = false;
      for (StackTraceElement e : stack) {
        String s = e.toString();
        if (s.indexOf("btools") >= 0) {
          positiveMatch = true;
        }
        if (s.indexOf("Thread.sleep") >= 0 || s.indexOf("PlainSocketImpl.socketAccept") >= 0) {
          return false;
        }
      }
      return positiveMatch;
    }
  
    public static void main(String[] args) throws Exception {
      System.out.println("StackSampler...");
      Class<?> clazz = Class.forName(args[0]);
      String[] args2 = new String[args.length - 1];
      for (int i = 1; i < args.length; i++) {
        args2[i - 1] = args[i];
      }
      StackSampler t = new StackSampler(new File("stacks.log"), 1000);
      t.start();
      try {
        clazz.getMethod("main", String[].class).invoke(null, new Object[]{args2});
      } finally {
        t.close();
      }
    }
  }
  