This commit is contained in:
syuilo 2018-09-15 05:40:58 +09:00
parent e615a3fdf3
commit c985fed3e4
No known key found for this signature in database
GPG Key ID: BDC4C49D06AB9D69
7 changed files with 200 additions and 2 deletions

View File

@ -518,6 +518,7 @@ desktop/views/components/charts.vue:
notes: "投稿" notes: "投稿"
users: "ユーザー" users: "ユーザー"
drive: "ドライブ" drive: "ドライブ"
network: "ネットワーク"
charts: charts:
notes: "投稿の増減 (統合)" notes: "投稿の増減 (統合)"
local-notes: "投稿の増減 (ローカル)" local-notes: "投稿の増減 (ローカル)"
@ -529,6 +530,9 @@ desktop/views/components/charts.vue:
drive-total: "ドライブ使用量の累計" drive-total: "ドライブ使用量の累計"
drive-files: "ドライブのファイル数の増減" drive-files: "ドライブのファイル数の増減"
drive-files-total: "ドライブのファイル数の累計" drive-files-total: "ドライブのファイル数の累計"
network-requests: "リクエスト"
network-time: "応答時間"
network-usage: "通信量"
desktop/views/components/choose-file-from-drive-window.vue: desktop/views/components/choose-file-from-drive-window.vue:
choose-file: "ファイル選択中" choose-file: "ファイル選択中"

View File

@ -179,6 +179,7 @@
"redis": "2.8.0", "redis": "2.8.0",
"request": "2.88.0", "request": "2.88.0",
"request-promise-native": "1.0.5", "request-promise-native": "1.0.5",
"request-stats": "3.0.0",
"rimraf": "2.6.2", "rimraf": "2.6.2",
"rndstr": "1.0.0", "rndstr": "1.0.0",
"s-age": "1.1.2", "s-age": "1.1.2",

View File

@ -19,6 +19,11 @@
<option value="drive">%i18n:@charts.drive%</option> <option value="drive">%i18n:@charts.drive%</option>
<option value="drive-total">%i18n:@charts.drive-total%</option> <option value="drive-total">%i18n:@charts.drive-total%</option>
</optgroup> </optgroup>
<optgroup label="%i18n:@network%">
<option value="network-requests">%i18n:@charts.network-requests%</option>
<option value="network-time">%i18n:@charts.network-time%</option>
<option value="network-usage">%i18n:@charts.network-usage%</option>
</optgroup>
</select> </select>
<div> <div>
<span @click="span = 'day'" :class="{ active: span == 'day' }">%i18n:@per-day%</span> | <span @click="span = 'hour'" :class="{ active: span == 'hour' }">%i18n:@per-hour%</span> <span @click="span = 'day'" :class="{ active: span == 'day' }">%i18n:@per-day%</span> | <span @click="span = 'hour'" :class="{ active: span == 'hour' }">%i18n:@per-hour%</span>
@ -41,7 +46,10 @@ const colors = {
localPlus: 'rgb(52, 178, 118)', localPlus: 'rgb(52, 178, 118)',
remotePlus: 'rgb(158, 255, 209)', remotePlus: 'rgb(158, 255, 209)',
localMinus: 'rgb(255, 97, 74)', localMinus: 'rgb(255, 97, 74)',
remoteMinus: 'rgb(255, 149, 134)' remoteMinus: 'rgb(255, 149, 134)',
incoming: 'rgb(52, 178, 118)',
outgoing: 'rgb(255, 97, 74)',
}; };
const rgba = (color: string): string => { const rgba = (color: string): string => {
@ -75,6 +83,9 @@ export default Vue.extend({
case 'drive-total': return this.driveTotalChart(); case 'drive-total': return this.driveTotalChart();
case 'drive-files': return this.driveFilesChart(); case 'drive-files': return this.driveFilesChart();
case 'drive-files-total': return this.driveFilesTotalChart(); case 'drive-files-total': return this.driveFilesTotalChart();
case 'network-requests': return this.networkRequestsChart();
case 'network-time': return this.networkTimeChart();
case 'network-usage': return this.networkUsageChart();
} }
}, },
@ -544,8 +555,96 @@ export default Vue.extend({
} }
} }
}]; }];
},
networkRequestsChart(): any {
const data = this.stats.slice().reverse().map(x => ({
date: new Date(x.date),
requests: x.network.requests
}));
return [{
datasets: [{
label: 'Requests',
fill: true,
backgroundColor: rgba(colors.localPlus),
borderColor: colors.localPlus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: data.map(x => ({ t: x.date, y: x.requests }))
}]
}];
},
networkTimeChart(): any {
const data = this.stats.slice().reverse().map(x => ({
date: new Date(x.date),
time: x.network.requests != 0 ? (x.network.totalTime / x.network.requests) : 0,
}));
return [{
datasets: [{
label: 'Avg time (ms)',
fill: true,
backgroundColor: rgba(colors.localPlus),
borderColor: colors.localPlus,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: data.map(x => ({ t: x.date, y: x.time }))
}]
}];
},
networkUsageChart(): any {
const data = this.stats.slice().reverse().map(x => ({
date: new Date(x.date),
incoming: x.network.incomingBytes,
outgoing: x.network.outgoingBytes
}));
return [{
datasets: [{
label: 'Incoming',
fill: true,
backgroundColor: rgba(colors.incoming),
borderColor: colors.incoming,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: data.map(x => ({ t: x.date, y: x.incoming }))
}, {
label: 'Outgoing',
fill: true,
backgroundColor: rgba(colors.outgoing),
borderColor: colors.outgoing,
borderWidth: 2,
pointBackgroundColor: '#fff',
lineTension: 0,
data: data.map(x => ({ t: x.date, y: x.outgoing }))
}]
}, {
scales: {
yAxes: [{
ticks: {
callback: value => {
return Vue.filter('bytes')(value, 1);
} }
} }
}]
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
const label = data.datasets[tooltipItem.datasetIndex].label || '';
return `${label}: ${Vue.filter('bytes')(tooltipItem.yLabel, 1)}`;
}
}
}
}];
},
}
}); });
</script> </script>

View File

@ -204,4 +204,30 @@ export interface IStats {
decSize: number; decSize: number;
}; };
}; };
/**
*
*/
network: {
/**
*
*/
requests: number;
/**
*
* TIP: (totalTime / requests)
*/
totalTime: number;
/**
*
*/
incomingBytes: number;
/**
*
*/
outgoingBytes: number;
};
} }

View File

@ -6,6 +6,15 @@ type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
function migrateStats(stats: IStats[]) { function migrateStats(stats: IStats[]) {
stats.forEach(stat => { stats.forEach(stat => {
if (stat.network == null) {
stat.network = {
requests: 0,
totalTime: 0,
incomingBytes: 0,
outgoingBytes: 0
};
}
const isOldData = const isOldData =
stat.users.local.inc == null || stat.users.local.inc == null ||
stat.users.local.dec == null || stat.users.local.dec == null ||
@ -180,6 +189,12 @@ export default (params: any) => new Promise(async (res, rej) => {
decCount: 0, decCount: 0,
decSize: 0 decSize: 0
} }
},
network: {
requests: 0,
totalTime: 0,
incomingBytes: 0,
outgoingBytes: 0
} }
}); });
} else { } else {
@ -236,6 +251,12 @@ export default (params: any) => new Promise(async (res, rej) => {
decCount: 0, decCount: 0,
decSize: 0 decSize: 0
} }
},
network: {
requests: 0,
totalTime: 0,
incomingBytes: 0,
outgoingBytes: 0
} }
}); });
} }

View File

@ -11,11 +11,13 @@ import * as Router from 'koa-router';
import * as mount from 'koa-mount'; import * as mount from 'koa-mount';
import * as compress from 'koa-compress'; import * as compress from 'koa-compress';
import * as logger from 'koa-logger'; import * as logger from 'koa-logger';
const requestStats = require('request-stats');
//const slow = require('koa-slow'); //const slow = require('koa-slow');
import activityPub from './activitypub'; import activityPub from './activitypub';
import webFinger from './webfinger'; import webFinger from './webfinger';
import config from '../config'; import config from '../config';
import { updateNetworkStats } from '../services/update-chart';
// Init app // Init app
const app = new Koa(); const app = new Koa();
@ -81,4 +83,27 @@ export default () => new Promise(resolve => {
// Listen // Listen
server.listen(config.port, resolve); server.listen(config.port, resolve);
//#region Network stats
let queue: any[] = [];
requestStats(server, (stats: any) => {
if (stats.ok) {
queue.push(stats);
}
});
// Bulk write
setInterval(() => {
if (queue.length == 0) return;
const requests = queue.length;
const time = queue.reduce((a, b) => a + b.time, 0);
const incomingBytes = queue.reduce((a, b) => a + b.req.bytes, 0);
const outgoingBytes = queue.reduce((a, b) => a + b.res.bytes, 0);
queue = [];
updateNetworkStats(requests, time, incomingBytes, outgoingBytes);
}, 5000);
//#endregion
}); });

View File

@ -96,6 +96,12 @@ async function getCurrentStats(span: 'day' | 'hour'): Promise<IStats> {
decCount: 0, decCount: 0,
decSize: 0 decSize: 0
} }
},
network: {
requests: 0,
totalTime: 0,
incomingBytes: 0,
outgoingBytes: 0
} }
}; };
@ -161,6 +167,12 @@ async function getCurrentStats(span: 'day' | 'hour'): Promise<IStats> {
decCount: 0, decCount: 0,
decSize: 0 decSize: 0
} }
},
network: {
requests: 0,
totalTime: 0,
incomingBytes: 0,
outgoingBytes: 0
} }
}; };
@ -243,3 +255,13 @@ export async function updateDriveStats(file: IDriveFile, isAdditional: boolean)
await update(inc); await update(inc);
} }
export async function updateNetworkStats(requests: number, time: number, incomingBytes: number, outgoingBytes: number) {
const inc = {} as any;
inc['network.requests'] = requests;
inc['network.totalTime'] = time;
inc['network.incomingBytes'] = incomingBytes;
inc['network.outgoingBytes'] = outgoingBytes;
await update(inc);
}