在这里插入图片描述

目录

  1. 概述
  2. 工具功能
  3. 核心实现
  4. Kotlin 源代码
  5. JavaScript 编译代码
  6. ArkTS 调用代码
  7. 实战案例
  8. 最佳实践

概述

本文档介绍如何在 Kotlin Multiplatform (KMP) 鸿蒙跨端开发中实现一个完整的日志生成工具系统。日志是应用开发和运维中的一个基础组件,用于记录应用的运行状态、错误信息、性能数据等。无论是进行应用调试、性能分析还是故障排查,一个功能强大的日志工具都能提供必要的支持。

这个案例展示了如何使用 Kotlin 的字符串处理、时间管理和控制台输出来创建一个功能丰富的日志生成工具。日志工具需要能够支持多种日志级别、提供灵活的格式化选项、支持日志过滤和搜索、提供性能统计等。通过 KMP,这个工具可以无缝编译到 JavaScript,在 OpenHarmony 应用中运行,并支持实时日志输出。

在实际应用中,日志生成工具广泛应用于以下场景:应用调试中的信息输出、性能监控中的数据记录、错误追踪中的堆栈信息、用户行为分析中的事件记录等。通过支持多种日志级别、提供详细的时间戳和上下文信息、生成结构化日志,我们可以帮助开发者更好地理解应用的运行情况。同时,通过 KMP 框架的跨端能力,我们可以在不同平台上使用相同的日志逻辑,确保日志的一致性。

工具的特点

  • 多级别日志:支持 DEBUG、INFO、WARN、ERROR、FATAL 等多个日志级别
  • 灵活的格式化:支持自定义日志格式和输出模板
  • 时间戳管理:自动添加精确的时间戳信息
  • 日志过滤:支持按级别、标签、内容等过滤日志
  • 性能统计:记录日志统计信息和性能数据
  • 跨端兼容:一份 Kotlin 代码可同时服务多个平台

工具功能

1. 日志级别管理

日志级别是日志系统的基础概念,用于区分不同严重程度的日志信息。不同的日志级别适用于不同的场景,开发者可以根据需要选择合适的级别。DEBUG 级别用于开发调试,INFO 级别用于一般信息,WARN 级别用于警告信息,ERROR 级别用于错误信息,FATAL 级别用于致命错误。

  • DEBUG:用于开发调试的详细信息
  • INFO:用于一般信息和重要事件
  • WARN:用于警告信息和潜在问题
  • ERROR:用于错误信息和异常
  • FATAL:用于致命错误和系统崩溃

2. 日志格式化

日志格式化是指将日志信息按照指定的格式进行组织和输出。合理的日志格式可以使日志更加易读和易于分析。日志格式通常包括时间戳、日志级别、标签、线程信息、消息内容等。开发者可以根据需要自定义日志格式。

  • 时间戳:记录日志生成的时间
  • 日志级别:标识日志的严重程度
  • 标签:用于分类和过滤日志
  • 线程信息:记录日志所在的线程
  • 消息内容:日志的具体内容

3. 日志过滤和搜索

日志过滤和搜索功能允许开发者快速找到感兴趣的日志信息。通过按级别、标签、时间范围等条件过滤,可以大大提高日志分析的效率。搜索功能支持正则表达式和关键词搜索。

  • 按级别过滤:只显示指定级别的日志
  • 按标签过滤:只显示指定标签的日志
  • 按时间范围过滤:只显示指定时间范围内的日志
  • 关键词搜索:搜索包含特定关键词的日志

4. 日志统计和分析

日志统计和分析功能提供了日志的汇总信息和性能数据。这些信息可以帮助开发者了解应用的运行情况和性能特征。统计信息包括日志总数、各级别日志数量、最常见的标签等。

  • 日志总数:统计所有日志的数量
  • 级别统计:统计各级别日志的数量
  • 标签统计:统计各标签日志的数量
  • 性能数据:记录日志操作的性能指标

5. 控制台输出管理

控制台输出管理功能控制日志的输出方式和目标。开发者可以选择输出到控制台、文件或其他目标。对于控制台输出,可以设置输出的颜色、格式等。

  • 控制台输出:输出到标准输出或错误输出
  • 颜色输出:为不同级别的日志使用不同的颜色
  • 缓冲管理:管理输出缓冲以提高性能
  • 输出控制:控制日志的启用和禁用

核心实现

1. 日志级别定义

enum class LogLevel(val level: Int, val name: String) {
    DEBUG(0, "DEBUG"),
    INFO(1, "INFO"),
    WARN(2, "WARN"),
    ERROR(3, "ERROR"),
    FATAL(4, "FATAL");
    
    companion object {
        fun fromString(name: String): LogLevel {
            return values().find { it.name == name.uppercase() } ?: INFO
        }
    }
}

data class LogEntry(
    val timestamp: String,
    val level: LogLevel,
    val tag: String,
    val message: String,
    val thread: String,
    val stackTrace: String? = null
)

代码说明: 日志级别通过枚举定义,每个级别有对应的数值和名称。LogEntry 数据类封装了日志的所有信息,包括时间戳、级别、标签、消息、线程和堆栈跟踪。

2. 日志格式化

class LogFormatter {
    private var format = "[%timestamp%] [%level%] [%tag%] %message%"
    
    fun setFormat(newFormat: String) {
        format = newFormat
    }
    
    fun format(entry: LogEntry): String {
        var result = format
        result = result.replace("%timestamp%", entry.timestamp)
        result = result.replace("%level%", entry.level.name)
        result = result.replace("%tag%", entry.tag)
        result = result.replace("%message%", entry.message)
        result = result.replace("%thread%", entry.thread)
        
        if (entry.stackTrace != null && result.contains("%stacktrace%")) {
            result = result.replace("%stacktrace%", entry.stackTrace)
        }
        
        return result
    }
    
    fun formatWithColor(entry: LogEntry): String {
        val colorCode = when (entry.level) {
            LogLevel.DEBUG -> "\u001B[36m"    // Cyan
            LogLevel.INFO -> "\u001B[32m"     // Green
            LogLevel.WARN -> "\u001B[33m"     // Yellow
            LogLevel.ERROR -> "\u001B[31m"    // Red
            LogLevel.FATAL -> "\u001B[35m"    // Magenta
        }
        val resetCode = "\u001B[0m"
        
        val formatted = format(entry)
        return "$colorCode$formatted$resetCode"
    }
}

代码说明: LogFormatter 类负责将日志条目格式化为字符串。支持自定义格式模板和颜色输出。颜色输出使用 ANSI 转义码,可以在支持的终端中显示彩色输出。

3. 日志记录器

class Logger(val tag: String) {
    private val entries = mutableListOf<LogEntry>()
    private val formatter = LogFormatter()
    private var minLevel = LogLevel.DEBUG
    private var enableConsole = true
    private var enableColor = true
    
    fun setMinLevel(level: LogLevel) {
        minLevel = level
    }
    
    fun setConsoleEnabled(enabled: Boolean) {
        enableConsole = enabled
    }
    
    fun setColorEnabled(enabled: Boolean) {
        enableColor = enabled
    }
    
    private fun log(level: LogLevel, message: String, throwable: Throwable? = null) {
        if (level.level < minLevel.level) return
        
        val timestamp = java.time.LocalDateTime.now().format(
            java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")
        )
        val thread = Thread.currentThread().name
        val stackTrace = throwable?.stackTraceToString()
        
        val entry = LogEntry(timestamp, level, tag, message, thread, stackTrace)
        entries.add(entry)
        
        if (enableConsole) {
            val output = if (enableColor) {
                formatter.formatWithColor(entry)
            } else {
                formatter.format(entry)
            }
            
            if (level == LogLevel.ERROR || level == LogLevel.FATAL) {
                System.err.println(output)
            } else {
                println(output)
            }
        }
    }
    
    fun debug(message: String) = log(LogLevel.DEBUG, message)
    fun info(message: String) = log(LogLevel.INFO, message)
    fun warn(message: String) = log(LogLevel.WARN, message)
    fun error(message: String, throwable: Throwable? = null) = log(LogLevel.ERROR, message, throwable)
    fun fatal(message: String, throwable: Throwable? = null) = log(LogLevel.FATAL, message, throwable)
    
    fun getEntries(): List<LogEntry> = entries.toList()
    
    fun clearEntries() {
        entries.clear()
    }
}

代码说明: Logger 类是日志记录的主要接口。提供了 debug、info、warn、error、fatal 等方法用于记录不同级别的日志。支持设置最小日志级别、控制台输出和颜色输出。

4. 日志过滤和搜索

class LogFilter {
    fun filterByLevel(entries: List<LogEntry>, level: LogLevel): List<LogEntry> {
        return entries.filter { it.level == level }
    }
    
    fun filterByTag(entries: List<LogEntry>, tag: String): List<LogEntry> {
        return entries.filter { it.tag == tag }
    }
    
    fun filterByLevelRange(entries: List<LogEntry>, minLevel: LogLevel, maxLevel: LogLevel): List<LogEntry> {
        return entries.filter { it.level.level in minLevel.level..maxLevel.level }
    }
    
    fun filterByTimeRange(entries: List<LogEntry>, startTime: String, endTime: String): List<LogEntry> {
        return entries.filter { it.timestamp in startTime..endTime }
    }
    
    fun searchByKeyword(entries: List<LogEntry>, keyword: String): List<LogEntry> {
        return entries.filter { it.message.contains(keyword, ignoreCase = true) }
    }
    
    fun searchByRegex(entries: List<LogEntry>, pattern: String): List<LogEntry> {
        val regex = Regex(pattern)
        return entries.filter { regex.containsMatchIn(it.message) }
    }
}

代码说明: LogFilter 类提供了多种过滤和搜索功能。支持按级别、标签、时间范围过滤,以及关键词和正则表达式搜索。这些功能可以帮助开发者快速定位感兴趣的日志。

5. 日志统计

class LogStatistics(private val entries: List<LogEntry>) {
    
    fun getTotalCount(): Int = entries.size
    
    fun getCountByLevel(): Map<LogLevel, Int> {
        return entries.groupingBy { it.level }.eachCount()
    }
    
    fun getCountByTag(): Map<String, Int> {
        return entries.groupingBy { it.tag }.eachCount()
    }
    
    fun getMostCommonTag(): String? {
        return entries.groupingBy { it.tag }.eachCount().maxByOrNull { it.value }?.key
    }
    
    fun getMostCommonLevel(): LogLevel? {
        return entries.groupingBy { it.level }.eachCount().maxByOrNull { it.value }?.key
    }
    
    fun getErrorCount(): Int {
        return entries.count { it.level == LogLevel.ERROR || it.level == LogLevel.FATAL }
    }
    
    fun getWarningCount(): Int {
        return entries.count { it.level == LogLevel.WARN }
    }
    
    fun getSummary(): Map<String, Any> {
        return mapOf(
            "totalCount" to getTotalCount(),
            "countByLevel" to getCountByLevel(),
            "countByTag" to getCountByTag(),
            "errorCount" to getErrorCount(),
            "warningCount" to getWarningCount(),
            "mostCommonTag" to (getMostCommonTag() ?: "unknown"),
            "mostCommonLevel" to (getMostCommonLevel()?.name ?: "unknown")
        )
    }
}

代码说明: LogStatistics 类提供了日志的统计和分析功能。可以统计各级别日志的数量、各标签日志的数量、错误和警告的总数等。getSummary() 方法返回一个包含所有统计信息的映射。


Kotlin 源代码

// Logger.kt
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter

enum class LogLevel(val level: Int, val name: String) {
    DEBUG(0, "DEBUG"),
    INFO(1, "INFO"),
    WARN(2, "WARN"),
    ERROR(3, "ERROR"),
    FATAL(4, "FATAL")
}

data class LogEntry(
    val timestamp: String,
    val level: LogLevel,
    val tag: String,
    val message: String,
    val thread: String,
    val stackTrace: String? = null
)

class LogFormatter {
    private var format = "[%timestamp%] [%level%] [%tag%] %message%"
    
    fun setFormat(newFormat: String) {
        format = newFormat
    }
    
    fun format(entry: LogEntry): String {
        var result = format
        result = result.replace("%timestamp%", entry.timestamp)
        result = result.replace("%level%", entry.level.name)
        result = result.replace("%tag%", entry.tag)
        result = result.replace("%message%", entry.message)
        result = result.replace("%thread%", entry.thread)
        
        if (entry.stackTrace != null && result.contains("%stacktrace%")) {
            result = result.replace("%stacktrace%", entry.stackTrace)
        }
        
        return result
    }
    
    fun formatWithColor(entry: LogEntry): String {
        val colorCode = when (entry.level) {
            LogLevel.DEBUG -> "\u001B[36m"
            LogLevel.INFO -> "\u001B[32m"
            LogLevel.WARN -> "\u001B[33m"
            LogLevel.ERROR -> "\u001B[31m"
            LogLevel.FATAL -> "\u001B[35m"
        }
        val resetCode = "\u001B[0m"
        
        val formatted = format(entry)
        return "$colorCode$formatted$resetCode"
    }
}

class Logger(val tag: String) {
    private val entries = mutableListOf<LogEntry>()
    private val formatter = LogFormatter()
    private var minLevel = LogLevel.DEBUG
    private var enableConsole = true
    private var enableColor = true
    
    fun setMinLevel(level: LogLevel) {
        minLevel = level
    }
    
    fun setConsoleEnabled(enabled: Boolean) {
        enableConsole = enabled
    }
    
    fun setColorEnabled(enabled: Boolean) {
        enableColor = enabled
    }
    
    private fun log(level: LogLevel, message: String, throwable: Throwable? = null) {
        if (level.level < minLevel.level) return
        
        val timestamp = LocalDateTime.now().format(
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")
        )
        val thread = Thread.currentThread().name
        val stackTrace = throwable?.stackTraceToString()
        
        val entry = LogEntry(timestamp, level, tag, message, thread, stackTrace)
        entries.add(entry)
        
        if (enableConsole) {
            val output = if (enableColor) {
                formatter.formatWithColor(entry)
            } else {
                formatter.format(entry)
            }
            
            if (level == LogLevel.ERROR || level == LogLevel.FATAL) {
                System.err.println(output)
            } else {
                println(output)
            }
        }
    }
    
    fun debug(message: String) = log(LogLevel.DEBUG, message)
    fun info(message: String) = log(LogLevel.INFO, message)
    fun warn(message: String) = log(LogLevel.WARN, message)
    fun error(message: String, throwable: Throwable? = null) = log(LogLevel.ERROR, message, throwable)
    fun fatal(message: String, throwable: Throwable? = null) = log(LogLevel.FATAL, message, throwable)
    
    fun getEntries(): List<LogEntry> = entries.toList()
    fun clearEntries() { entries.clear() }
}

class LogFilter {
    fun filterByLevel(entries: List<LogEntry>, level: LogLevel): List<LogEntry> {
        return entries.filter { it.level == level }
    }
    
    fun filterByTag(entries: List<LogEntry>, tag: String): List<LogEntry> {
        return entries.filter { it.tag == tag }
    }
    
    fun searchByKeyword(entries: List<LogEntry>, keyword: String): List<LogEntry> {
        return entries.filter { it.message.contains(keyword, ignoreCase = true) }
    }
}

class LogStatistics(private val entries: List<LogEntry>) {
    
    fun getTotalCount(): Int = entries.size
    
    fun getCountByLevel(): Map<LogLevel, Int> {
        return entries.groupingBy { it.level }.eachCount()
    }
    
    fun getCountByTag(): Map<String, Int> {
        return entries.groupingBy { it.tag }.eachCount()
    }
    
    fun getErrorCount(): Int {
        return entries.count { it.level == LogLevel.ERROR || it.level == LogLevel.FATAL }
    }
    
    fun getSummary(): Map<String, Any> {
        return mapOf(
            "totalCount" to getTotalCount(),
            "countByLevel" to getCountByLevel(),
            "errorCount" to getErrorCount()
        )
    }
}

fun main() {
    val logger = Logger("MainActivity")
    
    logger.debug("应用启动")
    logger.info("初始化完成")
    logger.warn("内存使用率较高")
    logger.error("网络连接失败")
    
    val stats = LogStatistics(logger.getEntries())
    println("日志统计: ${stats.getSummary()}")
}

Kotlin 代码说明: 这个实现提供了完整的日志功能。Logger 类是主要接口,提供了多个日志级别的方法。LogFormatter 类负责格式化日志,支持颜色输出。LogFilter 类提供了过滤功能,LogStatistics 类提供了统计功能。


JavaScript 编译代码

// Logger.js
const LogLevel = {
    DEBUG: { level: 0, name: "DEBUG" },
    INFO: { level: 1, name: "INFO" },
    WARN: { level: 2, name: "WARN" },
    ERROR: { level: 3, name: "ERROR" },
    FATAL: { level: 4, name: "FATAL" }
};

class LogEntry {
    constructor(timestamp, level, tag, message, thread, stackTrace = null) {
        this.timestamp = timestamp;
        this.level = level;
        this.tag = tag;
        this.message = message;
        this.thread = thread;
        this.stackTrace = stackTrace;
    }
}

class LogFormatter {
    constructor() {
        this.format = "[%timestamp%] [%level%] [%tag%] %message%";
    }
    
    setFormat(newFormat) {
        this.format = newFormat;
    }
    
    format(entry) {
        let result = this.format;
        result = result.replace("%timestamp%", entry.timestamp);
        result = result.replace("%level%", entry.level.name);
        result = result.replace("%tag%", entry.tag);
        result = result.replace("%message%", entry.message);
        result = result.replace("%thread%", entry.thread);
        
        if (entry.stackTrace && result.includes("%stacktrace%")) {
            result = result.replace("%stacktrace%", entry.stackTrace);
        }
        
        return result;
    }
    
    formatWithColor(entry) {
        const colorCode = {
            DEBUG: "\x1b[36m",
            INFO: "\x1b[32m",
            WARN: "\x1b[33m",
            ERROR: "\x1b[31m",
            FATAL: "\x1b[35m"
        }[entry.level.name];
        
        const resetCode = "\x1b[0m";
        const formatted = this.format(entry);
        return `${colorCode}${formatted}${resetCode}`;
    }
}

class Logger {
    constructor(tag) {
        this.tag = tag;
        this.entries = [];
        this.formatter = new LogFormatter();
        this.minLevel = LogLevel.DEBUG;
        this.enableConsole = true;
        this.enableColor = true;
    }
    
    setMinLevel(level) {
        this.minLevel = level;
    }
    
    setConsoleEnabled(enabled) {
        this.enableConsole = enabled;
    }
    
    setColorEnabled(enabled) {
        this.enableColor = enabled;
    }
    
    log(level, message, throwable = null) {
        if (level.level < this.minLevel.level) return;
        
        const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 23);
        const thread = "main";
        const stackTrace = throwable ? throwable.stack : null;
        
        const entry = new LogEntry(timestamp, level, this.tag, message, thread, stackTrace);
        this.entries.push(entry);
        
        if (this.enableConsole) {
            const output = this.enableColor ? 
                this.formatter.formatWithColor(entry) : 
                this.formatter.format(entry);
            
            if (level === LogLevel.ERROR || level === LogLevel.FATAL) {
                console.error(output);
            } else {
                console.log(output);
            }
        }
    }
    
    debug(message) { this.log(LogLevel.DEBUG, message); }
    info(message) { this.log(LogLevel.INFO, message); }
    warn(message) { this.log(LogLevel.WARN, message); }
    error(message, throwable = null) { this.log(LogLevel.ERROR, message, throwable); }
    fatal(message, throwable = null) { this.log(LogLevel.FATAL, message, throwable); }
    
    getEntries() { return [...this.entries]; }
    clearEntries() { this.entries = []; }
}

class LogFilter {
    filterByLevel(entries, level) {
        return entries.filter(e => e.level === level);
    }
    
    filterByTag(entries, tag) {
        return entries.filter(e => e.tag === tag);
    }
    
    searchByKeyword(entries, keyword) {
        return entries.filter(e => e.message.toLowerCase().includes(keyword.toLowerCase()));
    }
}

class LogStatistics {
    constructor(entries) {
        this.entries = entries;
    }
    
    getTotalCount() {
        return this.entries.length;
    }
    
    getCountByLevel() {
        const counts = {};
        this.entries.forEach(e => {
            counts[e.level.name] = (counts[e.level.name] || 0) + 1;
        });
        return counts;
    }
    
    getErrorCount() {
        return this.entries.filter(e => 
            e.level === LogLevel.ERROR || e.level === LogLevel.FATAL
        ).length;
    }
    
    getSummary() {
        return {
            totalCount: this.getTotalCount(),
            countByLevel: this.getCountByLevel(),
            errorCount: this.getErrorCount()
        };
    }
}

// 使用示例
const logger = new Logger("MainActivity");
logger.debug("应用启动");
logger.info("初始化完成");
logger.warn("内存使用率较高");
logger.error("网络连接失败");

const stats = new LogStatistics(logger.getEntries());
console.log("日志统计:", stats.getSummary());

JavaScript 代码说明: JavaScript 版本是 Kotlin 代码的直接转译。使用对象模拟枚举,使用类实现日志功能。整体逻辑和算法与 Kotlin 版本保持一致,确保跨平台的一致性。


ArkTS 调用代码

// LoggerPage.ets
import { Logger, LogLevel, LogFilter, LogStatistics } from './Logger';

@Entry
@Component
struct LoggerPage {
    @State logOutput: string = '';
    @State filterLevel: string = 'ALL';
    @State searchKeyword: string = '';
    @State logHistory: string[] = [];
    @State statistics: string = '';
    @State enableColor: boolean = true;
    @State minLogLevel: string = 'DEBUG';
    
    private logger: Logger = new Logger("LoggerPage");
    private filter: LogFilter = new LogFilter();
    private logLevels = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'];
    private filterOptions = ['ALL', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'];
    
    addLog(level: string, message: string) {
        switch (level) {
            case 'DEBUG':
                this.logger.debug(message);
                break;
            case 'INFO':
                this.logger.info(message);
                break;
            case 'WARN':
                this.logger.warn(message);
                break;
            case 'ERROR':
                this.logger.error(message);
                break;
            case 'FATAL':
                this.logger.fatal(message);
                break;
        }
        this.updateLogDisplay();
    }
    
    updateLogDisplay() {
        const entries = this.logger.getEntries();
        this.logHistory = entries.map(e => 
            `[${e.timestamp}] [${e.level.name}] [${e.tag}] ${e.message}`
        );
        this.logOutput = this.logHistory.join('\n');
    }
    
    filterLogs() {
        const entries = this.logger.getEntries();
        let filtered = entries;
        
        if (this.filterLevel !== 'ALL') {
            filtered = this.filter.filterByLevel(filtered, this.filterLevel);
        }
        
        if (this.searchKeyword.length > 0) {
            filtered = this.filter.searchByKeyword(filtered, this.searchKeyword);
        }
        
        this.logHistory = filtered.map(e => 
            `[${e.timestamp}] [${e.level.name}] [${e.tag}] ${e.message}`
        );
        this.logOutput = this.logHistory.join('\n');
    }
    
    updateStatistics() {
        const stats = new LogStatistics(this.logger.getEntries());
        const summary = stats.getSummary();
        this.statistics = `总日志数: ${summary.totalCount}\n错误数: ${summary.errorCount}\n级别分布: ${JSON.stringify(summary.countByLevel)}`;
    }
    
    clearLogs() {
        this.logger.clearEntries();
        this.logOutput = '';
        this.logHistory = [];
        this.statistics = '';
    }
    
    build() {
        Column() {
            Text('日志生成工具')
                .fontSize(24)
                .fontWeight(FontWeight.Bold)
                .margin({ top: 20, bottom: 20 })
            
            // 日志级别选择
            Row() {
                Text('日志级别:')
                    .fontSize(12)
                    .fontColor('#666666')
                    .margin({ right: 10 })
                
                Select(this.logLevels)
                    .value('INFO')
                    .onSelect((index: number) => {
                        this.logger.setMinLevel(this.logLevels[index]);
                    })
                    .flex(1)
            }
            .margin({ bottom: 15 })
            .width('100%')
            
            // 快速日志按钮
            Row() {
                Button('Debug')
                    .flex(1)
                    .height(40)
                    .margin({ right: 5 })
                    .onClick(() => this.addLog('DEBUG', '调试信息'))
                
                Button('Info')
                    .flex(1)
                    .height(40)
                    .margin({ right: 5 })
                    .onClick(() => this.addLog('INFO', '一般信息'))
                
                Button('Warn')
                    .flex(1)
                    .height(40)
                    .margin({ right: 5 })
                    .onClick(() => this.addLog('WARN', '警告信息'))
                
                Button('Error')
                    .flex(1)
                    .height(40)
                    .onClick(() => this.addLog('ERROR', '错误信息'))
            }
            .margin({ bottom: 15 })
            .width('100%')
            
            // 过滤选项
            Row() {
                Text('过滤:')
                    .fontSize(12)
                    .fontColor('#666666')
                    .margin({ right: 10 })
                
                Select(this.filterOptions)
                    .value('ALL')
                    .onSelect((index: number) => {
                        this.filterLevel = this.filterOptions[index];
                        this.filterLogs();
                    })
                    .flex(1)
            }
            .margin({ bottom: 15 })
            .width('100%')
            
            // 搜索框
            Row() {
                TextInput({ placeholder: '搜索关键词' })
                    .value(this.searchKeyword)
                    .onChange((value: string) => {
                        this.searchKeyword = value;
                        this.filterLogs();
                    })
                    .flex(1)
                    .margin({ right: 10 })
                
                Button('统计')
                    .width(60)
                    .height(40)
                    .onClick(() => this.updateStatistics())
            }
            .margin({ bottom: 15 })
            .width('100%')
            
            // 日志显示区域
            Column() {
                Text('日志输出:')
                    .fontSize(14)
                    .fontWeight(FontWeight.Bold)
                    .margin({ bottom: 10 })
                
                Scroll() {
                    Text(this.logOutput)
                        .fontSize(11)
                        .fontColor('#333333')
                        .fontFamily('monospace')
                        .selectable(true)
                        .width('100%')
                        .padding(10)
                }
                .height(200)
                .width('100%')
                .backgroundColor('#f5f5f5')
                .borderRadius(4)
            }
            .width('100%')
            .margin({ bottom: 15 })
            
            // 统计信息
            if (this.statistics.length > 0) {
                Column() {
                    Text('统计信息:')
                        .fontSize(14)
                        .fontWeight(FontWeight.Bold)
                        .margin({ bottom: 10 })
                    
                    Text(this.statistics)
                        .fontSize(12)
                        .fontColor('#666666')
                        .width('100%')
                        .padding(10)
                        .backgroundColor('#fafafa')
                        .borderRadius(4)
                }
                .width('100%')
                .margin({ bottom: 15 })
            }
            
            // 操作按钮
            Row() {
                Button('刷新')
                    .flex(1)
                    .height(40)
                    .margin({ right: 10 })
                    .onClick(() => this.updateLogDisplay())
                
                Button('清空')
                    .flex(1)
                    .height(40)
                    .onClick(() => this.clearLogs())
            }
            .width('100%')
        }
        .padding(20)
        .width('100%')
        .height('100%')
        .backgroundColor('#ffffff')
    }
}

ArkTS 代码说明: 这个示例展示了如何在 ArkTS 中构建一个完整的日志管理用户界面。页面包含了日志级别选择、快速日志按钮、过滤选项、搜索框、日志显示区域和统计信息。用户可以快速添加不同级别的日志,并进行过滤和搜索。整个界面采用了现代化的设计,提供了良好的用户体验。


实战案例

案例 1: 应用启动日志

在应用启动时,记录各个阶段的日志,便于调试和性能分析。

val logger = Logger("App")
logger.info("应用启动开始")
logger.debug("初始化数据库")
logger.debug("加载配置文件")
logger.info("应用启动完成")

案例 2: 错误追踪

在发生错误时,记录详细的错误信息和堆栈跟踪。

val logger = Logger("NetworkManager")
try {
    // 网络操作
} catch (e: Exception) {
    logger.error("网络请求失败", e)
}

案例 3: 性能监控

记录关键操作的性能数据,用于性能分析。

val logger = Logger("PerformanceMonitor")
logger.info("开始数据库查询")
logger.debug("查询耗时: 150ms")
logger.warn("查询耗时超过100ms")

最佳实践

1. 日志级别选择

  • DEBUG:仅在开发时使用,记录详细的调试信息
  • INFO:记录重要的业务事件和状态变化
  • WARN:记录潜在的问题和异常情况
  • ERROR:记录错误和异常
  • FATAL:记录致命错误和系统崩溃

2. 日志内容

  • 简洁明了:日志信息应该清晰简洁
  • 包含上下文:提供足够的上下文信息
  • 避免敏感信息:不要记录密码、令牌等敏感信息
  • 使用结构化日志:使用统一的格式和标签

3. 性能考虑

  • 异步输出:对于高频日志,使用异步输出
  • 日志缓冲:使用缓冲减少 I/O 操作
  • 日志轮转:定期清理旧日志,防止日志文件过大
  • 条件日志:根据日志级别条件输出日志

4. 日志管理

  • 统一标签:为不同模块使用统一的标签
  • 日志搜索:提供日志搜索和过滤功能
  • 日志分析:定期分析日志,发现问题
  • 日志备份:定期备份重要的日志

5. 跨平台一致性

  • 统一格式:在所有平台上使用统一的日志格式
  • 一致的级别:在所有平台上使用相同的日志级别
  • 共享逻辑:使用 KMP 共享日志逻辑
  • 平台适配:根据平台特性进行适配

总结

日志生成工具是现代应用开发中的一个重要组件。通过使用 Kotlin Multiplatform,我们可以编写一次代码,然后在多个平台上运行,大大提高了开发效率和代码的可维护性。这个案例展示了如何实现多级别日志、灵活的格式化、日志过滤和统计等功能。

在实际应用中,应该根据具体的需求选择合适的日志级别和格式,并遵循最佳实践来确保日志的有效性和性能。同时,应该定期进行日志分析和优化,以提高应用的可维护性和可调试性。通过合理使用日志工具,我们可以为应用的开发、测试和运维提供强大的支持。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐