Skip to content

Commit

Permalink
Add debug toolbar
Browse files Browse the repository at this point in the history
Signed-off-by: Carl Schwan <carl@carlschwan.eu>
  • Loading branch information
CarlSchwan committed Jan 29, 2022
1 parent ce0b8c7 commit c655242
Show file tree
Hide file tree
Showing 14 changed files with 443 additions and 17 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
!/apps/files_versions
!/apps/lookup_server_connector
!/apps/user_ldap
!/apps/profiler
!/apps/oauth2
!/apps/provisioning_api
!/apps/settings
Expand Down
4 changes: 2 additions & 2 deletions apps/profiler/composer/composer/installed.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
'type' => 'library',
'install_path' => __DIR__ . '/../',
'aliases' => array(),
'reference' => 'c2ac970afa95bfa323a1ac70cb5314851c645145',
'reference' => 'c6fd482edf33214a9ad4787e4cac278f871fa7c8',
'name' => '__root__',
'dev' => false,
),
Expand All @@ -16,7 +16,7 @@
'type' => 'library',
'install_path' => __DIR__ . '/../',
'aliases' => array(),
'reference' => 'c2ac970afa95bfa323a1ac70cb5314851c645145',
'reference' => 'c6fd482edf33214a9ad4787e4cac278f871fa7c8',
'dev_requirement' => false,
),
),
Expand Down
208 changes: 208 additions & 0 deletions apps/profiler/src/ProfilerToolbar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
<template>
<div id="profiler-toolbar">
<footer v-if="profile" class="bottom-bar">
<div role="button" class="toolbar-block" @click="openProfiler('info')">
<div class="text-v-center px-3" :class="background">
{{ profile.statusCode }}
</div>
<div class="text-v-center px-3">
{{ profile.collectors.router.controllerName }}::{{ profile.collectors.router.actionName }}
</div>
<div class="info">
<div><b>HTTP Status:</b> {{ profile.statusCode }} </div>
<div><b>Controller:</b> {{ profile.collectors.router.appName }}/{{ profile.collectors.router.controllerName }}::{{ profile.collectors.router.actionName }} </div>
<div><b>Profiled on:</b> {{ time }} </div>
<div><b>Token:</b> {{ profile.token }}</div>
</div>
</div>
<div role="button" class="toolbar-block text-v-center px-3" @click="openProfiler('event')">
{{ displayDuration(profile.collectors.event.runtime.duration + profile.collectors.event.autoloader.duration) }} ms
<div class="info" style="width: 225px">
<div><b>Total time:</b> {{ displayDuration(profile.collectors.event.runtime.duration + profile.collectors.event.autoloader.duration) }} ms</div>
<div><b>Boot:</b> {{ displayDuration(profile.collectors.event.boot.duration) }} ms</div>
<div v-if="profile.collectors.event.run_route">
<b>Run route:</b> {{ displayDuration(profile.collectors.event.run_route.duration) }} ms
</div>
<div v-if="profile.collectors.event.setup_fs">
<b>Setup filesystem:</b> {{ displayDuration(profile.collectors.event.setup_fs.duration) }} ms
</div>
</div>
</div>

<div role="button" class="toolbar-block text-v-center px-3" @click="openProfiler('db')">
{{ queriesNumber }} in {{ queriesTime }} ms
<div class="info" style="width: 225px">
<div><b>Number of queries:</b> {{ queriesNumber }}</div>
<div><b>Query time:</b> {{ queriesTime }} ms</div>
</div>
</div>

<div role="button" class="toolbar-block text-v-center px-3" @click="openProfiler('db')">
{{ stackElements.length }} AJAX requests
<div class="info" style="width: 500px; max-height: 600px; overflow-x: scroll">
<div v-for="(stackElement, index) in stackElements" :key="index">
<a :href="generateAjaxUrl(stackElement)">
{{ stackElement.url }}
in {{ (stackElement.duration).toFixed() }} ms
<span class="lighter">({{ stackElement.profile }})</span>
</a>
</div>
</div>
</div>
</footer>
</div>
</template>

<script>
import { loadState } from '@nextcloud/initial-state'
import { mapState } from 'vuex'
import { generateUrl } from '@nextcloud/router'
const token = loadState('profiler', 'request-token')
export default {
name: 'ProfilerToolbar',
data() {
return {
token,
}
},
computed: {
profile() {
return this.profiles[this.token]
},
queriesNumber() {
return Object.values(this.profile.collectors.db.queries).length
},
queriesTime() {
return (Object.values(this.profile.collectors.db.queries).reduce((acc, query) => {
return query.executionMS + acc
}, 0) * 1000).toFixed(1)
},
background() {
if (!this.profile) {
return ''
}
if (this.profile.statusCode === 200) {
return 'status-success'
}
if (this.profile.statusCode === 500) {
return 'status-error'
}
return 'status-warning'
},
time() {
if (!this.profile) {
return ''
}
return new Date(this.profile.time * 1000).toUTCString()
},
...mapState(['profiles', 'stackElements']),
},
mounted() {
this.$store.dispatch('loadProfile', { token })
},
methods: {
displayDuration(time) {
return (time * 1000.0).toFixed(2)
},
generateAjaxUrl(stackElement) {
return generateUrl('/apps/profiler/profiler/db/{token}', {
token: stackElement.profile,
})
},
openProfiler(view) {
document.location = generateUrl('/apps/profiler/profiler/{view}/{token}', {
view,
token: this.token,
})
},
},
}
</script>

<style lang="scss" scoped>
.bottom-bar {
position: fixed;
width: 100%;
bottom: 0;
left: 0;
display: flex;
z-index: 10;
flex-direction: row;
background-color: #222;
justify-content: start;
height: 36px;
font-size: 12px;
border-bottom: 1px solid var(--color-border);
& > .toolbar-block {
height: 100%;
}
.pr-3, .px-3 {
padding-right: 1rem !important;
}
.pl-3, .px-3 {
padding-left: 1rem !important;
}
.lighter {
color: #ddd;
}
.text-v-center {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.toolbar-block:hover {
position: relative;
background-color: #444;
border-radius: 0;
.info {
display: block;
padding: 10px;
max-width: 480px;
max-height: 480px;
word-wrap: break-word;
overflow: hidden;
}
}
.toolbar-block {
display: flex;
flex-direction: row;
justify-content: center;
color: white;
.info {
background-color: #444;
bottom: 36px;
color: #F5F5F5;
display: none;
padding: .5rem;
position: absolute;
a {
color: #F5F5F5;
}
}
}
}
.status-success {
background-color: rgba(112, 196, 137, 0.75);
}
.status-error {
background-color: rgba(231, 55, 51, 0.65);
}
.status-warning {
background-color: rgba(213, 118, 41, 0.75);
}
.url {
margin-left: 48px;
}
</style>
5 changes: 2 additions & 3 deletions apps/profiler/src/components/ProfileHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ export default {
if (!this.profile) {
return ''
}
if (this.profile.statusCode === '200') {
if (this.profile.statusCode === 200) {
return 'status-success'
}
if (this.profile.statusCode === '500') {
if (this.profile.statusCode === 500) {
return 'status-error'
}
return 'status-warning'
Expand Down Expand Up @@ -73,5 +73,4 @@ export default {
.url {
margin-left: 48px;
}
</style>
4 changes: 4 additions & 0 deletions apps/profiler/src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ Vue.use(Vuex)
export default new Store({
state: {
profiles: {},
stackElements: [],
},
mutations: {
addProfile(state, { token, profile }) {
Vue.set(state.profiles, token, profile)
},
addStackElement(state, stackElement) {
state.stackElements.push(stackElement)
},
},
getters: {
profile: (state) => (token) => {
Expand Down
Loading

0 comments on commit c655242

Please sign in to comment.