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: "投稿"
 | 
			
		||||
  users: "ユーザー"
 | 
			
		||||
  drive: "ドライブ"
 | 
			
		||||
  network: "ネットワーク"
 | 
			
		||||
  charts:
 | 
			
		||||
    notes: "投稿の増減 (統合)"
 | 
			
		||||
    local-notes: "投稿の増減 (ローカル)"
 | 
			
		||||
| 
						 | 
				
			
			@ -529,6 +530,9 @@ desktop/views/components/charts.vue:
 | 
			
		|||
    drive-total: "ドライブ使用量の累計"
 | 
			
		||||
    drive-files: "ドライブのファイル数の増減"
 | 
			
		||||
    drive-files-total: "ドライブのファイル数の累計"
 | 
			
		||||
    network-requests: "リクエスト"
 | 
			
		||||
    network-time: "応答時間"
 | 
			
		||||
    network-usage: "通信量"
 | 
			
		||||
 | 
			
		||||
desktop/views/components/choose-file-from-drive-window.vue:
 | 
			
		||||
  choose-file: "ファイル選択中"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -179,6 +179,7 @@
 | 
			
		|||
		"redis": "2.8.0",
 | 
			
		||||
		"request": "2.88.0",
 | 
			
		||||
		"request-promise-native": "1.0.5",
 | 
			
		||||
		"request-stats": "3.0.0",
 | 
			
		||||
		"rimraf": "2.6.2",
 | 
			
		||||
		"rndstr": "1.0.0",
 | 
			
		||||
		"s-age": "1.1.2",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,11 @@
 | 
			
		|||
				<option value="drive">%i18n:@charts.drive%</option>
 | 
			
		||||
				<option value="drive-total">%i18n:@charts.drive-total%</option>
 | 
			
		||||
			</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>
 | 
			
		||||
		<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>
 | 
			
		||||
| 
						 | 
				
			
			@ -41,7 +46,10 @@ const colors = {
 | 
			
		|||
	localPlus: 'rgb(52, 178, 118)',
 | 
			
		||||
	remotePlus: 'rgb(158, 255, 209)',
 | 
			
		||||
	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 => {
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +83,9 @@ export default Vue.extend({
 | 
			
		|||
				case 'drive-total': return this.driveTotalChart();
 | 
			
		||||
				case 'drive-files': return this.driveFilesChart();
 | 
			
		||||
				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>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -204,4 +204,30 @@ export interface IStats {
 | 
			
		|||
			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[]) {
 | 
			
		||||
	stats.forEach(stat => {
 | 
			
		||||
		if (stat.network == null) {
 | 
			
		||||
			stat.network = {
 | 
			
		||||
				requests: 0,
 | 
			
		||||
				totalTime: 0,
 | 
			
		||||
				incomingBytes: 0,
 | 
			
		||||
				outgoingBytes: 0
 | 
			
		||||
			};
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const isOldData =
 | 
			
		||||
			stat.users.local.inc == null ||
 | 
			
		||||
			stat.users.local.dec == null ||
 | 
			
		||||
| 
						 | 
				
			
			@ -180,6 +189,12 @@ export default (params: any) => new Promise(async (res, rej) => {
 | 
			
		|||
								decCount: 0,
 | 
			
		||||
								decSize: 0
 | 
			
		||||
							}
 | 
			
		||||
						},
 | 
			
		||||
						network: {
 | 
			
		||||
							requests: 0,
 | 
			
		||||
							totalTime: 0,
 | 
			
		||||
							incomingBytes: 0,
 | 
			
		||||
							outgoingBytes: 0
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
				} else {
 | 
			
		||||
| 
						 | 
				
			
			@ -236,6 +251,12 @@ export default (params: any) => new Promise(async (res, rej) => {
 | 
			
		|||
								decCount: 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 compress from 'koa-compress';
 | 
			
		||||
import * as logger from 'koa-logger';
 | 
			
		||||
const requestStats = require('request-stats');
 | 
			
		||||
//const slow = require('koa-slow');
 | 
			
		||||
 | 
			
		||||
import activityPub from './activitypub';
 | 
			
		||||
import webFinger from './webfinger';
 | 
			
		||||
import config from '../config';
 | 
			
		||||
import { updateNetworkStats } from '../services/update-chart';
 | 
			
		||||
 | 
			
		||||
// Init app
 | 
			
		||||
const app = new Koa();
 | 
			
		||||
| 
						 | 
				
			
			@ -81,4 +83,27 @@ export default () => new Promise(resolve => {
 | 
			
		|||
 | 
			
		||||
	// Listen
 | 
			
		||||
	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,
 | 
			
		||||
						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,
 | 
			
		||||
						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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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