├── .gitignore
├── source
└── cfml
│ └── plugins
│ ├── overview.cfm
│ ├── analysis.cfm
│ ├── language.xml
│ ├── getLang.cfm
│ ├── .vscode
│ └── settings.json
│ ├── scopes.cfm
│ ├── related.cfm
│ ├── footer.cfm
│ ├── queries.cfm
│ ├── aborts.cfm
│ ├── dumps.cfm
│ ├── parts.cfm
│ ├── exceptions.cfm
│ ├── traces.cfm
│ ├── contextSelector.cfm
│ ├── timers.cfm
│ ├── css
│ └── style.css
│ ├── Action.cfc
│ ├── applications.cfm
│ ├── memory.cfm
│ ├── templates.cfm
│ ├── settings.cfm
│ ├── requests.cfm
│ ├── threads.cfm
│ ├── renderUtils.cfc
│ ├── js
│ ├── perf.js
│ └── jquery-3.6.0.slim.min.js
│ ├── toolbar.cfm
│ └── perf.cfc
├── dist
└── extension-PerformanceAnalyzer-2.1.1.1.lex
├── server.json
├── .vscode
└── settings.json
├── login.cfm
├── box.json
├── index.cfm
├── Application.cfc
├── README.md
├── add-lgpl-header.xml
└── License.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea/
2 | *.iml
3 |
--------------------------------------------------------------------------------
/source/cfml/plugins/overview.cfm:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/source/cfml/plugins/analysis.cfm:
--------------------------------------------------------------------------------
1 |
2 |
3 | setTitle( "Analysis" );
4 | cfinclude(template="related.cfm");
5 |
6 |
--------------------------------------------------------------------------------
/dist/extension-PerformanceAnalyzer-2.1.1.1.lex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zspitzer/lucee-performance-analyzer/HEAD/dist/extension-PerformanceAnalyzer-2.1.1.1.lex
--------------------------------------------------------------------------------
/source/cfml/plugins/language.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Performance
5 |
6 |
7 |
--------------------------------------------------------------------------------
/source/cfml/plugins/getLang.cfm:
--------------------------------------------------------------------------------
1 |
2 | var pluginLanguage = {
3 | strings: arguments.lang,
4 | locale: session.LUCEE_ADMIN_LANG
5 | };
6 | setting showdebugoutput="false";
7 | content type="text/javascript" reset="yes";
8 | echo ('var pluginLanguage = #serializeJson( pluginLanguage )#;');
9 | abort;
10 |
--------------------------------------------------------------------------------
/server.json:
--------------------------------------------------------------------------------
1 | {
2 | "jvm":{
3 | "args":"-Djava.net.useSystemProxies=true"
4 | },
5 | "app":{
6 | "cfengine":"lucee@5.3.8-SNAPSHOT+162",
7 | "serverHomeDirectory":"../lucee-perf-analzyer-server"
8 | },
9 | "http":{
10 | "port":49215
11 | },
12 | "openBrowserURL":"http://perf-analyzer.localhost:49215/index.cfm"
13 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "Gert",
4 | "Klinkenberg"
5 | ],
6 | "workbench.colorCustomizations": {
7 | "activityBar.background": "#28301F",
8 | "titleBar.activeBackground": "#38432B",
9 | "titleBar.activeForeground": "#F9FAF8"
10 | },
11 | "files.trimTrailingWhitespace": true,
12 | "editor.detectIndentation": false,
13 | "editor.insertSpaces": false
14 | }
--------------------------------------------------------------------------------
/source/cfml/plugins/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.renderWhitespace": "boundary",
3 | "files.trimFinalNewlines": true,
4 | "files.trimTrailingWhitespace": true,
5 | "editor.detectIndentation": false,
6 | "editor.insertSpaces": false,
7 | "eslint.enable": true,
8 | "workbench.colorCustomizations": {
9 | "activityBar.background": "#173320",
10 | "titleBar.activeBackground": "#20482D",
11 | "titleBar.activeForeground": "#F8FCF9"
12 | }
13 | }
--------------------------------------------------------------------------------
/source/cfml/plugins/scopes.cfm:
--------------------------------------------------------------------------------
1 |
2 | param name="arguments.req.maxrows" default ="100";
3 | local.scopes = this.Perf.getLogs(arguments.req, "scopes");
4 | local.q = local.scopes.q;
5 | local.src_rows = local.q.recordcount
6 | setTitle( "Variable Scoping Problems");
7 |
8 |
9 |
10 |
11 |
12 |
13 | #renderTemplateHead()#
14 |
15 | Line
16 | Variable
17 | Resolved Scope
18 | Total
19 |
20 |
21 |
22 |
23 |
24 | #renderTemplateLink( arguments.req, local.q.template )#
25 | #NumberFormat( local.q.line )#
26 | #local.q.name#
27 | #local.q.resolvedScope#
28 | #NumberFormat( local.q.total )#
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/source/cfml/plugins/related.cfm:
--------------------------------------------------------------------------------
1 |
2 | param name="arguments.req.template" default ="";
3 | param name="arguments.req.url" default ="";
4 | param name="arguments.req.log" default ="";
5 | param name="request.subtitle" default="";
6 | local.subTitle = request.subtitle; //stash
7 | local.timer = getTickCount();
8 | local.related = 0;
9 | arguments.req.maxrows = (Len(arguments.req.log) eq 0 ? 25 : 100);
10 |
11 | loop array="#path_reports#" item="local.report"{
12 | if ( report neq arguments.req.pLuginAction ){
13 | timer label="Related: #report#" {
14 | saveContent variable="local.html" {
15 | cfinclude( template=report & ".cfm" );
16 | }
17 | if ( local.q.recordcount gt 0 ){
18 | echo( "#request.subtitle# #local.html#" );
19 | related++;
20 | }
21 | }
22 | }
23 | }
24 | local.reqType = (Len(arguments.req.log) eq 0 ? "Path" : "Log" );
25 | request.subtitle = ( related gt 0 ) ? ( variables.exactTemplatePath ? "Template" : local.reqType) & " Analysis" : local.subTitle; //pop
26 |
27 |
--------------------------------------------------------------------------------
/source/cfml/plugins/footer.cfm:
--------------------------------------------------------------------------------
1 |
2 | function hasJavaMethod( obj, name ) {
3 | loop array=arguments.obj.getClass().getMethods() item="local.m" {
4 | if( m.getName() == arguments.name ) return true;
5 | }
6 | return false;
7 | }
8 |
9 |
10 |
11 | This report is based on all the debugging logs currently in memory ( #this.perf.getRawLogCount()# logs, #this.perf.getDebugMemUsage()# )
12 | (note #request.hiddenPerfAnalyzerOwnLogs# logs from Performance Analzyer hidden)
13 |
14 | click column headers to sort
15 |
16 |
17 |
18 |
19 |
20 |
22 |
23 |
24 | #variables.renderUtils.includeLang()#
25 | #variables.renderUtils.includeJavascript( "perf" )#
26 |
27 |
28 | Lucee Performance Analyzer
29 |
30 |
31 |
--------------------------------------------------------------------------------
/source/cfml/plugins/queries.cfm:
--------------------------------------------------------------------------------
1 |
2 | param name="arguments.req.maxrows" default ="1000";
3 | local.queries = this.Perf.getLogs(arguments.req, "queries");
4 | local.q = queries.q
5 | setTitle("Slowest Queries");
6 |
7 |
8 |
9 |
10 |
11 |
12 | #renderTemplateHead()#
13 |
14 | Line
15 | Name
16 | Datasource
17 | Total time
18 | Min
19 | Max
20 | Avg
21 | Executions
22 |
23 |
24 |
25 |
26 |
27 | #renderTemplateLink(arguments.req, local.q.template)#
28 | #NumberFormat(local.q.line)#
29 | #local.q.name#
30 | #local.q.datasource#
31 | #DecimalFormat(local.q.totalTime/(1000*1000))#
32 | #DecimalFormat(local.q.minTime/(1000*1000))#
33 | #DecimalFormat(local.q.maxTime/(1000*1000))#
34 | #DecimalFormat(local.q.avgTime/(1000*1000))#
35 | #NumberFormat(local.q.executions)#
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/source/cfml/plugins/aborts.cfm:
--------------------------------------------------------------------------------
1 |
2 | param name="arguments.req.maxrows" default="1000";
3 | local._total_aborts = 0;
4 | local.aborts = this.Perf.getLogs(arguments.req, "aborts");
5 | local.q = local.aborts.q
6 | setTitle( "Aborts" );
7 |
8 |
9 |
10 |
11 |
12 |
13 | #renderTemplateLink( arguments.req, local.q.template )#
14 | #local.q.line#
15 | #NumberFormat( local.q.executions )#
16 |
17 |
18 | local._total_aborts += local.q.executions;
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | Totals
28 | #numberFormat( local._total_aborts )#
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | #renderTemplateHead()#
38 |
39 | Line
40 | Count
41 |
42 |
43 | #totals#
44 |
45 |
46 | #body#
47 |
--------------------------------------------------------------------------------
/source/cfml/plugins/dumps.cfm:
--------------------------------------------------------------------------------
1 |
2 | param name="arguments.req.maxrows" default="1000";
3 | local._total_dumps = 0;
4 | local.dumps = this.Perf.getLogs(arguments.req, "dumps");
5 | local.q = local.dumps.q
6 | setTitle( "Dumps" );
7 |
8 |
9 |
10 |
11 |
12 |
13 | #dump(local.q.output)#
14 | #renderTemplateLink( arguments.req, local.q.template )#
15 | #local.q.line#
16 | #NumberFormat( local.q.dumps )#
17 |
18 |
19 | local._total_dumps += local.q.dumps;
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | Totals
29 | #numberFormat( local._total_dumps )#
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | Output
38 |
39 | #renderTemplateHead()#
40 |
41 | Line
42 | Count
43 |
44 |
45 | #totals#
46 |
47 |
48 | #body#
49 |
--------------------------------------------------------------------------------
/login.cfm:
--------------------------------------------------------------------------------
1 |
2 | param name="form.password" default="";
3 | variables.login_error = "";
4 |
5 | if (len(form.password) gt 0){
6 | admin action="checkPassword"
7 | type="#request.adminType#";
8 | admin action="hashPassword"
9 | type="#request.adminType#"
10 | pw="#form.password#"
11 | returnVariable="hashedPassword";
12 | try {
13 | admin action="connect"
14 | type="#request.adminType#"
15 | password="#hashedPassword#";
16 | session["password" & request.adminType] = hashedPassword;
17 | session.LUCEE_ADMIN_LANG = "EN";
18 | location url="index.cfm?action=plugin" addtoken="false";
19 |
20 | } catch(e){
21 | variables.login_error = cfcatch.message;
22 | }
23 | }
24 | variables.style=FileRead("source\cfml\plugins\css\style.css"); // assets require a login
25 |
26 |
27 |
30 |
41 |
44 |
--------------------------------------------------------------------------------
/source/cfml/plugins/parts.cfm:
--------------------------------------------------------------------------------
1 |
2 | param name="arguments.req.template" default ="";
3 | param name="arguments.req.maxrows" default ="100";
4 | setTitle("Page Parts");
5 | local.parts = this.Perf.getLogs(arguments.req, "parts");
6 | local.q = local.parts.q;
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | #renderTemplateHead()#
15 |
16 | Lines
17 | Total time
18 | Count
19 | Min
20 | Max
21 | Avg
22 |
23 | Requests
24 |
25 |
26 |
27 |
28 |
29 | #renderTemplateLink( arguments.req, local.q.template )#
30 | #local.q.lines#
31 | #NumberFormat( local.q.totalTime / ( 1000 * 1000 ) )#
32 | #NumberFormat( local.q.totalCount)#
33 | #NumberFormat( local.q.minTime / ( 1000 * 1000 ) )#
34 | #NumberFormat( local.q.maxTime / ( 1000 * 1000 ) )#
35 | #NumberFormat( local.q.avgTime / ( 1000 * 1000 ) )#
36 |
37 | #NumberFormat( local.q.executions )#
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/source/cfml/plugins/exceptions.cfm:
--------------------------------------------------------------------------------
1 |
2 | param name="arguments.req.maxrows" default="1000";
3 | local._total_executions = 0;
4 | local.exceptions = this.Perf.getLogs(arguments.req, "exceptions");
5 | local.q = local.exceptions.q
6 | setTitle( "Exceptions" );
7 |
8 |
9 |
10 |
11 |
12 |
13 | #local.q._type#
14 | #local.q.message#
15 | #local.q.detail#
16 | #renderTemplateLink( arguments.req, local.q.template )#
17 | #local.q.line#
18 | #NumberFormat( local.q.executions )#
19 |
20 |
21 | local._total_executions += local.q.executions;
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Totals
31 | #numberFormat( local._total_executions )#
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Type
40 | Message
41 | Detail
42 |
43 | #renderTemplateHead()#
44 |
45 | Line
46 | Count
47 |
48 |
49 | #totals#
50 |
51 |
52 | #body#
53 |
--------------------------------------------------------------------------------
/source/cfml/plugins/traces.cfm:
--------------------------------------------------------------------------------
1 |
2 | param name="arguments.req.maxrows" default="1000";
3 | local._total_aborts = 0;
4 | local.traces = this.Perf.getLogs(arguments.req, "traces");
5 | local.q = local.traces.q
6 | setTitle( "Traces" );
7 |
8 |
9 |
10 |
11 |
12 |
13 | #renderTemplateLink( arguments.req, local.q.template )#
14 | #local.q.line#
15 | #local.q.text#
16 | #local.q.type#
17 | #local.q.action#
18 | #local.q.category#
19 | #prettyTime (local.q.time * 1000 * 1000 )#
20 |
21 | #local.q.var#
22 | =#local.q.varValue#
23 |
24 |
25 | #NumberFormat( local.q.executions )#
26 |
27 |
28 | local._total_aborts += local.q.executions;
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | Totals
38 | #numberFormat( local._total_aborts )#
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | #renderTemplateHead()#
48 |
49 | Line
50 | Text
51 | Type
52 | Action
53 | Category
54 | Time
55 | Var
56 | Count
57 |
58 |
59 | #totals#
60 |
61 |
62 | #body#
63 |
--------------------------------------------------------------------------------
/source/cfml/plugins/contextSelector.cfm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Warning: request.admintype is "#request.admintype#", should be either web or server??
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | #i18n('chooseLogLocation')#
18 |
19 | #i18n('serverContext')#
20 |
21 |
22 | selected>
23 |
24 | #rereplace(webContexts.path, "^(.{25}).+(.{40})$", "\1...\2")#
25 |
26 | #webContexts.path#
27 |
28 | - #webContexts.url#
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/source/cfml/plugins/timers.cfm:
--------------------------------------------------------------------------------
1 |
2 | param name="arguments.req.maxrows" default="1000";
3 | local.timers = this.Perf.getLogs(arguments.req, "timers");
4 | local.q = timers.q;
5 | local._total_time = 0;
6 | local._total_executions = 0;
7 | setTitle( "Timers" );
8 |
9 |
10 |
11 |
12 |
13 |
14 | #local.q.label#
15 | #renderTemplateLink( arguments.req, local.q.template )#
16 | #local.q.line#
17 | #prettyTime (local.q.totalTime * 1000 * 1000 )#
18 | #DecimalFormat(local.q.minTime/(1000*1000))#
19 | #DecimalFormat(local.q.maxTime/(1000*1000))#
20 | #DecimalFormat(local.q.avgTime/(1000*1000))#
21 | #NumberFormat( local.q.executions )#
22 |
23 |
24 | local._total_time += local.q.totalTime;
25 | local._total_executions += local.q.executions;
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | Totals
35 | #prettyTime( local._total_time * 1000 * 1000 )#
36 |
37 | #prettyNum( local._total_executions )#
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | Label
46 |
47 | #renderTemplateHead()#
48 |
49 | Line
50 | Total time
51 | Min
52 | Max
53 | Avg
54 | Count
55 |
56 |
57 | #totals#
58 |
59 |
60 | #body#
61 |
62 |
--------------------------------------------------------------------------------
/box.json:
--------------------------------------------------------------------------------
1 | {
2 | "name":"Lucee Performance Analyzer",
3 | "author":"Zac Spitzer",
4 | "version":"2.1.1.1",
5 | "bugs":"https://github.com/zspitzer/lucee-performance-analyzer/issues",
6 | "thumbnail": "https://raw.githubusercontent.com/zspitzer/lucee-performance-analyzer/master/build/images/logo.png",
7 | "changelog":"",
8 | "contributors":[],
9 | "dependencies":{},
10 | "description":"",
11 | "devDependencies":{},
12 | "documentation":"",
13 | "homepage":"https://github.com/zspitzer/lucee-performance-analyzer",
14 | "ignore":[],
15 | "installPaths":{},
16 | "instructions":"",
17 | "keywords":"logs lucee admin plugin performance",
18 | "license":[
19 | {
20 | "type":"",
21 | "URL":""
22 | }
23 | ],
24 | "location":"ForgeboxStorage",
25 | "private":false,
26 | "projectURL":"",
27 | "repository":{
28 | "type":"git",
29 | "URL":"https://github.com/zspitzer/lucee-performance-analyzer"
30 | },
31 | "scripts":{},
32 | "shortDescription":"A Lucee Admin plugin to analyze debug logs for performance problems, via aggregate reports from all the debug logs available",
33 | "slug":"A345C8CB-04CC-4D2B-93D50471D5105D83",
34 | "testbox":{
35 | "bundles":"",
36 | "directory":"tests.specs",
37 | "labels":"",
38 | "options":{},
39 | "recurse":true,
40 | "reporter":"",
41 | "runner":[
42 | {
43 | "default":""
44 | }
45 | ],
46 | "testBundles":"",
47 | "testSpecs":"",
48 | "testSuites":"",
49 | "verbose":true,
50 | "watchDelay":500,
51 | "watchPaths":"**.cfc"
52 | },
53 | "type":"lucee-extensions",
54 | "lucee-extension-releasetype": "all",
55 | "lucee-extension-mincoreversion": "5.2.8.50",
56 | "lucee-extension-category": "performance",
57 |
58 | "engines" : [
59 | { "type" : "lucee", "version" : ">=5.2.8" }
60 | ]
61 | }
62 |
--------------------------------------------------------------------------------
/source/cfml/plugins/css/style.css:
--------------------------------------------------------------------------------
1 |
2 | .maintbl td, .maintbl th {
3 | font-weight: normal;
4 | empty-cells: show;
5 | border: 1px solid #fff;
6 | }
7 |
8 | body, td, th {
9 | font-family:Arial, Helvetica, sans-serif;
10 | font-size : 12px;
11 | color:#333;
12 | }
13 |
14 | table {empty-cells:show; border-collapse: collapse;}
15 | td, th {
16 | padding: 4 4 4 4;
17 | vertical-align:top;
18 | }
19 | th, .maintbl th {/* like .tblHead */
20 | background-color:#39c; /* ABC */
21 | color:#efede5;
22 | font-weight:normal;
23 | text-align:left;
24 | }
25 |
26 | th a {
27 | color: inherit;
28 | text-decoration: underline;
29 | }
30 |
31 | .toolbar-filter, .toolbar-filter a {
32 | padding-right: 12px;
33 | text-decoration: none;
34 | }
35 |
36 | .toolbar-file-filter, .toolbar-file-filter a {
37 | padding-right: 3px;
38 | text-decoration: none;
39 | }
40 |
41 | .toolbar-file-filter H3, .toolbar-file-filter H1 {
42 | margin: 2 0;
43 | }
44 |
45 | hr {
46 | margin: 2;
47 | }
48 |
49 | .log-totals TD {
50 | font-weight: bolder;
51 | }
52 |
53 | table pre {
54 | margin: 0;
55 | font: unset;
56 | }
57 |
58 | .maintbl {
59 | width:auto;
60 | }
61 |
62 | #innercontent {
63 | margin-top: 10px;
64 | margin-left: 3px;
65 | }
66 |
67 | .unused-template, .unused-template TD {
68 | background-color:rgb(223 186 186);
69 | color:black;
70 | }
71 |
72 | a {
73 | color:black;
74 | }
75 |
76 | .no-wrap {
77 | white-space: nowrap;
78 | }
79 |
80 | .alt-row {
81 | background-color: #DFDFDF;
82 | }
83 |
84 | .header H1 {
85 | margin-bottom:2px;
86 | font-size: 1.5em;
87 | }
88 |
89 | .header {
90 | padding-bottom:12px;
91 | }
92 |
93 | .statusCode-4, .statusCode-5, .statusCode-6{
94 | background-color: red;
95 | color: white;
96 | }
97 |
98 | .statusCode-1, .statusCode-2 {
99 | /*normal */
100 | }
101 | .statusCode-3 {
102 | background-color: yellow;
103 | }
104 |
105 | .filter {
106 | padding-left: 10px;;
107 | }
108 |
109 | .filterSelected {
110 | font-weight: bolder;
111 | }
--------------------------------------------------------------------------------
/index.cfm:
--------------------------------------------------------------------------------
1 |
2 | request.self = ListFirst(cgi.REQUEST_URL,"?") &"?action=Plugin";
3 | url.action = "Plugin";
4 | url.plugin = "PerformanceAnalyzer";
5 | request.version = DeserializeJson(FileRead(ExpandPath(".\box.json"))).version;
6 | request.subtitle = "";
7 | request.title = "Lucee Performance Analyzer - #request.version#";
8 | param name="url.pluginAction" default="analysis";
9 | param name="url.xhr" default="false";
10 | variables.plugin = new source.cfml.plugins.Action(lang={},app={});
11 |
12 | request.action = ListLast( url.pluginAction, "/\/" );
13 | savecontent variable="body"{
14 | switch ( request.action ){
15 | case "logout":
16 | sessionInvalidate();
17 | location url="index.cfm" addtoken="false";
18 | case "login":
19 | if ( cgi.REQUEST_URL does not contain "/index.cfm" )
20 | location url="index.cfm" addtoken="false";
21 | cfinclude( template="login.cfm" );
22 | break;
23 | default:
24 | if ( StructKeyExists( variables.plugin, request.action ) )
25 | variables.plugin[ request.action ]( lang={}, app={}, req=url );
26 | if ( !url.xhr )
27 | variables.plugin.getRenderUtils().includeJavascript( "jquery-3.6.0.slim.min" );
28 | variables.plugin._display( template=request.action & ".cfm", lang={}, app={}, req=url );
29 | }
30 | }
31 |
32 |
33 |
34 |
35 |
36 | #request.subtitle# - #request.title#
37 |
38 |
39 |
40 |
41 |
42 |
43 |
50 |
51 | #variables.plugin.getRenderUtils().cleanHtml(body)#
52 |
53 |
54 |
55 |