package er.profiling.delegates; import java.text.DecimalFormat; import java.util.HashSet; import java.util.Set; import java.util.UUID; import com.webobjects.appserver.WOContext; import com.webobjects.appserver.WOElement; import com.webobjects.appserver.WORequest; import com.webobjects.appserver.WOResponse; import er.extensions.foundation.ERXProperties; import er.profiling.PFProfiler; import er.profiling.PFStatsChecker; import er.profiling.PFStatsNode; public class PFSummary implements PFProfiler.Delegate { private boolean _summaryEnabled; public void requestStarted(WORequest request) { _summaryEnabled = ERXProperties.booleanForKeyWithDefault("PFProfiler.summaryEnabled", true); } public void requestEnded(WORequest request) { // DO NOTHING } public void willAppendToResponse(WOElement element, WOResponse response, WOContext context) { // DO NOTHING } public void didAppendToResponse(WOElement element, WOResponse response, WOContext context) { // DO NOTHING } public void responseEnded(WOResponse response, WOContext context) { if (_summaryEnabled) { PFStatsNode rootStats = PFProfiler.currentStats().rootStats(); double total = rootStats.durationMillis(); int sqlCount = rootStats.countOf("SQL", false); double sqlDuration = rootStats.durationOfMillis("SQL", false); double sqlDurationPercent = sqlDuration / total; int d2wCount = rootStats.countOf("D2W", false); double d2wDuration = rootStats.durationOfMillis("D2W", false); double d2wDurationPercent = d2wDuration / total; double takeValuesFromRequest = rootStats.durationOfMillis("takeValuesFromRequest", false) / total; double invokeAction = rootStats.durationOfMillis("invokeAction", false) / total; double appendToResponse = rootStats.durationOfMillis("appendToResponse", false) / total; String uuid = UUID.randomUUID().toString(); PFProfiler.setStatsWithID(rootStats, uuid); StringBuilder profileString = new StringBuilder(); profileString.append("Profiler: " + String.format("%.2f", total) + "ms; "); profileString.append("SQL: " + DecimalFormat.getPercentInstance().format(sqlDurationPercent) + " (" + sqlCount + "); "); profileString.append("D2W: " + DecimalFormat.getPercentInstance().format(d2wDurationPercent) + " (" + d2wCount + "); "); profileString.append("T/I/A: " + DecimalFormat.getPercentInstance().format(takeValuesFromRequest) + " / " + DecimalFormat.getPercentInstance().format(invokeAction) + " / " + DecimalFormat.getPercentInstance().format(appendToResponse)); System.out.println(profileString); response .appendContentString("<div id=\"_profiler\" style=\"position: fixed; right: 0px; bottom: 0px; font-family: Helvetica; font-size: 9pt; font-weight:bold; white-space: no-wrap; clear: both; padding: 0.5em; padding-left: 10px; padding-right: 10px; background-color:rgba(240, 240, 255, 0.8); border: 1px solid rgb(200, 200, 215); border-bottom: none; border-right: none; border-top-left-radius: 10px\">"); response.appendContentString("<span style=\"color:rgb(150,150,150)\">profiler:</span> " + String.format("%.2f", total) + "ms"); Set<PFStatsNode> errorNodes = PFStatsChecker.checkForErrors(rootStats); if (!errorNodes.isEmpty()) { Set<String> errorTypes = new HashSet<>(); for (PFStatsNode errorNode : errorNodes) { errorTypes.add(errorNode.name()); } response.appendContentString("  |  "); response.appendContentString("<font color=\"red\">profiler errors " + errorTypes + "</font>"); } response.appendContentString("  <span style=\"color:rgb(150,150,150)\">|</span>  "); PFStatsNode.DurationCount oneMS = rootStats.countBetweenDurations(0, 1000000); PFStatsNode.DurationCount tenMS = rootStats.countBetweenDurations(1000000, 10 * 1000000); PFStatsNode.DurationCount hundredMS = rootStats.countBetweenDurations(10 * 1000000, 100 * 1000000); PFStatsNode.DurationCount moreMS = rootStats.countBetweenDurations(100 * 1000000, Long.MAX_VALUE); float maxHeight = 20; response.appendContentString("<style>#pf_histogram .pf_histogram_details { display: none; } #pf_histogram:hover .pf_histogram_details { display: block; }</style>"); response.appendContentString("<span id=\"pf_histogram\">"); response.appendContentString("<span style=\"background-color:rgb(200,200,200);margin:0px;padding:0px;width:10px;display:inline-table;font-size:0pt;height:" + (maxHeight * oneMS.millis() / total) + "px;\"> </span>"); response.appendContentString("<span style=\"background-color:rgb(150,150,150);margin:0px;padding:0px;width:10px;display:inline-table;font-size:0pt;height:" + (maxHeight * tenMS.millis() / total) + "px;\"> </span>"); response.appendContentString("<span style=\"background-color:rgb(100,100,100);margin:0px;padding:0px;width:10px;display:inline-table;font-size:0pt;height:" + (maxHeight * hundredMS.millis() / total) + "px;\"> </span>"); response.appendContentString("<span style=\"background-color:rgb( 50, 50, 50);margin:0px;padding:0px;width:10px;display:inline-table;font-size:0pt;height:" + (maxHeight * moreMS.millis() / total) + "px;\"> </span>"); response.appendContentString("<span class=\"pf_histogram_details\" style=\"position:absolute; top:-20px;background-color:rgba(240, 240, 255, 1.0);border: 1px solid rgb(200, 200, 215);padding:5px;-webkit-box-shadow: 0px 3px 10px rgb(100, 100, 100);\">"); response.appendContentString("<span style=\"color:rgb(150,150,150)\"><1ms:</span>"); response.appendContentString(DecimalFormat.getPercentInstance().format(oneMS.millis() / total)); response.appendContentString(" ("); response.appendContentString(String.valueOf(oneMS.count())); response.appendContentString(")"); response.appendContentString("<span style=\"color:rgb(150,150,150)\">, <10ms:</span>"); response.appendContentString(DecimalFormat.getPercentInstance().format(tenMS.millis() / total)); response.appendContentString(" ("); response.appendContentString(String.valueOf(tenMS.count())); response.appendContentString(")"); response.appendContentString("<span style=\"color:rgb(150,150,150)\">, <100ms:</span>"); response.appendContentString(DecimalFormat.getPercentInstance().format(hundredMS.millis() / total)); response.appendContentString(" ("); response.appendContentString(String.valueOf(hundredMS.count())); response.appendContentString(")"); response.appendContentString("<span style=\"color:rgb(150,150,150)\">, >=100ms:</span>"); response.appendContentString(DecimalFormat.getPercentInstance().format(moreMS.millis() / total)); response.appendContentString(" ("); response.appendContentString(String.valueOf(moreMS.count())); response.appendContentString(")"); response.appendContentString("</span>"); response.appendContentString("</span>"); response.appendContentString("  <span style=\"color:rgb(150,150,150)\">|</span>  "); response.appendContentString("<a href=\"" + context.completeURLWithRequestHandlerKey("profiler", "tree", "id=" + uuid + "&filter=SQL", false, 0) + "\" target=\"_blank\">SQL</a>: " + DecimalFormat.getPercentInstance().format(sqlDurationPercent) + " (" + sqlCount + ")"); response.appendContentString("  <span style=\"color:rgb(150,150,150)\">|</span>  "); response.appendContentString("<a href=\"" + context.completeURLWithRequestHandlerKey("profiler", "tree", "id=" + uuid + "&filter=D2W", false, 0) + "\" target=\"_blank\">D2W</a>: " + DecimalFormat.getPercentInstance().format(d2wDurationPercent) + " (" + d2wCount + ")"); response.appendContentString("  <span style=\"color:rgb(150,150,150)\">|</span>  "); response.appendContentString("<a href=\"" + context.completeURLWithRequestHandlerKey("profiler", "tree", "id=" + uuid + "&filter=takeValuesFromRequest&min=0.01", false, 0) + "\" target=\"_blank\">take</a>:"); response.appendContentString(DecimalFormat.getPercentInstance().format(takeValuesFromRequest)); response.appendContentString("<span style=\"color:rgb(150,150,150)\">, </span>"); response.appendContentString("<a href=\"" + context.completeURLWithRequestHandlerKey("profiler", "tree", "id=" + uuid + "&filter=invokeAction&min=0.01", false, 0) + "\" target=\"_blank\">invoke</a>:"); response.appendContentString(DecimalFormat.getPercentInstance().format(invokeAction)); response.appendContentString("<span style=\"color:rgb(150,150,150)\">, </span>"); response.appendContentString("<a href=\"" + context.completeURLWithRequestHandlerKey("profiler", "tree", "id=" + uuid + "&filter=appendToResponse&min=0.01", false, 0) + "\" target=\"_blank\">append</a>:"); response.appendContentString(DecimalFormat.getPercentInstance().format(appendToResponse)); response.appendContentString(" (<a href=\"" + context.completeURLWithRequestHandlerKey("profiler", "tree", "id=" + uuid + "&filter=takeValuesFromRequest,invokeAction,appendToResponse&min=0.01", false, 0) + "\" target=\"_blank\">all three</a>)"); response.appendContentString("  <span style=\"color:rgb(150,150,150)\">|</span>  "); response.appendContentString("<a href=\"" + context.completeURLWithRequestHandlerKey("profiler", "tree", "id=" + uuid + "&min=0.01", false, 0) + "\" target=\"_blank\">all</a>"); response.appendContentString("  <span style=\"color:rgb(150,150,150)\">|</span>  "); response.appendContentString("<a href=\"javascript:void(0);\" onClick=\"window.open('" + context.completeURLWithRequestHandlerKey("profiler", "heat", "", false, 0) + "','heat','width=1,height=1')\">"); if (PFHeatMap.isHeatEnabled()) { response.appendContentString("heat is on"); } else { response.appendContentString("heat is off"); } response.appendContentString("</a>"); response.appendContentString("</div>"); } } }