Resolve #2328
This commit is contained in:
		
							parent
							
								
									e615a3fdf3
								
							
						
					
					
						commit
						c985fed3e4
					
				
					 7 changed files with 200 additions and 2 deletions
				
			
		| 
						 | 
					@ -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: "ファイル選択中"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,7 +555,95 @@ 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>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -204,4 +204,30 @@ export interface IStats {
 | 
				
			||||||
			decSize: number;
 | 
								decSize: number;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * ネットワークに関する統計
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						network: {
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * サーバーへのリクエスト数
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							requests: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * 応答時間の合計
 | 
				
			||||||
 | 
							 * TIP: (totalTime / requests) でひとつのリクエストに平均でどれくらいの時間がかかったか知れる
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							totalTime: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * 合計受信データ量
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							incomingBytes: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 * 合計送信データ量
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							outgoingBytes: number;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue