Skip to content

Commit c655242

Browse files
committed
Add debug toolbar
Signed-off-by: Carl Schwan <carl@carlschwan.eu>
1 parent ce0b8c7 commit c655242

File tree

14 files changed

+443
-17
lines changed

14 files changed

+443
-17
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
!/apps/files_versions
3131
!/apps/lookup_server_connector
3232
!/apps/user_ldap
33+
!/apps/profiler
3334
!/apps/oauth2
3435
!/apps/provisioning_api
3536
!/apps/settings

apps/profiler/composer/composer/installed.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
'type' => 'library',
66
'install_path' => __DIR__ . '/../',
77
'aliases' => array(),
8-
'reference' => 'c2ac970afa95bfa323a1ac70cb5314851c645145',
8+
'reference' => 'c6fd482edf33214a9ad4787e4cac278f871fa7c8',
99
'name' => '__root__',
1010
'dev' => false,
1111
),
@@ -16,7 +16,7 @@
1616
'type' => 'library',
1717
'install_path' => __DIR__ . '/../',
1818
'aliases' => array(),
19-
'reference' => 'c2ac970afa95bfa323a1ac70cb5314851c645145',
19+
'reference' => 'c6fd482edf33214a9ad4787e4cac278f871fa7c8',
2020
'dev_requirement' => false,
2121
),
2222
),
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
<template>
2+
<div id="profiler-toolbar">
3+
<footer v-if="profile" class="bottom-bar">
4+
<div role="button" class="toolbar-block" @click="openProfiler('info')">
5+
<div class="text-v-center px-3" :class="background">
6+
{{ profile.statusCode }}
7+
</div>
8+
<div class="text-v-center px-3">
9+
{{ profile.collectors.router.controllerName }}::{{ profile.collectors.router.actionName }}
10+
</div>
11+
<div class="info">
12+
<div><b>HTTP Status:</b> {{ profile.statusCode }} </div>
13+
<div><b>Controller:</b> {{ profile.collectors.router.appName }}/{{ profile.collectors.router.controllerName }}::{{ profile.collectors.router.actionName }} </div>
14+
<div><b>Profiled on:</b> {{ time }} </div>
15+
<div><b>Token:</b> {{ profile.token }}</div>
16+
</div>
17+
</div>
18+
<div role="button" class="toolbar-block text-v-center px-3" @click="openProfiler('event')">
19+
{{ displayDuration(profile.collectors.event.runtime.duration + profile.collectors.event.autoloader.duration) }} ms
20+
<div class="info" style="width: 225px">
21+
<div><b>Total time:</b> {{ displayDuration(profile.collectors.event.runtime.duration + profile.collectors.event.autoloader.duration) }} ms</div>
22+
<div><b>Boot:</b> {{ displayDuration(profile.collectors.event.boot.duration) }} ms</div>
23+
<div v-if="profile.collectors.event.run_route">
24+
<b>Run route:</b> {{ displayDuration(profile.collectors.event.run_route.duration) }} ms
25+
</div>
26+
<div v-if="profile.collectors.event.setup_fs">
27+
<b>Setup filesystem:</b> {{ displayDuration(profile.collectors.event.setup_fs.duration) }} ms
28+
</div>
29+
</div>
30+
</div>
31+
32+
<div role="button" class="toolbar-block text-v-center px-3" @click="openProfiler('db')">
33+
{{ queriesNumber }} in {{ queriesTime }} ms
34+
<div class="info" style="width: 225px">
35+
<div><b>Number of queries:</b> {{ queriesNumber }}</div>
36+
<div><b>Query time:</b> {{ queriesTime }} ms</div>
37+
</div>
38+
</div>
39+
40+
<div role="button" class="toolbar-block text-v-center px-3" @click="openProfiler('db')">
41+
{{ stackElements.length }} AJAX requests
42+
<div class="info" style="width: 500px; max-height: 600px; overflow-x: scroll">
43+
<div v-for="(stackElement, index) in stackElements" :key="index">
44+
<a :href="generateAjaxUrl(stackElement)">
45+
{{ stackElement.url }}
46+
in {{ (stackElement.duration).toFixed() }} ms
47+
<span class="lighter">({{ stackElement.profile }})</span>
48+
</a>
49+
</div>
50+
</div>
51+
</div>
52+
</footer>
53+
</div>
54+
</template>
55+
56+
<script>
57+
import { loadState } from '@nextcloud/initial-state'
58+
import { mapState } from 'vuex'
59+
import { generateUrl } from '@nextcloud/router'
60+
61+
const token = loadState('profiler', 'request-token')
62+
63+
export default {
64+
name: 'ProfilerToolbar',
65+
data() {
66+
return {
67+
token,
68+
}
69+
},
70+
computed: {
71+
profile() {
72+
return this.profiles[this.token]
73+
},
74+
queriesNumber() {
75+
return Object.values(this.profile.collectors.db.queries).length
76+
},
77+
queriesTime() {
78+
return (Object.values(this.profile.collectors.db.queries).reduce((acc, query) => {
79+
return query.executionMS + acc
80+
}, 0) * 1000).toFixed(1)
81+
},
82+
background() {
83+
if (!this.profile) {
84+
return ''
85+
}
86+
if (this.profile.statusCode === 200) {
87+
return 'status-success'
88+
}
89+
if (this.profile.statusCode === 500) {
90+
return 'status-error'
91+
}
92+
return 'status-warning'
93+
},
94+
time() {
95+
if (!this.profile) {
96+
return ''
97+
}
98+
return new Date(this.profile.time * 1000).toUTCString()
99+
},
100+
...mapState(['profiles', 'stackElements']),
101+
},
102+
mounted() {
103+
this.$store.dispatch('loadProfile', { token })
104+
},
105+
methods: {
106+
displayDuration(time) {
107+
return (time * 1000.0).toFixed(2)
108+
},
109+
generateAjaxUrl(stackElement) {
110+
return generateUrl('/apps/profiler/profiler/db/{token}', {
111+
token: stackElement.profile,
112+
})
113+
},
114+
openProfiler(view) {
115+
document.location = generateUrl('/apps/profiler/profiler/{view}/{token}', {
116+
view,
117+
token: this.token,
118+
})
119+
},
120+
},
121+
}
122+
</script>
123+
124+
<style lang="scss" scoped>
125+
.bottom-bar {
126+
position: fixed;
127+
width: 100%;
128+
bottom: 0;
129+
left: 0;
130+
display: flex;
131+
z-index: 10;
132+
flex-direction: row;
133+
background-color: #222;
134+
justify-content: start;
135+
height: 36px;
136+
font-size: 12px;
137+
border-bottom: 1px solid var(--color-border);
138+
139+
& > .toolbar-block {
140+
height: 100%;
141+
}
142+
143+
.pr-3, .px-3 {
144+
padding-right: 1rem !important;
145+
}
146+
147+
.pl-3, .px-3 {
148+
padding-left: 1rem !important;
149+
}
150+
151+
.lighter {
152+
color: #ddd;
153+
}
154+
155+
.text-v-center {
156+
height: 100%;
157+
display: flex;
158+
flex-direction: column;
159+
align-items: center;
160+
justify-content: center;
161+
}
162+
163+
.toolbar-block:hover {
164+
position: relative;
165+
background-color: #444;
166+
border-radius: 0;
167+
.info {
168+
display: block;
169+
padding: 10px;
170+
max-width: 480px;
171+
max-height: 480px;
172+
word-wrap: break-word;
173+
overflow: hidden;
174+
}
175+
}
176+
177+
.toolbar-block {
178+
display: flex;
179+
flex-direction: row;
180+
justify-content: center;
181+
color: white;
182+
.info {
183+
background-color: #444;
184+
bottom: 36px;
185+
color: #F5F5F5;
186+
display: none;
187+
padding: .5rem;
188+
position: absolute;
189+
190+
a {
191+
color: #F5F5F5;
192+
}
193+
}
194+
}
195+
}
196+
.status-success {
197+
background-color: rgba(112, 196, 137, 0.75);
198+
}
199+
.status-error {
200+
background-color: rgba(231, 55, 51, 0.65);
201+
}
202+
.status-warning {
203+
background-color: rgba(213, 118, 41, 0.75);
204+
}
205+
.url {
206+
margin-left: 48px;
207+
}
208+
</style>

apps/profiler/src/components/ProfileHeader.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ export default {
2525
if (!this.profile) {
2626
return ''
2727
}
28-
if (this.profile.statusCode === '200') {
28+
if (this.profile.statusCode === 200) {
2929
return 'status-success'
3030
}
31-
if (this.profile.statusCode === '500') {
31+
if (this.profile.statusCode === 500) {
3232
return 'status-error'
3333
}
3434
return 'status-warning'
@@ -73,5 +73,4 @@ export default {
7373
.url {
7474
margin-left: 48px;
7575
}
76-
7776
</style>

apps/profiler/src/store.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@ Vue.use(Vuex)
88
export default new Store({
99
state: {
1010
profiles: {},
11+
stackElements: [],
1112
},
1213
mutations: {
1314
addProfile(state, { token, profile }) {
1415
Vue.set(state.profiles, token, profile)
1516
},
17+
addStackElement(state, stackElement) {
18+
state.stackElements.push(stackElement)
19+
},
1620
},
1721
getters: {
1822
profile: (state) => (token) => {

0 commit comments

Comments
 (0)