Files
gh-icehugh-web3-skills-plug…/skills/walrus-monitor.md
2025-11-29 18:47:53 +08:00

757 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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*