# Dev-Falsework-GO **Repository Path**: mstes/util ## Basic Information - **Project Name**: Dev-Falsework-GO - **Description**: 基于go的公用的微服务开发工具包,包含orm、filesystem、redis、rabbitmq、etcd等 - **Primary Language**: Unknown - **License**: AGPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 11 - **Forks**: 1 - **Created**: 2025-10-25 - **Last Updated**: 2025-10-28 ## Categories & Tags **Categories**: microservice **Tags**: None ## README # 微服务开发常用组件 本文档为 `util` 目录下核心工具模块的使用说明,包含完整的功能(持续更新)介绍、可直接复用的代码示例及输出说明,旨在帮助开发者快速集成到项目中,减少重复开发工作,同时内置的所有组件使用者均可以自由增加接口等,非常灵活。 ## 1. logger 日志工具 ### 1.1 功能概述 `logger` 模块提供多场景适配的日志解决方案,支持 **控制台输出、文件轮转、Etcd 组件日志、ORM 数据库日志** 四种核心实例。所有日志默认以 **JSON 格式**输出,包含「时间戳、日志级别、调用文件及行号、日志内容」等关键字段,同时支持自定义扩展字段,满足开发调试、生产监控、链路追踪等需求。 ### 1.2 快速开始 #### 前置依赖导入 ```go import loggerutil "util/logger" ``` #### 核心日志实例对比 | 日志实例 | 核心能力 | 适用场景 | 关键特性 | |-------------------|---------------------------|-------------------------|---------------------------| | StdoutLogger | 控制台打印日志 | 本地开发、调试测试 | 支持显示调用文件+行号 | | RollFileLogger | 日志文件按规则轮转 | 生产环境日志持久化 | 按大小/天数切割、备份管理 | | EtcdLogger | Etcd 组件专属日志输出 | Etcd 客户端/服务端日志 | 适配 Etcd 组件日志格式 | | OrmLogger | 数据库 ORM 操作日志跟踪 | Gorm SQL 执行监控 | 显示 SQL 语句、耗时、行数 | ### 1.3 各实例使用示例 #### 1.3.1 StdoutLogger(控制台日志) **用途**:开发阶段快速打印日志到控制台,便于实时查看调试信息,支持开启「调用位置报告」(显示日志所在文件及行号)。 **完整代码示例**(路径:`logger/test/debug/main.go`): ```go package main import loggerutil "util/logger" func main() { // 1. 创建控制台日志实例,配置日志名称和调用报告 loggerutil.Log = loggerutil.NewStdoutlogger( loggerutil.WithStdoutLoggerName("default"), // 日志实例名称(用于区分多实例) loggerutil.WithStdoutCallReport(), // 开启调用位置报告(文件+行号) ) // 2. 定义日志实例并设置日志级别(Debug 级别会输出所有层级日志) var baselogger loggerutil.LogOutput = loggerutil.Log baselogger.SetLevel(loggerutil.Debug) // 可选级别:Debug/Info/Warn/Error/Fatal // 3. 输出不同级别日志 baselogger.DEBUG("debug log:开发调试信息") baselogger.INFO("info log:业务正常运行信息") baselogger.WARN("warn log:需关注的警告信息") baselogger.ERROR("error log:业务异常信息") // baselogger.FATAL("FATAL log:致命错误,输出后终止程序") // 按需启用 // 4. Etcd 组件专属日志示例(无需额外配置,直接创建使用) etcdLogger := loggerutil.NewEtcdLogger() etcdLogger.INFO("etcd 客户端初始化成功") etcdLogger.ERROR("etcd 连接超时,重试中...") } ``` **输出结果**(JSON 格式,可直接用日志分析工具解析): ```json {"file":"/util/logger/test/debug/main.go:12","level":"debug","msg":"debug log:开发调试信息","time":"2025-10-26 11:52:08.410ms"} {"file":"/util/logger/test/debug/main.go:13","level":"info","msg":"info log:业务正常运行信息","time":"2025-10-26 11:52:08.410ms"} {"file":"/util/logger/test/debug/main.go:14","level":"warning","msg":"warn log:需关注的警告信息","time":"2025-10-26 11:52:08.410ms"} {"file":"/util/logger/test/debug/main.go:15","level":"error","msg":"error log:业务异常信息","time":"2025-10-26 11:52:08.410ms"} {"file":"/util/logger/etcdlogger.go:XX","level":"info","msg":"etcd 客户端初始化成功","time":"2025-10-26 11:52:08.411ms"} {"file":"/util/logger/etcdlogger.go:XX","level":"error","msg":"etcd 连接超时,重试中...","time":"2025-10-26 11:52:08.411ms"} ``` #### 1.3.2 RollFileLogger(文件轮转日志) **用途**:生产环境将日志写入文件,支持按「文件大小」或「保留天数」自动切割日志,避免单文件过大导致的存储/读取问题,同时支持备份文件管理。 **完整代码示例**(路径:`logger/test/release/main.go`): ```go package main import ( loggerutil "util/logger" "github.com/google/uuid" // 用于生成唯一请求ID(示例依赖,按需导入) ) func main() { // 1. 配置日志轮转参数(核心参数需根据业务调整) logConfig := &loggerutil.LogConfig{ LoggerName: "rollfilelogger-default", // 日志实例名称 Filename: "./logs/test.log", // 日志文件路径(建议绝对路径) MaxSize: 1, // 单文件最大大小(单位:GB) MaxBackups: 5, // 最大备份文件数量(超过自动删除旧文件) MaxDay: 7, // 日志保留天数(超过自动清理) Compress: true, // 是否压缩备份文件(节省存储空间) } // 2. 创建文件轮转日志实例,开启调用位置报告 loggerutil.Log = loggerutil.NewRollFileLogger( loggerutil.WithRollFileConfig(logConfig), loggerutil.WithFileCallReport(), // 开启调用位置报告(文件+行号) ) // 3. 定义日志实例并设置级别 var baselogger loggerutil.LogOutput = loggerutil.Log baselogger.SetLevel(loggerutil.Info) // 生产环境建议设为 Info,减少日志量 // 4. 追加自定义字段(如 request_id,用于链路追踪) baselogger.AppendFields(loggerutil.LogFields{ "request_id": uuid.NewString(), // 唯一请求ID "service": "user-service", // 服务名称 }).Error("用户登录失败:密码错误") // 链式调用输出日志 // 5. 输出普通日志 baselogger.INFO("用户注册成功:uid=user123456") baselogger.WARN("用户余额不足:uid=user123456") } ``` **核心特性说明**: - 自动切割:当文件大小达到 `MaxSize` 或时间超过 `MaxDay` 时,自动生成新日志文件(如 `test.log.20251026`)。 - 备份管理:备份文件数量超过 `MaxBackups` 时,自动删除最早的备份文件,避免磁盘占满。 - 字段扩展:支持通过 `AppendFields` 追加业务自定义字段,便于日志分析和问题定位。 #### 1.3.3 OrmLogger(数据库 ORM 日志) **用途**:配合 `db` 模块使用,输出 Gorm 执行的「SQL 语句、执行耗时、错误信息、影响行数」,支持设置慢查询阈值,便于监控数据库操作性能。 **使用方式**:在 `db` 客户端初始化时关联(具体示例见 2.3.2 节 `db` 模块初始化代码),核心依赖以下代码: ```go // 创建 ORM 日志实例,设置慢查询阈值(单位:ms,超过此值的 SQL 会标记为慢查询) ormLogger := loggerutil.NewOrmLogger() slowTTL := int64(200) // 慢查询阈值:200ms ``` **输出结果示例**(包含 SQL 执行详情): ```json {"file":"/util/logger/ormlogger.go:20","level":"info","msg":"SQL = INSERT INTO users (created_at,updated_at,deleted_at,uid,name) VALUES ('2025-10-26 12:38:56.905','2025-10-26 12:38:56.905',NULL,'b3301625-77e8-47b3-89c0-971a5e79988e','test_name'),error = ,elapsed = 1ms,rows = 1","time":"2025-10-26 12:38:56.906ms"} {"file":"/util/logger/ormlogger.go:20","level":"warn","msg":"SQL = SELECT * FROM users WHERE uid = 'b3301625-77e8-47b3-89c0-971a5e79988e',error = ,elapsed = 250ms,rows = 1 [SLOW QUERY]","time":"2025-10-26 12:38:56.913ms"} ``` ## 2. db 数据库工具 ### 2.1 功能概述 `db` 模块基于 **Gorm v2** 封装,提供 MySQL 数据库的「快速连接、表自动创建、CRUD 操作、联表查询、连接池管理」等功能。支持关联 `logger` 模块输出 SQL 日志,简化数据库操作流程,同时内置软删除、字段约束等特性,降低开发者使用成本。 ### 2.2 快速开始 #### 前置依赖导入 ```go import ( dbutil "util/db" loggerutil "util/logger" "gorm.io/gorm" // 按需导入,定义表模型时需用到 ) ``` #### 核心依赖说明 - ORM 框架:`gorm.io/gorm`(已内置封装,无需额外处理版本依赖) - MySQL 驱动:模块内部已集成,无需手动导入驱动包 ### 2.3 完整使用流程 #### 2.3.1 步骤 1:定义表模型 **用途**:通过 Go 结构体映射数据库表,支持自定义字段类型、约束(如唯一键、非空、默认值),结构体字段标签 `gorm` 用于配置数据库表结构。 **代码示例**(路径:`db/test/model.go`): ```go package main import "gorm.io/gorm" // User 用户表模型(映射数据库中的 `users` 表,表名自动复数化) type User struct { gorm.Model // 内置字段:ID(int64)、CreatedAt(time)、UpdatedAt(time)、DeletedAt(time)(软删除标记) UID string `json:"uid" gorm:"column:uid;type:varchar(128);not null;unique"` // 用户唯一ID:非空、唯一 Name string `json:"name" gorm:"column:name;type:varchar(128);not null"` // 用户名:非空 Age int `json:"age" gorm:"column:age;type:int;default:0"` // 年龄:默认值 0 } // TableName 自定义表名(可选,默认是结构体名复数形式) func (User) TableName() string { return "users" } ``` #### 2.3.2 步骤 2:初始化数据库客户端 **用途**:配置 MySQL 连接信息、关联 ORM 日志、设置连接池参数,创建可复用的数据库客户端实例(建议全局单例使用)。 **代码示例**(路径:`db/test/main.go`): ```go package main import ( dbutil "util/db" loggerutil "util/logger" ) func main() { // 1. 初始化日志(业务日志 + ORM SQL 日志) // 1.1 业务日志:用于输出数据库操作的业务级日志(如客户端创建失败) loggerutil.Log = loggerutil.NewStdoutlogger(loggerutil.WithStdoutLoggerName("db-business-log")) baseLogger := loggerutil.Log // 1.2 ORM 日志:用于输出 SQL 执行详情(关联 logger 模块的 OrmLogger) ormLogger := loggerutil.NewOrmLogger() slowTTL := int64(200) // 慢查询阈值:超过 200ms 的 SQL 会标记为警告 // 2. 配置 MySQL 连接信息(需根据实际环境调整) mysqlConfig := &dbutil.MysqlConfig{ User: "root", // 数据库用户名 Password: "123456", // 数据库密码 Ip: "127.0.0.1", // 数据库 IP 地址 Port: "3306", // 数据库端口 Db: "cpr_test", // 数据库名称 SSL: false, // 是否启用 SSL 连接(本地环境一般关闭) AuthCreateTable: true, // 表不存在时自动创建(开发环境建议开启,生产环境按需关闭) MaxOpenConns: 10, // 连接池最大打开连接数 MaxIdleConns: 5, // 连接池最大空闲连接数 ConnMaxLifetime: 300, // 连接最大存活时间(单位:秒) ConnMaxIdleTime: 60, // 连接最大空闲时间(单位:秒) } // 3. 创建数据库客户端(泛型指定表模型,支持多模型复用) client, err := dbutil.NewDbClient( dbutil.UseLogger[User](ormLogger, slowTTL), // 关联 ORM 日志和慢查询阈值 dbutil.UseMysqlDriver[User](mysqlConfig), // 关联 MySQL 驱动和连接配置 ) if err != nil { baseLogger.FATAL("创建数据库客户端失败:%v", err) // 致命错误,终止程序 } baseLogger.INFO("数据库客户端初始化成功") // 后续数据库操作(见 2.3.3 节)... } ``` #### 2.3.3 步骤 3:核心数据库操作 基于初始化后的客户端,支持「插入、查询、更新、删除、联表查询」等操作,以下为完整示例: ```go package main import ( "fmt" dbutil "util/db" loggerutil "util/logger" "github.com/google/uuid" ) func main() { // ... 省略客户端初始化代码(见 2.3.2 节)... baseLogger := loggerutil.Log client := // 初始化后的 db 客户端 // 1. 插入单条数据 newUser := &User{ UID: uuid.NewString(), // 生成唯一 UID Name: "测试用户", Age: 25, } if err := client.InsertOne(newUser); err != nil { baseLogger.ERROR("插入用户失败:%v", err) return } baseLogger.INFO("插入用户成功:uid=%s, name=%s", newUser.UID, newUser.Name) // 2. 查询所有数据(不含软删除数据) var allUsers []User if err := client.AllQuery(&allUsers); err != nil { baseLogger.ERROR("查询所有用户失败:%v", err) return } baseLogger.INFO("当前用户总数:%d", len(allUsers)) for _, user := range allUsers { fmt.Printf("用户信息:ID=%d, UID=%s, Name=%s, Age=%d\n", user.ID, user.UID, user.Name, user.Age) } // 3. 条件查询(按 UID 查询单条数据) var targetUser []User targetUID := newUser.UID // 要查询的 UID if err := client.EasyQuery(&targetUser, "uid = ?", targetUID); err != nil { baseLogger.ERROR("按 UID 查询用户失败:%v", err) return } if len(targetUser) == 0 { baseLogger.WARN("未找到 UID 为 %s 的用户", targetUID) return } baseLogger.INFO("查询到用户:UID=%s, Name=%s", targetUser[0].UID, targetUser[0].Name) // 4. 联表查询(示例:用户表与订单表联查,需先定义订单表模型) // 4.1 定义订单表模型(示例) type Order struct { gorm.Model OrderID string `json:"order_id" gorm:"column:order_id;type:varchar(128);not null;unique"` UID string `json:"uid" gorm:"column:uid;type:varchar(128);not null"` // 关联用户 UID Amount int `json:"amount" gorm:"column:amount;type:int;not null"` } // 4.2 定义联表结果结构体(只保留需要的字段) type UserOrderResult struct { UID string `json:"uid" gorm:"column:uid"` Name string `json:"name" gorm:"column:name"` OrderID string `json:"order_id" gorm:"column:order_id"` Amount int `json:"amount" gorm:"column:amount"` } var joinResults []UserOrderResult // 4.3 配置联表参数 joinParams := []dbutil.JoinParam{ { Table: "orders", // 关联表名 Alias: "o", // 关联表别名 JoinType: dbutil.LeftJoin, // 连接类型:LeftJoin/InnerJoin/RightJoin OnCondition: "users.uid = o.uid", // 关联条件(用户表 UID = 订单表 UID) }, } // 4.4 配置查询条件(WHERE 子句) whereCond := &dbutil.JoinWhereParms{ QueryStr: "users.uid = ?", // WHERE 条件 Args: []any{targetUID}, // 条件参数(当前用户 UID) } // 4.5 执行联表查询 if err := client.JoinQuery( &joinResults, // 接收联表结果的变量 "users", // 主表名 joinParams, // 联表参数 "o.created_at DESC", // 排序条件(可选:按订单创建时间倒序) whereCond, // WHERE 条件 "users.uid, users.name, o.order_id, o.amount", // 要查询的字段(可选,默认查所有) 10, // 分页大小(-1 表示不分页) ); err != nil { baseLogger.ERROR("联表查询失败:%v", err) return } baseLogger.INFO("用户 %s 的订单总数:%d", targetUID, len(joinResults)) for _, res := range joinResults { fmt.Printf("订单信息:UID=%s, Name=%s, OrderID=%s, Amount=%d\n", res.UID, res.Name, res.OrderID, res.Amount) } } ``` **输出结果示例**(包含业务日志和 SQL 日志): ```json // 业务日志:插入成功 {"file":"/util/db/test/main.go:35","level":"info","msg":"插入用户成功:uid=b3301625-77e8-47b3-89c0-971a5e79988e, name=测试用户","time":"2025-10-26 12:38:56.906ms"} // ORM SQL 日志:插入操作 {"file":"/util/logger/ormlogger.go:20","level":"info","msg":"SQL = INSERT INTO users (created_at,updated_at,deleted_at,uid,name,age) VALUES ('2025-10-26 12:38:56.905','2025-10-26 12:38:56.905',NULL,'b3301625-77e8-47b3-89c0-971a5e79988e','测试用户',25),error = ,elapsed = 1ms,rows = 1","time":"2025-10-26 12:38:56.906ms"} // 业务日志:联表查询结果 {"file":"/util/db/test/main.go:88","level":"info","msg":"用户 b3301625-77e8-47b3-89c0-971a5e79988e 的订单总数:2","time":"2025-10-26 12:38:56.920ms"} ``` ## 3. 待补充模块 - **etcd 模块**:路径 `etcd/*`,功能为 Etcd 客户端封装及核心操作(如键值对管理、租约、Watch 等),当前文档待完善,后续将补充完整使用说明。 ## 4. 注意事项 1. 生产环境中,`RollFileLogger` 的 `Filename` 建议使用绝对路径,避免日志文件路径混乱。 2. `db` 模块的 `MysqlConfig` 中,`AuthCreateTable` 生产环境建议设为 `false`,表结构通过 SQL 脚本管理更安全。 3. 日志级别选择:开发环境用 `Debug`,生产环境用 `Info` 或 `Warn`,减少不必要的日志开销。 4. `db` 客户端建议全局单例使用,避免频繁创建连接导致性能问题。