/*
* Copyright 1998-2014 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package thredds.server.admin;
import thredds.servlet.Debug;
import thredds.servlet.ServletUtil;
import ucar.nc2.dataset.NetcdfDataset;
import java.util.*;
import java.io.PrintStream;
import javax.servlet.http.HttpServletRequest;
import ucar.nc2.grib.collection.GribCdmIndex;
import ucar.nc2.util.cache.FileCacheIF;
import ucar.unidata.io.RandomAccessFile;
/**
* A Singleton class instantiated by Spring, to populate the Debug methods in the
* DebugHandler class.
*
* @author caron
* @since Jan 15, 2009
*/
public class DebugCommands {
private String version, builddate;
public DebugCommands() {
makeGeneralActions();
makeDebugActions();
makeCacheActions();
}
public void setVersion(String version) {
this.version = version;
}
public void setBuilddate(String builddate) {
this.builddate = builddate;
}
protected void makeCacheActions() {
DebugController.Category debugHandler = DebugController.find("Caches");
DebugController.Action act;
act = new DebugController.Action("showCaches", "Show All File Object Caches") {
public void doAction(DebugController.Event e) {
Formatter f = new Formatter(e.pw);
FileCacheIF fc;
fc = RandomAccessFile.getGlobalFileCache();
if (fc == null) f.format("%nRandomAccessFile : turned off%n");
else {
f.format("%n%n");
fc.showCache(f);
}
fc = NetcdfDataset.getNetcdfFileCache();
if (fc == null) f.format("NetcdfDatasetFileCache : turned off%n");
else {
f.format("%n%n");
fc.showCache(f);
}
fc = GribCdmIndex.gribCollectionCache;
if (fc == null) f.format("%nTimePartitionCache : turned off%n");
else {
f.format("%n%n");
fc.showCache(f);
}
e.pw.flush();
}
};
debugHandler.addAction(act);
act = new DebugController.Action("clearCaches", "Clear All File Object Caches") {
public void doAction(DebugController.Event e) {
NetcdfDataset.getNetcdfFileCache().clearCache(false);
RandomAccessFile.getGlobalFileCache().clearCache(false);
FileCacheIF fc = GribCdmIndex.gribCollectionCache;
if (fc != null) fc.clearCache(false);
e.pw.println(" ClearCache ok");
}
};
debugHandler.addAction(act);
act = new DebugController.Action("disableRAFCache", "Disable RandomAccessFile Cache") {
public void doAction(DebugController.Event e) {
RandomAccessFile.getGlobalFileCache().disable();
e.pw.println(" Disable RandomAccessFile Cache ok");
}
};
debugHandler.addAction(act);
act = new DebugController.Action("forceRAFCache", "Force clear RandomAccessFile Cache") {
public void doAction(DebugController.Event e) {
RandomAccessFile.getGlobalFileCache().clearCache(true);
e.pw.println(" RandomAccessFile force clearCache done");
}
};
debugHandler.addAction(act);
act = new DebugController.Action("disableNetcdfCache", "Disable NetcdfDatasetFile Cache") {
public void doAction(DebugController.Event e) {
NetcdfDataset.disableNetcdfFileCache();
e.pw.println(" Disable NetcdfFile Cache ok");
}
};
debugHandler.addAction(act);
act = new DebugController.Action("forceNCCache", "Force clear NetcdfDatasetFile Cache") {
public void doAction(DebugController.Event e) {
NetcdfDataset.getNetcdfFileCache().clearCache(true);
e.pw.println(" NetcdfFileCache force clearCache done");
}
};
debugHandler.addAction(act);
act = new DebugController.Action("disableTimePartitionCache", "Disable TimePartition Cache") {
public void doAction(DebugController.Event e) {
GribCdmIndex.disableGribCollectionCache();
e.pw.println(" Disable gribCollectionCache ok");
}
};
debugHandler.addAction(act);
act = new DebugController.Action("forceGCCache", "Force clear TimePartition Cache") {
public void doAction(DebugController.Event e) {
FileCacheIF fc = GribCdmIndex.gribCollectionCache;
if (fc != null) fc.clearCache(true);
e.pw.println(" gribCollectionCache force clearCache done");
}
};
debugHandler.addAction(act);
}
protected void makeDebugActions() {
DebugController.Category debugHandler = DebugController.find("Debug");
DebugController.Action act;
act = new DebugController.Action("enableRafHandles", "Toggle tracking open RAF") {
public void doAction(DebugController.Event e) {
try {
RandomAccessFile.setDebugLeaks( !RandomAccessFile.getDebugLeaks());
e.pw.println(" Tracking RAF=" + RandomAccessFile.getDebugLeaks());
} catch (Exception ioe) {
e.pw.println(ioe.getMessage());
}
}
};
debugHandler.addAction(act);
act = new DebugController.Action("showRafHandles", "Show open RAF") {
public void doAction(DebugController.Event e) {
try {
List<String> names = RandomAccessFile.getOpenFiles();
e.pw.println("count=" + names.size());
for (String s : names) {
e.pw.println(" " + s);
}
} catch (Exception ioe) {
e.pw.println(ioe.getMessage());
}
}
};
debugHandler.addAction(act);
}
protected void makeGeneralActions() {
DebugController.Category debugHandler = DebugController.find("General");
DebugController.Action act;
act = new DebugController.Action("showVersion", "Show Build Version") {
public void doAction(DebugController.Event e) {
try {
e.pw.println("version= "+version);
e.pw.println("build date= "+builddate);
} catch (Exception ioe) {
e.pw.println(ioe.getMessage());
}
}
};
debugHandler.addAction(act);
act = new DebugController.Action("showRuntime", "Show Runtime info") {
public void doAction(DebugController.Event e) {
Runtime runt = Runtime.getRuntime();
double scale = 1.0 / (1000.0 * 1000.0);
e.pw.println(" freeMemory= " + scale * runt.freeMemory() + " Mb");
e.pw.println(" totalMemory= " + scale * runt.totalMemory() + " Mb");
e.pw.println(" maxMemory= " + scale * runt.maxMemory() + " Mb");
e.pw.println(" availableProcessors= " + runt.availableProcessors());
e.pw.println();
ServletUtil.showThreads(e.pw);
}
};
debugHandler.addAction(act);
act = new DebugController.Action("showFlags", "Show Debugging Flags") {
public void doAction(DebugController.Event e) {
showFlags(e.req, e.pw);
}
};
debugHandler.addAction(act);
act = new DebugController.Action("toggleFlag", null) {
public void doAction(DebugController.Event e) {
if (e.target != null) {
String flag = e.target;
Debug.set(flag, !Debug.isSet(flag));
} else
e.pw.println(" Must be toggleFlag=<flagName>");
showFlags(e.req, e.pw);
}
};
debugHandler.addAction(act);
/* act = new DebugHandler.Action("showLoggers", "Show Log4J info") {
public void doAction(DebugHandler.Event e) {
showLoggers(e.req, e.pw);
}
};
debugHandler.addAction(act);
act = new DebugHandler.Action("setLogger", null) {
public void doAction(DebugHandler.Event e) {
if (e.target == null) {
e.pw.println(" Must be setLogger=loggerName");
return;
}
StringTokenizer stoker = new StringTokenizer(e.target, "&=");
if (stoker.countTokens() < 3) {
e.pw.println(" Must be setLogger=loggerName&setLevel=levelName");
return;
}
String loggerName = stoker.nextToken();
stoker.nextToken(); // level=
String levelName = stoker.nextToken();
boolean isRootLogger = loggerName.equals("root");
if (!isRootLogger && LogManager.exists(loggerName) == null) {
e.pw.println(" Unknown logger=" + loggerName);
return;
}
if (Level.toLevel(levelName, null) == null) {
e.pw.println(" Unknown level=" + levelName);
return;
}
Logger log = isRootLogger ? LogManager.getRootLogger() : LogManager.getLogger(loggerName);
log.setLevel(Level.toLevel(levelName));
e.pw.println(loggerName + " set to " + levelName);
showLoggers(e.req, e.pw);
}
};
debugHandler.addAction(act); */
act = new DebugController.Action("showRequest", "Show HTTP Request info") {
public void doAction(DebugController.Event e) {
e.pw.println(ServletUtil.showRequestDetail(null, e.req));
}
};
debugHandler.addAction(act);
act = new DebugController.Action("showSystemProperties", "Show Server info") {
public void doAction(DebugController.Event e) {
ServletUtil.showServerInfo(e.pw);
}
};
debugHandler.addAction(act);
/* act = new DebugHandler.Action("showServletInfo", "Show Servlet info") {
public void doAction(DebugHandler.Event e) {
ServletUtil.showServletInfo(ThreddsDefaultServlet.this, e.pw);
}
};
debugHandler.addAction(act); */
act = new DebugController.Action("showSession", "Show HTTP Session info") {
public void doAction(DebugController.Event e) {
ServletUtil.showSession(e.req, e.res, e.pw);
}
};
debugHandler.addAction(act);
act = new DebugController.Action("showSecurity", "Show Security info") {
public void doAction(DebugController.Event e) {
e.pw.println(ServletUtil.showSecurity(e.req, "admin"));
}
};
debugHandler.addAction(act);
/* debugHandler = DebugHandler.get("catalogs");
act = new DebugHandler.Action("reinit", "Reinitialize") {
public void doAction(DebugHandler.Event e) {
// TODO The calls to reinit() and initCatalogs() are synchronized but should be atomic.
// TODO Should change this to build config data structure and synch only when replacing the old with the new structure.
catHandler.reinit();
ThreddsConfig.readConfig(log);
initCatalogs();
e.pw.println("reinit ok");
}
};
debugHandler.addAction(act); */
}
void showFlags(HttpServletRequest req, PrintStream pw) {
for (String key : Debug.keySet()) {
String url = req.getRequestURI() + "?toggleFlag=" + key;
pw.println(" <a href='" + url + "'>" + key + " = " + Debug.isSet(key) + "</a>");
}
}
/* private void changeLogs(String datePattern, long maxFileSize, int maxFiles) {
// get the existing appender
Logger logger = LogManager.getLogger("thredds");
FileAppender fapp = (FileAppender) logger.getAppender("threddsServlet");
PatternLayout playout = (PatternLayout) fapp.getLayout();
String filename = fapp.getFile();
// create a new one
Appender newAppender = null;
try {
if (null != datePattern) {
newAppender = new DailyRollingFileAppender(playout, filename, datePattern);
} else if (maxFileSize > 0) {
RollingFileAppender rapp = new RollingFileAppender(playout, filename);
rapp.setMaximumFileSize(maxFileSize);
rapp.setMaxBackupIndex(maxFiles);
newAppender = rapp;
} else {
return;
}
} catch (IOException ioe) {
log.error("Error changing the logger", ioe);
}
// replace wherever you find it
Logger root = LogManager.getRootLogger();
replaceAppender(root, "threddsServlet", newAppender);
Enumeration logEnums = LogManager.getCurrentLoggers();
while (logEnums.hasMoreElements()) {
Logger log = (Logger) logEnums.nextElement();
replaceAppender(log, "threddsServlet", newAppender);
}
} */
/* private void replaceAppender(Logger logger, String want, Appender replaceWith) {
Enumeration appenders = logger.getAllAppenders();
while (appenders.hasMoreElements()) {
Appender app = (Appender) appenders.nextElement();
if (app.getName().equals(want)) {
logger.removeAppender(app);
logger.addAppender(replaceWith);
}
}
}
void showLoggers(HttpServletRequest req, PrintStream pw) {
Logger root = LogManager.getRootLogger();
showLogger(req, root, pw);
Enumeration logEnums = LogManager.getCurrentLoggers();
List<Logger> loggersSorted = Collections.list(logEnums);
Collections.sort(loggersSorted, new LoggerComparator());
for (Logger logger : loggersSorted) {
showLogger(req, logger, pw);
}
}
private void showLogger(HttpServletRequest req, Logger logger, PrintStream pw) {
pw.print(" logger = " + logger.getName() + " level= ");
String url = req.getRequestURI() + "?setLogger=" + logger.getName() + "&level=";
showLevel(url, Level.ALL, logger.getEffectiveLevel(), pw);
showLevel(url, Level.DEBUG, logger.getEffectiveLevel(), pw);
showLevel(url, Level.INFO, logger.getEffectiveLevel(), pw);
showLevel(url, Level.WARN, logger.getEffectiveLevel(), pw);
showLevel(url, Level.ERROR, logger.getEffectiveLevel(), pw);
showLevel(url, Level.FATAL, logger.getEffectiveLevel(), pw);
showLevel(url, Level.OFF, logger.getEffectiveLevel(), pw);
pw.println();
Enumeration appenders = logger.getAllAppenders();
while (appenders.hasMoreElements()) {
Appender app = (Appender) appenders.nextElement();
pw.println(" appender= " + app.getName() + " " + app.getClass().getName());
Layout layout = app.getLayout();
if (layout instanceof PatternLayout) {
PatternLayout playout = (PatternLayout) layout;
pw.println(" layout pattern= " + playout.getConversionPattern());
}
if (app instanceof AppenderSkeleton) {
AppenderSkeleton skapp = (AppenderSkeleton) app;
if (skapp.getThreshold() != null)
pw.println(" threshold=" + skapp.getThreshold());
}
if (app instanceof FileAppender) {
FileAppender fapp = (FileAppender) app;
pw.println(" file=" + fapp.getFile());
}
}
}
private void showLevel(String baseUrl, Level show, Level current, PrintStream pw) {
if (show.toInt() != current.toInt())
pw.print(" <a href='" + baseUrl + show + "'>" + show + "</a>");
else
pw.print(" " + show);
}
private class LoggerComparator implements Comparator<Logger> {
public int compare(Logger log1, Logger log2) {
return log1.getName().compareTo(log2.getName());
}
public boolean equals(Object o) {
return this == o;
}
} */
}