在这里插入图片描述

目录

  1. 概述
  2. 性能监控基础
  3. 核心功能
  4. Kotlin 源代码
  5. JavaScript 编译代码
  6. ArkTS 调用代码
  7. 监控指标详解
  8. 实战应用

概述

在现代互联网应用中,API的性能直接影响用户体验和系统可靠性。API性能监控是确保系统稳定运行的关键手段,它帮助开发者实时了解API的响应时间、吞吐量、错误率等关键指标,及时发现和解决性能问题。本文档介绍如何在 Kotlin Multiplatform (KMP) 框架下,结合 OpenHarmony 鸿蒙操作系统,实现一个功能完整的API性能监控工具。

API性能监控工具是一个综合性的性能追踪平台,它不仅能够收集API调用的详细数据,还能够进行实时分析、生成性能报告、提供优化建议。通过KMP框架的跨端能力,这个工具可以在Android、iOS、Web和OpenHarmony等多个平台上运行,为开发者提供了一个强大的API性能分析和优化工具。

API性能监控的重要性

API性能监控在现代应用开发中的重要性日益凸显:

  1. 实时问题发现:通过实时监控,可以快速发现API性能下降或故障,及时采取措施。
  2. 用户体验优化:了解API的响应时间,可以优化用户体验,减少用户等待时间。
  3. 容量规划:通过监控吞吐量和并发数,可以进行合理的容量规划和资源分配。
  4. 故障排查:详细的监控数据可以帮助快速定位和解决问题。
  5. 性能基准:建立性能基准,持续监控和改进系统性能。

工具的核心价值

API性能监控工具提供以下价值:

  • 实时监控:实时收集和展示API的性能数据
  • 详细统计:提供响应时间、吞吐量、错误率等多维度统计
  • 性能告警:当性能指标超过阈值时自动告警
  • 趋势分析:分析性能数据的变化趋势,预测潜在问题
  • 对比分析:支持不同时间段、不同API的性能对比
  • 跨平台支持:一份代码可在多个平台运行,提高开发效率

性能监控基础

关键性能指标(KPI)

响应时间(Response Time):从发送请求到收到响应的时间。通常分为最小值、最大值、平均值、中位数等。响应时间是用户最直观感受到的性能指标。

吞吐量(Throughput):单位时间内处理的请求数,通常用请求/秒表示。吞吐量反映了系统的处理能力。

错误率(Error Rate):失败请求占总请求的比例。错误率是系统可靠性的重要指标。

并发数(Concurrency):同时处理的请求数。并发数反映了系统的并发处理能力。

可用性(Availability):系统正常运行的时间比例。可用性是系统稳定性的重要指标。

性能监控的层次

应用层监控:监控应用内部的API调用性能,包括网络请求、数据库查询等。

网络层监控:监控网络传输的性能,包括延迟、丢包率等。

系统层监控:监控系统资源的使用情况,包括CPU、内存、磁盘等。

业务层监控:监控业务相关的性能指标,如订单处理时间、支付成功率等。

监控数据的收集方式

主动监控:定期主动发送请求,监控API的可用性和性能。

被动监控:收集实际用户请求的性能数据。

合成监控:模拟真实用户的操作流程,监控端到端的性能。


核心功能

1. API调用追踪

系统需要能够追踪每个API调用的完整生命周期,包括请求发送、响应接收、数据处理等各个阶段。通过详细的追踪数据,可以准确定位性能瓶颈。

2. 性能数据收集

系统需要收集API调用的各种性能数据,包括响应时间、请求大小、响应大小、错误信息等。这些数据是后续分析的基础。

3. 实时分析

系统需要对收集的数据进行实时分析,计算各种统计指标,如平均响应时间、最大响应时间、错误率等。

4. 性能告警

当性能指标超过预设的阈值时,系统应该自动发出告警,提醒开发者注意。

5. 报告生成

系统需要能够生成详细的性能报告,包括性能统计、趋势分析、问题诊断等。

6. 性能优化建议

基于监控数据和分析结果,系统应该能够提供具体的性能优化建议。


Kotlin 源代码

// APIPerformanceMonitor.kt
import java.time.LocalDateTime
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicLong
import kotlin.math.*

data class APICall(
    val id: String,
    val apiName: String,
    val method: String,
    val url: String,
    val requestSize: Long,
    val responseSize: Long,
    val responseTime: Long,
    val statusCode: Int,
    val timestamp: String,
    val errorMessage: String = ""
)

data class PerformanceMetrics(
    val apiName: String,
    val totalCalls: Long,
    val successCalls: Long,
    val failedCalls: Long,
    val averageResponseTime: Double,
    val minResponseTime: Long,
    val maxResponseTime: Long,
    val medianResponseTime: Double,
    val p95ResponseTime: Double,
    val p99ResponseTime: Double,
    val errorRate: Double,
    val throughput: Double,
    val averageRequestSize: Double,
    val averageResponseSize: Double
)

data class PerformanceAlert(
    val id: String,
    val apiName: String,
    val alertType: String,
    val threshold: Double,
    val actualValue: Double,
    val severity: String,
    val timestamp: String,
    val message: String
)

class APIPerformanceMonitor {
    private val apiCalls = mutableListOf<APICall>()
    private val callIdCounter = AtomicLong(0)
    private val alerts = mutableListOf<PerformanceAlert>()
    private val alertIdCounter = AtomicLong(0)
    
    // 记录API调用
    fun recordAPICall(
        apiName: String,
        method: String,
        url: String,
        requestSize: Long,
        responseSize: Long,
        responseTime: Long,
        statusCode: Int,
        errorMessage: String = ""
    ): APICall {
        val id = "CALL${callIdCounter.incrementAndGet()}"
        val call = APICall(
            id = id,
            apiName = apiName,
            method = method,
            url = url,
            requestSize = requestSize,
            responseSize = responseSize,
            responseTime = responseTime,
            statusCode = statusCode,
            timestamp = LocalDateTime.now().toString(),
            errorMessage = errorMessage
        )
        
        apiCalls.add(call)
        
        // 检查性能告警
        checkPerformanceAlerts(apiName, responseTime, statusCode)
        
        return call
    }
    
    // 获取特定API的性能指标
    fun getPerformanceMetrics(apiName: String): PerformanceMetrics {
        val calls = apiCalls.filter { it.apiName == apiName }
        
        if (calls.isEmpty()) {
            return PerformanceMetrics(
                apiName = apiName,
                totalCalls = 0,
                successCalls = 0,
                failedCalls = 0,
                averageResponseTime = 0.0,
                minResponseTime = 0,
                maxResponseTime = 0,
                medianResponseTime = 0.0,
                p95ResponseTime = 0.0,
                p99ResponseTime = 0.0,
                errorRate = 0.0,
                throughput = 0.0,
                averageRequestSize = 0.0,
                averageResponseSize = 0.0
            )
        }
        
        val totalCalls = calls.size.toLong()
        val successCalls = calls.count { it.statusCode in 200..299 }.toLong()
        val failedCalls = totalCalls - successCalls
        
        val responseTimes = calls.map { it.responseTime }.sorted()
        val averageResponseTime = responseTimes.average()
        val minResponseTime = responseTimes.minOrNull() ?: 0L
        val maxResponseTime = responseTimes.maxOrNull() ?: 0L
        val medianResponseTime = calculatePercentile(responseTimes, 50.0)
        val p95ResponseTime = calculatePercentile(responseTimes, 95.0)
        val p99ResponseTime = calculatePercentile(responseTimes, 99.0)
        
        val errorRate = if (totalCalls > 0) (failedCalls.toDouble() / totalCalls) * 100 else 0.0
        val throughput = totalCalls.toDouble() / 60.0 // 假设监控周期为60秒
        
        val averageRequestSize = calls.map { it.requestSize }.average()
        val averageResponseSize = calls.map { it.responseSize }.average()
        
        return PerformanceMetrics(
            apiName = apiName,
            totalCalls = totalCalls,
            successCalls = successCalls,
            failedCalls = failedCalls,
            averageResponseTime = averageResponseTime,
            minResponseTime = minResponseTime,
            maxResponseTime = maxResponseTime,
            medianResponseTime = medianResponseTime,
            p95ResponseTime = p95ResponseTime,
            p99ResponseTime = p99ResponseTime,
            errorRate = errorRate,
            throughput = throughput,
            averageRequestSize = averageRequestSize,
            averageResponseSize = averageResponseSize
        )
    }
    
    // 获取所有API的性能指标
    fun getAllPerformanceMetrics(): List<PerformanceMetrics> {
        val apiNames = apiCalls.map { it.apiName }.distinct()
        return apiNames.map { getPerformanceMetrics(it) }
    }
    
    // 检查性能告警
    private fun checkPerformanceAlerts(apiName: String, responseTime: Long, statusCode: Int) {
        val metrics = getPerformanceMetrics(apiName)
        
        // 检查响应时间告警
        if (responseTime > 5000) { // 5秒阈值
            createAlert(
                apiName = apiName,
                alertType = "SLOW_RESPONSE",
                threshold = 5000.0,
                actualValue = responseTime.toDouble(),
                severity = if (responseTime > 10000) "CRITICAL" else "WARNING",
                message = "API响应时间过长: ${responseTime}ms"
            )
        }
        
        // 检查错误率告警
        if (metrics.errorRate > 5.0) { // 5%错误率阈值
            createAlert(
                apiName = apiName,
                alertType = "HIGH_ERROR_RATE",
                threshold = 5.0,
                actualValue = metrics.errorRate,
                severity = if (metrics.errorRate > 10.0) "CRITICAL" else "WARNING",
                message = "API错误率过高: ${String.format("%.2f", metrics.errorRate)}%"
            )
        }
    }
    
    // 创建告警
    private fun createAlert(
        apiName: String,
        alertType: String,
        threshold: Double,
        actualValue: Double,
        severity: String,
        message: String
    ) {
        val alert = PerformanceAlert(
            id = "ALERT${alertIdCounter.incrementAndGet()}",
            apiName = apiName,
            alertType = alertType,
            threshold = threshold,
            actualValue = actualValue,
            severity = severity,
            timestamp = LocalDateTime.now().toString(),
            message = message
        )
        
        alerts.add(alert)
    }
    
    // 获取告警列表
    fun getAlerts(severity: String = ""): List<PerformanceAlert> {
        return if (severity.isEmpty()) {
            alerts.toList()
        } else {
            alerts.filter { it.severity == severity }
        }
    }
    
    // 计算百分位数
    private fun calculatePercentile(sortedValues: List<Long>, percentile: Double): Double {
        if (sortedValues.isEmpty()) return 0.0
        
        val index = ((percentile / 100.0) * (sortedValues.size - 1)).toInt()
        return sortedValues[index].toDouble()
    }
    
    // 获取性能趋势
    fun getPerformanceTrend(apiName: String, intervalMinutes: Int = 5): Map<String, Any> {
        val calls = apiCalls.filter { it.apiName == apiName }
        val now = LocalDateTime.now()
        
        val trends = mutableMapOf<String, List<Double>>()
        val responseTimes = mutableListOf<Double>()
        val errorRates = mutableListOf<Double>()
        
        for (i in 0 until 12) {
            val intervalStart = now.minusMinutes((12 - i) * intervalMinutes.toLong())
            val intervalEnd = now.minusMinutes((11 - i) * intervalMinutes.toLong())
            
            val intervalCalls = calls.filter {
                val callTime = LocalDateTime.parse(it.timestamp)
                callTime.isAfter(intervalStart) && callTime.isBefore(intervalEnd)
            }
            
            if (intervalCalls.isNotEmpty()) {
                responseTimes.add(intervalCalls.map { it.responseTime }.average())
                val errorCount = intervalCalls.count { it.statusCode !in 200..299 }
                errorRates.add((errorCount.toDouble() / intervalCalls.size) * 100)
            }
        }
        
        trends["responseTimes"] = responseTimes
        trends["errorRates"] = errorRates
        
        return mapOf(
            "apiName" to apiName,
            "trends" to trends,
            "interval" to intervalMinutes
        )
    }
    
    // 生成性能报告
    fun generatePerformanceReport(): Map<String, Any> {
        val allMetrics = getAllPerformanceMetrics()
        
        return mapOf(
            "timestamp" to LocalDateTime.now().toString(),
            "totalAPIs" to allMetrics.size,
            "totalCalls" to allMetrics.sumOf { it.totalCalls },
            "totalErrors" to allMetrics.sumOf { it.failedCalls },
            "averageResponseTime" to allMetrics.map { it.averageResponseTime }.average(),
            "overallErrorRate" to (allMetrics.sumOf { it.failedCalls }.toDouble() / 
                    allMetrics.sumOf { it.totalCalls }) * 100,
            "metrics" to allMetrics,
            "alerts" to alerts.takeLast(10),
            "recommendations" to generateRecommendations(allMetrics)
        )
    }
    
    // 生成优化建议
    private fun generateRecommendations(metrics: List<PerformanceMetrics>): List<String> {
        val recommendations = mutableListOf<String>()
        
        for (metric in metrics) {
            if (metric.averageResponseTime > 2000) {
                recommendations.add("API '${metric.apiName}' 响应时间过长(${metric.averageResponseTime}ms),建议优化数据库查询或添加缓存")
            }
            
            if (metric.errorRate > 5.0) {
                recommendations.add("API '${metric.apiName}' 错误率较高(${metric.errorRate}%),建议检查错误日志并修复问题")
            }
            
            if (metric.p99ResponseTime > 10000) {
                recommendations.add("API '${metric.apiName}' 的P99响应时间过长(${metric.p99ResponseTime}ms),可能存在性能波动")
            }
        }
        
        return recommendations
    }
    
    // 清空数据
    fun clearData() {
        apiCalls.clear()
        alerts.clear()
    }
}

fun main() {
    val monitor = APIPerformanceMonitor()
    
    // 模拟API调用
    monitor.recordAPICall(
        apiName = "getUserInfo",
        method = "GET",
        url = "/api/users/123",
        requestSize = 100,
        responseSize = 500,
        responseTime = 150,
        statusCode = 200
    )
    
    monitor.recordAPICall(
        apiName = "getUserInfo",
        method = "GET",
        url = "/api/users/124",
        requestSize = 100,
        responseSize = 520,
        responseTime = 200,
        statusCode = 200
    )
    
    monitor.recordAPICall(
        apiName = "getUserInfo",
        method = "GET",
        url = "/api/users/125",
        requestSize = 100,
        responseSize = 480,
        responseTime = 6000,
        statusCode = 500,
        errorMessage = "Database connection timeout"
    )
    
    // 获取性能指标
    val metrics = monitor.getPerformanceMetrics("getUserInfo")
    println("API性能指标:")
    println("总调用数: ${metrics.totalCalls}")
    println("成功调用: ${metrics.successCalls}")
    println("失败调用: ${metrics.failedCalls}")
    println("平均响应时间: ${metrics.averageResponseTime}ms")
    println("错误率: ${String.format("%.2f", metrics.errorRate)}%")
    
    // 获取报告
    val report = monitor.generatePerformanceReport()
    println("\n性能报告: $report")
}

Kotlin代码说明:这个Kotlin实现提供了完整的API性能监控功能。APIPerformanceMonitor 类能够记录API调用、计算性能指标、检测性能问题、生成告警和报告。通过使用数据类、集合操作和并发工具,代码既简洁又高效。系统支持多维度的性能分析,从单个API的详细指标到整体系统的性能趋势,为开发者提供了全面的性能监控能力。


JavaScript 编译代码

// APIPerformanceMonitor.js
class APICall {
    constructor(id, apiName, method, url, requestSize, responseSize, responseTime, statusCode, timestamp, errorMessage = "") {
        this.id = id;
        this.apiName = apiName;
        this.method = method;
        this.url = url;
        this.requestSize = requestSize;
        this.responseSize = responseSize;
        this.responseTime = responseTime;
        this.statusCode = statusCode;
        this.timestamp = timestamp;
        this.errorMessage = errorMessage;
    }
}

class PerformanceMetrics {
    constructor(apiName, totalCalls, successCalls, failedCalls, averageResponseTime, 
                minResponseTime, maxResponseTime, medianResponseTime, p95ResponseTime, 
                p99ResponseTime, errorRate, throughput, averageRequestSize, averageResponseSize) {
        this.apiName = apiName;
        this.totalCalls = totalCalls;
        this.successCalls = successCalls;
        this.failedCalls = failedCalls;
        this.averageResponseTime = averageResponseTime;
        this.minResponseTime = minResponseTime;
        this.maxResponseTime = maxResponseTime;
        this.medianResponseTime = medianResponseTime;
        this.p95ResponseTime = p95ResponseTime;
        this.p99ResponseTime = p99ResponseTime;
        this.errorRate = errorRate;
        this.throughput = throughput;
        this.averageRequestSize = averageRequestSize;
        this.averageResponseSize = averageResponseSize;
    }
}

class PerformanceAlert {
    constructor(id, apiName, alertType, threshold, actualValue, severity, timestamp, message) {
        this.id = id;
        this.apiName = apiName;
        this.alertType = alertType;
        this.threshold = threshold;
        this.actualValue = actualValue;
        this.severity = severity;
        this.timestamp = timestamp;
        this.message = message;
    }
}

class APIPerformanceMonitor {
    constructor() {
        this.apiCalls = [];
        this.callIdCounter = 0;
        this.alerts = [];
        this.alertIdCounter = 0;
    }
    
    recordAPICall(apiName, method, url, requestSize, responseSize, responseTime, statusCode, errorMessage = "") {
        const id = `CALL${++this.callIdCounter}`;
        const call = new APICall(
            id,
            apiName,
            method,
            url,
            requestSize,
            responseSize,
            responseTime,
            statusCode,
            new Date().toISOString(),
            errorMessage
        );
        
        this.apiCalls.push(call);
        this.checkPerformanceAlerts(apiName, responseTime, statusCode);
        
        return call;
    }
    
    getPerformanceMetrics(apiName) {
        const calls = this.apiCalls.filter(c => c.apiName === apiName);
        
        if (calls.length === 0) {
            return new PerformanceMetrics(apiName, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
        }
        
        const totalCalls = calls.length;
        const successCalls = calls.filter(c => c.statusCode >= 200 && c.statusCode < 300).length;
        const failedCalls = totalCalls - successCalls;
        
        const responseTimes = calls.map(c => c.responseTime).sort((a, b) => a - b);
        const averageResponseTime = responseTimes.reduce((a, b) => a + b, 0) / responseTimes.length;
        const minResponseTime = Math.min(...responseTimes);
        const maxResponseTime = Math.max(...responseTimes);
        const medianResponseTime = this.calculatePercentile(responseTimes, 50);
        const p95ResponseTime = this.calculatePercentile(responseTimes, 95);
        const p99ResponseTime = this.calculatePercentile(responseTimes, 99);
        
        const errorRate = (failedCalls / totalCalls) * 100;
        const throughput = totalCalls / 60;
        
        const averageRequestSize = calls.reduce((sum, c) => sum + c.requestSize, 0) / calls.length;
        const averageResponseSize = calls.reduce((sum, c) => sum + c.responseSize, 0) / calls.length;
        
        return new PerformanceMetrics(
            apiName,
            totalCalls,
            successCalls,
            failedCalls,
            averageResponseTime,
            minResponseTime,
            maxResponseTime,
            medianResponseTime,
            p95ResponseTime,
            p99ResponseTime,
            errorRate,
            throughput,
            averageRequestSize,
            averageResponseSize
        );
    }
    
    getAllPerformanceMetrics() {
        const apiNames = [...new Set(this.apiCalls.map(c => c.apiName))];
        return apiNames.map(name => this.getPerformanceMetrics(name));
    }
    
    checkPerformanceAlerts(apiName, responseTime, statusCode) {
        const metrics = this.getPerformanceMetrics(apiName);
        
        if (responseTime > 5000) {
            this.createAlert(
                apiName,
                "SLOW_RESPONSE",
                5000,
                responseTime,
                responseTime > 10000 ? "CRITICAL" : "WARNING",
                `API响应时间过长: ${responseTime}ms`
            );
        }
        
        if (metrics.errorRate > 5.0) {
            this.createAlert(
                apiName,
                "HIGH_ERROR_RATE",
                5.0,
                metrics.errorRate,
                metrics.errorRate > 10.0 ? "CRITICAL" : "WARNING",
                `API错误率过高: ${metrics.errorRate.toFixed(2)}%`
            );
        }
    }
    
    createAlert(apiName, alertType, threshold, actualValue, severity, message) {
        const alert = new PerformanceAlert(
            `ALERT${++this.alertIdCounter}`,
            apiName,
            alertType,
            threshold,
            actualValue,
            severity,
            new Date().toISOString(),
            message
        );
        
        this.alerts.push(alert);
    }
    
    getAlerts(severity = "") {
        return severity ? this.alerts.filter(a => a.severity === severity) : this.alerts;
    }
    
    calculatePercentile(sortedValues, percentile) {
        if (sortedValues.length === 0) return 0;
        const index = Math.floor((percentile / 100) * (sortedValues.length - 1));
        return sortedValues[index];
    }
    
    getPerformanceTrend(apiName, intervalMinutes = 5) {
        const calls = this.apiCalls.filter(c => c.apiName === apiName);
        const now = new Date();
        
        const responseTimes = [];
        const errorRates = [];
        
        for (let i = 0; i < 12; i++) {
            const intervalStart = new Date(now.getTime() - (12 - i) * intervalMinutes * 60000);
            const intervalEnd = new Date(now.getTime() - (11 - i) * intervalMinutes * 60000);
            
            const intervalCalls = calls.filter(c => {
                const callTime = new Date(c.timestamp);
                return callTime > intervalStart && callTime < intervalEnd;
            });
            
            if (intervalCalls.length > 0) {
                const avgTime = intervalCalls.reduce((sum, c) => sum + c.responseTime, 0) / intervalCalls.length;
                responseTimes.push(avgTime);
                
                const errorCount = intervalCalls.filter(c => c.statusCode < 200 || c.statusCode >= 300).length;
                errorRates.push((errorCount / intervalCalls.length) * 100);
            }
        }
        
        return {
            apiName: apiName,
            trends: {
                responseTimes: responseTimes,
                errorRates: errorRates
            },
            interval: intervalMinutes
        };
    }
    
    generatePerformanceReport() {
        const allMetrics = this.getAllPerformanceMetrics();
        const totalCalls = allMetrics.reduce((sum, m) => sum + m.totalCalls, 0);
        const totalErrors = allMetrics.reduce((sum, m) => sum + m.failedCalls, 0);
        
        return {
            timestamp: new Date().toISOString(),
            totalAPIs: allMetrics.length,
            totalCalls: totalCalls,
            totalErrors: totalErrors,
            averageResponseTime: allMetrics.reduce((sum, m) => sum + m.averageResponseTime, 0) / allMetrics.length,
            overallErrorRate: (totalErrors / totalCalls) * 100,
            metrics: allMetrics,
            alerts: this.alerts.slice(-10),
            recommendations: this.generateRecommendations(allMetrics)
        };
    }
    
    generateRecommendations(metrics) {
        const recommendations = [];
        
        for (const metric of metrics) {
            if (metric.averageResponseTime > 2000) {
                recommendations.push(`API '${metric.apiName}' 响应时间过长(${metric.averageResponseTime}ms),建议优化数据库查询或添加缓存`);
            }
            
            if (metric.errorRate > 5.0) {
                recommendations.push(`API '${metric.apiName}' 错误率较高(${metric.errorRate}%),建议检查错误日志并修复问题`);
            }
            
            if (metric.p99ResponseTime > 10000) {
                recommendations.push(`API '${metric.apiName}' 的P99响应时间过长(${metric.p99ResponseTime}ms),可能存在性能波动`);
            }
        }
        
        return recommendations;
    }
    
    clearData() {
        this.apiCalls = [];
        this.alerts = [];
    }
}

// 使用示例
const monitor = new APIPerformanceMonitor();

monitor.recordAPICall("getUserInfo", "GET", "/api/users/123", 100, 500, 150, 200);
monitor.recordAPICall("getUserInfo", "GET", "/api/users/124", 100, 520, 200, 200);
monitor.recordAPICall("getUserInfo", "GET", "/api/users/125", 100, 480, 6000, 500, "Database connection timeout");

const metrics = monitor.getPerformanceMetrics("getUserInfo");
console.log("API性能指标:");
console.log("总调用数:", metrics.totalCalls);
console.log("成功调用:", metrics.successCalls);
console.log("失败调用:", metrics.failedCalls);
console.log("平均响应时间:", metrics.averageResponseTime, "ms");
console.log("错误率:", metrics.errorRate.toFixed(2), "%");

const report = monitor.generatePerformanceReport();
console.log("\n性能报告:", report);

JavaScript代码说明:JavaScript版本是Kotlin代码的直接转译。我们使用ES6的class语法定义各个类,使用数组方法进行数据处理。整体逻辑和算法与Kotlin版本保持一致,确保跨平台的一致性。JavaScript的灵活性使得代码更加简洁,同时保持了清晰的结构和完整的功能。


ArkTS 调用代码

// APIMonitorPage.ets
import { APIPerformanceMonitor } from './APIPerformanceMonitor';

@Entry
@Component
struct APIMonitorPage {
    @State apiName: string = '';
    @State method: string = 'GET';
    @State url: string = '';
    @State requestSize: number = 100;
    @State responseSize: number = 500;
    @State responseTime: number = 150;
    @State statusCode: number = 200;
    @State selectedTab: number = 0;
    @State metrics: any = null;
    @State allMetrics: Array<any> = [];
    @State alerts: Array<any> = [];
    @State report: any = null;
    @State isLoading: boolean = false;
    @State errorMessage: string = '';
    @State trend: any = null;
    
    private monitor: APIPerformanceMonitor = new APIPerformanceMonitor();
    
    private methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'];
    
    recordAPICall() {
        if (!this.apiName.trim() || !this.url.trim()) {
            this.errorMessage = '请输入API名称和URL';
            return;
        }
        
        this.isLoading = true;
        this.errorMessage = '';
        
        try {
            this.monitor.recordAPICall(
                this.apiName,
                this.method,
                this.url,
                this.requestSize,
                this.responseSize,
                this.responseTime,
                this.statusCode
            );
            
            this.metrics = this.monitor.getPerformanceMetrics(this.apiName);
            this.allMetrics = this.monitor.getAllPerformanceMetrics();
            this.alerts = this.monitor.getAlerts();
            
            AlertDialog.show({
                message: 'API调用已记录'
            });
        } catch (error) {
            this.errorMessage = '记录失败: ' + error.message;
        } finally {
            this.isLoading = false;
        }
    }
    
    generateReport() {
        this.isLoading = true;
        
        try {
            this.report = this.monitor.generatePerformanceReport();
        } catch (error) {
            this.errorMessage = '生成报告失败: ' + error.message;
        } finally {
            this.isLoading = false;
        }
    }
    
    getTrendData() {
        if (!this.apiName.trim()) {
            this.errorMessage = '请先输入API名称';
            return;
        }
        
        try {
            this.trend = this.monitor.getPerformanceTrend(this.apiName, 5);
        } catch (error) {
            this.errorMessage = '获取趋势数据失败: ' + error.message;
        }
    }
    
    getStatusColor(statusCode: number): string {
        if (statusCode >= 200 && statusCode < 300) return '#4CAF50';
        if (statusCode >= 300 && statusCode < 400) return '#2196F3';
        if (statusCode >= 400 && statusCode < 500) return '#FF9800';
        return '#F44336';
    }
    
    getSeverityColor(severity: string): string {
        switch (severity) {
            case 'CRITICAL': return '#F44336';
            case 'WARNING': return '#FF9800';
            case 'INFO': return '#2196F3';
            default: return '#999999';
        }
    }
    
    build() {
        Column() {
            // 顶部标题
            Text('API性能监控工具')
                .fontSize(24)
                .fontWeight(FontWeight.Bold)
                .margin({ top: 20, bottom: 20 })
            
            // 标签页
            Tabs({ barPosition: BarPosition.Start }) {
                TabContent() {
                    Column() {
                        Text('记录API调用')
                            .fontSize(14)
                            .fontWeight(FontWeight.Bold)
                            .margin({ bottom: 15 })
                        
                        Text('API名称:')
                            .fontSize(12)
                            .margin({ bottom: 5 })
                        TextInput({ placeholder: '例如: getUserInfo' })
                            .value(this.apiName)
                            .onChange((value: string) => {
                                this.apiName = value;
                            })
                            .height(40)
                            .padding(10)
                            .border({ width: 1, color: '#cccccc' })
                            .margin({ bottom: 15 })
                        
                        Row() {
                            Column() {
                                Text('请求方法:')
                                    .fontSize(12)
                                    .margin({ bottom: 5 })
                                Select(this.methods.map(m => ({ value: m })))
                                    .value(this.method)
                                    .onSelect((index: number, value?: string) => {
                                        this.method = value || 'GET';
                                    })
                            }
                            .flex(1)
                            
                            Column() {
                                Text('状态码:')
                                    .fontSize(12)
                                    .margin({ bottom: 5 })
                                TextInput({ placeholder: '200' })
                                    .type(InputType.Number)
                                    .value(this.statusCode.toString())
                                    .onChange((value: string) => {
                                        this.statusCode = parseInt(value) || 200;
                                    })
                                    .height(40)
                                    .padding(10)
                                    .border({ width: 1, color: '#cccccc' })
                            }
                            .flex(1)
                            .margin({ left: 10 })
                        }
                        .margin({ bottom: 15 })
                        
                        Text('URL:')
                            .fontSize(12)
                            .margin({ bottom: 5 })
                        TextInput({ placeholder: '/api/users/123' })
                            .value(this.url)
                            .onChange((value: string) => {
                                this.url = value;
                            })
                            .height(40)
                            .padding(10)
                            .border({ width: 1, color: '#cccccc' })
                            .margin({ bottom: 15 })
                        
                        Row() {
                            Column() {
                                Text('请求大小(B):')
                                    .fontSize(12)
                                    .margin({ bottom: 5 })
                                TextInput({ placeholder: '100' })
                                    .type(InputType.Number)
                                    .value(this.requestSize.toString())
                                    .onChange((value: string) => {
                                        this.requestSize = parseInt(value) || 100;
                                    })
                                    .height(40)
                                    .padding(10)
                                    .border({ width: 1, color: '#cccccc' })
                            }
                            .flex(1)
                            
                            Column() {
                                Text('响应大小(B):')
                                    .fontSize(12)
                                    .margin({ bottom: 5 })
                                TextInput({ placeholder: '500' })
                                    .type(InputType.Number)
                                    .value(this.responseSize.toString())
                                    .onChange((value: string) => {
                                        this.responseSize = parseInt(value) || 500;
                                    })
                                    .height(40)
                                    .padding(10)
                                    .border({ width: 1, color: '#cccccc' })
                            }
                            .flex(1)
                            .margin({ left: 10 })
                        }
                        .margin({ bottom: 15 })
                        
                        Text('响应时间(ms):')
                            .fontSize(12)
                            .margin({ bottom: 5 })
                        Slider({ value: this.responseTime, min: 10, max: 10000, step: 10 })
                            .onChange((value: number) => {
                                this.responseTime = value;
                            })
                            .margin({ bottom: 10 })
                        Text(`${this.responseTime}ms`)
                            .fontSize(12)
                            .fontColor('#2196F3')
                            .margin({ bottom: 15 })
                        
                        Button('记录调用')
                            .width('100%')
                            .height(40)
                            .margin({ bottom: 15 })
                            .onClick(() => {
                                this.recordAPICall();
                            })
                            .enabled(!this.isLoading)
                        
                        if (this.errorMessage) {
                            Text(this.errorMessage)
                                .fontSize(12)
                                .fontColor('#F44336')
                                .margin({ bottom: 15 })
                        }
                    }
                    .padding(15)
                }
                .tabBar('📝 记录调用')
                
                TabContent() {
                    Column() {
                        if (this.metrics) {
                            Text('性能指标')
                                .fontSize(16)
                                .fontWeight(FontWeight.Bold)
                                .margin({ bottom: 15 })
                            
                            Row() {
                                Column() {
                                    Text('总调用数')
                                        .fontSize(11)
                                        .fontColor('#999999')
                                    Text(this.metrics.totalCalls.toString())
                                        .fontSize(18)
                                        .fontWeight(FontWeight.Bold)
                                        .fontColor('#2196F3')
                                        .margin({ top: 5 })
                                }
                                .flex(1)
                                .alignItems(HorizontalAlign.Center)
                                .padding(10)
                                .backgroundColor('#F5F5F5')
                                .borderRadius(5)
                                
                                Column() {
                                    Text('成功调用')
                                        .fontSize(11)
                                        .fontColor('#999999')
                                    Text(this.metrics.successCalls.toString())
                                        .fontSize(18)
                                        .fontWeight(FontWeight.Bold)
                                        .fontColor('#4CAF50')
                                        .margin({ top: 5 })
                                }
                                .flex(1)
                                .alignItems(HorizontalAlign.Center)
                                .padding(10)
                                .backgroundColor('#F5F5F5')
                                .borderRadius(5)
                                .margin({ left: 10 })
                                
                                Column() {
                                    Text('失败调用')
                                        .fontSize(11)
                                        .fontColor('#999999')
                                    Text(this.metrics.failedCalls.toString())
                                        .fontSize(18)
                                        .fontWeight(FontWeight.Bold)
                                        .fontColor('#F44336')
                                        .margin({ top: 5 })
                                }
                                .flex(1)
                                .alignItems(HorizontalAlign.Center)
                                .padding(10)
                                .backgroundColor('#F5F5F5')
                                .borderRadius(5)
                                .margin({ left: 10 })
                            }
                            .margin({ bottom: 15 })
                            
                            Column() {
                                Row() {
                                    Text('平均响应时间:')
                                        .fontSize(12)
                                    Text(`${this.metrics.averageResponseTime.toFixed(2)}ms`)
                                        .fontSize(12)
                                        .fontWeight(FontWeight.Bold)
                                        .fontColor('#2196F3')
                                }
                                .margin({ bottom: 10 })
                                
                                Row() {
                                    Text('最小响应时间:')
                                        .fontSize(12)
                                    Text(`${this.metrics.minResponseTime}ms`)
                                        .fontSize(12)
                                        .fontWeight(FontWeight.Bold)
                                }
                                .margin({ bottom: 10 })
                                
                                Row() {
                                    Text('最大响应时间:')
                                        .fontSize(12)
                                    Text(`${this.metrics.maxResponseTime}ms`)
                                        .fontSize(12)
                                        .fontWeight(FontWeight.Bold)
                                }
                                .margin({ bottom: 10 })
                                
                                Row() {
                                    Text('P95响应时间:')
                                        .fontSize(12)
                                    Text(`${this.metrics.p95ResponseTime.toFixed(2)}ms`)
                                        .fontSize(12)
                                        .fontWeight(FontWeight.Bold)
                                }
                                .margin({ bottom: 10 })
                                
                                Row() {
                                    Text('P99响应时间:')
                                        .fontSize(12)
                                    Text(`${this.metrics.p99ResponseTime.toFixed(2)}ms`)
                                        .fontSize(12)
                                        .fontWeight(FontWeight.Bold)
                                }
                                .margin({ bottom: 10 })
                                
                                Row() {
                                    Text('错误率:')
                                        .fontSize(12)
                                    Text(`${this.metrics.errorRate.toFixed(2)}%`)
                                        .fontSize(12)
                                        .fontWeight(FontWeight.Bold)
                                        .fontColor(this.metrics.errorRate > 5 ? '#F44336' : '#4CAF50')
                                }
                            }
                            .padding(10)
                            .backgroundColor('#F5F5F5')
                            .borderRadius(5)
                        } else {
                            Text('请先记录API调用')
                                .fontSize(12)
                                .fontColor('#999999')
                        }
                    }
                    .padding(15)
                }
                .tabBar('📊 性能指标')
                
                TabContent() {
                    Column() {
                        if (this.alerts.length > 0) {
                            Text('性能告警')
                                .fontSize(16)
                                .fontWeight(FontWeight.Bold)
                                .margin({ bottom: 15 })
                            
                            List() {
                                ForEach(this.alerts, (alert: any) => {
                                    ListItem() {
                                        Column() {
                                            Row() {
                                                Text(alert.alertType)
                                                    .fontSize(12)
                                                    .fontWeight(FontWeight.Bold)
                                                    .flex(1)
                                                Text(alert.severity)
                                                    .fontSize(11)
                                                    .fontColor('#FFFFFF')
                                                    .fontWeight(FontWeight.Bold)
                                                    .padding({ left: 8, right: 8, top: 4, bottom: 4 })
                                                    .backgroundColor(this.getSeverityColor(alert.severity))
                                                    .borderRadius(3)
                                            }
                                            .margin({ bottom: 8 })
                                            
                                            Text(alert.message)
                                                .fontSize(12)
                                                .fontColor('#666666')
                                                .margin({ bottom: 8 })
                                            
                                            Text(alert.timestamp)
                                                .fontSize(10)
                                                .fontColor('#999999')
                                        }
                                        .padding(10)
                                        .border({ width: 1, color: '#eeeeee' })
                                        .borderRadius(5)
                                    }
                                }, (alert: any) => alert.id)
                            }
                        } else {
                            Text('暂无告警')
                                .fontSize(12)
                                .fontColor('#999999')
                        }
                    }
                    .padding(15)
                }
                .tabBar('⚠️ 告警')
                
                TabContent() {
                    Column() {
                        Button('生成报告')
                            .width('100%')
                            .height(40)
                            .margin({ bottom: 15 })
                            .onClick(() => {
                                this.generateReport();
                            })
                        
                        if (this.report) {
                            Text('性能报告')
                                .fontSize(16)
                                .fontWeight(FontWeight.Bold)
                                .margin({ bottom: 15 })
                            
                            Column() {
                                Row() {
                                    Text('总API数:')
                                        .fontSize(12)
                                    Text(this.report.totalAPIs.toString())
                                        .fontSize(12)
                                        .fontWeight(FontWeight.Bold)
                                        .fontColor('#2196F3')
                                }
                                .margin({ bottom: 10 })
                                
                                Row() {
                                    Text('总调用数:')
                                        .fontSize(12)
                                    Text(this.report.totalCalls.toString())
                                        .fontSize(12)
                                        .fontWeight(FontWeight.Bold)
                                }
                                .margin({ bottom: 10 })
                                
                                Row() {
                                    Text('总错误数:')
                                        .fontSize(12)
                                    Text(this.report.totalErrors.toString())
                                        .fontSize(12)
                                        .fontWeight(FontWeight.Bold)
                                        .fontColor('#F44336')
                                }
                                .margin({ bottom: 10 })
                                
                                Row() {
                                    Text('平均响应时间:')
                                        .fontSize(12)
                                    Text(`${this.report.averageResponseTime.toFixed(2)}ms`)
                                        .fontSize(12)
                                        .fontWeight(FontWeight.Bold)
                                }
                                .margin({ bottom: 10 })
                                
                                Row() {
                                    Text('总体错误率:')
                                        .fontSize(12)
                                    Text(`${this.report.overallErrorRate.toFixed(2)}%`)
                                        .fontSize(12)
                                        .fontWeight(FontWeight.Bold)
                                        .fontColor(this.report.overallErrorRate > 5 ? '#F44336' : '#4CAF50')
                                }
                            }
                            .padding(10)
                            .backgroundColor('#F5F5F5')
                            .borderRadius(5)
                            .margin({ bottom: 15 })
                            
                            if (this.report.recommendations && this.report.recommendations.length > 0) {
                                Text('优化建议:')
                                    .fontSize(14)
                                    .fontWeight(FontWeight.Bold)
                                    .margin({ bottom: 10 })
                                
                                Column() {
                                    ForEach(this.report.recommendations, (rec: string, index: number) => {
                                        Row() {
                                            Text('💡')
                                                .fontSize(14)
                                                .margin({ right: 10 })
                                            Text(rec)
                                                .fontSize(11)
                                                .flex(1)
                                        }
                                        .padding(10)
                                        .margin({ bottom: 8 })
                                        .backgroundColor('#E8F5E9')
                                        .borderRadius(5)
                                    }, (rec: string, index: number) => index.toString())
                                }
                            }
                        }
                    }
                    .padding(15)
                }
                .tabBar('📈 报告')
            }
            .width('100%')
            .flex(1)
        }
        .padding(10)
        .width('100%')
        .height('100%')
    }
}

ArkTS代码说明:这个ArkTS实现展示了如何在OpenHarmony应用中集成API性能监控工具。通过使用标签页组件,用户可以在记录调用、查看性能指标、查看告警和生成报告之间切换。UI设计直观,提供了良好的用户体验。每个标签页都有不同的功能,用户可以全面地了解API的性能特性和问题。


监控指标详解

响应时间指标

平均响应时间:所有请求的平均响应时间,反映API的整体性能。

最小/最大响应时间:响应时间的极值,帮助了解性能的波动范围。

中位数响应时间:50%的请求在这个时间内完成,比平均值更能反映典型情况。

P95/P99响应时间:95%/99%的请求在这个时间内完成,反映性能的尾部情况。

可靠性指标

错误率:失败请求的比例,是系统可靠性的重要指标。

成功率:成功请求的比例,通常应该在99%以上。

吞吐量:单位时间内处理的请求数,反映系统的处理能力。

资源指标

平均请求大小:平均每个请求的数据量,影响网络带宽消耗。

平均响应大小:平均每个响应的数据量,影响网络带宽和客户端处理。


实战应用

应用场景1:电商平台API监控

在电商平台中,订单API、支付API等关键API的性能直接影响用户体验。通过API性能监控,可以实时发现性能问题,如支付API响应时间过长,可能导致用户放弃购买。通过监控数据,可以及时优化数据库查询、添加缓存等。

应用场景2:社交媒体API监控

在社交媒体应用中,用户信息API、消息API等高频调用的API需要特别关注。通过监控可以发现高峰期的性能下降,及时进行扩容或优化。

应用场景3:金融系统API监控

在金融系统中,交易API、账户查询API等关键API的可靠性至关重要。通过监控可以确保这些API的高可用性,及时发现和解决问题。

应用场景4:IoT系统API监控

在IoT系统中,大量设备同时调用API,需要监控API的吞吐量和并发处理能力。通过监控可以发现系统的瓶颈,进行相应的优化。


总结

API性能监控工具是现代应用开发中的重要工具。通过KMP框架和OpenHarmony操作系统的结合,我们可以实现一个功能完整、高效可靠的API性能监控工具。

这个工具不仅能够实时收集和分析API的性能数据,还能够自动检测性能问题、生成告警和报告、提供优化建议。通过本文介绍的Kotlin实现、JavaScript编译和ArkTS调用,开发者可以快速构建自己的API性能监控系统。

在实际应用中,API性能监控的价值远不止于此。从性能优化到故障排查,从容量规划到用户体验改进,API性能监控都发挥着重要的作用。通过持续监控和优化,可以构建更加高效和可靠的系统。

掌握好API性能监控的方法和工具,对于提升系统性能和用户体验都有重要的帮助。通过这个工具的学习和使用,希望能够帮助开发者更好地理解和优化自己的API,构建更加高效和可靠的系统。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐