prevent huge data amounts, separate sources
This commit is contained in:
parent
39f9f17b95
commit
b6ecd65748
@ -11,15 +11,19 @@ const db = require ('../db');
|
|||||||
const { http } = require ('@sapphirecode/consts');
|
const { http } = require ('@sapphirecode/consts');
|
||||||
|
|
||||||
module.exports = async (req, res) => {
|
module.exports = async (req, res) => {
|
||||||
if (
|
const limit = parseInt (req.headers.limit);
|
||||||
typeof req.headers.app_id === 'undefined'
|
const offset = parseInt (req.headers.offset);
|
||||||
|| isNaN (parseInt (req.headers.app_id))
|
const app_id = parseInt (req.headers.app_id);
|
||||||
) {
|
|
||||||
|
if (isNaN (app_id)) {
|
||||||
res.status (http.status_bad_request)
|
res.status (http.status_bad_request)
|
||||||
.end ();
|
.end ('app id not specified');
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
res.status (http.status_ok)
|
res.status (http.status_ok)
|
||||||
.json (await db.log.get_all (parseInt (req.headers.app_id)));
|
.json (await db.log.get_all (
|
||||||
}
|
parseInt (req.headers.app_id),
|
||||||
|
isNaN (limit) ? 100 : limit,
|
||||||
|
isNaN (offset) ? 0 : offset
|
||||||
|
));
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports = (get_db) => ({
|
module.exports = (get_db) => ({
|
||||||
get_all (app_id) {
|
get_all (app_id, limit = 100, offset = 0) {
|
||||||
const knex = get_db ();
|
const knex = get_db ();
|
||||||
return knex.select (
|
return knex.select (
|
||||||
'id',
|
'id',
|
||||||
@ -17,7 +17,10 @@ module.exports = (get_db) => ({
|
|||||||
'timestamp'
|
'timestamp'
|
||||||
)
|
)
|
||||||
.from ('log')
|
.from ('log')
|
||||||
.where ({ app_id });
|
.where ({ app_id })
|
||||||
|
.orderBy ('timestamp')
|
||||||
|
.limit (Math.min (limit, 10000))
|
||||||
|
.offset (offset);
|
||||||
},
|
},
|
||||||
insert (app_id, message, data = '{}', timestamp = (new Date)) {
|
insert (app_id, message, data = '{}', timestamp = (new Date)) {
|
||||||
const knex = get_db ();
|
const knex = get_db ();
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sapphirecode/consts": "^1.1.28",
|
"@sapphirecode/consts": "^1.1.28",
|
||||||
|
"@sapphirecode/crypto-helper": "^1.1.57",
|
||||||
"@sapphirecode/utilities": "^1.8.5",
|
"@sapphirecode/utilities": "^1.8.5",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"chart.js": "^2.9.3",
|
"chart.js": "^2.9.3",
|
||||||
|
@ -7,6 +7,14 @@
|
|||||||
class="label"
|
class="label"
|
||||||
v-text="template.name"
|
v-text="template.name"
|
||||||
/>
|
/>
|
||||||
|
<button
|
||||||
|
v-if="removable"
|
||||||
|
class="array_remove"
|
||||||
|
type="button"
|
||||||
|
@click="$emit('remove')"
|
||||||
|
>
|
||||||
|
X
|
||||||
|
</button>
|
||||||
<!-- editor -->
|
<!-- editor -->
|
||||||
<div
|
<div
|
||||||
v-if="template.type === 'object'"
|
v-if="template.type === 'object'"
|
||||||
@ -26,10 +34,11 @@
|
|||||||
>
|
>
|
||||||
<ConfigEditor
|
<ConfigEditor
|
||||||
v-for="(child,key) of config"
|
v-for="(child,key) of config"
|
||||||
:key="key"
|
:key="salt (key)"
|
||||||
v-model="config[key]"
|
v-model="config[key]"
|
||||||
:template="template.child"
|
:template="template.child"
|
||||||
:enabled="is_enabled(template.child.if)"
|
:removable="true"
|
||||||
|
@remove="config.splice(key, 1)"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@ -83,8 +92,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { create_salt } from '@sapphirecode/crypto-helper';
|
||||||
import { resolve_data } from '../helper';
|
import { resolve_data } from '../helper';
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ConfigEditor',
|
name: 'ConfigEditor',
|
||||||
props: {
|
props: {
|
||||||
@ -98,6 +109,10 @@ export default {
|
|||||||
enabled: {
|
enabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
|
},
|
||||||
|
removable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
@ -155,6 +170,9 @@ export default {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
},
|
||||||
|
salt () {
|
||||||
|
return create_salt ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -177,4 +195,11 @@ export default {
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
grid-column: label;
|
grid-column: label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.array_remove {
|
||||||
|
display: inline-block;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -5,8 +5,17 @@
|
|||||||
* Created by Timo Hocker <timo@scode.ovh>, August 2020
|
* Created by Timo Hocker <timo@scode.ovh>, August 2020
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default [
|
export default {
|
||||||
|
sources: [
|
||||||
{
|
{
|
||||||
|
name: 'default',
|
||||||
|
limit: 10,
|
||||||
|
offset: 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
displays: [
|
||||||
|
{
|
||||||
|
source: 'default',
|
||||||
type: 'chart',
|
type: 'chart',
|
||||||
x: 'timestamp',
|
x: 'timestamp',
|
||||||
y: [
|
y: [
|
||||||
@ -31,6 +40,7 @@ export default [
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
source: 'default',
|
||||||
type: 'table',
|
type: 'table',
|
||||||
columns: [
|
columns: [
|
||||||
'id',
|
'id',
|
||||||
@ -39,4 +49,5 @@ export default [
|
|||||||
'timestamp'
|
'timestamp'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
};
|
||||||
|
@ -11,17 +11,42 @@ import Vuex from 'vuex';
|
|||||||
Vue.use (Vuex);
|
Vue.use (Vuex);
|
||||||
|
|
||||||
export default new Vuex.Store ({
|
export default new Vuex.Store ({
|
||||||
state: { log: [] },
|
state: { log: {} },
|
||||||
mutations: {
|
mutations: {
|
||||||
set_log (state, log) {
|
set_log (state, log) {
|
||||||
state.log = log;
|
state.log = log;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
getters: {
|
||||||
|
log (state) {
|
||||||
|
return (source) => {
|
||||||
|
if (typeof state.log[source] === 'undefined')
|
||||||
|
return [];
|
||||||
|
return state.log[source];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
actions: {
|
actions: {
|
||||||
async get_log ({ commit }, { app_id }) {
|
async get_log ({ commit }, { app_id, sources }) {
|
||||||
const log = await fetch ('/log', { headers: { app_id } })
|
const logs = {};
|
||||||
.then ((res) => res.json ());
|
for (const source of sources) {
|
||||||
commit ('set_log', log);
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const log = await fetch ('/log', {
|
||||||
|
headers: {
|
||||||
|
app_id,
|
||||||
|
offset: source.offset,
|
||||||
|
limit: source.limit
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then ((res) => res.json ())
|
||||||
|
.then ((json) => json.map ((entry) => {
|
||||||
|
entry.data = JSON.parse (entry.data);
|
||||||
|
return entry;
|
||||||
|
}));
|
||||||
|
logs[source.name] = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
commit ('set_log', logs);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modules: {}
|
modules: {}
|
||||||
|
@ -6,10 +6,39 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
type: 'object',
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
name: 'sources',
|
||||||
child: {
|
child: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: [
|
properties: [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'name'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
name: 'limit'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
name: 'offset'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'array',
|
||||||
|
name: 'displays',
|
||||||
|
child: {
|
||||||
|
type: 'object',
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'source'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
name: 'type',
|
name: 'type',
|
||||||
@ -45,4 +74,6 @@ export default {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
:template="template"
|
:template="template"
|
||||||
/>
|
/>
|
||||||
<ViewComponent
|
<ViewComponent
|
||||||
v-for="(item,key) of saved_config"
|
v-for="(item,key) of saved_config.displays"
|
||||||
:key="key"
|
:key="key"
|
||||||
:config="item"
|
:config="item"
|
||||||
:data="parsed_log"
|
:data="log(item.source)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -32,17 +32,9 @@ export default {
|
|||||||
template: default_template
|
template: default_template
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: { ...Vuex.mapGetters ({ log: 'log' }) },
|
||||||
parsed_log () {
|
|
||||||
return this.log.map ((l) => {
|
|
||||||
l.data = JSON.parse (l.data);
|
|
||||||
return l;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
...Vuex.mapState ({ log: (state) => state.log })
|
|
||||||
},
|
|
||||||
mounted () {
|
mounted () {
|
||||||
this.get_log ({ app_id: this.$route.params.id });
|
this.fetch_log ();
|
||||||
document.body.addEventListener ('keydown', (ev) => {
|
document.body.addEventListener ('keydown', (ev) => {
|
||||||
if (ev.key === 's' && ev.ctrlKey) {
|
if (ev.key === 's' && ev.ctrlKey) {
|
||||||
this.save_config ();
|
this.save_config ();
|
||||||
@ -59,6 +51,13 @@ export default {
|
|||||||
body: JSON.stringify (this.config)
|
body: JSON.stringify (this.config)
|
||||||
});
|
});
|
||||||
this.saved_config = copy_object (this.config);
|
this.saved_config = copy_object (this.config);
|
||||||
|
this.fetch_log ();
|
||||||
|
},
|
||||||
|
fetch_log () {
|
||||||
|
this.get_log ({
|
||||||
|
app_id: this.$route.params.id,
|
||||||
|
sources: this.saved_config.sources
|
||||||
|
});
|
||||||
},
|
},
|
||||||
...Vuex.mapActions ({ get_log: 'get_log' })
|
...Vuex.mapActions ({ get_log: 'get_log' })
|
||||||
}
|
}
|
||||||
|
12
yarn.lock
12
yarn.lock
@ -941,6 +941,18 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@sapphirecode/consts/-/consts-1.1.28.tgz#4f9400a80666c3e41b55acada999c877d32eb55c"
|
resolved "https://registry.yarnpkg.com/@sapphirecode/consts/-/consts-1.1.28.tgz#4f9400a80666c3e41b55acada999c877d32eb55c"
|
||||||
integrity sha512-OVZpkhOJtdzf379GNVPBb3D1iqTTSger8/LF/hmq9dqvrcfHm+rara2jChg9qOqk840EEzZCLEFLjyEMz+aDeA==
|
integrity sha512-OVZpkhOJtdzf379GNVPBb3D1iqTTSger8/LF/hmq9dqvrcfHm+rara2jChg9qOqk840EEzZCLEFLjyEMz+aDeA==
|
||||||
|
|
||||||
|
"@sapphirecode/crypto-helper@^1.1.57":
|
||||||
|
version "1.1.57"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sapphirecode/crypto-helper/-/crypto-helper-1.1.57.tgz#cfa7d7fefd417e875c2b080816b63edf699d79bf"
|
||||||
|
integrity sha512-ReKGCFOMq+S8y/XEY2bjG5BQFoYzoebiJi/1BYuu6WXLLTIzGO2JkZ7rsFZV2FEW1dQGVdbjpGmovMwtZjJhtw==
|
||||||
|
dependencies:
|
||||||
|
"@sapphirecode/encoding-helper" "^1.0.38"
|
||||||
|
|
||||||
|
"@sapphirecode/encoding-helper@^1.0.38":
|
||||||
|
version "1.0.49"
|
||||||
|
resolved "https://registry.yarnpkg.com/@sapphirecode/encoding-helper/-/encoding-helper-1.0.49.tgz#cb5389ff3b469910b4067b5b0487e99c55320424"
|
||||||
|
integrity sha512-iMgBXnXPFDuPlWJdECap+VIAwrkN0wAUK/ah4V5xJM1jmUhCHjqORv75bhkmPY+92DeusZaxBnQkC1hboeTW7A==
|
||||||
|
|
||||||
"@sapphirecode/eslint-config-es6@^1.1.1":
|
"@sapphirecode/eslint-config-es6@^1.1.1":
|
||||||
version "1.1.17"
|
version "1.1.17"
|
||||||
resolved "https://registry.yarnpkg.com/@sapphirecode/eslint-config-es6/-/eslint-config-es6-1.1.17.tgz#52e554d1fa9870cc813d2a39bb84ae85f9db612d"
|
resolved "https://registry.yarnpkg.com/@sapphirecode/eslint-config-es6/-/eslint-config-es6-1.1.17.tgz#52e554d1fa9870cc813d2a39bb84ae85f9db612d"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user