From a655640ab25362d99a41be58fdaeb857969bbb46 Mon Sep 17 00:00:00 2001 From: Jimmy Xue Date: Sun, 30 Nov 2025 13:43:43 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8C=85=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 33 ++-- SETUP.md | 4 +- config/config.go | 36 +++- config/example.json | 7 + docs/README.md | 15 +- docs/config.md | 24 ++- docs/datetime.md | 6 +- docs/email.md | 10 +- docs/factory.md | 32 +++- docs/http.md | 4 +- docs/logger.md | 266 ++++++++++++++++++++++++++++ docs/middleware.md | 30 ++-- docs/migration.md | 2 +- docs/sms.md | 10 +- docs/storage.md | 22 +-- email/email.go | 2 +- examples/config_example.go | 4 +- examples/datetime_example.go | 2 +- examples/datetime_utc_example.go | 2 +- examples/email_example.go | 4 +- examples/factory_example.go | 4 +- examples/http_example.go | 2 +- examples/logger_example.go | 52 ++++++ examples/middleware_example.go | 6 +- examples/migration_example.go | 2 +- examples/migration_reset_example.go | 2 +- examples/sms_example.go | 4 +- examples/storage_example.go | 6 +- factory/factory.go | 17 +- go.mod | 2 +- http/request.go | 2 +- logger/logger.go | 207 ++++++++++++++++++++++ middleware/timezone.go | 2 +- sms/sms.go | 2 +- storage/handler.go | 2 +- storage/minio.go | 2 +- storage/oss.go | 2 +- storage/storage.go | 2 +- 38 files changed, 729 insertions(+), 104 deletions(-) create mode 100644 docs/logger.md create mode 100644 examples/logger_example.go create mode 100644 logger/logger.go diff --git a/README.md b/README.md index 29f0d9d..5cad687 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,9 @@ ### 9. 工厂工具 (factory) 提供从配置直接创建已初始化客户端对象的功能,避免调用方重复实现创建逻辑。 +### 10. 日志工具 (logger) +提供统一的日志记录功能,支持多种日志级别和输出方式,使用Go标准库实现。 + ## 安装 ### 1. 配置私有仓库(重要) @@ -50,7 +53,7 @@ go env GOPRIVATE ### 2. 安装模块 ```bash -go get git.toowon.com/jimmy/go-commom +go get git.toowon.com/jimmy/go-common ``` ## 使用示例 @@ -65,12 +68,13 @@ go get git.toowon.com/jimmy/go-commom - [邮件工具文档](./docs/email.md) - [短信工具文档](./docs/sms.md) - [工厂工具文档](./docs/factory.md) +- [日志工具文档](./docs/logger.md) ### 快速示例 #### 数据库迁移 ```go -import "git.toowon.com/jimmy/go-commom/migration" +import "git.toowon.com/jimmy/go-common/migration" migrator := migration.NewMigrator(db) migrator.AddMigration(migration.Migration{ @@ -85,7 +89,7 @@ migrator.Up() #### 日期转换 ```go -import "git.toowon.com/jimmy/go-commom/datetime" +import "git.toowon.com/jimmy/go-common/datetime" datetime.SetDefaultTimeZone(datetime.AsiaShanghai) now := datetime.Now() @@ -94,7 +98,7 @@ str := datetime.FormatDateTime(now) #### HTTP响应 ```go -import "git.toowon.com/jimmy/go-commom/http" +import "git.toowon.com/jimmy/go-common/http" http.Success(w, data) http.SuccessPage(w, list, total, page, pageSize) @@ -104,8 +108,8 @@ http.Error(w, 1001, "业务错误") #### 中间件 ```go import ( - "git.toowon.com/jimmy/go-commom/middleware" - "git.toowon.com/jimmy/go-commom/http" + "git.toowon.com/jimmy/go-common/middleware" + "git.toowon.com/jimmy/go-common/http" ) // CORS + 时区中间件 @@ -121,7 +125,7 @@ timezone := http.GetTimezone(r) #### 配置管理 ```go -import "git.toowon.com/jimmy/go-commom/config" +import "git.toowon.com/jimmy/go-common/config" // 从文件加载配置 cfg, err := config.LoadFromFile("./config.json") @@ -134,7 +138,7 @@ corsConfig := cfg.GetCORS() #### 文件上传和查看 ```go -import "git.toowon.com/jimmy/go-commom/storage" +import "git.toowon.com/jimmy/go-common/storage" // 创建存储实例 storage, _ := storage.NewStorage(storage.StorageTypeOSS, cfg) @@ -152,7 +156,7 @@ proxyHandler := storage.NewProxyHandler(storage) #### 邮件发送 ```go -import "git.toowon.com/jimmy/go-commom/email" +import "git.toowon.com/jimmy/go-common/email" // 从配置创建邮件发送器 mailer, _ := email.NewEmail(cfg.GetEmail()) @@ -167,7 +171,7 @@ mailer.SendSimple( #### 短信发送 ```go -import "git.toowon.com/jimmy/go-commom/sms" +import "git.toowon.com/jimmy/go-common/sms" // 从配置创建短信发送器 smsClient, _ := sms.NewSMS(cfg.GetSMS()) @@ -182,8 +186,8 @@ smsClient.SendSimple( #### 使用工厂直接获取客户端(推荐) ```go import ( - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/factory" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/factory" ) // 加载配置并创建工厂 @@ -197,6 +201,11 @@ smsClient, _ := fac.GetSMSClient() // 直接使用 emailClient.SendSimple(...) smsClient.SendSimple(...) + +// 获取日志记录器(已初始化,可直接使用) +logger, _ := fac.GetLogger() +logger.Info("Application started") +logger.Error("Error occurred: %v", err) ``` 更多示例请查看 [examples](./examples/) 目录。 diff --git a/SETUP.md b/SETUP.md index 8ea75c9..bf255a4 100644 --- a/SETUP.md +++ b/SETUP.md @@ -130,7 +130,7 @@ go env -w GONOSUMDB=git.toowon.com 2. 确认 Git 认证已配置 3. 尝试手动克隆仓库验证: ```bash - git clone git@git.toowon.com:jimmy/go-commom.git + git clone git@git.toowon.com:jimmy/go-common.git ``` #### 问题2:go mod download 失败 @@ -164,7 +164,7 @@ git config --global url."git@git.toowon.com:".insteadOf "https://git.toowon.com/ go env | grep GOPRIVATE # 4. 测试模块下载 -go get git.toowon.com/jimmy/go-commom@latest +go get git.toowon.com/jimmy/go-common@latest ``` ### 参考文档 diff --git a/config/config.go b/config/config.go index ce04d9f..c22db8d 100644 --- a/config/config.go +++ b/config/config.go @@ -6,7 +6,7 @@ import ( "os" "path/filepath" - "git.toowon.com/jimmy/go-commom/middleware" + "git.toowon.com/jimmy/go-common/middleware" ) // Config 应用配置 @@ -18,6 +18,7 @@ type Config struct { MinIO *MinIOConfig `json:"minio"` Email *EmailConfig `json:"email"` SMS *SMSConfig `json:"sms"` + Logger *LoggerConfig `json:"logger"` } // DatabaseConfig 数据库配置 @@ -218,6 +219,24 @@ type SMSConfig struct { Timeout int `json:"timeout"` } +// LoggerConfig 日志配置 +type LoggerConfig struct { + // Level 日志级别: debug, info, warn, error + Level string `json:"level"` + + // Output 输出方式: stdout, stderr, file, both + Output string `json:"output"` + + // FilePath 日志文件路径(当output为file或both时必需) + FilePath string `json:"filePath"` + + // Prefix 日志前缀 + Prefix string `json:"prefix"` + + // DisableTimestamp 禁用时间戳 + DisableTimestamp bool `json:"disableTimestamp"` +} + // LoadFromFile 从文件加载配置 // filePath: 配置文件路径(支持绝对路径和相对路径) func LoadFromFile(filePath string) (*Config, error) { @@ -342,6 +361,16 @@ func (c *Config) setDefaults() { c.SMS.Timeout = 10 } } + + // 日志默认值 + if c.Logger != nil { + if c.Logger.Level == "" { + c.Logger.Level = "info" + } + if c.Logger.Output == "" { + c.Logger.Output = "stdout" + } + } } // GetDatabase 获取数据库配置 @@ -390,6 +419,11 @@ func (c *Config) GetSMS() *SMSConfig { return c.SMS } +// GetLogger 获取日志配置 +func (c *Config) GetLogger() *LoggerConfig { + return c.Logger +} + // GetDatabaseDSN 获取数据库连接字符串 func (c *Config) GetDatabaseDSN() (string, error) { if c.Database == nil { diff --git a/config/example.json b/config/example.json index ba35d26..5c6b021 100644 --- a/config/example.json +++ b/config/example.json @@ -69,6 +69,13 @@ "templateCode": "SMS_123456789", "endpoint": "", "timeout": 10 + }, + "logger": { + "level": "info", + "output": "stdout", + "filePath": "", + "prefix": "app", + "disableTimestamp": false } } diff --git a/docs/README.md b/docs/README.md index a61aad8..8c83d20 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,13 +11,14 @@ - [邮件工具](./email.md) - SMTP邮件发送 - [短信工具](./sms.md) - 阿里云短信发送 - [工厂工具](./factory.md) - 从配置直接创建已初始化客户端对象 +- [日志工具](./logger.md) - 统一的日志记录功能 ## 快速开始 ### 安装 ```bash -go get git.toowon.com/jimmy/go-commom +go get git.toowon.com/jimmy/go-common ``` ### 使用示例 @@ -25,7 +26,7 @@ go get git.toowon.com/jimmy/go-commom #### 数据库迁移 ```go -import "git.toowon.com/jimmy/go-commom/migration" +import "git.toowon.com/jimmy/go-common/migration" migrator := migration.NewMigrator(db) migrator.AddMigration(migration.Migration{ @@ -41,7 +42,7 @@ migrator.Up() #### 日期转换 ```go -import "git.toowon.com/jimmy/go-commom/datetime" +import "git.toowon.com/jimmy/go-common/datetime" datetime.SetDefaultTimeZone(datetime.AsiaShanghai) now := datetime.Now() @@ -51,7 +52,7 @@ str := datetime.FormatDateTime(now) #### HTTP响应 ```go -import "git.toowon.com/jimmy/go-commom/http" +import "git.toowon.com/jimmy/go-common/http" http.Success(w, data) http.SuccessPage(w, list, total, page, pageSize) @@ -62,8 +63,8 @@ http.Error(w, 1001, "业务错误") ```go import ( - "git.toowon.com/jimmy/go-commom/middleware" - "git.toowon.com/jimmy/go-commom/http" + "git.toowon.com/jimmy/go-common/middleware" + "git.toowon.com/jimmy/go-common/http" ) // CORS + 时区中间件 @@ -80,7 +81,7 @@ timezone := http.GetTimezone(r) #### 配置管理 ```go -import "git.toowon.com/jimmy/go-commom/config" +import "git.toowon.com/jimmy/go-common/config" // 从文件加载配置 cfg, err := config.LoadFromFile("./config.json") diff --git a/docs/config.md b/docs/config.md index 9b39d05..5dfb998 100644 --- a/docs/config.md +++ b/docs/config.md @@ -103,7 +103,7 @@ ### 1. 加载配置文件 ```go -import "git.toowon.com/jimmy/go-commom/config" +import "git.toowon.com/jimmy/go-common/config" // 从文件加载配置(支持绝对路径和相对路径) config, err := config.LoadFromFile("/path/to/config.json") @@ -167,7 +167,7 @@ addr := config.GetRedisAddr() corsConfig := config.GetCORS() // 使用CORS中间件 -import "git.toowon.com/jimmy/go-commom/middleware" +import "git.toowon.com/jimmy/go-common/middleware" chain := middleware.NewChain( middleware.CORS(corsConfig), ) @@ -279,6 +279,16 @@ if minioConfig != nil { | Endpoint | string | 服务端点(可选,默认使用区域端点) | - | | Timeout | int | 请求超时时间(秒) | 10 | +### LoggerConfig 日志配置 + +| 字段 | 类型 | 说明 | 默认值 | +|------|------|------|--------| +| Level | string | 日志级别: debug, info, warn, error | info | +| Output | string | 输出方式: stdout, stderr, file, both | stdout | +| FilePath | string | 日志文件路径(当output为file或both时必需) | - | +| Prefix | string | 日志前缀 | - | +| DisableTimestamp | bool | 禁用时间戳 | false | + ## 完整示例 ### 示例1:加载配置并使用 @@ -289,8 +299,8 @@ package main import ( "log" - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/middleware" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/middleware" "gorm.io/driver/mysql" "gorm.io/gorm" ) @@ -466,6 +476,12 @@ dsn, err := cfg.GetDatabaseDSN() **返回:** 短信配置对象(可能为nil) +### (c *Config) GetLogger() *LoggerConfig + +获取日志配置。 + +**返回:** 日志配置对象(可能为nil) + ## 注意事项 1. **配置文件路径**: diff --git a/docs/datetime.md b/docs/datetime.md index 90a1c83..2a5510e 100644 --- a/docs/datetime.md +++ b/docs/datetime.md @@ -19,7 +19,7 @@ ### 1. 设置默认时区 ```go -import "git.toowon.com/jimmy/go-commom/datetime" +import "git.toowon.com/jimmy/go-common/datetime" // 设置默认时区为上海时区 err := datetime.SetDefaultTimeZone(datetime.AsiaShanghai) @@ -401,7 +401,7 @@ import ( "log" "time" - "git.toowon.com/jimmy/go-commom/datetime" + "git.toowon.com/jimmy/go-common/datetime" ) func main() { @@ -428,7 +428,7 @@ import ( "fmt" "log" - "git.toowon.com/jimmy/go-commom/datetime" + "git.toowon.com/jimmy/go-common/datetime" ) func main() { diff --git a/docs/email.md b/docs/email.md index a6a52cf..bb28d5a 100644 --- a/docs/email.md +++ b/docs/email.md @@ -18,8 +18,8 @@ ```go import ( - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/email" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/email" ) // 从配置加载 @@ -107,7 +107,7 @@ if err != nil { ### 5. 使用Message结构发送(便捷方法) ```go -import "git.toowon.com/jimmy/go-commom/email" +import "git.toowon.com/jimmy/go-common/email" msg := &email.Message{ To: []string{"to@example.com"}, @@ -295,8 +295,8 @@ package main import ( "log" - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/email" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/email" ) func main() { diff --git a/docs/factory.md b/docs/factory.md index 5e784f4..4e35230 100644 --- a/docs/factory.md +++ b/docs/factory.md @@ -16,8 +16,8 @@ ```go import ( - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/factory" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/factory" ) // 加载配置 @@ -63,7 +63,21 @@ resp, err := smsClient.SendSimple( ) ``` -### 4. 完整示例 +### 4. 获取日志记录器(已初始化) + +```go +// 直接获取已初始化的日志记录器 +logger, err := fac.GetLogger() +if err != nil { + log.Fatal(err) +} + +// 直接使用,无需再创建 +logger.Info("Application started") +logger.Error("Error occurred: %v", err) +``` + +### 5. 完整示例 ```go package main @@ -71,8 +85,8 @@ package main import ( "log" - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/factory" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/factory" ) func main() { @@ -152,6 +166,14 @@ func main() { **说明:** 如果短信配置为nil,返回错误。 +### (f *Factory) GetLogger() (*logger.Logger, error) + +获取日志记录器(已初始化)。 + +**返回:** 已初始化的日志记录器对象和错误信息 + +**说明:** 如果日志配置为nil,会使用默认配置创建。 + ### (f *Factory) GetConfig() *config.Config 获取配置对象。 diff --git a/docs/http.md b/docs/http.md index 3559c51..b75d52b 100644 --- a/docs/http.md +++ b/docs/http.md @@ -49,7 +49,7 @@ HTTP Restful工具提供了标准化的HTTP请求和响应处理功能,包含 ```go import ( "net/http" - "git.toowon.com/jimmy/go-commom/http" + "git.toowon.com/jimmy/go-common/http" ) // 简单成功响应(data为nil) @@ -198,7 +198,7 @@ package main import ( "net/http" - "git.toowon.com/jimmy/go-commom/http" + "git.toowon.com/jimmy/go-common/http" ) // 用户列表接口 diff --git a/docs/logger.md b/docs/logger.md new file mode 100644 index 0000000..5b77f2c --- /dev/null +++ b/docs/logger.md @@ -0,0 +1,266 @@ +# 日志工具文档 + +## 概述 + +日志工具提供了统一的日志记录功能,使用Go标准库实现,无需第三方依赖。 + +## 功能特性 + +- 支持多种日志级别(debug, info, warn, error) +- 支持多种输出方式(stdout, stderr, file, both) +- 支持日志文件自动创建 +- 支持日志前缀 +- 支持禁用时间戳 +- 支持带字段的日志记录 +- 使用配置工具统一管理配置 + +## 使用方法 + +### 1. 从配置创建日志记录器(推荐) + +```go +import ( + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/factory" +) + +// 加载配置 +cfg, err := config.LoadFromFile("./config.json") +if err != nil { + log.Fatal(err) +} + +// 使用工厂创建日志记录器(已初始化,可直接使用) +fac := factory.NewFactory(cfg) +logger, err := fac.GetLogger() +if err != nil { + log.Fatal(err) +} + +// 直接使用 +logger.Info("Application started") +logger.Error("Failed to connect: %v", err) +``` + +### 2. 直接创建日志记录器 + +```go +import ( + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/logger" +) + +// 从配置获取日志配置 +cfg, _ := config.LoadFromFile("./config.json") +loggerConfig := cfg.GetLogger() + +// 创建日志记录器 +logger, err := logger.NewLogger(loggerConfig) +if err != nil { + log.Fatal(err) +} + +// 使用默认配置(如果loggerConfig为nil) +logger, err := logger.NewLogger(nil) +``` + +### 3. 基本日志记录 + +```go +// 记录不同级别的日志 +logger.Debug("Debug message: %s", "debug info") +logger.Info("Info message: %s", "info") +logger.Warn("Warning message: %s", "warning") +logger.Error("Error message: %s", "error") + +// 致命错误(会退出程序) +logger.Fatal("Fatal error: %s", "fatal") + +// 恐慌错误(会触发panic) +logger.Panic("Panic error: %s", "panic") +``` + +### 4. 带字段的日志记录 + +```go +// 记录带字段的日志 +fields := map[string]interface{}{ + "user_id": 123, + "action": "login", +} +logger.Infof(fields, "User logged in") +logger.Errorf(fields, "Failed to process request") +``` + +## API 参考 + +### NewLogger(cfg *config.LoggerConfig) (*Logger, error) + +创建日志记录器。 + +**参数:** +- `cfg`: 日志配置对象(如果为nil,使用默认配置) + +**返回:** 日志记录器实例和错误信息 + +### (l *Logger) Debug(format string, v ...interface{}) + +记录调试日志。 + +### (l *Logger) Info(format string, v ...interface{}) + +记录信息日志。 + +### (l *Logger) Warn(format string, v ...interface{}) + +记录警告日志。 + +### (l *Logger) Error(format string, v ...interface{}) + +记录错误日志。 + +### (l *Logger) Fatal(format string, v ...interface{}) + +记录致命错误日志并退出程序。 + +### (l *Logger) Panic(format string, v ...interface{}) + +记录恐慌日志并触发panic。 + +### (l *Logger) Debugf(fields map[string]interface{}, format string, v ...interface{}) + +记录调试日志(带字段)。 + +### (l *Logger) Infof(fields map[string]interface{}, format string, v ...interface{}) + +记录信息日志(带字段)。 + +### (l *Logger) Warnf(fields map[string]interface{}, format string, v ...interface{}) + +记录警告日志(带字段)。 + +### (l *Logger) Errorf(fields map[string]interface{}, format string, v ...interface{}) + +记录错误日志(带字段)。 + +## 配置说明 + +日志配置通过 `config.LoggerConfig` 提供: + +| 字段 | 类型 | 说明 | 默认值 | +|------|------|------|--------| +| Level | string | 日志级别: debug, info, warn, error | info | +| Output | string | 输出方式: stdout, stderr, file, both | stdout | +| FilePath | string | 日志文件路径(当output为file或both时必需) | - | +| Prefix | string | 日志前缀 | - | +| DisableTimestamp | bool | 禁用时间戳 | false | + +## 配置示例 + +### 输出到标准输出 + +```json +{ + "logger": { + "level": "info", + "output": "stdout", + "prefix": "app" + } +} +``` + +### 输出到文件 + +```json +{ + "logger": { + "level": "debug", + "output": "file", + "filePath": "./logs/app.log", + "prefix": "app" + } +} +``` + +### 同时输出到标准输出和文件 + +```json +{ + "logger": { + "level": "info", + "output": "both", + "filePath": "./logs/app.log", + "prefix": "app", + "disableTimestamp": false + } +} +``` + +## 日志级别说明 + +- **debug**: 调试信息,最详细的日志级别 +- **info**: 一般信息,正常的程序运行信息 +- **warn**: 警告信息,可能的问题但不影响程序运行 +- **error**: 错误信息,程序运行中的错误 + +## 注意事项 + +1. **文件路径**: + - 当output为`file`或`both`时,必须提供`filePath` + - 日志文件目录会自动创建(如果不存在) + +2. **日志级别**: + - 设置为`debug`时,会记录所有级别的日志 + - 设置为`info`时,会记录info、warn、error级别的日志 + - 设置为`warn`时,只记录warn和error级别的日志 + - 设置为`error`时,只记录error级别的日志 + +3. **文件权限**: + - 日志文件创建时使用0666权限 + - 目录创建时使用0755权限 + +4. **性能考虑**: + - 使用标准库log包,性能较好 + - 文件输出使用追加模式,不会覆盖已有日志 + +## 完整示例 + +```go +package main + +import ( + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/factory" +) + +func main() { + // 加载配置 + cfg, err := config.LoadFromFile("./config.json") + if err != nil { + log.Fatal(err) + } + + // 使用工厂创建日志记录器 + fac := factory.NewFactory(cfg) + logger, err := fac.GetLogger() + if err != nil { + log.Fatal(err) + } + + // 使用日志记录器 + logger.Info("Application started") + + // 记录带字段的日志 + logger.Infof(map[string]interface{}{ + "user_id": 123, + "action": "login", + }, "User logged in successfully") + + logger.Error("An error occurred: %v", err) +} +``` + +## 示例 + +完整示例请参考 `examples/logger_example.go` + diff --git a/docs/middleware.md b/docs/middleware.md index 416a1bc..e4c0679 100644 --- a/docs/middleware.md +++ b/docs/middleware.md @@ -29,7 +29,7 @@ CORS中间件用于处理跨域资源共享,支持: ```go import ( "net/http" - "git.toowon.com/jimmy/go-commom/middleware" + "git.toowon.com/jimmy/go-common/middleware" ) func main() { @@ -50,7 +50,7 @@ func main() { ```go import ( "net/http" - "git.toowon.com/jimmy/go-commom/middleware" + "git.toowon.com/jimmy/go-common/middleware" ) func main() { @@ -131,9 +131,9 @@ corsHandler := middleware.CORS(corsConfig)(handler) ```go import ( "net/http" - "git.toowon.com/jimmy/go-commom/middleware" - "git.toowon.com/jimmy/go-commom/http" - "git.toowon.com/jimmy/go-commom/datetime" + "git.toowon.com/jimmy/go-common/middleware" + "git.toowon.com/jimmy/go-common/http" + "git.toowon.com/jimmy/go-common/datetime" ) func handler(w http.ResponseWriter, r *http.Request) { @@ -162,8 +162,8 @@ func main() { ```go import ( "net/http" - "git.toowon.com/jimmy/go-commom/middleware" - "git.toowon.com/jimmy/go-commom/datetime" + "git.toowon.com/jimmy/go-common/middleware" + "git.toowon.com/jimmy/go-common/datetime" ) func handler(w http.ResponseWriter, r *http.Request) { @@ -183,8 +183,8 @@ func main() { ```go import ( "net/http" - "git.toowon.com/jimmy/go-commom/http" - "git.toowon.com/jimmy/go-commom/datetime" + "git.toowon.com/jimmy/go-common/http" + "git.toowon.com/jimmy/go-common/datetime" ) func GetUserList(w http.ResponseWriter, r *http.Request) { @@ -240,7 +240,7 @@ X-Timezone: Asia/Shanghai ```go import ( "net/http" - "git.toowon.com/jimmy/go-commom/middleware" + "git.toowon.com/jimmy/go-common/middleware" ) func handler(w http.ResponseWriter, r *http.Request) { @@ -282,9 +282,9 @@ import ( "log" "net/http" - "git.toowon.com/jimmy/go-commom/middleware" - "git.toowon.com/jimmy/go-commom/http" - "git.toowon.com/jimmy/go-commom/datetime" + "git.toowon.com/jimmy/go-common/middleware" + "git.toowon.com/jimmy/go-common/http" + "git.toowon.com/jimmy/go-common/datetime" ) func apiHandler(w http.ResponseWriter, r *http.Request) { @@ -331,8 +331,8 @@ package main import ( "net/http" - "git.toowon.com/jimmy/go-commom/middleware" - "git.toowon.com/jimmy/go-commom/http" + "git.toowon.com/jimmy/go-common/middleware" + "git.toowon.com/jimmy/go-common/http" ) func main() { diff --git a/docs/migration.md b/docs/migration.md index 6c63a7f..d67f389 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -21,7 +21,7 @@ import ( "gorm.io/driver/mysql" "gorm.io/gorm" - "git.toowon.com/jimmy/go-commom/migration" + "git.toowon.com/jimmy/go-common/migration" ) // 初始化数据库连接 diff --git a/docs/sms.md b/docs/sms.md index 75ca96e..c858017 100644 --- a/docs/sms.md +++ b/docs/sms.md @@ -19,8 +19,8 @@ ```go import ( - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/sms" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/sms" ) // 从配置加载 @@ -102,7 +102,7 @@ if err != nil { ### 5. 使用SendRequest结构发送(便捷方法) ```go -import "git.toowon.com/jimmy/go-commom/sms" +import "git.toowon.com/jimmy/go-common/sms" req := &sms.SendRequest{ PhoneNumbers: []string{"13800138000", "13900139000"}, @@ -329,8 +329,8 @@ import ( "fmt" "log" - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/sms" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/sms" ) func main() { diff --git a/docs/storage.md b/docs/storage.md index 6b03175..0075c63 100644 --- a/docs/storage.md +++ b/docs/storage.md @@ -21,8 +21,8 @@ ```go import ( - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/storage" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/storage" ) // 加载配置 @@ -50,7 +50,7 @@ if err != nil { import ( "context" "os" - "git.toowon.com/jimmy/go-commom/storage" + "git.toowon.com/jimmy/go-common/storage" ) // 打开文件 @@ -81,7 +81,7 @@ fmt.Printf("File URL: %s\n", url) ```go import ( "net/http" - "git.toowon.com/jimmy/go-commom/storage" + "git.toowon.com/jimmy/go-common/storage" ) // 创建上传处理器 @@ -125,7 +125,7 @@ curl -X POST http://localhost:8080/upload \ ```go import ( "net/http" - "git.toowon.com/jimmy/go-commom/storage" + "git.toowon.com/jimmy/go-common/storage" ) // 创建代理查看处理器 @@ -144,7 +144,7 @@ GET /file?key=images/test.jpg ### 5. 生成对象键 ```go -import "git.toowon.com/jimmy/go-commom/storage" +import "git.toowon.com/jimmy/go-common/storage" // 生成简单对象键 objectKey := storage.GenerateObjectKey("images/", "test.jpg") @@ -288,9 +288,9 @@ import ( "log" "net/http" - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/middleware" - "git.toowon.com/jimmy/go-commom/storage" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/middleware" + "git.toowon.com/jimmy/go-common/storage" ) func main() { @@ -344,8 +344,8 @@ import ( "log" "os" - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/storage" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/storage" ) func main() { diff --git a/email/email.go b/email/email.go index 8c852f5..a703e9d 100644 --- a/email/email.go +++ b/email/email.go @@ -8,7 +8,7 @@ import ( "net/smtp" "time" - "git.toowon.com/jimmy/go-commom/config" + "git.toowon.com/jimmy/go-common/config" ) // Email 邮件发送器 diff --git a/examples/config_example.go b/examples/config_example.go index 0054005..853b9d7 100644 --- a/examples/config_example.go +++ b/examples/config_example.go @@ -4,8 +4,8 @@ import ( "fmt" "log" - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/middleware" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/middleware" // "gorm.io/driver/mysql" // "gorm.io/gorm" ) diff --git a/examples/datetime_example.go b/examples/datetime_example.go index 4cc93d6..a8119e0 100644 --- a/examples/datetime_example.go +++ b/examples/datetime_example.go @@ -5,7 +5,7 @@ import ( "log" "time" - "git.toowon.com/jimmy/go-commom/datetime" + "git.toowon.com/jimmy/go-common/datetime" ) func main() { diff --git a/examples/datetime_utc_example.go b/examples/datetime_utc_example.go index 36d9804..5547781 100644 --- a/examples/datetime_utc_example.go +++ b/examples/datetime_utc_example.go @@ -5,7 +5,7 @@ import ( "log" "time" - "git.toowon.com/jimmy/go-commom/datetime" + "git.toowon.com/jimmy/go-common/datetime" ) func main() { diff --git a/examples/email_example.go b/examples/email_example.go index 0b759da..0aeeb03 100644 --- a/examples/email_example.go +++ b/examples/email_example.go @@ -4,8 +4,8 @@ import ( "fmt" "log" - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/email" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/email" ) func main() { diff --git a/examples/factory_example.go b/examples/factory_example.go index dba3dec..5fc5c67 100644 --- a/examples/factory_example.go +++ b/examples/factory_example.go @@ -4,8 +4,8 @@ import ( "fmt" "log" - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/factory" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/factory" ) func main() { diff --git a/examples/http_example.go b/examples/http_example.go index 9043bb3..8e7d490 100644 --- a/examples/http_example.go +++ b/examples/http_example.go @@ -4,7 +4,7 @@ import ( "log" "net/http" - "git.toowon.com/jimmy/go-commom/http" + "git.toowon.com/jimmy/go-common/http" ) // 用户结构 diff --git a/examples/logger_example.go b/examples/logger_example.go new file mode 100644 index 0000000..8c23129 --- /dev/null +++ b/examples/logger_example.go @@ -0,0 +1,52 @@ +package main + +import ( + "log" + + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/factory" +) + +func main() { + // 加载配置 + cfg, err := config.LoadFromFile("./config/example.json") + if err != nil { + log.Fatal("Failed to load config:", err) + } + + // 使用工厂创建日志记录器(推荐方式) + fac := factory.NewFactory(cfg) + logger, err := fac.GetLogger() + if err != nil { + log.Fatal("Failed to create logger:", err) + } + + // 示例1:基本日志记录 + logger.Info("Application started") + logger.Debug("Debug message: %s", "This is a debug message") + logger.Warn("Warning message: %s", "This is a warning") + logger.Error("Error message: %s", "This is an error") + + // 示例2:带字段的日志记录 + logger.Infof(map[string]interface{}{ + "user_id": 123, + "action": "login", + "ip": "192.168.1.1", + }, "User logged in successfully") + + logger.Errorf(map[string]interface{}{ + "error_code": 1001, + "module": "database", + }, "Failed to connect to database: %v", "connection timeout") + + // 示例3:不同级别的日志 + logger.Debug("This is a debug log") + logger.Info("This is an info log") + logger.Warn("This is a warn log") + logger.Error("This is an error log") + + // 注意:Fatal和Panic会终止程序,示例中不执行 + // logger.Fatal("This would exit the program") + // logger.Panic("This would panic") +} + diff --git a/examples/middleware_example.go b/examples/middleware_example.go index 47dc890..6e6adc3 100644 --- a/examples/middleware_example.go +++ b/examples/middleware_example.go @@ -4,9 +4,9 @@ import ( "log" "net/http" - "git.toowon.com/jimmy/go-commom/datetime" - "git.toowon.com/jimmy/go-commom/http" - "git.toowon.com/jimmy/go-commom/middleware" + "git.toowon.com/jimmy/go-common/datetime" + "git.toowon.com/jimmy/go-common/http" + "git.toowon.com/jimmy/go-common/middleware" ) // 示例:使用CORS和时区中间件 diff --git a/examples/migration_example.go b/examples/migration_example.go index efb44e4..c9bfb0f 100644 --- a/examples/migration_example.go +++ b/examples/migration_example.go @@ -6,7 +6,7 @@ import ( "gorm.io/driver/mysql" "gorm.io/gorm" - "git.toowon.com/jimmy/go-commom/migration" + "git.toowon.com/jimmy/go-common/migration" ) func main() { diff --git a/examples/migration_reset_example.go b/examples/migration_reset_example.go index b509931..ad211c9 100644 --- a/examples/migration_reset_example.go +++ b/examples/migration_reset_example.go @@ -4,7 +4,7 @@ import ( "fmt" "log" - "git.toowon.com/jimmy/go-commom/migration" + "git.toowon.com/jimmy/go-common/migration" "gorm.io/driver/sqlite" "gorm.io/gorm" ) diff --git a/examples/sms_example.go b/examples/sms_example.go index bc46cd5..273e392 100644 --- a/examples/sms_example.go +++ b/examples/sms_example.go @@ -4,8 +4,8 @@ import ( "fmt" "log" - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/sms" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/sms" ) func main() { diff --git a/examples/storage_example.go b/examples/storage_example.go index c495b12..4ea7ecd 100644 --- a/examples/storage_example.go +++ b/examples/storage_example.go @@ -4,9 +4,9 @@ import ( "log" "net/http" - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/middleware" - "git.toowon.com/jimmy/go-commom/storage" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/middleware" + "git.toowon.com/jimmy/go-common/storage" ) func main() { diff --git a/factory/factory.go b/factory/factory.go index 215a2b5..272fd9e 100644 --- a/factory/factory.go +++ b/factory/factory.go @@ -3,9 +3,10 @@ package factory import ( "fmt" - "git.toowon.com/jimmy/go-commom/config" - "git.toowon.com/jimmy/go-commom/email" - "git.toowon.com/jimmy/go-commom/sms" + "git.toowon.com/jimmy/go-common/config" + "git.toowon.com/jimmy/go-common/email" + "git.toowon.com/jimmy/go-common/logger" + "git.toowon.com/jimmy/go-common/sms" ) // Factory 工厂类,用于从配置创建各种客户端对象 @@ -38,6 +39,16 @@ func (f *Factory) GetSMSClient() (*sms.SMS, error) { return sms.NewSMS(f.cfg.SMS) } +// GetLogger 获取日志记录器(已初始化) +// 返回已初始化的日志记录器对象,可直接使用 +func (f *Factory) GetLogger() (*logger.Logger, error) { + if f.cfg.Logger == nil { + // 如果没有配置,使用默认配置创建 + return logger.NewLogger(nil) + } + return logger.NewLogger(f.cfg.Logger) +} + // GetConfig 获取配置对象 func (f *Factory) GetConfig() *config.Config { return f.cfg diff --git a/go.mod b/go.mod index 059301a..73efd25 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module git.toowon.com/jimmy/go-commom +module git.toowon.com/jimmy/go-common go 1.21 diff --git a/http/request.go b/http/request.go index 59ad956..15d0811 100644 --- a/http/request.go +++ b/http/request.go @@ -7,7 +7,7 @@ import ( "net/http" "strconv" - "git.toowon.com/jimmy/go-commom/middleware" + "git.toowon.com/jimmy/go-common/middleware" ) // ParseJSON 解析JSON请求体 diff --git a/logger/logger.go b/logger/logger.go new file mode 100644 index 0000000..32c0be6 --- /dev/null +++ b/logger/logger.go @@ -0,0 +1,207 @@ +package logger + +import ( + "fmt" + "io" + "log" + "os" + "path/filepath" + + "git.toowon.com/jimmy/go-common/config" +) + +// Logger 日志记录器 +type Logger struct { + infoLog *log.Logger + errorLog *log.Logger + warnLog *log.Logger + debugLog *log.Logger + config *config.LoggerConfig +} + +// NewLogger 创建日志记录器 +func NewLogger(cfg *config.LoggerConfig) (*Logger, error) { + if cfg == nil { + // 使用默认配置 + cfg = &config.LoggerConfig{ + Level: "info", + Output: "stdout", + FilePath: "", + } + } + + // 设置默认值 + if cfg.Level == "" { + cfg.Level = "info" + } + if cfg.Output == "" { + cfg.Output = "stdout" + } + + // 创建输出目标 + var writers []io.Writer + switch cfg.Output { + case "stdout": + writers = append(writers, os.Stdout) + case "stderr": + writers = append(writers, os.Stderr) + case "file": + if cfg.FilePath == "" { + return nil, fmt.Errorf("file path is required when output is file") + } + // 确保目录存在 + dir := filepath.Dir(cfg.FilePath) + if err := os.MkdirAll(dir, 0755); err != nil { + return nil, fmt.Errorf("failed to create log directory: %w", err) + } + file, err := os.OpenFile(cfg.FilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + return nil, fmt.Errorf("failed to open log file: %w", err) + } + writers = append(writers, file) + case "both": + writers = append(writers, os.Stdout) + if cfg.FilePath == "" { + return nil, fmt.Errorf("file path is required when output is both") + } + dir := filepath.Dir(cfg.FilePath) + if err := os.MkdirAll(dir, 0755); err != nil { + return nil, fmt.Errorf("failed to create log directory: %w", err) + } + file, err := os.OpenFile(cfg.FilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + return nil, fmt.Errorf("failed to open log file: %w", err) + } + writers = append(writers, file) + default: + return nil, fmt.Errorf("invalid output type: %s", cfg.Output) + } + + // 创建多写入器 + multiWriter := io.MultiWriter(writers...) + + // 创建日志前缀 + prefix := "" + if cfg.Prefix != "" { + prefix = cfg.Prefix + " " + } + + // 创建日志记录器 + logger := &Logger{ + config: cfg, + } + + // 根据日志级别创建不同的logger + flags := log.LstdFlags + if cfg.DisableTimestamp { + flags = 0 + } + + if cfg.Level == "debug" || cfg.Level == "info" || cfg.Level == "warn" || cfg.Level == "error" { + logger.infoLog = log.New(multiWriter, prefix+"[INFO] ", flags) + logger.warnLog = log.New(multiWriter, prefix+"[WARN] ", flags) + logger.errorLog = log.New(multiWriter, prefix+"[ERROR] ", flags) + if cfg.Level == "debug" { + logger.debugLog = log.New(multiWriter, prefix+"[DEBUG] ", flags) + } + } + + return logger, nil +} + +// Debug 记录调试日志 +func (l *Logger) Debug(format string, v ...interface{}) { + if l.debugLog != nil { + l.debugLog.Printf(format, v...) + } +} + +// Info 记录信息日志 +func (l *Logger) Info(format string, v ...interface{}) { + if l.infoLog != nil { + l.infoLog.Printf(format, v...) + } +} + +// Warn 记录警告日志 +func (l *Logger) Warn(format string, v ...interface{}) { + if l.warnLog != nil { + l.warnLog.Printf(format, v...) + } +} + +// Error 记录错误日志 +func (l *Logger) Error(format string, v ...interface{}) { + if l.errorLog != nil { + l.errorLog.Printf(format, v...) + } +} + +// Fatal 记录致命错误日志并退出程序 +func (l *Logger) Fatal(format string, v ...interface{}) { + if l.errorLog != nil { + l.errorLog.Fatalf(format, v...) + } else { + log.Fatalf(format, v...) + } +} + +// Panic 记录恐慌日志并触发panic +func (l *Logger) Panic(format string, v ...interface{}) { + if l.errorLog != nil { + l.errorLog.Panicf(format, v...) + } else { + log.Panicf(format, v...) + } +} + +// WithFields 创建带字段的日志记录器(简化版,返回格式化字符串) +func (l *Logger) WithFields(fields map[string]interface{}) *Logger { + // 返回自身,实际使用时可以在format中包含fields + return l +} + +// formatFields 格式化字段 +func formatFields(fields map[string]interface{}) string { + if len(fields) == 0 { + return "" + } + result := "" + for k, v := range fields { + result += fmt.Sprintf("%s=%v ", k, v) + } + return result +} + +// Debugf 记录调试日志(带字段) +func (l *Logger) Debugf(fields map[string]interface{}, format string, v ...interface{}) { + if l.debugLog != nil { + fieldStr := formatFields(fields) + l.debugLog.Printf(fieldStr+format, v...) + } +} + +// Infof 记录信息日志(带字段) +func (l *Logger) Infof(fields map[string]interface{}, format string, v ...interface{}) { + if l.infoLog != nil { + fieldStr := formatFields(fields) + l.infoLog.Printf(fieldStr+format, v...) + } +} + +// Warnf 记录警告日志(带字段) +func (l *Logger) Warnf(fields map[string]interface{}, format string, v ...interface{}) { + if l.warnLog != nil { + fieldStr := formatFields(fields) + l.warnLog.Printf(fieldStr+format, v...) + } +} + +// Errorf 记录错误日志(带字段) +func (l *Logger) Errorf(fields map[string]interface{}, format string, v ...interface{}) { + if l.errorLog != nil { + fieldStr := formatFields(fields) + l.errorLog.Printf(fieldStr+format, v...) + } +} + diff --git a/middleware/timezone.go b/middleware/timezone.go index ce240ab..d561c40 100644 --- a/middleware/timezone.go +++ b/middleware/timezone.go @@ -4,7 +4,7 @@ import ( "context" "net/http" - "git.toowon.com/jimmy/go-commom/datetime" + "git.toowon.com/jimmy/go-common/datetime" ) // TimezoneKey context中存储时区的key diff --git a/sms/sms.go b/sms/sms.go index 5516a30..fe89ca0 100644 --- a/sms/sms.go +++ b/sms/sms.go @@ -13,7 +13,7 @@ import ( "strings" "time" - "git.toowon.com/jimmy/go-commom/config" + "git.toowon.com/jimmy/go-common/config" ) // SMS 短信发送器 diff --git a/storage/handler.go b/storage/handler.go index 8d81cd2..7e7d8cc 100644 --- a/storage/handler.go +++ b/storage/handler.go @@ -9,7 +9,7 @@ import ( "strings" "time" - commonhttp "git.toowon.com/jimmy/go-commom/http" + commonhttp "git.toowon.com/jimmy/go-common/http" ) // UploadHandler 文件上传处理器 diff --git a/storage/minio.go b/storage/minio.go index f7299ae..18e1aca 100644 --- a/storage/minio.go +++ b/storage/minio.go @@ -6,7 +6,7 @@ import ( "io" "strings" - "git.toowon.com/jimmy/go-commom/config" + "git.toowon.com/jimmy/go-common/config" ) // MinIOStorage MinIO存储实现 diff --git a/storage/oss.go b/storage/oss.go index 486bfce..44bc165 100644 --- a/storage/oss.go +++ b/storage/oss.go @@ -6,7 +6,7 @@ import ( "io" "strings" - "git.toowon.com/jimmy/go-commom/config" + "git.toowon.com/jimmy/go-common/config" ) // OSSStorage OSS存储实现 diff --git a/storage/storage.go b/storage/storage.go index f056ac0..6f7ea5f 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -6,7 +6,7 @@ import ( "io" "time" - "git.toowon.com/jimmy/go-commom/config" + "git.toowon.com/jimmy/go-common/config" ) // Storage 存储接口