package dmg.cells.services ; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; import java.util.Date; import dmg.cells.nucleus.CellAdapter; import dmg.cells.nucleus.CellNucleus; import org.dcache.util.Args; import static org.dcache.util.ByteUnit.KiB; import static org.dcache.util.ByteUnit.MiB; public class MemoryWatch extends CellAdapter implements Runnable { private static final Logger _log = LoggerFactory.getLogger(MemoryWatch.class); private CellNucleus _nucleus; private Args _args; private long _update = 10 ; private final Object _lock = new Object() ; private Thread _queryThread; private Runtime _runtime = Runtime.getRuntime() ; private boolean _output; private String _outputFile; private int _generations = 2 ; private int _current; private int _maxFileSize = MiB.toBytes(1); public MemoryWatch(String name, String args) { super(name, args); _nucleus = getNucleus(); _args = getArgs(); } @Override protected void starting() throws Exception { String var; // // update // if ((var = _args.getOpt("update")) != null) { try { _update = Integer.parseInt(var); } catch (Exception ee) { _log.warn("Update not accepted : " + var); } } // // filesize // if ((var = _args.getOpt("maxFilesize")) != null) { try { _maxFileSize = Integer.parseInt(var); } catch (Exception ee) { _log.warn("New 'maxFilesize' not accepted : " + var); } } // // generations // if ((var = _args.getOpt("generations")) != null) { try { _generations = Integer.parseInt(var); } catch (Exception ee) { _log.warn("New 'generations' not accepted : " + var); } } if ((var = _args.getOpt("output")) != null) { _output = true; if (!var.isEmpty()) { _outputFile = var; } } // // and now the worker. // _queryThread = _nucleus.newThread(this, "queryThread"); } @Override protected void started() { _queryThread.start(); } @Override protected void stopped() { if (_queryThread != null) { _queryThread.interrupt(); } } public void say(String str ){ if( _output ){ if( _outputFile != null ){ try{ PrintWriter pw; String name = _outputFile + '.' + (_current % _generations ) ; File f = new File(name) ; if( f.exists() && ( f.length() > _maxFileSize ) ){ _current++ ; name = _outputFile + '.' + (_current % _generations ) ; pw = new PrintWriter( new FileWriter( name , false ) ) ; }else{ pw = new PrintWriter( new FileWriter( name , true ) ) ; } try{ pw.println(str) ; }catch(Exception ee){ }finally{ try{ pw.close() ; }catch(Exception eeee ){} } }catch(Exception xx){} }else{ _log.info(str) ; } } } @Override @SuppressFBWarnings( value="DM_GC", justification="Although bad practice, the GC call is part of the design of the cell" ) public void run(){ while( ! Thread.interrupted() ){ _runtime.gc() ; long fm = _runtime.freeMemory() ; long tm = _runtime.totalMemory() ; say(" free " + fm + " total " + tm + " used " + (tm-fm) + ' ' + (new Date()).toString() ) ; try{ long update ; synchronized(_lock){ update = _update * 1000 ; } Thread.sleep( update ) ; }catch(InterruptedException e ){ break ; } } say( "Update thread finished" ) ; } @Override public void getInfo( PrintWriter pw ){ super.getInfo(pw); pw.println("Output : "+ (_output ? (_outputFile == null ? "<stdout>" : _outputFile) : "disabled" ) ) ; pw.println("Update : "+_update+" seconds" ) ; } public static final String hh_set_generations = "<outputfileGenerations(1...10)>" ; public String ac_set_generations_$_1( Args args ) { int g = Integer.parseInt( args.argv(0) ) ; if( ( g < 1 ) || ( g > 10 ) ) { throw new IllegalArgumentException("Generations not in range (1...10)"); } _generations = g ; return "OutputFile generations = "+_generations ; } public static final String hh_set_maxFilesize = "<output filesize limit(>10k)>" ; public String ac_set_maxFilesize_$_1( Args args ) { int g = Integer.parseInt( args.argv(0) ) ; if( g < KiB.toBytes(1) ) { throw new IllegalArgumentException("maxFilesize not in range (>1k)"); } _maxFileSize = g ; return "Maximum output filesize = "+_maxFileSize ; } public static final String hh_set_output = "off|on|<filename>" ; public String ac_set_output_$_1( Args args ){ String what = args.argv(0) ; switch (what) { case "off": _output = false; _outputFile = null; break; case "on": _output = true; _outputFile = null; break; default: _outputFile = what; _output = true; break; } return "Output "+ (_output? "set to "+(_outputFile==null?"stdout":_outputFile): "disabled" ); } public static final String hh_set_update = "<updateTime/sec>" ; public String ac_set_update_$_1( Args args )throws NumberFormatException { synchronized( _lock ) { _update = Integer.parseInt( args.argv(0) ) ; } return "Update time set to "+_update+" seconds" ; } public String ac_gc( Args args ){ _runtime.gc() ; return "" ; } }