001/* 002 * jPOS Project [http://jpos.org] 003 * Copyright (C) 2000-2026 jPOS Software SRL 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jpos.util; 020 021import java.io.PrintStream; 022 023/** 024 * Periodically dumps Thread and memory usage 025 * @author apr@cs.com.uy 026 * @version $Id$ 027 * @see Logger 028 */ 029public class SystemMonitor implements Runnable, LogSource, Loggeable 030{ 031 private Logger logger = null; 032 private String realm = null; 033 private int sleepTime = 0; 034 private int delay = 0; 035 private Thread thread = null; 036 private volatile boolean shutdown = false; 037 038 /** 039 * noargs constructor 040 */ 041 public SystemMonitor () { 042 super(); 043 } 044 /** 045 * Constructs a monitor with the given polling interval and logger binding. 046 * 047 * @param sleepTime sleep 048 * @param logger current logger 049 * @param realm instance realm 050 */ 051 public SystemMonitor (int sleepTime, Logger logger, String realm) { 052 setLogger (logger, realm); 053 this.sleepTime = sleepTime; 054 startThread(); 055 } 056 057 private void startThread() { 058 if (thread != null) 059 thread.interrupt(); 060 else if (sleepTime > 0) { 061 thread = new Thread(this,"SystemMonitor"); 062 thread.setPriority (Thread.MIN_PRIORITY); 063 thread.start(); 064 } 065 } 066 067 /** 068 * Sets the polling interval and (re)starts the monitor thread. 069 * 070 * @param sleepTime new sleepTime; 071 */ 072 public void setSleepTime (int sleepTime) { 073 this.sleepTime = sleepTime; 074 startThread(); 075 } 076 077 void dumpThreads (ThreadGroup g, PrintStream p, String indent) { 078 Thread[] list = new Thread[g.activeCount()+5]; 079 int nthreads = g.enumerate(list); 080 for (int i=0; i<nthreads; i++) 081 p.println (indent + list[i]); 082 } 083 084 /** 085 * Recursively dumps {@code g} and every parent thread group, with their threads. 086 * 087 * @param g starting thread group 088 * @param p destination stream 089 * @param indent prefix used for indentation 090 */ 091 public void showThreadGroup (ThreadGroup g, PrintStream p, String indent) { 092 if (g.getParent() != null) 093 showThreadGroup (g.getParent(), p, indent + " "); 094 else 095 dumpThreads (g, p, indent + " "); 096 } 097 098 public void run() { 099 while (!shutdown) { 100 Logger.log (new LogEvent (this, "SystemMonitor", this)); 101 try { 102 long expected = System.currentTimeMillis() + sleepTime; 103 Thread.sleep (sleepTime); 104 delay = (int) (System.currentTimeMillis() - expected); 105 } catch (InterruptedException e) { } 106 } 107 } 108 109 /** Signals the monitor's run loop to terminate. */ 110 public void shutdown() { 111 shutdown = true; 112 } 113 114 public void dump (PrintStream p, String indent) { 115 String newIndent = indent + " "; 116 Runtime r = Runtime.getRuntime(); 117 p.println (indent + "--- memory ---"); 118 p.println (newIndent+" freeMemory="+r.freeMemory()); 119 p.println (newIndent+"totalMemory="+r.totalMemory()); 120 p.println (newIndent+"inUseMemory="+(r.totalMemory()-r.freeMemory())); 121 p.println (""); 122 p.println (indent + "--- threads ---"); 123 p.println (newIndent+" delay="+delay+" ms"); 124 p.println (newIndent+" threads="+Thread.activeCount()); 125 showThreadGroup (Thread.currentThread().getThreadGroup(), p, newIndent); 126 p.println (""); 127 NameRegistrar.getInstance().dump (p, indent); 128 } 129 public void setLogger (Logger logger, String realm) { 130 this.logger = logger; 131 this.realm = realm; 132 } 133 public String getRealm () { 134 return realm; 135 } 136 public Logger getLogger() { 137 return logger; 138 } 139} 140 141