Skip to content

Commit

Permalink
2.1.0.9 Add Page Parts report
Browse files Browse the repository at this point in the history
  • Loading branch information
zspitzer committed Apr 10, 2021
1 parent 828a1c3 commit 1a539ad
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 25 deletions.
11 changes: 8 additions & 3 deletions Application.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,14 @@
//if(fileName!="admin.cfm" && fileName!="web.cfm" && fileName!="server.cfm" && fileName!="index.cfm") {
public function onRequestStart() {
// if not logged in, we only allow access to admin|web|server[.cfm]
if(!structKeyExists(session, "passwordWeb") && !structKeyExists(session, "passwordServer")){
var fileName=listLast(cgi.script_name,"/");
//if(fileName!="admin.cfm" && fileName!="web.cfm" && fileName!="server.cfm" && fileName!="index.cfm") {

if ( !StructKeyExists( session, "password" & request.adminType ) ){
structDelete( session, "passwordWeb" );
structDelete( session, "passwordServer" );
}

if(!structKeyExists( session, "passwordWeb" ) && !structKeyExists( session, "passwordServer" )){
var fileName = listLast( cgi.script_name, "/" );

if (getDirectoryFromPath(ExpandPath(cgi.SCRIPT_NAME)) neq GetDirectoryFromPath(GetCurrentTemplatePath())
|| fileName!="index.cfm") {
Expand Down
2 changes: 1 addition & 1 deletion box.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name":"Lucee Performance Analyzer",
"author":"Zac Spitzer",
"version":"2.1.0.8",
"version":"2.1.0.9",
"bugs":"https://github.com/zspitzer/lucee-performance-analyzer/issues",
"thumbnail": "https://raw.githubusercontent.com/zspitzer/lucee-performance-analyzer/master/build/images/logo.png",
"changelog":"",
Expand Down
4 changes: 2 additions & 2 deletions build.number
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#Build Number for ANT. Do not edit!
#Tue Apr 06 17:01:14 CEST 2021
build.number=9
#Sat Apr 10 17:31:55 CEST 2021
build.number=10
Binary file not shown.
41 changes: 41 additions & 0 deletions source/cfml/plugins/parts.cfm
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<cfscript>
param name="arguments.req.template" default ="";
param name="arguments.req.maxrows" default ="100";
setTitle("Page Parts");
local.parts = this.Perf.getLogs(arguments.req, "parts");
local.q = local.parts.q;
</cfscript>


<table class="maintbl checkboxtbl sort-table">
<thead>
<tr>
<cfoutput>
#renderTemplateHead()#
</cfoutput>
<th>Lines</th>
<th>Total time</th>
<th>Count</th>
<th>Min</th>
<th>Max</th>
<th>Avg</th>
<!---<th>Query</th>--->
<th>Requests</th>
</tr>
</thead>
<tbody>
<cfoutput query="local.q" maxrows=#arguments.req.maxrows#>
<tr class="#altRow(local.q.currentRow)#">
#renderTemplateLink( arguments.req, local.q.template )#
<td align="right">#local.q.lines#</td>
<td align="right">#NumberFormat( local.q.totalTime / ( 1000 * 1000 ) )#</td>
<td align="right">#NumberFormat( local.q.totalCount)#</td>
<td align="right">#NumberFormat( local.q.minTime / ( 1000 * 1000 ) )#</td>
<td align="right">#NumberFormat( local.q.maxTime / ( 1000 * 1000 ) )#</td>
<td align="right">#NumberFormat( local.q.avgTime / ( 1000 * 1000 ) )#</td>
<!---<td align="right">#NumberFormat(local.q.avgQuery / ( 1000 * 1000 ) )#</td>--->
<td align="right">#NumberFormat( local.q.executions )#</td>
</tr>
</cfoutput>
</tbody>
</table>
65 changes: 56 additions & 9 deletions source/cfml/plugins/perf.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ component {
timer label="prepare Logs" {
loop from="#this.debugLogs.len()#" to="1" step=-1 index="local.i" {
if ( !StructKeyExists( this.debugLogs[i], "scope" ) )
this.debugLogs[ i ].scope.cgi = local.log.cgi; // pre 5.3++
this.debugLogs[ i ]["scope"].scope.cgi = local.log.cgi; // pre 5.3++
if ( !StructKeyExists( this.debugLogs[i], "size" ) )
this.debugLogs[ i ].size = SizeOf( this.debugLogs[i] ); // expensive, do it once (cheeky, debug logs are writeable)
this.debugLogs[ i ]["size"] = SizeOf( this.debugLogs[i] ); // expensive, do it once (cheeky, debug logs are writeable)
this.debugLogsIndex[ this.debugLogs[i].id ] = i;
}
}
Expand Down Expand Up @@ -54,7 +54,7 @@ component {
offset = singleSlash + 1;
if ( len( arguments.requestUrl ) gt offset){
if (qs gt 0){
str = Mid( arguments.requestUrl, offset, qs-offset );
str = Mid( arguments.requestUrl, offset, qs - offset );
} else {
str = Mid( arguments.requestUrl, offset );
}
Expand Down Expand Up @@ -91,7 +91,12 @@ component {
}

public struct function getLog( string logId ){
return this.debugLogs[ this.debugLogsIndex[ arguments.logId ] ];
if ( StructKeyExists( this.debugLogsIndex, arguments.logId )
&& ArrayIndexExists( this.debugLogs, this.debugLogsIndex[ arguments.logId ]))
return this.debugLogs[ this.debugLogsIndex[ arguments.logId ] ];
else
return {};

}

public struct function getLogs(struct req={}, string logType=""){
Expand All @@ -116,9 +121,9 @@ component {
}

// hide performance analyzer
if (true){
if ( application.applicationName eq "lucee-performance-analzyer" ){
var perfUrl = ListFirst( cgi.REQUEST_URL, "?" );
local.logs = local.logs.filter(function(row){
local.logs = local.logs.filter( function( row ){
return arguments.row.scope.cgi.REQUEST_URL does not contain variables.perfUrl;
});
}
Expand All @@ -134,7 +139,7 @@ component {
public string function getDebugMemUsage(){
local.s = 0;
loop from="#this.debugLogs.len()#" to="1" step=-1 index="local.i" {
local.s += this.debugLogs[local.i].size;
local.s += this.debugLogs[ local.i ].size;
}
return DecimalFormat( local.s / 1024 / 1024 ) & " Mb";
}
Expand All @@ -149,6 +154,9 @@ component {
case "pages":
local.result = getPages( arguments.logs );
break;
case "parts":
local.result = getParts( arguments.logs );
break;
case "exceptions":
local.result = getExceptions( arguments.logs );
break;
Expand Down Expand Up @@ -260,6 +268,44 @@ component {
};
}

public struct function getParts( required array logs ){
var q = QueryNew('id,count,min,max,avg,total,path,start,end,startLine,endLine,snippet,template,requestUrl,lines');
loop from="#arguments.logs.len()#" to="1" step=-1 index="local.i" {
local.log = arguments.logs[local.i];

if ( StructKeyExists( local.log, "pageParts" )){
local.parts=local.log.pageParts;
loop query="#local.parts#" {
local.r = queryAddRow( q, queryRowData( local.parts, local.parts.currentrow ) );
QuerySetCell( q, "requestUrl", local.log.scope.cgi.REQUEST_URL, local.r );
QuerySetCell( q, "template", local.q.path[r], local.r );
QuerySetCell( q, "lines", "#local.q.startline[r]# - #local.q.endline[r]#", local.r );
}
}
}
// QoQ doesn't like count
```
<cfquery name="local.q_parts" dbtype="query">

select id, count as _count, min as _min, max as _max, avg as _avg,
total, path, start, end as _end, startLine, endLine, snippet, template, requestUrl, lines
from q
</cfquery>

<cfquery name="local.q_parts" dbtype="query">
select template, lines, min(_min) as minTime, max(_max) as maxTime, avg(_avg) as avgTime,
sum(total) as totalTime, sum(_count) as totalCount,
sum(total) as total, count(*) as executions
from q_parts
group by template, lines
order by totalTime desc
</cfquery>
```
return {
q: q_parts
};
}

public struct function getScopes( required array logs ){
var q_scopes = QueryNew( "template,line,scope,count,name,requestUrl" );
loop from="#arguments.logs.len()#" to="1" step=-1 index="local.i" {
Expand Down Expand Up @@ -422,7 +468,7 @@ component {
}
}
}
<!--- Qoq doesn't like count --->
// QoQ doesn't like count
```
<cfquery name="local.q_queries" dbtype="query">
select name, time, sql, src as template, line, count as total, datasource, cacheType
Expand All @@ -444,7 +490,7 @@ component {
}

public struct function getDebugLogs( required array logs ){
var q = QueryNew( "template,requestUrl,path,total,query,load,app,scope,exceptions,starttime,id,size" );
var q = QueryNew( "template,requestUrl,path,total,query,load,app,scope,exceptions,starttime,id,size,isThread" );
local.totals = {
app = 0,
query: 0,
Expand Down Expand Up @@ -505,6 +551,7 @@ component {
QuerySetCell( local.q, "scope", _scope, local.r);
QuerySetCell( local.q, "exceptions", _exp, local.r);
QuerySetCell( local.q, "requestUrl", local.log.scope.cgi.REQUEST_URL, local.r );
QuerySetCell( local.q, "isThread", ( Len( local.log.scope.cgi.HTTP_USER_AGENT ) eq 0 ), local.r );

local.totals.size += + local.log.size / 1000;
local.totals.app += _app;
Expand Down
2 changes: 1 addition & 1 deletion source/cfml/plugins/renderUtils.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ component hint="various rendering related files"{
}

public function cleanHtml( required string content ){
return ReReplace( arguments.content, "[\r\n]\s*([\r\n]|\Z)", Chr(10), "ALL" )
return ReReplace( arguments.content, "[\r\n]\s*([\r\n]|\Z)", Chr(10), "ALL" );
}

}
6 changes: 5 additions & 1 deletion source/cfml/plugins/requests.cfm
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@
<cfloop query="local.q" maxrows="#arguments.req.maxrows#">
<cfoutput>
<cfif arguments.req.consoleDump>
<cfscript>
if (!iSJson( SerializeJson( this.Perf.getLog( q.id ) ) ) )
throw "json error";
</cfscript>
<script>
console.log( "#JsStringFormat(q.requestUrl)#", #SerializeJson( this.Perf.getLog( q.id ) )# );
</script>
</cfif>
<tr class="#altRow( local.q.currentRow )#">
<td>#renderRequestLink( arguments.req, local.q.path, local.q.id )#</td>
<td>#renderRequestLink( arguments.req, local.q.path, local.q.id )# <cfif local.q.isThread>(thread)</cfif></td>
<td>
<a href="#local.baseUrl#&url=#urlEncodedFormat(q.requestUrl)#" title="Filter by Request URL">By Url</a>,&nbsp;
<cfset local.host = this.Perf.getHost(q.requestUrl)>
Expand Down
31 changes: 23 additions & 8 deletions source/cfml/plugins/toolbar.cfm
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
variables.req = arguments.req;
local.reports = ["Requests", "Templates", "Scopes", "Queries", "Timers", "Exceptions", "Dumps", "Aborts", "Traces", "Memory", "Threads", "Settings"];
if ( Len( arguments.req.template ) || Len( arguments.req.url ) || Len( arguments.req.log ) )
//if ( Len( arguments.req.template ) || Len( arguments.req.url ) || Len( arguments.req.log ) )
ArrayPrepend(local.reports, "Analysis");
local.path_reports = ["Requests", "Templates", "Scopes", "Queries", "Timers", "Exceptions", "Dumps", "Aborts", "Traces"];
local.path_reports = ["Requests", "Templates", "Scopes", "Queries", "Timers", "Exceptions", "Dumps", "Aborts", "Traces", "Parts"];
local.lastLogDate = now();
local.urlExtra = "";
if ( StructKeyExists(arguments.req, "since") and arguments.req.since and isDate(arguments.req.since))
Expand All @@ -27,25 +27,30 @@
if ( variables.exactTemplatePath && DirectoryExists( arguments.req.template ))
variables.exactTemplatePath = false;
void function renderRequestLink ( req, linkTemplate, logId ){
void function renderRequestLink ( required struct req, linkTemplate, logId ){
var temp = arguments.linkTemplate;
if (len( arguments.req.url ) gt 0 and find( arguments.req.url, arguments.linkTemplate, 1 ) eq 1)
temp = mid( arguments.linkTemplate, len( arguments.req.url ) + 1 );
if ( Len(temp) eq 0)
temp = arguments.linkTemplate;
echo('<a href="?action=#arguments.req.action#&plugin=#arguments.req.plugin#&pluginAction=Analysis'
& '&log=#urlEncodedFormat(arguments.logId)#"'
& 'title="show only problems from this request" class="toolbar-filter">#htmleditformat( temp )#</a>');
}
void function renderTemplateLink ( req, reqPath ){
void function renderTemplateLink ( required struct req, reqPath ){
var temp = arguments.reqPath;
if (len( arguments.req.template ) gt 0 and find( arguments.req.template, arguments.reqPath, 1 ) eq 1)
temp = mid( arguments.reqPath, len( arguments.req.template ) + 2 );
if ( Len(temp) eq 0)
temp = arguments.reqPath;
if ( !variables.exactTemplatePath ){
echo("<td>");
echo('<a href="?action=#arguments.req.action#&plugin=#arguments.req.plugin#&pluginAction=#arguments.req.pluginAction#'
& '&template=#urlEncodedFormat(arguments.reqPath)#"'
& 'title="show only problems from this template" class="toolbar-filter">#htmleditformat( temp )#</a>');
// TODO if (len(singleLog.scope.cgi.http_user_agent) eq 0>Empty, probably a Lucee thread)
echo("</td>");
}
}
Expand All @@ -59,20 +64,20 @@
return variables.exactTemplatePath ? 0 : 1;
};
void function setTitle(title){
void function setTitle( string title ){
var t = ListFirst( ListLast( GetCurrentTemplatePath(), "\/" ), "." );
if ( variables.req.pluginAction eq t )
echo( "<h3>#arguments.title#</h3>" );
request.subtitle = arguments.title;
}
string function altRow(currentrow){
string function altRow( numeric currentrow ){
if ( arguments.currentRow mod 2 eq 1 )
return "alt-row";
return "zzz";
}
string function prettyTime( n ){
string function prettyTime( numeric n ){
if ( arguments.n == 0 )
return "";
var s = arguments.n / ( 1000 * 1000 );
Expand All @@ -81,7 +86,7 @@
return NumberFormat( s );
}
string function prettyNum( n=0, boolean large=false ){
string function prettyNum( numeric n=0, boolean large=false ){
if ( arguments.n == 0 )
return "";
Expand All @@ -101,8 +106,18 @@
<h3>Request Log: #arguments.req.log#
&nbsp; <a href="#local.baseUrl#" class="toolbar-filter" title="Remove URL Filter">(clear)</a>
</h3>
<cfset local.singleLog = this.perf.getLog(arguments.req.log )>
<cfif StructCount(singleLog)>
Url: #encodeForHtml( singleLog.scope.cgi.request_url )#<br>
User-Agent: <cfif len(singleLog.scope.cgi.http_user_agent) eq 0>Empty, probably a Lucee thread<cfelse>#encodeForHtml(singleLog.scope.cgi.http_user_agent)#</cfif><br>
<cfelse>
Log not found?<br>
</cfif>
<br>
</span>
<cfdump label="raw debug log" var=#local.singleLog# expand=false>
<hr>

</cfoutput>
</cfif>

Expand Down

0 comments on commit 1a539ad

Please sign in to comment.