345 lines
8.9 KiB
Dart
345 lines
8.9 KiB
Dart
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:logging/logging.dart';
|
|
|
|
/// 性能监控器
|
|
/// 用于监控和记录应用程序性能指标
|
|
class PerformanceMonitor {
|
|
PerformanceMonitor({bool enabled = true}) : _enabled = enabled {
|
|
if (_enabled) {
|
|
_logger.info('性能监控器已启用');
|
|
}
|
|
}
|
|
static final Logger _logger = Logger('PerformanceMonitor');
|
|
|
|
final Map<String, PerformanceMetric> _metrics = {};
|
|
final Map<String, List<Duration>> _measurements = {};
|
|
final bool _enabled;
|
|
|
|
/// 测量异步操作的执行时间
|
|
Future<T> measure<T>(
|
|
String operationName,
|
|
Future<T> Function() operation,
|
|
) async {
|
|
if (!_enabled) {
|
|
return operation();
|
|
}
|
|
|
|
final stopwatch = Stopwatch()..start();
|
|
|
|
try {
|
|
final result = await operation();
|
|
stopwatch.stop();
|
|
|
|
_recordMeasurement(operationName, stopwatch.elapsed);
|
|
|
|
return result;
|
|
} on Object catch (e) {
|
|
stopwatch.stop();
|
|
_recordMeasurement(operationName, stopwatch.elapsed, error: e);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
/// 测量同步操作的执行时间
|
|
T measureSync<T>(String operationName, T Function() operation) {
|
|
if (!_enabled) {
|
|
return operation();
|
|
}
|
|
|
|
final stopwatch = Stopwatch()..start();
|
|
|
|
try {
|
|
final result = operation();
|
|
stopwatch.stop();
|
|
|
|
_recordMeasurement(operationName, stopwatch.elapsed);
|
|
|
|
return result;
|
|
} on Object catch (e) {
|
|
stopwatch.stop();
|
|
_recordMeasurement(operationName, stopwatch.elapsed, error: e);
|
|
rethrow;
|
|
}
|
|
}
|
|
|
|
/// 开始计时
|
|
PerformanceTimer startTimer(String operationName) {
|
|
return PerformanceTimer(operationName, this);
|
|
}
|
|
|
|
/// 记录测量结果
|
|
void _recordMeasurement(
|
|
String operationName,
|
|
Duration duration, {
|
|
dynamic error,
|
|
}) {
|
|
if (!_enabled) return;
|
|
|
|
// 记录到测量历史中
|
|
_measurements.putIfAbsent(operationName, () => []);
|
|
_measurements[operationName]!.add(duration);
|
|
|
|
// 更新或创建性能指标
|
|
if (_metrics.containsKey(operationName)) {
|
|
_metrics[operationName]!.addMeasurement(duration, error: error);
|
|
} else {
|
|
_metrics[operationName] = PerformanceMetric(operationName);
|
|
_metrics[operationName]!.addMeasurement(duration, error: error);
|
|
}
|
|
|
|
// 记录日志
|
|
final status = error != null ? 'ERROR' : 'SUCCESS';
|
|
_logger.info('$operationName: ${duration.inMilliseconds}ms [$status]');
|
|
}
|
|
|
|
/// 获取所有性能指标
|
|
Map<String, PerformanceMetric> getMetrics() {
|
|
return Map.unmodifiable(_metrics);
|
|
}
|
|
|
|
/// 获取特定操作的性能指标
|
|
PerformanceMetric? getMetric(String operationName) {
|
|
return _metrics[operationName];
|
|
}
|
|
|
|
/// 获取性能报告
|
|
PerformanceReport generateReport() {
|
|
final totalOperations =
|
|
_metrics.values.fold(0, (sum, metric) => sum + metric.count);
|
|
final totalTime = _metrics.values.fold(
|
|
Duration.zero,
|
|
(sum, metric) => sum + metric.totalTime,
|
|
);
|
|
|
|
return PerformanceReport(
|
|
totalOperations: totalOperations,
|
|
totalTime: totalTime,
|
|
metrics: Map.from(_metrics),
|
|
generatedAt: DateTime.now(),
|
|
);
|
|
}
|
|
|
|
/// 清空所有指标
|
|
void clear() {
|
|
_metrics.clear();
|
|
_measurements.clear();
|
|
}
|
|
|
|
/// 获取慢操作(执行时间超过阈值)
|
|
List<SlowOperation> getSlowOperations([
|
|
Duration threshold = const Duration(milliseconds: 500),
|
|
]) {
|
|
final slowOps = <SlowOperation>[];
|
|
|
|
for (final metric in _metrics.values) {
|
|
if (metric.maxTime >= threshold) {
|
|
slowOps.add(
|
|
SlowOperation(
|
|
name: metric.operationName,
|
|
maxTime: metric.maxTime,
|
|
avgTime: metric.averageTime,
|
|
count: metric.count,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// 按最大执行时间排序
|
|
slowOps.sort((a, b) => b.maxTime.compareTo(a.maxTime));
|
|
|
|
return slowOps;
|
|
}
|
|
|
|
/// 导出性能数据到文件
|
|
Future<void> exportToFile(String filePath) async {
|
|
if (!_enabled) return;
|
|
|
|
try {
|
|
final report = generateReport();
|
|
final data = {
|
|
'generatedAt': report.generatedAt.toIso8601String(),
|
|
'summary': {
|
|
'totalOperations': report.totalOperations,
|
|
'totalTime': report.totalTime.inMilliseconds,
|
|
},
|
|
'metrics': report.metrics.map(
|
|
(key, value) => MapEntry(key, {
|
|
'operationName': value.operationName,
|
|
'count': value.count,
|
|
'totalTime': value.totalTime.inMilliseconds,
|
|
'averageTime': value.averageTime.inMilliseconds,
|
|
'minTime': value.minTime.inMilliseconds,
|
|
'maxTime': value.maxTime.inMilliseconds,
|
|
'errorCount': value.errorCount,
|
|
'lastExecuted': value.lastExecuted?.toIso8601String(),
|
|
}),
|
|
),
|
|
};
|
|
|
|
final file = File(filePath);
|
|
await file.writeAsString(json.encode(data));
|
|
|
|
_logger.info('性能数据已导出到: $filePath');
|
|
} catch (e) {
|
|
_logger.severe('导出性能数据失败: $e');
|
|
}
|
|
}
|
|
|
|
/// 打印性能摘要
|
|
void printSummary() {
|
|
if (!_enabled) {
|
|
_logger.info('性能监控器已禁用');
|
|
return;
|
|
}
|
|
|
|
if (_metrics.isEmpty) {
|
|
_logger.info('没有性能数据');
|
|
return;
|
|
}
|
|
|
|
final buffer = StringBuffer()
|
|
..writeln('\n🔍 性能监控摘要:')
|
|
..writeln('=' * 50);
|
|
|
|
final sortedMetrics = _metrics.values.toList()
|
|
..sort((a, b) => b.totalTime.compareTo(a.totalTime));
|
|
|
|
for (final metric in sortedMetrics) {
|
|
buffer
|
|
..writeln('${metric.operationName}:')
|
|
..writeln(' 执行次数: ${metric.count}')
|
|
..writeln(' 总时间: ${metric.totalTime.inMilliseconds}ms')
|
|
..writeln(' 平均时间: ${metric.averageTime.inMilliseconds}ms')
|
|
..writeln(' 最小时间: ${metric.minTime.inMilliseconds}ms')
|
|
..writeln(' 最大时间: ${metric.maxTime.inMilliseconds}ms');
|
|
if (metric.errorCount > 0) {
|
|
buffer.writeln(' 错误次数: ${metric.errorCount}');
|
|
}
|
|
buffer.writeln();
|
|
}
|
|
|
|
final slowOps = getSlowOperations();
|
|
if (slowOps.isNotEmpty) {
|
|
buffer.writeln('🐌 慢操作 (>500ms):');
|
|
for (final op in slowOps.take(5)) {
|
|
buffer.writeln(' ${op.name}: ${op.maxTime.inMilliseconds}ms (最大)');
|
|
}
|
|
}
|
|
|
|
_logger.info(buffer.toString());
|
|
}
|
|
}
|
|
|
|
/// 性能计时器
|
|
class PerformanceTimer {
|
|
PerformanceTimer(this.operationName, this.monitor)
|
|
: _stopwatch = Stopwatch()..start();
|
|
final String operationName;
|
|
final PerformanceMonitor monitor;
|
|
final Stopwatch _stopwatch;
|
|
|
|
/// 停止计时并记录结果
|
|
void stop({dynamic error}) {
|
|
if (!_stopwatch.isRunning) return;
|
|
|
|
_stopwatch.stop();
|
|
monitor._recordMeasurement(operationName, _stopwatch.elapsed, error: error);
|
|
}
|
|
|
|
/// 获取当前经过的时间
|
|
Duration get elapsed => _stopwatch.elapsed;
|
|
}
|
|
|
|
/// 性能指标
|
|
class PerformanceMetric {
|
|
PerformanceMetric(this.operationName);
|
|
final String operationName;
|
|
int count = 0;
|
|
Duration totalTime = Duration.zero;
|
|
Duration minTime = Duration.zero;
|
|
Duration maxTime = Duration.zero;
|
|
int errorCount = 0;
|
|
DateTime? lastExecuted;
|
|
|
|
/// 添加测量结果
|
|
void addMeasurement(Duration duration, {dynamic error}) {
|
|
count++;
|
|
totalTime += duration;
|
|
lastExecuted = DateTime.now();
|
|
|
|
if (error != null) {
|
|
errorCount++;
|
|
}
|
|
|
|
if (count == 1) {
|
|
minTime = duration;
|
|
maxTime = duration;
|
|
} else {
|
|
if (duration < minTime) minTime = duration;
|
|
if (duration > maxTime) maxTime = duration;
|
|
}
|
|
}
|
|
|
|
/// 平均执行时间
|
|
Duration get averageTime {
|
|
if (count == 0) return Duration.zero;
|
|
return Duration(microseconds: totalTime.inMicroseconds ~/ count);
|
|
}
|
|
|
|
/// 成功率
|
|
double get successRate {
|
|
if (count == 0) return 0;
|
|
return (count - errorCount) / count;
|
|
}
|
|
}
|
|
|
|
/// 性能报告
|
|
class PerformanceReport {
|
|
const PerformanceReport({
|
|
required this.totalOperations,
|
|
required this.totalTime,
|
|
required this.metrics,
|
|
required this.generatedAt,
|
|
});
|
|
final int totalOperations;
|
|
final Duration totalTime;
|
|
final Map<String, PerformanceMetric> metrics;
|
|
final DateTime generatedAt;
|
|
|
|
/// 获取最慢的操作
|
|
PerformanceMetric? get slowestOperation {
|
|
if (metrics.isEmpty) return null;
|
|
|
|
return metrics.values.reduce((a, b) => a.maxTime > b.maxTime ? a : b);
|
|
}
|
|
|
|
/// 获取最频繁的操作
|
|
PerformanceMetric? get mostFrequentOperation {
|
|
if (metrics.isEmpty) return null;
|
|
|
|
return metrics.values.reduce((a, b) => a.count > b.count ? a : b);
|
|
}
|
|
|
|
/// 获取平均执行时间
|
|
Duration get averageExecutionTime {
|
|
if (totalOperations == 0) return Duration.zero;
|
|
return Duration(microseconds: totalTime.inMicroseconds ~/ totalOperations);
|
|
}
|
|
}
|
|
|
|
/// 慢操作信息
|
|
class SlowOperation {
|
|
const SlowOperation({
|
|
required this.name,
|
|
required this.maxTime,
|
|
required this.avgTime,
|
|
required this.count,
|
|
});
|
|
final String name;
|
|
final Duration maxTime;
|
|
final Duration avgTime;
|
|
final int count;
|
|
}
|