757 lines
22 KiB
Markdown
757 lines
22 KiB
Markdown
---
|
||
name: walrus-monitor
|
||
description: Walrus 监控分析专家 - 存储使用监控、成本分析和性能指标跟踪
|
||
parameters:
|
||
- name: monitor-type
|
||
type: string
|
||
description: 监控类型 (usage/cost/performance/errors/analytics)
|
||
required: true
|
||
- name: time-range
|
||
type: string
|
||
description: 时间范围 (1h/24h/7d/30d/custom)
|
||
default: 24h
|
||
- name: metrics
|
||
type: array
|
||
description: 需要监控的具体指标
|
||
default: []
|
||
---
|
||
|
||
# Walrus 监控分析技能
|
||
|
||
## 技能概述
|
||
|
||
`walrus-monitor` 是专业的监控分析助手,提供全面的 Walrus 存储系统监控、成本分析和性能指标跟踪功能,帮助开发者优化资源使用和控制成本。
|
||
|
||
## 监控维度
|
||
|
||
### 1. 存储使用监控
|
||
|
||
#### 实时存储指标
|
||
```typescript
|
||
class StorageMonitor {
|
||
private metrics: StorageMetrics[] = [];
|
||
private alerts: Alert[] = [];
|
||
|
||
async collectStorageMetrics(): Promise<StorageMetrics> {
|
||
const client = await this.getWalrusClient();
|
||
const accountAddress = this.getAccountAddress();
|
||
|
||
// 获取账户存储信息
|
||
const storageInfo = await client.getStorageInfo(accountAddress);
|
||
const blobIds = storageInfo.storedBlobs || [];
|
||
|
||
// 计算存储统计
|
||
const metrics: StorageMetrics = {
|
||
timestamp: Date.now(),
|
||
totalFiles: blobIds.length,
|
||
totalSize: 0,
|
||
totalCost: 0,
|
||
storageDistribution: {},
|
||
fileAges: [],
|
||
oldestFile: null,
|
||
newestFile: null,
|
||
expiringSoon: [],
|
||
expired: []
|
||
};
|
||
|
||
// 分析每个文件
|
||
for (const blobId of blobIds) {
|
||
try {
|
||
const [file] = await client.walrus.getFiles({ ids: [blobId] });
|
||
const metadata = await this.getFileMetadata(file);
|
||
const storedUntil = await file.storedUntil();
|
||
|
||
metrics.totalSize += metadata.size;
|
||
metrics.totalCost += metadata.estimatedCost;
|
||
|
||
// 文件类型分布
|
||
const fileType = this.getFileType(metadata.mimeType);
|
||
metrics.storageDistribution[fileType] =
|
||
(metrics.storageDistribution[fileType] || 0) + 1;
|
||
|
||
// 文件年龄分析
|
||
const age = Date.now() - metadata.uploadTime;
|
||
metrics.fileAges.push(age);
|
||
|
||
// 检查过期状态
|
||
const daysToExpiry = Math.floor((storedUntil.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
|
||
if (daysToExpiry < 7) {
|
||
metrics.expiringSoon.push({
|
||
blobId,
|
||
fileName: metadata.identifier,
|
||
daysToExpiry,
|
||
size: metadata.size
|
||
});
|
||
}
|
||
|
||
if (daysToExpiry < 0) {
|
||
metrics.expired.push({
|
||
blobId,
|
||
fileName: metadata.identifier,
|
||
daysExpired: Math.abs(daysToExpiry),
|
||
size: metadata.size
|
||
});
|
||
}
|
||
|
||
// 更新最新和最旧文件
|
||
if (!metrics.oldestFile || age > metrics.oldestFile.age) {
|
||
metrics.oldestFile = {
|
||
blobId,
|
||
fileName: metadata.identifier,
|
||
age,
|
||
uploadDate: new Date(metadata.uploadTime)
|
||
};
|
||
}
|
||
|
||
if (!metrics.newestFile || age < metrics.newestFile.age) {
|
||
metrics.newestFile = {
|
||
blobId,
|
||
fileName: metadata.identifier,
|
||
age,
|
||
uploadDate: new Date(metadata.uploadTime)
|
||
};
|
||
}
|
||
|
||
} catch (error) {
|
||
console.warn(`Failed to analyze blob ${blobId}:`, error.message);
|
||
}
|
||
}
|
||
|
||
// 存储指标历史
|
||
this.metrics.push(metrics);
|
||
if (this.metrics.length > 1000) {
|
||
this.metrics.shift(); // 保留最近1000条记录
|
||
}
|
||
|
||
// 检查告警条件
|
||
this.checkStorageAlerts(metrics);
|
||
|
||
return metrics;
|
||
}
|
||
|
||
private checkStorageAlerts(metrics: StorageMetrics): void {
|
||
// 存储空间告警
|
||
if (metrics.totalSize > 100 * 1024 * 1024 * 1024) { // 100GB
|
||
this.createAlert({
|
||
type: 'STORAGE_LIMIT',
|
||
severity: 'WARNING',
|
||
message: `存储使用量达到 ${this.formatBytes(metrics.totalSize)}`,
|
||
recommendation: '考虑清理过期文件或升级存储计划'
|
||
});
|
||
}
|
||
|
||
// 文件数量告警
|
||
if (metrics.totalFiles > 10000) {
|
||
this.createAlert({
|
||
type: 'FILE_COUNT_LIMIT',
|
||
severity: 'INFO',
|
||
message: `文件数量达到 ${metrics.totalFiles}`,
|
||
recommendation: '考虑实施文件归档策略'
|
||
});
|
||
}
|
||
|
||
// 即将过期告警
|
||
if (metrics.expiringSoon.length > 0) {
|
||
this.createAlert({
|
||
type: 'EXPIRING_FILES',
|
||
severity: 'WARNING',
|
||
message: `${metrics.expiringSoon.length} 个文件将在7天内过期`,
|
||
recommendation: '续期或备份重要文件'
|
||
});
|
||
}
|
||
}
|
||
|
||
getStorageTrends(timeRange: number = 7 * 24 * 60 * 60 * 1000): StorageTrends {
|
||
const cutoff = Date.now() - timeRange;
|
||
const relevantMetrics = this.metrics.filter(m => m.timestamp >= cutoff);
|
||
|
||
if (relevantMetrics.length < 2) {
|
||
return {
|
||
growthRate: 0,
|
||
costGrowthRate: 0,
|
||
fileGrowthRate: 0,
|
||
projectedUsage: null,
|
||
projectedCost: null
|
||
};
|
||
}
|
||
|
||
const oldest = relevantMetrics[0];
|
||
const newest = relevantMetrics[relevantMetrics.length - 1];
|
||
const timeDiff = newest.timestamp - oldest.timestamp;
|
||
|
||
return {
|
||
growthRate: this.calculateGrowthRate(oldest.totalSize, newest.totalSize, timeDiff),
|
||
costGrowthRate: this.calculateGrowthRate(oldest.totalCost, newest.totalCost, timeDiff),
|
||
fileGrowthRate: this.calculateGrowthRate(oldest.totalFiles, newest.totalFiles, timeDiff),
|
||
projectedUsage: this.projectUsage(newest.totalSize, this.calculateGrowthRate(oldest.totalSize, newest.totalSize, timeDiff)),
|
||
projectedCost: this.projectCost(newest.totalCost, this.calculateGrowthRate(oldest.totalCost, newest.totalCost, timeDiff))
|
||
};
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 成本分析
|
||
|
||
#### 成本监控和优化
|
||
```typescript
|
||
class CostAnalyzer {
|
||
private costHistory: CostRecord[] = [];
|
||
private pricingModel: PricingModel;
|
||
|
||
constructor() {
|
||
this.pricingModel = {
|
||
storagePerGBPerEpoch: 0.001,
|
||
writeFeePerMB: 0.0001,
|
||
readFeePerMB: 0.00001,
|
||
gasMultiplier: 1.0
|
||
};
|
||
}
|
||
|
||
async analyzeCosts(timeRange: number = 30 * 24 * 60 * 60 * 1000): Promise<CostAnalysis> {
|
||
const records = this.getRelevantCostRecords(timeRange);
|
||
const storageMetrics = await this.getStorageMetrics(timeRange);
|
||
|
||
return {
|
||
totalCost: this.calculateTotalCost(records),
|
||
storageCost: this.calculateStorageCost(storageMetrics),
|
||
transactionCost: this.calculateTransactionCost(records),
|
||
breakdown: this.getCostBreakdown(records),
|
||
optimization: this.getOptimizationSuggestions(storageMetrics, records),
|
||
forecast: this.forecastCosts(records, storageMetrics)
|
||
};
|
||
}
|
||
|
||
private calculateStorageCost(metrics: StorageMetrics[]): number {
|
||
return metrics.reduce((total, metric) => {
|
||
const storageEpochs = 30; // 假设30天的轮数
|
||
const sizeGB = metric.totalSize / (1024 * 1024 * 1024);
|
||
return total + (sizeGB * this.pricingModel.storagePerGBPerEpoch * storageEpochs);
|
||
}, 0);
|
||
}
|
||
|
||
private calculateTransactionCost(records: CostRecord[]): number {
|
||
return records
|
||
.filter(r => r.type === 'transaction')
|
||
.reduce((total, record) => total + record.amount, 0);
|
||
}
|
||
|
||
private getOptimizationSuggestions(metrics: StorageMetrics[], records: CostRecord[]): OptimizationSuggestion[] {
|
||
const suggestions: OptimizationSuggestion[] = [];
|
||
|
||
// 分析文件大小分布
|
||
const sizeDistribution = this.analyzeSizeDistribution(metrics);
|
||
if (sizeDistribution.smallFiles > sizeDistribution.largeFiles * 2) {
|
||
suggestions.push({
|
||
type: 'BUNDLE_SMALL_FILES',
|
||
description: '检测到大量小文件,建议使用 Quilt 打包存储',
|
||
potentialSavings: '20-30%',
|
||
difficulty: 'medium',
|
||
implementation: this.getBundleImplementation()
|
||
});
|
||
}
|
||
|
||
// 分析存储时长
|
||
const avgStorageTime = this.calculateAverageStorageTime(metrics);
|
||
if (avgStorageTime > 90) { // 超过90天
|
||
suggestions.push({
|
||
type: 'OPTIMIZE_STORAGE_DURATION',
|
||
description: `平均存储时长 ${avgStorageTime} 天,建议实施生命周期管理`,
|
||
potentialSavings: '40-60%',
|
||
difficulty: 'low',
|
||
implementation: this.getLifecycleImplementation()
|
||
});
|
||
}
|
||
|
||
// 分析访问模式
|
||
const accessPattern = this.analyzeAccessPattern(records);
|
||
if (accessPattern.readHeavy) {
|
||
suggestions.push({
|
||
type: 'IMPLEMENT_CACHING',
|
||
description: '读取频繁,建议实施缓存层',
|
||
potentialSavings: '50-70%',
|
||
difficulty: 'medium',
|
||
implementation: this.getCacheImplementation()
|
||
});
|
||
}
|
||
|
||
return suggestions;
|
||
}
|
||
|
||
private getBundleImplementation(): string {
|
||
return `
|
||
// 使用 Quilt 打包小文件
|
||
async function bundleSmallFiles(files: WalrusFile[]): Promise<string> {
|
||
const quilt = QuiltBuilder.create()
|
||
.addFiles(files)
|
||
.build();
|
||
|
||
const result = await client.walrus.writeFiles({
|
||
files: [quilt],
|
||
epochs: 30,
|
||
deletable: true,
|
||
signer: keypair
|
||
});
|
||
|
||
return result[0].blobId;
|
||
}
|
||
|
||
// 原本多个小文件:
|
||
// File 1: 10KB, File 2: 15KB, File 3: 8KB = 33KB 总计
|
||
// 打包后:单个 Quilt 包含所有文件,减少存储开销
|
||
`;
|
||
}
|
||
|
||
private getLifecycleImplementation(): string {
|
||
return `
|
||
// 自动生命周期管理
|
||
class StorageLifecycleManager {
|
||
async manageExpiredFiles() {
|
||
const expiringFiles = await this.getFilesExpiringWithin(7);
|
||
|
||
for (const file of expiringFiles) {
|
||
const accessFrequency = await this.getAccessFrequency(file.blobId);
|
||
|
||
if (accessFrequency === 'never') {
|
||
// 删除未访问的文件
|
||
await this.deleteFile(file.blobId);
|
||
} else if (accessFrequency === 'rare') {
|
||
// 降低存储时长
|
||
await this.reduceStorageEpochs(file.blobId, 10);
|
||
} else {
|
||
// 续期重要文件
|
||
await this.extendStorage(file.blobId, 30);
|
||
}
|
||
}
|
||
}
|
||
|
||
private async getAccessFrequency(blobId: string): Promise<'never' | 'rare' | 'frequent'> {
|
||
// 分析访问日志
|
||
const accessLogs = await this.getAccessLogs(blobId, 30); // 30天内
|
||
const accessCount = accessLogs.length;
|
||
|
||
if (accessCount === 0) return 'never';
|
||
if (accessCount < 5) return 'rare';
|
||
return 'frequent';
|
||
}
|
||
}
|
||
`;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. 性能监控
|
||
|
||
#### 实时性能指标
|
||
```typescript
|
||
class PerformanceMonitor {
|
||
private performanceMetrics: PerformanceMetric[] = [];
|
||
private slowQueries: SlowQuery[] = [];
|
||
private alerts: PerformanceAlert[] = [];
|
||
|
||
async recordPerformanceMetric(
|
||
operation: string,
|
||
duration: number,
|
||
success: boolean,
|
||
metadata: any = {}
|
||
): Promise<void> {
|
||
const metric: PerformanceMetric = {
|
||
timestamp: Date.now(),
|
||
operation,
|
||
duration,
|
||
success,
|
||
metadata
|
||
};
|
||
|
||
this.performanceMetrics.push(metric);
|
||
|
||
// 限制历史数据
|
||
if (this.performanceMetrics.length > 10000) {
|
||
this.performanceMetrics.shift();
|
||
}
|
||
|
||
// 检查性能告警
|
||
this.checkPerformanceAlerts(metric);
|
||
|
||
// 记录慢操作
|
||
if (duration > this.getSlowThreshold(operation)) {
|
||
this.slowQueries.push({
|
||
...metric,
|
||
threshold: this.getSlowThreshold(operation),
|
||
severity: this.getSeverityLevel(duration, this.getSlowThreshold(operation))
|
||
});
|
||
|
||
// 限制慢查询记录
|
||
if (this.slowQueries.length > 1000) {
|
||
this.slowQueries.shift();
|
||
}
|
||
}
|
||
}
|
||
|
||
getPerformanceAnalysis(timeRange: number = 24 * 60 * 60 * 1000): PerformanceAnalysis {
|
||
const metrics = this.getRelevantMetrics(timeRange);
|
||
|
||
return {
|
||
overview: this.getPerformanceOverview(metrics),
|
||
operations: this.analyzeOperations(metrics),
|
||
trends: this.analyzeTrends(metrics),
|
||
bottlenecks: this.identifyBottlenecks(metrics),
|
||
recommendations: this.getPerformanceRecommendations(metrics)
|
||
};
|
||
}
|
||
|
||
private analyzeOperations(metrics: PerformanceMetric[]): OperationAnalysis[] {
|
||
const operationGroups = this.groupBy(metrics, 'operation');
|
||
const analyses: OperationAnalysis[] = [];
|
||
|
||
for (const [operation, operationMetrics] of Object.entries(operationGroups)) {
|
||
const durations = operationMetrics.map(m => m.duration);
|
||
const successRate = operationMetrics.filter(m => m.success).length / operationMetrics.length;
|
||
|
||
analyses.push({
|
||
operation,
|
||
totalCalls: operationMetrics.length,
|
||
successRate,
|
||
avgDuration: durations.reduce((a, b) => a + b, 0) / durations.length,
|
||
minDuration: Math.min(...durations),
|
||
maxDuration: Math.max(...durations),
|
||
p95: this.percentile(durations, 0.95),
|
||
p99: this.percentile(durations, 0.99),
|
||
errorRate: 1 - successRate,
|
||
slowQueries: operationMetrics.filter(m => m.duration > this.getSlowThreshold(operation)).length
|
||
});
|
||
}
|
||
|
||
return analyses.sort((a, b) => b.avgDuration - a.avgDuration);
|
||
}
|
||
|
||
private identifyBottlenecks(metrics: PerformanceMetric[]): PerformanceBottleneck[] {
|
||
const bottlenecks: PerformanceBottleneck[] = [];
|
||
|
||
// 识别慢操作
|
||
const slowOperations = this.analyzeOperations(metrics)
|
||
.filter(op => op.avgDuration > this.getSlowThreshold(op.operation));
|
||
|
||
for (const operation of slowOperations) {
|
||
bottlenecks.push({
|
||
type: 'SLOW_OPERATION',
|
||
operation: operation.operation,
|
||
severity: this.getBottleneckSeverity(operation.avgDuration, this.getSlowThreshold(operation.operation)),
|
||
impact: 'medium',
|
||
description: `\${operation.operation} 平均耗时 \${operation.avgDuration}ms`,
|
||
suggestion: this.getOptimizationSuggestion(operation.operation)
|
||
});
|
||
}
|
||
|
||
// 识别错误率高的操作
|
||
const highErrorOps = this.analyzeOperations(metrics)
|
||
.filter(op => op.errorRate > 0.05); // 5% 错误率
|
||
|
||
for (const operation of highErrorOps) {
|
||
bottlenecks.push({
|
||
type: 'HIGH_ERROR_RATE',
|
||
operation: operation.operation,
|
||
severity: 'high',
|
||
impact: 'high',
|
||
description: `\${operation.operation} 错误率 \${(operation.errorRate * 100).toFixed(1)}%`,
|
||
suggestion: this.getErrorOptimizationSuggestion(operation.operation)
|
||
});
|
||
}
|
||
|
||
return bottlenecks;
|
||
}
|
||
|
||
private getPerformanceRecommendations(metrics: PerformanceMetric[]): PerformanceRecommendation[] {
|
||
const recommendations: PerformanceRecommendation[] = [];
|
||
|
||
// 分析上传性能
|
||
const uploadMetrics = metrics.filter(m => m.operation.startsWith('upload'));
|
||
if (uploadMetrics.length > 0) {
|
||
const avgUploadSize = this.getAverageUploadSize(uploadMetrics);
|
||
const avgUploadTime = uploadMetrics.reduce((sum, m) => sum + m.duration, 0) / uploadMetrics.length;
|
||
|
||
if (avgUploadSize > 10 * 1024 * 1024 && avgUploadTime > 10000) { // 10MB, 10s
|
||
recommendations.push({
|
||
type: 'UPLOAD_OPTIMIZATION',
|
||
priority: 'high',
|
||
title: '大文件上传优化',
|
||
description: '检测到大文件上传性能问题',
|
||
implementation: `
|
||
// 实施分块上传和断点续传
|
||
class ChunkedUploader {
|
||
async uploadLargeFile(file: File, chunkSize = 5 * 1024 * 1024): Promise<string> {
|
||
const chunks = Math.ceil(file.size / chunkSize);
|
||
const chunkIds: string[] = [];
|
||
|
||
for (let i = 0; i < chunks; i++) {
|
||
const start = i * chunkSize;
|
||
const end = Math.min(start + chunkSize, file.size);
|
||
const chunk = file.slice(start, end);
|
||
|
||
const result = await this.uploadChunk(chunk, i, chunks);
|
||
chunkIds.push(result.blobId);
|
||
|
||
// 更新进度
|
||
this.updateProgress((i + 1) / chunks);
|
||
}
|
||
|
||
// 创建文件清单
|
||
return await this.createManifest(chunkIds, file);
|
||
}
|
||
}
|
||
|
||
// 使用压缩减少传输量
|
||
const compressedFile = await this.compressFile(file);
|
||
const uploadResult = await client.walrus.writeFiles({
|
||
files: [compressedFile],
|
||
epochs: 10,
|
||
signer: keypair
|
||
});
|
||
`,
|
||
expectedImprovement: '50-70%'
|
||
});
|
||
}
|
||
}
|
||
|
||
// 分析批量操作性能
|
||
const batchMetrics = metrics.filter(m => m.operation.includes('batch'));
|
||
if (batchMetrics.length > 0) {
|
||
const concurrencyIssues = batchMetrics.filter(m => m.duration > 60000).length; // 超过1分钟
|
||
|
||
if (concurrencyIssues > batchMetrics.length * 0.3) { // 30%超时
|
||
recommendations.push({
|
||
type: 'BATCH_OPTIMIZATION',
|
||
priority: 'medium',
|
||
title: '批量操作并发优化',
|
||
description: '批量操作存在并发瓶颈',
|
||
implementation: `
|
||
// 优化并发控制
|
||
class OptimizedBatchProcessor {
|
||
private readonly MAX_CONCURRENT = 3;
|
||
private readonly RETRY_DELAY = 1000;
|
||
|
||
async processBatch<T>(items: T[], processor: (item: T) => Promise<any>): Promise<any[]> {
|
||
const results: any[] = [];
|
||
const chunks = this.chunkArray(items, this.MAX_CONCURRENT);
|
||
|
||
for (const chunk of chunks) {
|
||
const chunkPromises = chunk.map(async (item, index) => {
|
||
try {
|
||
return await this.withRetry(() => processor(item), 3);
|
||
} catch (error) {
|
||
console.error(\`Batch item failed: \${error.message}\`);
|
||
return null;
|
||
}
|
||
});
|
||
|
||
const chunkResults = await Promise.all(chunkPromises);
|
||
results.push(...chunkResults);
|
||
|
||
// 批次间延迟
|
||
if (chunks.indexOf(chunk) < chunks.length - 1) {
|
||
await this.delay(this.RETRY_DELAY);
|
||
}
|
||
}
|
||
|
||
return results;
|
||
}
|
||
}
|
||
`,
|
||
expectedImprovement: '30-50%'
|
||
});
|
||
}
|
||
}
|
||
|
||
return recommendations;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4. 错误监控
|
||
|
||
#### 错误统计和分析
|
||
```typescript
|
||
class ErrorMonitor {
|
||
private errorLog: ErrorRecord[] = [];
|
||
private errorPatterns: ErrorPattern[] = [];
|
||
|
||
recordError(error: Error, context: ErrorContext): void {
|
||
const errorRecord: ErrorRecord = {
|
||
timestamp: Date.now(),
|
||
message: error.message,
|
||
stack: error.stack,
|
||
type: this.classifyError(error),
|
||
severity: this.determineSeverity(error, context),
|
||
context,
|
||
resolved: false
|
||
};
|
||
|
||
this.errorLog.push(errorRecord);
|
||
|
||
// 分析错误模式
|
||
this.analyzeErrorPattern(errorRecord);
|
||
|
||
// 错误告警
|
||
this.checkErrorAlerts(errorRecord);
|
||
}
|
||
|
||
getErrorAnalysis(timeRange: number = 24 * 60 * 60 * 1000): ErrorAnalysis {
|
||
const recentErrors = this.getRecentErrors(timeRange);
|
||
|
||
return {
|
||
summary: this.getErrorSummary(recentErrors),
|
||
trends: this.getErrorTrends(recentErrors),
|
||
patterns: this.getErrorPatterns(recentErrors),
|
||
recommendations: this.getErrorRecommendations(recentErrors),
|
||
resolutionRate: this.calculateResolutionRate(recentErrors)
|
||
};
|
||
}
|
||
|
||
private analyzeErrorPattern(errorRecord: ErrorRecord): void {
|
||
const patternKey = this.getPatternKey(errorRecord);
|
||
let pattern = this.errorPatterns.find(p => p.key === patternKey);
|
||
|
||
if (!pattern) {
|
||
pattern = {
|
||
key: patternKey,
|
||
type: errorRecord.type,
|
||
count: 0,
|
||
firstOccurrence: errorRecord.timestamp,
|
||
lastOccurrence: errorRecord.timestamp,
|
||
contexts: [],
|
||
resolutions: []
|
||
};
|
||
this.errorPatterns.push(pattern);
|
||
}
|
||
|
||
pattern.count++;
|
||
pattern.lastOccurrence = errorRecord.timestamp;
|
||
|
||
// 记录上下文
|
||
const contextHash = this.hashContext(errorRecord.context);
|
||
if (!pattern.contexts.some(c => c.hash === contextHash)) {
|
||
pattern.contexts.push({
|
||
hash: contextHash,
|
||
context: errorRecord.context,
|
||
occurrences: 1
|
||
});
|
||
} else {
|
||
const existingContext = pattern.contexts.find(c => c.hash === contextHash);
|
||
if (existingContext) {
|
||
existingContext.occurrences++;
|
||
}
|
||
}
|
||
}
|
||
|
||
private getErrorRecommendations(errors: ErrorRecord[]): ErrorRecommendation[] {
|
||
const recommendations: ErrorRecommendation[] = [];
|
||
|
||
// 分析最常见的错误类型
|
||
const errorTypes = this.groupBy(errors, 'type');
|
||
const mostCommonType = Object.entries(errorTypes)
|
||
.sort(([, a], [, b]) => b.length - a.length)[0];
|
||
|
||
if (mostCommonType && mostCommonType[1].length > errors.length * 0.3) { // 30%以上
|
||
recommendations.push({
|
||
type: 'PREVENTION',
|
||
priority: 'high',
|
||
title: `高频率 \${mostCommonType[0]} 错误`,
|
||
description: `\${mostCommonType[1].length} 次错误中 \${mostCommonType[1].length} 次是 \${mostCommonType[0]} 错误`,
|
||
implementation: this.getPreventionImplementation(mostCommonType[0]),
|
||
expectedReduction: '60-80%'
|
||
});
|
||
}
|
||
|
||
// 分析网络相关错误
|
||
const networkErrors = errors.filter(e => e.type === 'network' || e.type === 'timeout');
|
||
if (networkErrors.length > errors.length * 0.2) { // 20%以上
|
||
recommendations.push({
|
||
type: 'NETWORK_OPTIMIZATION',
|
||
priority: 'medium',
|
||
title: '网络连接优化',
|
||
description: '检测到大量网络相关错误',
|
||
implementation: `
|
||
// 实施网络优化策略
|
||
class NetworkOptimizer {
|
||
private readonly circuitBreaker = new CircuitBreaker({
|
||
failureThreshold: 5,
|
||
recoveryTimeout: 60000,
|
||
monitoringPeriod: 30000
|
||
});
|
||
|
||
async robustRequest(url: string, options: RequestInit = {}): Promise<Response> {
|
||
return this.circuitBreaker.execute(async () => {
|
||
// 使用指数退避重试
|
||
return this.withRetry(() => fetch(url, {
|
||
...options,
|
||
timeout: 30000
|
||
}), 3);
|
||
});
|
||
}
|
||
|
||
private async withRetry<T>(
|
||
operation: () => Promise<T>,
|
||
maxRetries: number = 3
|
||
): Promise<T> {
|
||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||
try {
|
||
return await operation();
|
||
} catch (error) {
|
||
if (attempt === maxRetries || !this.isRetryableError(error)) {
|
||
throw error;
|
||
}
|
||
|
||
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
|
||
await this.delay(delay);
|
||
}
|
||
}
|
||
|
||
throw new Error('Max retries exceeded');
|
||
}
|
||
}
|
||
`,
|
||
expectedReduction: '70-90%'
|
||
});
|
||
}
|
||
|
||
return recommendations;
|
||
}
|
||
}
|
||
```
|
||
|
||
## 使用方法
|
||
|
||
### 存储使用监控
|
||
```typescript
|
||
skill: "walrus-monitor"
|
||
// monitor-type: usage
|
||
// time-range: 7d
|
||
// metrics: ["total-size", "file-count", "cost", "aging"]
|
||
```
|
||
|
||
### 成本分析
|
||
```typescript
|
||
skill: "walrus-monitor"
|
||
// monitor-type: cost
|
||
// time-range: 30d
|
||
// metrics: ["storage-cost", "transaction-cost", "optimization-suggestions"]
|
||
```
|
||
|
||
### 性能监控
|
||
```typescript
|
||
skill: "walrus-monitor"
|
||
// monitor-type: performance
|
||
// time-range: 24h
|
||
// metrics: ["upload-speed", "download-speed", "error-rate", "bottlenecks"]
|
||
```
|
||
|
||
### 错误分析
|
||
```typescript
|
||
skill: "walrus-monitor"
|
||
// monitor-type: errors
|
||
// time-range: 7d
|
||
// metrics: ["error-patterns", "resolution-rate", "prevention-suggestions"]
|
||
```
|
||
|
||
---
|
||
|
||
*更新时间:2025-11-11* |