在这里插入图片描述

项目概述

日志解析与聚合是现代应用开发中的关键需求。无论是在系统监控、性能分析、错误追踪还是审计日志中,都需要进行各种日志处理操作。然而,不同的编程语言和平台对日志处理的实现方式各不相同,这导致开发者需要在不同平台上重复编写类似的逻辑。

本文介绍一个基于 Kotlin Multiplatform (KMP) 和 OpenHarmony 平台的日志解析与聚合高级工具库。这个工具库提供了一套完整的日志处理能力,包括日志解析、日志过滤、日志聚合、日志统计等功能。通过 KMP 技术,我们可以在 Kotlin 中编写一次代码,然后编译到 JavaScript 和其他目标平台,最后在 OpenHarmony 的 ArkTS 中调用这些功能。

技术架构

多平台支持

  • Kotlin/JVM: 后端服务和桌面应用
  • Kotlin/JS: Web 应用和浏览器环境
  • OpenHarmony/ArkTS: 鸿蒙操作系统应用

核心功能模块

  1. 日志解析: 解析不同格式的日志
  2. 日志过滤: 按条件过滤日志
  3. 日志聚合: 聚合多个日志源
  4. 日志统计: 统计日志信息
  5. 日志搜索: 搜索特定日志
  6. 日志分类: 对日志进行分类
  7. 性能分析: 分析日志性能指标
  8. 错误追踪: 追踪错误日志
    在这里插入图片描述

Kotlin 实现

核心日志处理类

// 文件: src/commonMain/kotlin/LogProcessor.kt

/**
 * 日志处理工具类
 * 提供日志解析、聚合、统计等功能
 */
class LogProcessor {
    
    data class LogEntry(
        val timestamp: String,
        val level: String,
        val message: String,
        val source: String = ""
    )
    
    /**
     * 解析日志行
     * @param logLine 日志行
     * @return 日志条目
     */
    fun parseLogLine(logLine: String): LogEntry? {
        val pattern = "\\[(.*?)\\]\\s+\\[(.*?)\\]\\s+(.*)".toRegex()
        val match = pattern.find(logLine)
        
        return if (match != null) {
            LogEntry(
                timestamp = match.groupValues[1],
                level = match.groupValues[2],
                message = match.groupValues[3]
            )
        } else {
            null
        }
    }
    
    /**
     * 解析多行日志
     * @param logs 日志字符串
     * @return 日志条目列表
     */
    fun parseLogs(logs: String): List<LogEntry> {
        return logs.split("\n")
            .mapNotNull { parseLogLine(it) }
    }
    
    /**
     * 按日志级别过滤
     * @param logs 日志列表
     * @param level 日志级别
     * @return 过滤后的日志列表
     */
    fun filterByLevel(logs: List<LogEntry>, level: String): List<LogEntry> {
        return logs.filter { it.level.equals(level, ignoreCase = true) }
    }
    
    /**
     * 按关键词搜索
     * @param logs 日志列表
     * @param keyword 关键词
     * @return 匹配的日志列表
     */
    fun searchByKeyword(logs: List<LogEntry>, keyword: String): List<LogEntry> {
        return logs.filter { it.message.contains(keyword, ignoreCase = true) }
    }
    
    /**
     * 按时间范围过滤
     * @param logs 日志列表
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 过滤后的日志列表
     */
    fun filterByTimeRange(logs: List<LogEntry>, startTime: String, endTime: String): List<LogEntry> {
        return logs.filter { it.timestamp in startTime..endTime }
    }
    
    /**
     * 统计日志级别分布
     * @param logs 日志列表
     * @return 级别分布映射
     */
    fun countByLevel(logs: List<LogEntry>): Map<String, Int> {
        return logs.groupingBy { it.level }.eachCount()
    }
    
    /**
     * 统计日志来源分布
     * @param logs 日志列表
     * @return 来源分布映射
     */
    fun countBySource(logs: List<LogEntry>): Map<String, Int> {
        return logs.groupingBy { it.source }.eachCount()
    }
    
    /**
     * 获取日志统计信息
     * @param logs 日志列表
     * @return 统计信息映射
     */
    fun getStatistics(logs: List<LogEntry>): Map<String, Any> {
        val levelCounts = countByLevel(logs)
        val errorCount = levelCounts["ERROR"] ?: 0
        val warningCount = levelCounts["WARN"] ?: 0
        val infoCount = levelCounts["INFO"] ?: 0
        
        return mapOf(
            "totalCount" to logs.size,
            "errorCount" to errorCount,
            "warningCount" to warningCount,
            "infoCount" to infoCount,
            "errorRate" to if (logs.isNotEmpty()) (errorCount * 100.0 / logs.size) else 0.0,
            "levelDistribution" to levelCounts
        )
    }
    
    /**
     * 聚合多个日志源
     * @param logSources 日志源列表
     * @return 聚合后的日志列表
     */
    fun aggregateLogs(logSources: List<String>): List<LogEntry> {
        return logSources.flatMap { parseLogs(it) }
            .sortedBy { it.timestamp }
    }
    
    /**
     * 提取错误日志
     * @param logs 日志列表
     * @return 错误日志列表
     */
    fun extractErrors(logs: List<LogEntry>): List<LogEntry> {
        return filterByLevel(logs, "ERROR")
    }
    
    /**
     * 提取警告日志
     * @param logs 日志列表
     * @return 警告日志列表
     */
    fun extractWarnings(logs: List<LogEntry>): List<LogEntry> {
        return filterByLevel(logs, "WARN")
    }
    
    /**
     * 分析性能指标
     * @param logs 日志列表
     * @return 性能指标映射
     */
    fun analyzePerformance(logs: List<LogEntry>): Map<String, Any> {
        val stats = getStatistics(logs)
        val errorRate = stats["errorRate"] as? Double ?: 0.0
        val totalCount = stats["totalCount"] as? Int ?: 0
        
        val healthScore = when {
            errorRate < 1.0 -> 95
            errorRate < 5.0 -> 85
            errorRate < 10.0 -> 75
            else -> 50
        }
        
        return mapOf(
            "healthScore" to healthScore,
            "errorRate" to errorRate,
            "totalLogs" to totalCount,
            "status" to when {
                healthScore >= 90 -> "优秀"
                healthScore >= 75 -> "良好"
                healthScore >= 60 -> "中等"
                else -> "需要改进"
            }
        )
    }
    
    /**
     * 获取日志摘要
     * @param logs 日志列表
     * @param limit 摘要条数
     * @return 日志摘要
     */
    fun getSummary(logs: List<LogEntry>, limit: Int = 10): String {
        val stats = getStatistics(logs)
        val errors = extractErrors(logs).take(limit)
        
        val summary = StringBuilder()
        summary.append("日志摘要\n")
        summary.append("总条数: ${stats["totalCount"]}\n")
        summary.append("错误数: ${stats["errorCount"]}\n")
        summary.append("警告数: ${stats["warningCount"]}\n")
        summary.append("错误率: ${String.format("%.2f", stats["errorRate"])}%\n\n")
        summary.append("最近错误:\n")
        
        errors.forEach { error ->
            summary.append("[${error.timestamp}] ${error.message}\n")
        }
        
        return summary.toString()
    }
}

Kotlin 实现的核心特点

Kotlin 实现中的日志处理功能充分利用了 Kotlin 标准库的字符串处理和集合操作能力。日志解析使用了正则表达式来提取日志信息。日志过滤使用了集合的 filter 方法。

日志聚合使用了 flatMapsortedBy 方法。统计功能使用了 groupingByeachCount 方法。性能分析使用了统计数据的组合计算。

JavaScript 实现

编译后的 JavaScript 代码

// 文件: build/js/packages/kmp_openharmony-js/kotlin/kmp_openharmony.js
// (由 Kotlin 编译器自动生成)

/**
 * LogProcessor 类的 JavaScript 版本
 * 通过 Kotlin/JS 编译器从 Kotlin 源代码生成
 */
class LogProcessor {
  /**
   * 解析日志行
   * @param {string} logLine - 日志行
   * @returns {Object} 日志条目
   */
  parseLogLine(logLine) {
    const pattern = /\[(.*?)\]\s+\[(.*?)\]\s+(.*)/;
    const match = logLine.match(pattern);

    if (match) {
      return {
        timestamp: match[1],
        level: match[2],
        message: match[3],
        source: ''
      };
    }
    return null;
  }

  /**
   * 解析多行日志
   * @param {string} logs - 日志字符串
   * @returns {Object[]} 日志条目列表
   */
  parseLogs(logs) {
    return logs.split('\n')
      .map(line => this.parseLogLine(line))
      .filter(entry => entry !== null);
  }

  /**
   * 按日志级别过滤
   * @param {Object[]} logs - 日志列表
   * @param {string} level - 日志级别
   * @returns {Object[]} 过滤后的日志列表
   */
  filterByLevel(logs, level) {
    return logs.filter(log => log.level.toUpperCase() === level.toUpperCase());
  }

  /**
   * 按关键词搜索
   * @param {Object[]} logs - 日志列表
   * @param {string} keyword - 关键词
   * @returns {Object[]} 匹配的日志列表
   */
  searchByKeyword(logs, keyword) {
    return logs.filter(log => log.message.toLowerCase().includes(keyword.toLowerCase()));
  }

  /**
   * 按时间范围过滤
   * @param {Object[]} logs - 日志列表
   * @param {string} startTime - 开始时间
   * @param {string} endTime - 结束时间
   * @returns {Object[]} 过滤后的日志列表
   */
  filterByTimeRange(logs, startTime, endTime) {
    return logs.filter(log => log.timestamp >= startTime && log.timestamp <= endTime);
  }

  /**
   * 统计日志级别分布
   * @param {Object[]} logs - 日志列表
   * @returns {Object} 级别分布
   */
  countByLevel(logs) {
    const counts = {};
    for (const log of logs) {
      counts[log.level] = (counts[log.level] || 0) + 1;
    }
    return counts;
  }

  /**
   * 获取日志统计信息
   * @param {Object[]} logs - 日志列表
   * @returns {Object} 统计信息
   */
  getStatistics(logs) {
    const levelCounts = this.countByLevel(logs);
    const errorCount = levelCounts['ERROR'] || 0;
    const warningCount = levelCounts['WARN'] || 0;
    const infoCount = levelCounts['INFO'] || 0;

    return {
      totalCount: logs.length,
      errorCount: errorCount,
      warningCount: warningCount,
      infoCount: infoCount,
      errorRate: logs.length > 0 ? (errorCount * 100.0 / logs.length) : 0.0,
      levelDistribution: levelCounts
    };
  }

  /**
   * 聚合多个日志源
   * @param {string[]} logSources - 日志源列表
   * @returns {Object[]} 聚合后的日志列表
   */
  aggregateLogs(logSources) {
    const allLogs = [];
    for (const source of logSources) {
      allLogs.push(...this.parseLogs(source));
    }
    return allLogs.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
  }

  /**
   * 提取错误日志
   * @param {Object[]} logs - 日志列表
   * @returns {Object[]} 错误日志列表
   */
  extractErrors(logs) {
    return this.filterByLevel(logs, 'ERROR');
  }

  /**
   * 分析性能指标
   * @param {Object[]} logs - 日志列表
   * @returns {Object} 性能指标
   */
  analyzePerformance(logs) {
    const stats = this.getStatistics(logs);
    const errorRate = stats.errorRate;

    let healthScore;
    if (errorRate < 1.0) healthScore = 95;
    else if (errorRate < 5.0) healthScore = 85;
    else if (errorRate < 10.0) healthScore = 75;
    else healthScore = 50;

    let status;
    if (healthScore >= 90) status = '优秀';
    else if (healthScore >= 75) status = '良好';
    else if (healthScore >= 60) status = '中等';
    else status = '需要改进';

    return {
      healthScore: healthScore,
      errorRate: errorRate,
      totalLogs: stats.totalCount,
      status: status
    };
  }
}

JavaScript 实现的特点

JavaScript 版本完全由 Kotlin/JS 编译器自动生成,确保了与 Kotlin 版本的行为完全一致。JavaScript 的数组方法和对象处理提供了必要的日志处理能力。

filter 方法用于过滤日志。map 方法用于转换日志。sort 方法用于排序日志。

ArkTS 调用代码

OpenHarmony 应用集成

// 文件: kmp_ceshiapp/entry/src/main/ets/pages/LogProcessorPage.ets

import { LogProcessor } from '../../../../../../../build/js/packages/kmp_openharmony-js/kotlin/kmp_openharmony';

@Entry
@Component
struct LogProcessorPage {
  @State selectedOperation: string = 'parse';
  @State inputLogs: string = '';
  @State result: string = '';
  @State resultTitle: string = '';

  private processor = new LogProcessor();

  private operations = [
    { name: '解析日志', value: 'parse' },
    { name: '错误日志', value: 'errors' },
    { name: '警告日志', value: 'warnings' },
    { name: '关键词搜索', value: 'search' },
    { name: '日志统计', value: 'statistics' },
    { name: '性能分析', value: 'performance' },
    { name: '日志摘要', value: 'summary' },
    { name: '级别分布', value: 'distribution' },
    { name: '时间范围', value: 'timerange' },
    { name: '聚合日志', value: 'aggregate' }
  ];

  build() {
    Column() {
      // 标题
      Text('📋 日志解析与聚合高级工具库')
        .fontSize(28)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FFFFFF')
        .width('100%')
        .padding(20)
        .backgroundColor('#1A237E')
        .textAlign(TextAlign.Center)

      Scroll() {
        Column() {
          // 操作选择
          Column() {
            Text('选择操作')
              .fontSize(14)
              .fontWeight(FontWeight.Bold)
              .fontColor('#333333')
              .margin({ bottom: 12 })

            Flex({ wrap: FlexWrap.Wrap }) {
              ForEach(this.operations, (op: { name: string; value: string }) => {
                Button(op.name)
                  .layoutWeight(1)
                  .height(40)
                  .margin({ right: 8, bottom: 8 })
                  .backgroundColor(this.selectedOperation === op.value ? '#1A237E' : '#E0E0E0')
                  .fontColor(this.selectedOperation === op.value ? '#FFFFFF' : '#333333')
                  .fontSize(11)
                  .onClick(() => {
                    this.selectedOperation = op.value;
                    this.result = '';
                    this.resultTitle = '';
                  })
              })
            }
            .width('100%')
          }
          .width('95%')
          .margin({ top: 16, left: '2.5%', right: '2.5%', bottom: 16 })
          .padding(12)
          .backgroundColor('#FFFFFF')
          .borderRadius(6)

          // 输入区域
          Column() {
            Text('输入日志')
              .fontSize(14)
              .fontWeight(FontWeight.Bold)
              .fontColor('#333333')
              .margin({ bottom: 8 })

            TextInput({ placeholder: '输入日志内容(每行一条)', text: this.inputLogs })
              .onChange((value) => this.inputLogs = value)
              .width('100%')
              .height(120)
              .padding(12)
              .border({ width: 1, color: '#4DB6AC' })
              .borderRadius(6)
              .fontSize(12)
          }
          .width('95%')
          .margin({ left: '2.5%', right: '2.5%', bottom: 16 })
          .padding(12)
          .backgroundColor('#FFFFFF')
          .borderRadius(6)

          // 操作按钮
          Row() {
            Button('✨ 处理')
              .layoutWeight(1)
              .height(44)
              .backgroundColor('#1A237E')
              .fontColor('#FFFFFF')
              .fontSize(14)
              .fontWeight(FontWeight.Bold)
              .borderRadius(6)
              .onClick(() => this.executeOperation())

            Blank()
              .width(12)

            Button('🔄 清空')
              .layoutWeight(1)
              .height(44)
              .backgroundColor('#F5F5F5')
              .fontColor('#1A237E')
              .fontSize(14)
              .border({ width: 1, color: '#4DB6AC' })
              .borderRadius(6)
              .onClick(() => {
                this.inputLogs = '';
                this.result = '';
                this.resultTitle = '';
              })
          }
          .width('95%')
          .margin({ left: '2.5%', right: '2.5%', bottom: 16 })

          // 结果显示
          if (this.resultTitle) {
            Column() {
              Text(this.resultTitle)
                .fontSize(16)
                .fontWeight(FontWeight.Bold)
                .fontColor('#FFFFFF')
                .width('100%')
                .padding(12)
                .backgroundColor('#1A237E')
                .borderRadius(6)
                .textAlign(TextAlign.Center)
                .margin({ bottom: 12 })

              Scroll() {
                Text(this.result)
                  .fontSize(12)
                  .fontColor('#333333')
                  .fontFamily('monospace')
                  .textAlign(TextAlign.Start)
                  .width('100%')
                  .padding(12)
                  .selectable(true)
              }
              .width('100%')
              .height(300)
              .backgroundColor('#F9F9F9')
              .border({ width: 1, color: '#4DB6AC' })
              .borderRadius(6)
            }
            .width('95%')
            .margin({ left: '2.5%', right: '2.5%', bottom: 16 })
            .padding(12)
            .backgroundColor('#FFFFFF')
            .borderRadius(6)
          }
        }
        .width('100%')
      }
      .layoutWeight(1)
      .width('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F5F5')
  }

  private executeOperation() {
    if (!this.inputLogs.trim()) {
      this.resultTitle = '❌ 错误';
      this.result = '请输入日志内容';
      return;
    }

    try {
      const logs = this.processor.parseLogs(this.inputLogs);

      switch (this.selectedOperation) {
        case 'parse':
          this.resultTitle = '📊 日志解析结果';
          this.result = `解析成功: ${logs.length} 条日志\n\n${logs.map(l => `[${l.timestamp}] [${l.level}] ${l.message}`).join('\n')}`;
          break;

        case 'errors':
          const errors = this.processor.extractErrors(logs);
          this.resultTitle = '❌ 错误日志';
          this.result = `找到 ${errors.length} 条错误\n\n${errors.map(e => `[${e.timestamp}] ${e.message}`).join('\n')}`;
          break;

        case 'warnings':
          const warnings = this.processor.filterByLevel(logs, 'WARN');
          this.resultTitle = '⚠️ 警告日志';
          this.result = `找到 ${warnings.length} 条警告\n\n${warnings.map(w => `[${w.timestamp}] ${w.message}`).join('\n')}`;
          break;

        case 'search':
          const searchResults = this.processor.searchByKeyword(logs, 'error');
          this.resultTitle = '🔍 搜索结果';
          this.result = `找到 ${searchResults.length} 条匹配\n\n${searchResults.map(r => `[${r.timestamp}] ${r.message}`).join('\n')}`;
          break;

        case 'statistics':
          const stats = this.processor.getStatistics(logs);
          this.resultTitle = '📈 日志统计';
          this.result = `总条数: ${stats.totalCount}\n错误数: ${stats.errorCount}\n警告数: ${stats.warningCount}\n信息数: ${stats.infoCount}\n错误率: ${stats.errorRate.toFixed(2)}%`;
          break;

        case 'performance':
          const perf = this.processor.analyzePerformance(logs);
          this.resultTitle = '⚡ 性能分析';
          this.result = `健康评分: ${perf.healthScore}\n状态: ${perf.status}\n错误率: ${perf.errorRate.toFixed(2)}%\n总日志: ${perf.totalLogs}`;
          break;

        case 'summary':
          const summary = this.processor.getSummary(logs, 5);
          this.resultTitle = '📄 日志摘要';
          this.result = summary;
          break;

        case 'distribution':
          const dist = this.processor.countByLevel(logs);
          this.resultTitle = '📊 级别分布';
          this.result = Object.entries(dist).map(([level, count]) => `${level}: ${count}`).join('\n');
          break;

        case 'timerange':
          const rangeFiltered = this.processor.filterByTimeRange(logs, '2025-12-02 09:00:00', '2025-12-02 23:59:59');
          this.resultTitle = '⏰ 时间范围过滤';
          this.result = `在指定时间范围内找到 ${rangeFiltered.length} 条日志`;
          break;

        case 'aggregate':
          const aggregated = this.processor.aggregateLogs([this.inputLogs]);
          this.resultTitle = '🔗 日志聚合';
          this.result = `聚合后共 ${aggregated.length} 条日志`;
          break;
      }
    } catch (e) {
      this.resultTitle = '❌ 处理出错';
      this.result = `错误: ${e}`;
    }
  }
}

ArkTS 集成的关键要点

在 OpenHarmony 应用中集成日志处理工具库需要考虑多种日志操作和用户体验。我们设计了一个灵活的 UI,能够支持不同的日志处理操作。

操作选择界面使用了 Flex 布局和 FlexWrap 来实现响应式的按钮排列。输入区域使用了较大的高度以容纳多行日志内容。

结果显示使用了可选择的文本,这样用户可以轻松复制处理结果。对于不同的操作,我们显示了相应的日志处理信息。

工作流程详解

日志处理的完整流程

  1. 操作选择: 用户在 ArkTS UI 中选择要执行的日志处理操作
  2. 日志输入: 用户输入要处理的日志内容
  3. 处理执行: 调用 LogProcessor 的相应方法
  4. 结果展示: 将处理结果显示在 UI 中

跨平台一致性

通过 KMP 技术,我们确保了在所有平台上的行为一致性。无论是在 Kotlin/JVM、Kotlin/JS 还是通过 ArkTS 调用,日志处理的逻辑和结果都是完全相同的。

实际应用场景

系统监控

在系统监控中,需要解析和分析系统日志。这个工具库提供了日志解析和统计功能。

应用调试

在应用调试中,需要搜索和过滤日志。这个工具库提供了日志搜索和过滤功能。

性能分析

在性能分析中,需要分析日志中的性能指标。这个工具库提供了性能分析功能。

错误追踪

在错误追踪中,需要提取和分析错误日志。这个工具库提供了错误提取和分析功能。

性能优化

流式处理

在处理大型日志文件时,应该考虑使用流式处理的方式以提高效率。

缓存结果

在频繁进行相同的日志分析时,可以缓存分析结果以避免重复计算。

安全性考虑

敏感信息过滤

在处理日志时,应该过滤敏感信息如密码、令牌等。

访问控制

在共享日志时,应该实施适当的访问控制以保护隐私。

总结

这个 KMP OpenHarmony 日志解析与聚合高级工具库展示了如何使用现代的跨平台技术来处理常见的日志处理任务。通过 Kotlin Multiplatform 技术,我们可以在一个地方编写业务逻辑,然后在多个平台上使用。

日志处理是应用开发中的重要功能。通过使用这样的工具库,开发者可以快速、可靠地处理各种日志处理操作,从而提高开发效率和应用可维护性。

在实际应用中,建议根据具体的需求进行定制和扩展,例如添加更复杂的日志分析算法、实现更全面的日志聚合功能等高级特性。同时,定期进行性能测试和优化,确保应用在处理大量日志时仍然保持良好的性能。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐