module hono import os import time import x.json2 // 日志级别枚举 pub enum LogLevel { debug = 0 info = 1 warn = 2 error = 3 } // 日志级别字符串映射 const log_level_strings = { LogLevel.debug: 'DEBUG' LogLevel.info: 'INFO' LogLevel.warn: 'WARN' LogLevel.error: 'ERROR' } // 日志输出类型 pub enum LogOutput { console file both } // 日志条目结构 pub struct LogEntry { pub mut: timestamp string level string message string module string function string file string line int fields map[string]string request_id string } // 日志配置 pub struct LoggerConfig { pub mut: level LogLevel = LogLevel.info output LogOutput = LogOutput.console file_path string = './logs/app.log' max_file_size u64 = 10 * 1024 * 1024 // 10MB max_backup_files int = 5 enable_colors bool = true enable_json bool time_format string = '2006-01-02 15:04:05' } // 日志器结构 pub struct Logger { pub mut: config LoggerConfig current_file_size u64 } // 创建新的日志器实例 pub fn new_logger(config LoggerConfig) &Logger { return &Logger{ config: config } } // 字符串转日志级别 pub fn parse_log_level(level_str string) LogLevel { match level_str.to_lower() { 'debug' { return LogLevel.debug } 'info' { return LogLevel.info } 'warn' { return LogLevel.warn } 'error' { return LogLevel.error } else { return LogLevel.info } } } // 日志级别转字符串 pub fn log_level_to_string(level LogLevel) string { return log_level_strings[level] or { 'INFO' } } // 检查日志级别是否应该输出 fn (l &Logger) should_log(level LogLevel) bool { return int(level) >= int(l.config.level) } // 格式化时间戳 fn format_timestamp() string { now := time.now() return now.format_ss() } // 获取ANSI颜色代码 fn get_color_code(level LogLevel) string { match level { .debug { return '\033[36m' } // 青色 .info { return '\033[32m' } // 绿色 .warn { return '\033[33m' } // 黄色 .error { return '\033[31m' } // 红色 } } // 重置ANSI颜色 const color_reset = '\033[0m' // 格式化日志消息(文本格式) fn (l &Logger) format_text_log(entry LogEntry) string { mut parts := []string{} // 时间戳 parts << '[${entry.timestamp}]' // 日志级别(带颜色) if l.config.enable_colors { color := get_color_code(parse_log_level(entry.level)) parts << '${color}${entry.level}${color_reset}' } else { parts << entry.level } // 模块信息 if entry.module != '' { parts << '[${entry.module}]' } // 消息 parts << entry.message // 附加字段 if entry.fields.len > 0 { mut field_parts := []string{} for key, value in entry.fields { field_parts << '${key}=${value}' } parts << '{${field_parts.join(', ')}}' } // 请求ID if entry.request_id != '' { parts << '[req:${entry.request_id}]' } return parts.join(' ') } // 格式化日志消息(JSON格式) fn (l &Logger) format_json_log(entry LogEntry) string { return json2.encode[LogEntry](entry) } // 写入日志到文件 fn (mut l Logger) write_to_file(content string) { // 确保日志目录存在 log_dir := os.dir(l.config.file_path) if !os.exists(log_dir) { os.mkdir_all(log_dir) or { eprintln('无法创建日志目录: ${err}') return } } // 检查文件大小,必要时轮转 if l.config.max_file_size > 0 { if os.exists(l.config.file_path) { file_size := os.file_size(l.config.file_path) if file_size >= l.config.max_file_size { l.rotate_log_file() } } } // 写入日志 mut file := os.open_append(l.config.file_path) or { eprintln('无法打开日志文件: ${err}') return } defer { file.close() } file.writeln(content) or { eprintln('无法写入日志文件: ${err}') } } // 轮转日志文件 fn (l &Logger) rotate_log_file() { // 删除最旧的备份文件 oldest_backup := '${l.config.file_path}.${l.config.max_backup_files}' if os.exists(oldest_backup) { os.rm(oldest_backup) or {} } // 移动现有备份文件 for i := l.config.max_backup_files - 1; i >= 1; i-- { old_file := '${l.config.file_path}.${i}' new_file := '${l.config.file_path}.${i + 1}' if os.exists(old_file) { os.mv(old_file, new_file) or {} } } // 移动当前日志文件为第一个备份 if os.exists(l.config.file_path) { backup_file := '${l.config.file_path}.1' os.mv(l.config.file_path, backup_file) or {} } } // 核心日志方法 fn (mut l Logger) log(level LogLevel, message string, mod_name string, fields map[string]string, request_id string) { if !l.should_log(level) { return } entry := LogEntry{ timestamp: format_timestamp() level: log_level_to_string(level) message: message module: mod_name fields: fields request_id: request_id } // 格式化日志内容 content := if l.config.enable_json { l.format_json_log(entry) } else { l.format_text_log(entry) } // 输出日志 match l.config.output { .console { println(content) } .file { l.write_to_file(content) } .both { println(content) l.write_to_file(content) } } } // 公共日志方法 pub fn (mut l Logger) debug(message string) { l.log(LogLevel.debug, message, '', {}, '') } pub fn (mut l Logger) info(message string) { l.log(LogLevel.info, message, '', {}, '') } pub fn (mut l Logger) warn(message string) { l.log(LogLevel.warn, message, '', {}, '') } pub fn (mut l Logger) error(message string) { l.log(LogLevel.error, message, '', {}, '') } // 带模块的日志方法 pub fn (mut l Logger) debug_with_module(message string, mod_name string) { l.log(LogLevel.debug, message, mod_name, {}, '') } pub fn (mut l Logger) info_with_module(message string, mod_name string) { l.log(LogLevel.info, message, mod_name, {}, '') } pub fn (mut l Logger) warn_with_module(message string, mod_name string) { l.log(LogLevel.warn, message, mod_name, {}, '') } pub fn (mut l Logger) error_with_module(message string, mod_name string) { l.log(LogLevel.error, message, mod_name, {}, '') } // 带字段的日志方法 pub fn (mut l Logger) debug_with_fields(message string, fields map[string]string) { l.log(LogLevel.debug, message, '', fields, '') } pub fn (mut l Logger) info_with_fields(message string, fields map[string]string) { l.log(LogLevel.info, message, '', fields, '') } pub fn (mut l Logger) warn_with_fields(message string, fields map[string]string) { l.log(LogLevel.warn, message, '', fields, '') } pub fn (mut l Logger) error_with_fields(message string, fields map[string]string) { l.log(LogLevel.error, message, '', fields, '') } // 带请求ID的日志方法 pub fn (mut l Logger) debug_with_request(message string, request_id string) { l.log(LogLevel.debug, message, '', {}, request_id) } pub fn (mut l Logger) info_with_request(message string, request_id string) { l.log(LogLevel.info, message, '', {}, request_id) } pub fn (mut l Logger) warn_with_request(message string, request_id string) { l.log(LogLevel.warn, message, '', {}, request_id) } pub fn (mut l Logger) error_with_request(message string, request_id string) { l.log(LogLevel.error, message, '', {}, request_id) } // 完整的日志方法 pub fn (mut l Logger) log_full(level LogLevel, message string, mod_name string, fields map[string]string, request_id string) { l.log(level, message, mod_name, fields, request_id) } // HTTP请求日志结构 pub struct RequestLog { pub mut: method string path string status_code int response_time f64 // 毫秒 user_agent string remote_addr string request_size u64 response_size u64 request_id string } // 记录HTTP请求日志 pub fn log_request(mut logger Logger, req_log RequestLog) { fields := { 'method': req_log.method 'path': req_log.path 'status': req_log.status_code.str() 'response_time': '${req_log.response_time:.2f}ms' 'user_agent': req_log.user_agent 'remote_addr': req_log.remote_addr 'request_size': req_log.request_size.str() 'response_size': req_log.response_size.str() } message := '${req_log.method} ${req_log.path} ${req_log.status_code} ${req_log.response_time:.2f}ms' logger.log_full(LogLevel.info, message, 'HTTP', fields, req_log.request_id) } // 性能监控日志 pub fn log_performance(mut logger Logger, operation string, duration f64, details map[string]string) { mut fields := { 'operation': operation 'duration': '${duration:.2f}ms' } // 合并详细信息 for key, value in details { fields[key] = value } message := '性能监控: ${operation} 耗时 ${duration:.2f}ms' logger.log_full(LogLevel.info, message, 'PERF', fields, '') } // 错误日志(带堆栈信息) pub fn log_error_with_stack(mut logger Logger, message string, err_details string, mod_name string) { fields := { 'error_details': err_details 'stack_trace': 'V语言暂不支持堆栈跟踪' } logger.log_full(LogLevel.error, message, mod_name, fields, '') }