- update gorm

master v1.0.79
李光春 2 years ago
parent c4d22be7c9
commit 3f0ab29c10

102
api.go

@ -12,32 +12,20 @@ import (
// ApiClient 接口
type ApiClient struct {
gormClient *dorm.GormClient // 数据库驱动
mongoClient *dorm.MongoClient // 数据库驱动
zapLog *ZapLog // 日志服务
logDebug bool // 日志开关
currentIp string // 当前ip
gormConfig struct {
gormClient *dorm.GormClient // 数据库驱动
zapLog *ZapLog // 日志服务
logDebug bool // 日志开关
currentIp string // 当前ip
gormConfig struct {
tableName string // 表名
insideIp string // 内网ip
hostname string // 主机名
goVersion string // go版本
}
mongoConfig struct {
databaseName string // 库名
collectionName string // 表名
insideIp string // 内网ip
hostname string // 主机名
goVersion string // go版本
}
log struct {
gorm bool // 日志开关
mongo bool // 日志开关
}
config struct {
os string // 系统类型
arch string // 系统架构
maxProCs int // CPU核数
os string // 系统类型
arch string // 系统架构
jsonStatus bool // json状态
}
}
@ -45,23 +33,16 @@ type ApiClient struct {
// string 表名
type apiGormClientFun func() (*dorm.GormClient, string)
// client 数据库服务
// string 库名
// string 表名
type apiMongoClientFun func() (*dorm.MongoClient, string, string)
// ApiClientConfig 接口实例配置
type ApiClientConfig struct {
GormClientFun apiGormClientFun // 日志配置
MongoClientFun apiMongoClientFun // 日志配置
Debug bool // 日志开关
ZapLog *ZapLog // 日志服务
CurrentIp string // 当前ip
GormClientFun apiGormClientFun // 日志配置
Debug bool // 日志开关
ZapLog *ZapLog // 日志服务
CurrentIp string // 当前ip
JsonStatus bool // json状态
}
// NewApiClient 创建接口实例化
// client 数据库服务
// tableName 表名
func NewApiClient(config *ApiClientConfig) (*ApiClient, error) {
var ctx = context.Background()
@ -72,6 +53,8 @@ func NewApiClient(config *ApiClientConfig) (*ApiClient, error) {
c.logDebug = config.Debug
c.config.jsonStatus = config.JsonStatus
if config.CurrentIp == "" {
config.CurrentIp = goip.GetOutsideIp(ctx)
}
@ -81,12 +64,10 @@ func NewApiClient(config *ApiClientConfig) (*ApiClient, error) {
c.config.os = runtime.GOOS
c.config.arch = runtime.GOARCH
c.config.maxProCs = runtime.GOMAXPROCS(0)
gormClient, gormTableName := config.GormClientFun()
mongoClient, mongoDatabaseName, mongoCollectionName := config.MongoClientFun()
if (gormClient == nil || gormClient.Db == nil) || (mongoClient == nil || mongoClient.Db == nil) {
if gormClient == nil || gormClient.Db == nil {
return nil, errors.New("没有设置驱动")
}
@ -110,36 +91,6 @@ func NewApiClient(config *ApiClientConfig) (*ApiClient, error) {
c.gormConfig.insideIp = goip.GetInsideIp(ctx)
c.gormConfig.goVersion = runtime.Version()
c.log.gorm = true
}
if mongoClient != nil || mongoClient.Db != nil {
c.mongoClient = mongoClient
if mongoDatabaseName == "" {
return nil, errors.New("没有设置库名")
}
c.mongoConfig.databaseName = mongoDatabaseName
if mongoCollectionName == "" {
return nil, errors.New("没有设置表名")
}
c.mongoConfig.collectionName = mongoCollectionName
c.mongoConfig.hostname = hostname
c.mongoConfig.insideIp = goip.GetInsideIp(ctx)
c.mongoConfig.goVersion = runtime.Version()
c.log.mongo = true
// 创建时间序列集合
c.mongoCreateCollection(ctx)
// 创建索引
c.mongoCreateIndexes(ctx)
}
return c, nil
@ -147,30 +98,15 @@ func NewApiClient(config *ApiClientConfig) (*ApiClient, error) {
// Middleware 中间件
func (c *ApiClient) Middleware(ctx context.Context, request gorequest.Response, sdkVersion string) {
if c.log.gorm {
c.GormMiddleware(ctx, request, sdkVersion)
}
if c.log.mongo {
c.MongoMiddleware(ctx, request, sdkVersion)
}
c.GormMiddleware(ctx, request, sdkVersion)
}
// MiddlewareXml 中间件
func (c *ApiClient) MiddlewareXml(ctx context.Context, request gorequest.Response, sdkVersion string) {
if c.log.gorm {
c.GormMiddlewareXml(ctx, request, sdkVersion)
}
if c.log.mongo {
c.MongoMiddlewareXml(ctx, request, sdkVersion)
}
c.GormMiddlewareXml(ctx, request, sdkVersion)
}
// MiddlewareCustom 中间件
func (c *ApiClient) MiddlewareCustom(ctx context.Context, api string, request gorequest.Response, sdkVersion string) {
if c.log.gorm {
c.GormMiddlewareCustom(ctx, api, request, sdkVersion)
}
if c.log.mongo {
c.MongoMiddlewareCustom(ctx, api, request, sdkVersion)
}
c.GormMiddlewareCustom(ctx, api, request, sdkVersion)
}

@ -9,50 +9,22 @@ import (
"go.dtapp.net/gotime"
"go.dtapp.net/gotrace_id"
"go.dtapp.net/gourl"
"gorm.io/gorm"
"gorm.io/datatypes"
"os"
"runtime"
"time"
"unicode/utf8"
)
// 模型结构体
type apiPostgresqlLog struct {
LogId uint `gorm:"primaryKey;comment:【记录】编号" json:"log_id,omitempty"` //【记录】编号
TraceId string `gorm:"index;comment:【系统】跟踪编号" json:"trace_id,omitempty"` //【系统】跟踪编号
RequestTime time.Time `gorm:"index;comment:【请求】时间" json:"request_time,omitempty"` //【请求】时间
RequestUri string `gorm:"comment:【请求】链接" json:"request_uri,omitempty"` //【请求】链接
RequestUrl string `gorm:"comment:【请求】链接" json:"request_url,omitempty"` //【请求】链接
RequestApi string `gorm:"index;comment:【请求】接口" json:"request_api,omitempty"` //【请求】接口
RequestMethod string `gorm:"index;comment:【请求】方式" json:"request_method,omitempty"` //【请求】方式
RequestParams string `gorm:"comment:【请求】参数" json:"request_params,omitempty"` //【请求】参数
RequestHeader string `gorm:"comment:【请求】头部" json:"request_header,omitempty"` //【请求】头部
RequestIp string `gorm:"index;comment:【请求】请求Ip" json:"request_ip,omitempty"` //【请求】请求Ip
ResponseHeader string `gorm:"comment:【返回】头部" json:"response_header,omitempty"` //【返回】头部
ResponseStatusCode int `gorm:"index;comment:【返回】状态码" json:"response_status_code,omitempty"` //【返回】状态码
ResponseBody string `gorm:"comment:【返回】数据" json:"response_content,omitempty"` //【返回】数据
ResponseContentLength int64 `gorm:"comment:【返回】大小" json:"response_content_length,omitempty"` //【返回】大小
ResponseTime time.Time `gorm:"index;comment:【返回】时间" json:"response_time,omitempty"` //【返回】时间
SystemHostName string `gorm:"index;comment:【系统】主机名" json:"system_host_name,omitempty"` //【系统】主机名
SystemInsideIp string `gorm:"index;comment:【系统】内网ip" json:"system_inside_ip,omitempty"` //【系统】内网ip
SystemOs string `gorm:"index;comment:【系统】系统类型" json:"system_os,omitempty"` //【系统】系统类型
SystemArch string `gorm:"index;comment:【系统】系统架构" json:"system_arch,omitempty"` //【系统】系统架构
SystemCpuQuantity int `gorm:"index;comment:【系统】CPU核数" json:"system_cpu_quantity,omitempty"` //【系统】CPU核数
GoVersion string `gorm:"index;comment:【程序】Go版本" json:"go_version,omitempty"` //【程序】Go版本
SdkVersion string `gorm:"index;comment:【程序】Sdk版本" json:"sdk_version,omitempty"` //【程序】Sdk版本
}
// ApiGormClientConfig 接口实例配置
type ApiGormClientConfig struct {
GormClientFun apiGormClientFun // 日志配置
Debug bool // 日志开关
ZapLog *ZapLog // 日志服务
CurrentIp string // 当前ip
JsonStatus bool // json状态
}
// NewApiGormClient 创建接口实例化
// client 数据库服务
// tableName 表名
func NewApiGormClient(config *ApiGormClientConfig) (*ApiClient, error) {
var ctx = context.Background()
@ -63,6 +35,8 @@ func NewApiGormClient(config *ApiGormClientConfig) (*ApiClient, error) {
c.logDebug = config.Debug
c.config.jsonStatus = config.JsonStatus
if config.CurrentIp == "" {
config.CurrentIp = goip.GetOutsideIp(ctx)
}
@ -94,60 +68,112 @@ func NewApiGormClient(config *ApiGormClientConfig) (*ApiClient, error) {
c.gormConfig.insideIp = goip.GetInsideIp(ctx)
c.gormConfig.goVersion = runtime.Version()
c.log.gorm = true
return c, nil
}
// 创建模型
func (c *ApiClient) gormAutoMigrate() (err error) {
err = c.gormClient.Db.Table(c.gormConfig.tableName).AutoMigrate(&apiPostgresqlLog{})
if err != nil {
c.zapLog.WithLogger().Sugar().Infof("[golog.api.gormAutoMigrate]%s", err)
if c.config.jsonStatus {
err = c.gormClient.Db.Table(c.gormConfig.tableName).AutoMigrate(&apiPostgresqlLogJson{})
if err != nil {
c.zapLog.WithLogger().Sugar().Errorf("创建模型:%s", err)
}
} else {
err = c.gormClient.Db.Table(c.gormConfig.tableName).AutoMigrate(&apiPostgresqlLogString{})
if err != nil {
c.zapLog.WithLogger().Sugar().Errorf("创建模型:%s", err)
}
}
return
return nil
}
// 记录日志
func (c *ApiClient) gormRecord(ctx context.Context, postgresqlLog apiPostgresqlLog) (err error) {
func (c *ApiClient) gormRecord(ctx context.Context, data apiPostgresqlLogString) (err error) {
if utf8.ValidString(postgresqlLog.ResponseBody) == false {
postgresqlLog.ResponseBody = ""
if utf8.ValidString(data.ResponseBody) == false {
data.ResponseBody = ""
}
postgresqlLog.SystemHostName = c.gormConfig.hostname
postgresqlLog.SystemInsideIp = c.gormConfig.insideIp
postgresqlLog.GoVersion = c.gormConfig.goVersion
postgresqlLog.TraceId = gotrace_id.GetTraceIdContext(ctx)
postgresqlLog.RequestIp = c.currentIp
postgresqlLog.SystemOs = c.config.os
postgresqlLog.SystemArch = c.config.arch
postgresqlLog.SystemCpuQuantity = c.config.maxProCs
err = c.gormClient.Db.Table(c.gormConfig.tableName).Create(&postgresqlLog).Error
if err != nil {
c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.gormRecord]%s", err)
data.SystemHostName = c.gormConfig.hostname
data.SystemInsideIp = c.gormConfig.insideIp
data.GoVersion = c.gormConfig.goVersion
data.TraceId = gotrace_id.GetTraceIdContext(ctx)
data.RequestIp = c.currentIp
data.SystemOs = c.config.os
data.SystemArch = c.config.arch
if c.config.jsonStatus {
err = c.gormClient.Db.Table(c.gormConfig.tableName).Create(&apiPostgresqlLogJson{
TraceId: data.TraceId,
RequestTime: data.RequestTime,
RequestUri: data.RequestUri,
RequestUrl: data.RequestUrl,
RequestApi: data.RequestApi,
RequestMethod: data.RequestMethod,
RequestParams: datatypes.JSON(data.RequestParams),
RequestHeader: datatypes.JSON(data.RequestHeader),
RequestIp: data.RequestIp,
ResponseHeader: datatypes.JSON(data.ResponseHeader),
ResponseStatusCode: data.ResponseStatusCode,
ResponseBody: datatypes.JSON(data.ResponseBody),
ResponseContentLength: data.ResponseContentLength,
ResponseTime: data.ResponseTime,
SystemHostName: data.SystemHostName,
SystemInsideIp: data.SystemInsideIp,
SystemOs: data.SystemOs,
SystemArch: data.SystemArch,
GoVersion: data.GoVersion,
SdkVersion: data.SdkVersion,
}).Error
if err != nil {
c.zapLog.WithTraceId(ctx).Sugar().Errorf("记录日志失败:%s", err)
}
} else {
err = c.gormClient.Db.Table(c.gormConfig.tableName).Create(&apiPostgresqlLogString{
TraceId: data.TraceId,
RequestTime: data.RequestTime,
RequestUri: data.RequestUri,
RequestUrl: data.RequestUrl,
RequestApi: data.RequestApi,
RequestMethod: data.RequestMethod,
RequestParams: data.RequestParams,
RequestHeader: data.RequestHeader,
RequestIp: data.RequestIp,
ResponseHeader: data.ResponseHeader,
ResponseStatusCode: data.ResponseStatusCode,
ResponseBody: data.ResponseBody,
ResponseContentLength: data.ResponseContentLength,
ResponseTime: data.ResponseTime,
SystemHostName: data.SystemHostName,
SystemInsideIp: data.SystemInsideIp,
SystemOs: data.SystemOs,
SystemArch: data.SystemArch,
GoVersion: data.GoVersion,
SdkVersion: data.SdkVersion,
}).Error
if err != nil {
c.zapLog.WithTraceId(ctx).Sugar().Errorf("记录日志失败:%s", err)
}
}
return
}
// GormQuery 查询
func (c *ApiClient) GormQuery(ctx context.Context) *gorm.DB {
return c.gormClient.Db.Table(c.gormConfig.tableName)
}
// GormDelete 删除
func (c *ApiClient) GormDelete(ctx context.Context, hour int64) error {
return c.gormClient.Db.Table(c.gormConfig.tableName).Where("request_time < ?", gotime.Current().BeforeHour(hour).Format()).Delete(&apiPostgresqlLog{}).Error
if c.config.jsonStatus {
return c.gormClient.Db.Table(c.gormConfig.tableName).Where("request_time < ?", gotime.Current().BeforeHour(hour).Format()).Delete(&apiPostgresqlLogJson{}).Error
} else {
return c.gormClient.Db.Table(c.gormConfig.tableName).Where("request_time < ?", gotime.Current().BeforeHour(hour).Format()).Delete(&apiPostgresqlLogString{}).Error
}
}
// GormMiddleware 中间件
func (c *ApiClient) GormMiddleware(ctx context.Context, request gorequest.Response, sdkVersion string) {
data := apiPostgresqlLog{
data := apiPostgresqlLogString{
RequestTime: request.RequestTime, //【请求】时间
RequestUri: request.RequestUri, //【请求】链接
RequestUrl: gourl.UriParse(request.RequestUri).Url, //【请求】链接
@ -185,7 +211,7 @@ func (c *ApiClient) GormMiddleware(ctx context.Context, request gorequest.Respon
// GormMiddlewareXml 中间件
func (c *ApiClient) GormMiddlewareXml(ctx context.Context, request gorequest.Response, sdkVersion string) {
data := apiPostgresqlLog{
data := apiPostgresqlLogString{
RequestTime: request.RequestTime, //【请求】时间
RequestUri: request.RequestUri, //【请求】链接
RequestUrl: gourl.UriParse(request.RequestUri).Url, //【请求】链接
@ -223,7 +249,7 @@ func (c *ApiClient) GormMiddlewareXml(ctx context.Context, request gorequest.Res
// GormMiddlewareCustom 中间件
func (c *ApiClient) GormMiddlewareCustom(ctx context.Context, api string, request gorequest.Response, sdkVersion string) {
data := apiPostgresqlLog{
data := apiPostgresqlLogString{
RequestTime: request.RequestTime, //【请求】时间
RequestUri: request.RequestUri, //【请求】链接
RequestUrl: gourl.UriParse(request.RequestUri).Url, //【请求】链接

@ -0,0 +1,31 @@
package golog
import (
"gorm.io/datatypes"
"time"
)
// 模型
type apiPostgresqlLogJson struct {
LogId uint `gorm:"primaryKey;comment:【记录】编号" json:"log_id,omitempty"` //【记录】编号
TraceId string `gorm:"index;comment:【系统】跟踪编号" json:"trace_id,omitempty"` //【系统】跟踪编号
RequestTime time.Time `gorm:"index;comment:【请求】时间" json:"request_time,omitempty"` //【请求】时间
RequestUri string `gorm:"comment:【请求】链接" json:"request_uri,omitempty"` //【请求】链接
RequestUrl string `gorm:"comment:【请求】链接" json:"request_url,omitempty"` //【请求】链接
RequestApi string `gorm:"index;comment:【请求】接口" json:"request_api,omitempty"` //【请求】接口
RequestMethod string `gorm:"index;comment:【请求】方式" json:"request_method,omitempty"` //【请求】方式
RequestParams datatypes.JSON `gorm:"type:jsonb;comment:【请求】参数" json:"request_params,omitempty"` //【请求】参数
RequestHeader datatypes.JSON `gorm:"type:jsonb;comment:【请求】头部" json:"request_header,omitempty"` //【请求】头部
RequestIp string `gorm:"index;comment:【请求】请求Ip" json:"request_ip,omitempty"` //【请求】请求Ip
ResponseHeader datatypes.JSON `gorm:"type:jsonb;comment:【返回】头部" json:"response_header,omitempty"` //【返回】头部
ResponseStatusCode int `gorm:"index;comment:【返回】状态码" json:"response_status_code,omitempty"` //【返回】状态码
ResponseBody datatypes.JSON `gorm:"type:jsonb;comment:【返回】数据" json:"response_content,omitempty"` //【返回】数据
ResponseContentLength int64 `gorm:"comment:【返回】大小" json:"response_content_length,omitempty"` //【返回】大小
ResponseTime time.Time `gorm:"index;comment:【返回】时间" json:"response_time,omitempty"` //【返回】时间
SystemHostName string `gorm:"index;comment:【系统】主机名" json:"system_host_name,omitempty"` //【系统】主机名
SystemInsideIp string `gorm:"index;comment:【系统】内网ip" json:"system_inside_ip,omitempty"` //【系统】内网ip
SystemOs string `gorm:"index;comment:【系统】系统类型" json:"system_os,omitempty"` //【系统】系统类型
SystemArch string `gorm:"index;comment:【系统】系统架构" json:"system_arch,omitempty"` //【系统】系统架构
GoVersion string `gorm:"comment:【程序】Go版本" json:"go_version,omitempty"` //【程序】Go版本
SdkVersion string `gorm:"comment:【程序】Sdk版本" json:"sdk_version,omitempty"` //【程序】Sdk版本
}

@ -0,0 +1,28 @@
package golog
import "time"
// 模型
type apiPostgresqlLogString struct {
LogId uint `gorm:"primaryKey;comment:【记录】编号" json:"log_id,omitempty"` //【记录】编号
TraceId string `gorm:"index;comment:【系统】跟踪编号" json:"trace_id,omitempty"` //【系统】跟踪编号
RequestTime time.Time `gorm:"index;comment:【请求】时间" json:"request_time,omitempty"` //【请求】时间
RequestUri string `gorm:"comment:【请求】链接" json:"request_uri,omitempty"` //【请求】链接
RequestUrl string `gorm:"comment:【请求】链接" json:"request_url,omitempty"` //【请求】链接
RequestApi string `gorm:"index;comment:【请求】接口" json:"request_api,omitempty"` //【请求】接口
RequestMethod string `gorm:"index;comment:【请求】方式" json:"request_method,omitempty"` //【请求】方式
RequestParams string `gorm:"comment:【请求】参数" json:"request_params,omitempty"` //【请求】参数
RequestHeader string `gorm:"comment:【请求】头部" json:"request_header,omitempty"` //【请求】头部
RequestIp string `gorm:"index;comment:【请求】请求Ip" json:"request_ip,omitempty"` //【请求】请求Ip
ResponseHeader string `gorm:"comment:【返回】头部" json:"response_header,omitempty"` //【返回】头部
ResponseStatusCode int `gorm:"index;comment:【返回】状态码" json:"response_status_code,omitempty"` //【返回】状态码
ResponseBody string `gorm:"comment:【返回】数据" json:"response_content,omitempty"` //【返回】数据
ResponseContentLength int64 `gorm:"comment:【返回】大小" json:"response_content_length,omitempty"` //【返回】大小
ResponseTime time.Time `gorm:"index;comment:【返回】时间" json:"response_time,omitempty"` //【返回】时间
SystemHostName string `gorm:"index;comment:【系统】主机名" json:"system_host_name,omitempty"` //【系统】主机名
SystemInsideIp string `gorm:"index;comment:【系统】内网ip" json:"system_inside_ip,omitempty"` //【系统】内网ip
SystemOs string `gorm:"index;comment:【系统】系统类型" json:"system_os,omitempty"` //【系统】系统类型
SystemArch string `gorm:"index;comment:【系统】系统架构" json:"system_arch,omitempty"` //【系统】系统架构
GoVersion string `gorm:"comment:【程序】Go版本" json:"go_version,omitempty"` //【程序】Go版本
SdkVersion string `gorm:"comment:【程序】Sdk版本" json:"sdk_version,omitempty"` //【程序】Sdk版本
}

@ -1,330 +0,0 @@
package golog
import (
"context"
"errors"
"go.dtapp.net/dorm"
"go.dtapp.net/goip"
"go.dtapp.net/gorequest"
"go.dtapp.net/gotime"
"go.dtapp.net/gotrace_id"
"go.dtapp.net/gourl"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"os"
"runtime"
)
// 模型结构体
type apiMongolLog struct {
LogId primitive.ObjectID `json:"log_id,omitempty" bson:"_id,omitempty"` //【记录】编号
LogTime primitive.DateTime `json:"log_time,omitempty" bson:"log_time,omitempty"` //【记录】时间
TraceId string `json:"trace_id,omitempty" bson:"trace_id,omitempty"` //【记录】跟踪编号
RequestTime dorm.BsonTime `json:"request_time,omitempty" bson:"request_time,omitempty"` //【请求】时间
RequestUri string `json:"request_uri,omitempty" bson:"request_uri,omitempty"` //【请求】链接
RequestUrl string `json:"request_url,omitempty" bson:"request_url,omitempty"` //【请求】链接
RequestApi string `json:"request_api,omitempty" bson:"request_api,omitempty"` //【请求】接口
RequestMethod string `json:"request_method,omitempty" bson:"request_method,omitempty"` //【请求】方式
RequestParams interface{} `json:"request_params,omitempty" bson:"request_params,omitempty"` //【请求】参数
RequestHeader interface{} `json:"request_header,omitempty" bson:"request_header,omitempty"` //【请求】头部
RequestIp string `json:"request_ip,omitempty" bson:"request_ip,omitempty"` //【请求】请求Ip
ResponseHeader interface{} `json:"response_header,omitempty" bson:"response_header,omitempty"` //【返回】头部
ResponseStatusCode int `json:"response_status_code,omitempty" bson:"response_status_code,omitempty"` //【返回】状态码
ResponseBody interface{} `json:"response_body,omitempty" bson:"response_body,omitempty"` //【返回】内容
ResponseContentLength int64 `json:"response_content_length,omitempty" bson:"response_content_length,omitempty"` //【返回】大小
ResponseTime dorm.BsonTime `json:"response_time,omitempty" bson:"response_time,omitempty"` //【返回】时间
SystemHostName string `json:"system_host_name,omitempty" bson:"system_host_name,omitempty"` //【系统】主机名
SystemInsideIp string `json:"system_inside_ip,omitempty" bson:"system_inside_ip,omitempty"` //【系统】内网ip
SystemOs string `json:"system_os,omitempty" bson:"system_os,omitempty"` //【系统】系统类型
SystemArch string `json:"system_arch,omitempty" bson:"system_arch,omitempty"` //【系统】系统架构
SystemCpuQuantity int `json:"system_cpu_quantity,omitempty" bson:"system_cpu_quantity,omitempty"` //【系统】CPU核数
GoVersion string `json:"go_version,omitempty" bson:"go_version,omitempty"` //【程序】Go版本
SdkVersion string `json:"sdk_version,omitempty" bson:"sdk_version,omitempty"` //【程序】Sdk版本
}
// ApiMongoClientConfig 接口实例配置
type ApiMongoClientConfig struct {
MongoClientFun apiMongoClientFun // 日志配置
Debug bool // 日志开关
ZapLog *ZapLog // 日志服务
CurrentIp string // 当前ip
}
// NewApiMongoClient 创建接口实例化
// client 数据库服务
// databaseName 库名
// collectionName 表名
func NewApiMongoClient(config *ApiMongoClientConfig) (*ApiClient, error) {
var ctx = context.Background()
c := &ApiClient{}
c.zapLog = config.ZapLog
c.logDebug = config.Debug
if config.CurrentIp == "" {
config.CurrentIp = goip.GetOutsideIp(ctx)
}
if config.CurrentIp != "" && config.CurrentIp != "0.0.0.0" {
c.currentIp = config.CurrentIp
}
client, databaseName, collectionName := config.MongoClientFun()
if client == nil || client.Db == nil {
return nil, errors.New("没有设置驱动")
}
c.mongoClient = client
if databaseName == "" {
return nil, errors.New("没有设置库名")
}
c.mongoConfig.databaseName = databaseName
if collectionName == "" {
return nil, errors.New("没有设置表名")
}
c.mongoConfig.collectionName = collectionName
hostname, _ := os.Hostname()
c.mongoConfig.hostname = hostname
c.mongoConfig.insideIp = goip.GetInsideIp(ctx)
c.mongoConfig.goVersion = runtime.Version()
c.log.mongo = true
// 创建时间序列集合
c.mongoCreateCollection(ctx)
// 创建索引
c.mongoCreateIndexes(ctx)
return c, nil
}
// 创建时间序列集合
func (c *ApiClient) mongoCreateCollection(ctx context.Context) {
var commandResult bson.M
commandErr := c.mongoClient.Db.Database(c.mongoConfig.databaseName).RunCommand(ctx, bson.D{{
"listCollections", 1,
}}).Decode(&commandResult)
if commandErr != nil {
c.zapLog.WithTraceId(ctx).Sugar().Errorf("检查时间序列集合:%s", commandErr)
} else {
err := c.mongoClient.Db.Database(c.mongoConfig.databaseName).CreateCollection(ctx, c.mongoConfig.collectionName, options.CreateCollection().SetTimeSeriesOptions(options.TimeSeries().SetTimeField("log_time")))
if err != nil {
c.zapLog.WithTraceId(ctx).Sugar().Errorf("创建时间序列集合:%s", err)
}
}
}
// 创建索引
func (c *ApiClient) mongoCreateIndexes(ctx context.Context) {
indexes, err := c.mongoClient.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).CreateManyIndexes(ctx, []mongo.IndexModel{
{
Keys: bson.D{{
Key: "trace_id",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "request_time",
Value: -1,
}},
}, {
Keys: bson.D{{
Key: "request_method",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "response_status_code",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "response_time",
Value: -1,
}},
}, {
Keys: bson.D{{
Key: "system_os",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "system_arch",
Value: -1,
}},
}, {
Keys: bson.D{{
Key: "go_version",
Value: -1,
}},
}, {
Keys: bson.D{{
Key: "sdk_version",
Value: -1,
}},
},
})
if err != nil {
c.zapLog.WithTraceId(ctx).Sugar().Errorf("创建索引:%s", err)
}
c.zapLog.WithTraceId(ctx).Sugar().Infof("创建索引:%s", indexes)
}
// 记录日志
func (c *ApiClient) mongoRecord(ctx context.Context, mongoLog apiMongolLog) (err error) {
mongoLog.SystemHostName = c.mongoConfig.hostname //【系统】主机名
mongoLog.SystemInsideIp = c.mongoConfig.insideIp //【系统】内网ip
mongoLog.GoVersion = c.mongoConfig.goVersion //【程序】Go版本
mongoLog.TraceId = gotrace_id.GetTraceIdContext(ctx) //【记录】跟踪编号
mongoLog.RequestIp = c.currentIp //【请求】请求Ip
mongoLog.SystemOs = c.config.os //【系统】系统类型
mongoLog.SystemArch = c.config.arch //【系统】系统架构
mongoLog.SystemCpuQuantity = c.config.maxProCs //【系统】CPU核数
mongoLog.LogId = primitive.NewObjectID() //【记录】编号
_, err = c.mongoClient.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).InsertOne(ctx, mongoLog)
if err != nil {
c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.mongoRecord]%s", err)
}
return err
}
// MongoQuery 查询
func (c *ApiClient) MongoQuery(ctx context.Context) *mongo.Collection {
return c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName)
}
// MongoDelete 删除
func (c *ApiClient) MongoDelete(ctx context.Context, hour int64) (*mongo.DeleteResult, error) {
filter := bson.D{{"log_time", bson.D{{"$lt", primitive.NewDateTimeFromTime(gotime.Current().BeforeHour(hour).Time)}}}}
return c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).DeleteMany(ctx, filter)
}
// MongoMiddleware 中间件
func (c *ApiClient) MongoMiddleware(ctx context.Context, request gorequest.Response, sdkVersion string) {
data := apiMongolLog{
LogTime: primitive.NewDateTimeFromTime(request.RequestTime), //【记录】时间
RequestTime: dorm.NewBsonTimeFromTime(request.RequestTime), //【请求】时间
RequestUri: request.RequestUri, //【请求】链接
RequestUrl: gourl.UriParse(request.RequestUri).Url, //【请求】链接
RequestApi: gourl.UriParse(request.RequestUri).Path, //【请求】接口
RequestMethod: request.RequestMethod, //【请求】方式
RequestParams: request.RequestParams, //【请求】参数
RequestHeader: request.RequestHeader, //【请求】头部
ResponseHeader: request.ResponseHeader, //【返回】头部
ResponseStatusCode: request.ResponseStatusCode, //【返回】状态码
ResponseContentLength: request.ResponseContentLength, //【返回】大小
ResponseTime: dorm.NewBsonTimeFromTime(request.ResponseTime), //【返回】时间
SdkVersion: sdkVersion, //【程序】Sdk版本
}
if request.ResponseHeader.Get("Content-Type") == "image/jpeg" || request.ResponseHeader.Get("Content-Type") == "image/png" || request.ResponseHeader.Get("Content-Type") == "image/jpg" {
c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddleware.type]%s %s", data.RequestUri, request.ResponseHeader.Get("Content-Type"))
} else {
if len(request.ResponseBody) > 0 {
data.ResponseBody = dorm.JsonDecodeNoError(request.ResponseBody) //【返回】内容
} else {
if c.logDebug {
c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddleware.len]%s %s", data.RequestUri, request.ResponseBody)
}
}
}
if c.logDebug {
c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddleware.data]%+v", data)
}
err := c.mongoRecord(ctx, data)
if err != nil {
c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.MongoMiddleware]%s", err.Error())
}
}
// MongoMiddlewareXml 中间件
func (c *ApiClient) MongoMiddlewareXml(ctx context.Context, request gorequest.Response, sdkVersion string) {
data := apiMongolLog{
LogTime: primitive.NewDateTimeFromTime(request.RequestTime), //【记录】时间
RequestTime: dorm.NewBsonTimeFromTime(request.RequestTime), //【请求】时间
RequestUri: request.RequestUri, //【请求】链接
RequestUrl: gourl.UriParse(request.RequestUri).Url, //【请求】链接
RequestApi: gourl.UriParse(request.RequestUri).Path, //【请求】接口
RequestMethod: request.RequestMethod, //【请求】方式
RequestParams: request.RequestParams, //【请求】参数
RequestHeader: request.RequestHeader, //【请求】头部
ResponseHeader: request.ResponseHeader, //【返回】头部
ResponseStatusCode: request.ResponseStatusCode, //【返回】状态码
ResponseContentLength: request.ResponseContentLength, //【返回】大小
ResponseTime: dorm.NewBsonTimeFromTime(request.ResponseTime), //【返回】时间
SdkVersion: sdkVersion, //【程序】Sdk版本
}
if request.ResponseHeader.Get("Content-Type") == "image/jpeg" || request.ResponseHeader.Get("Content-Type") == "image/png" || request.ResponseHeader.Get("Content-Type") == "image/jpg" {
c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddlewareXml.type]%s %s", data.RequestUri, request.ResponseHeader.Get("Content-Type"))
} else {
if len(request.ResponseBody) > 0 {
data.ResponseBody = dorm.XmlDecodeNoError(request.ResponseBody) //【返回】内容
} else {
if c.logDebug {
c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddlewareXml]%s %s", data.RequestUri, request.ResponseBody)
}
}
}
if c.logDebug {
c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddlewareXml.data]%+v", data)
}
err := c.mongoRecord(ctx, data)
if err != nil {
c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.MongoMiddlewareXml]%s", err.Error())
}
}
// MongoMiddlewareCustom 中间件
func (c *ApiClient) MongoMiddlewareCustom(ctx context.Context, api string, request gorequest.Response, sdkVersion string) {
data := apiMongolLog{
LogTime: primitive.NewDateTimeFromTime(request.RequestTime), //【记录】时间
RequestTime: dorm.NewBsonTimeFromTime(request.RequestTime), //【请求】时间
RequestUri: request.RequestUri, //【请求】链接
RequestUrl: gourl.UriParse(request.RequestUri).Url, //【请求】链接
RequestApi: api, //【请求】接口
RequestMethod: request.RequestMethod, //【请求】方式
RequestParams: request.RequestParams, //【请求】参数
RequestHeader: request.RequestHeader, //【请求】头部
ResponseHeader: request.ResponseHeader, //【返回】头部
ResponseStatusCode: request.ResponseStatusCode, //【返回】状态码
ResponseContentLength: request.ResponseContentLength, //【返回】大小
ResponseTime: dorm.NewBsonTimeFromTime(request.ResponseTime), //【返回】时间
SdkVersion: sdkVersion, //【程序】Sdk版本
}
if request.ResponseHeader.Get("Content-Type") == "image/jpeg" || request.ResponseHeader.Get("Content-Type") == "image/png" || request.ResponseHeader.Get("Content-Type") == "image/jpg" {
c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddlewareCustom.type]%s %s", data.RequestUri, request.ResponseHeader.Get("Content-Type"))
} else {
if len(request.ResponseBody) > 0 {
data.ResponseBody = dorm.JsonDecodeNoError(request.ResponseBody) //【返回】内容
} else {
if c.logDebug {
c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.MongoMiddlewareCustom]%s %s", data.RequestUri, request.ResponseBody)
}
}
}
if c.logDebug {
c.zapLog.WithTraceId(ctx).Sugar().Infof("[golog.api.mongoRecordJson.data]%+v", data)
}
err := c.mongoRecord(ctx, data)
if err != nil {
c.zapLog.WithTraceId(ctx).Sugar().Errorf("[golog.api.MongoMiddlewareCustom]%s", err.Error())
}
}

@ -1,5 +1,5 @@
package golog
const (
Version = "1.0.78"
Version = "1.0.79"
)

113
gin.go

@ -19,32 +19,20 @@ import (
// GinClient 框架
type GinClient struct {
gormClient *dorm.GormClient // 数据库驱动
mongoClient *dorm.MongoClient // 数据库驱动
ipService *goip.Client // ip服务
zapLog *ZapLog // 日志服务
logDebug bool // 日志开关
gormConfig struct {
gormClient *dorm.GormClient // 数据库驱动
ipService *goip.Client // ip服务
zapLog *ZapLog // 日志服务
logDebug bool // 日志开关
gormConfig struct {
tableName string // 表名
insideIp string // 内网ip
hostname string // 主机名
goVersion string // go版本
}
mongoConfig struct {
databaseName string // 库名
collectionName string // 表名
insideIp string // 内网ip
hostname string // 主机名
goVersion string // go版本
}
log struct {
gorm bool // 日志开关
mongo bool // 日志开关
}
config struct {
os string // 系统类型
arch string // 系统架构
maxProCs int // CPU核数
os string // 系统类型
arch string // 系统架构
jsonStatus bool // json状态
}
}
@ -52,18 +40,13 @@ type GinClient struct {
// string 表名
type ginGormClientFun func() (*dorm.GormClient, string)
// client 数据库服务
// string 库名
// string 表名
type ginMongoClientFun func() (*dorm.MongoClient, string, string)
// GinClientConfig 框架实例配置
type GinClientConfig struct {
IpService *goip.Client // ip服务
GormClientFun ginGormClientFun // 日志配置
MongoClientFun apiMongoClientFun // 日志配置
Debug bool // 日志开关
ZapLog *ZapLog // 日志服务
IpService *goip.Client // ip服务
GormClientFun ginGormClientFun // 日志配置
Debug bool // 日志开关
ZapLog *ZapLog // 日志服务
JsonStatus bool // json状态
}
// NewGinClient 创建框架实例化
@ -80,14 +63,14 @@ func NewGinClient(config *GinClientConfig) (*GinClient, error) {
c.logDebug = config.Debug
c.config.jsonStatus = config.JsonStatus
c.config.os = runtime.GOOS
c.config.arch = runtime.GOARCH
c.config.maxProCs = runtime.GOMAXPROCS(0)
gormClient, gormTableName := config.GormClientFun()
mongoClient, mongoDatabaseName, mongoCollectionName := config.MongoClientFun()
if (gormClient == nil || gormClient.Db == nil) || (mongoClient == nil || mongoClient.Db == nil) {
if gormClient == nil || gormClient.Db == nil {
return nil, errors.New("没有设置驱动")
}
@ -113,38 +96,6 @@ func NewGinClient(config *GinClientConfig) (*GinClient, error) {
c.gormConfig.insideIp = goip.GetInsideIp(ctx)
c.gormConfig.goVersion = runtime.Version()
c.log.gorm = true
}
if mongoClient != nil || mongoClient.Db != nil {
c.mongoClient = mongoClient
if mongoDatabaseName == "" {
return nil, errors.New("没有设置库名")
}
c.mongoConfig.databaseName = mongoDatabaseName
if mongoCollectionName == "" {
return nil, errors.New("没有设置表名")
}
c.mongoConfig.collectionName = mongoCollectionName
c.ipService = config.IpService
c.mongoConfig.hostname = hostname
c.mongoConfig.insideIp = goip.GetInsideIp(ctx)
c.mongoConfig.goVersion = runtime.Version()
c.log.mongo = true
// 创建时间序列集合
c.mongoCreateCollection(ctx)
// 创建索引
c.mongoCreateIndexes(ctx)
}
return c, nil
@ -244,32 +195,16 @@ func (c *GinClient) Middleware() gin.HandlerFunc {
var traceId = gotrace_id.GetGinTraceId(ginCtx)
// 记录
if c.log.gorm {
if dataJson {
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.Middleware]准备使用{gormRecordJson}保存数据:%s", data)
}
c.gormRecordJson(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp)
} else {
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.Middleware]准备使用{gormRecordXml}保存数据:%s", data)
}
c.gormRecordXml(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp)
if dataJson {
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.Middleware]准备使用{gormRecordJson}保存数据:%s", data)
}
}
// 记录
if c.log.mongo {
if dataJson {
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.Middleware]准备使用{mongoRecordJson}保存数据:%s", data)
}
c.mongoRecordJson(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp, requestClientIpLocationLatitude, requestClientIpLocationLongitude)
} else {
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.Middleware]准备使用{mongoRecordXml}保存数据:%s", data)
}
c.mongoRecordXml(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp, requestClientIpLocationLatitude, requestClientIpLocationLongitude)
c.gormRecordJson(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp, requestClientIpLocationLatitude, requestClientIpLocationLongitude)
} else {
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.Middleware]准备使用{gormRecordXml}保存数据:%s", data)
}
c.gormRecordXml(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp, requestClientIpLocationLatitude, requestClientIpLocationLongitude)
}
}()
}

@ -12,7 +12,7 @@ import (
"go.dtapp.net/gotime"
"go.dtapp.net/gotrace_id"
"go.dtapp.net/gourl"
"gorm.io/gorm"
"gorm.io/datatypes"
"io/ioutil"
"net"
"os"
@ -20,46 +20,13 @@ import (
"time"
)
// 模型结构体
type ginPostgresqlLog struct {
LogId uint `gorm:"primaryKey;comment:【记录】编号" json:"log_id,omitempty"` //【记录】编号
TraceId string `gorm:"index;comment:【系统】跟踪编号" json:"trace_id,omitempty"` //【系统】跟踪编号
RequestTime time.Time `gorm:"index;comment:【请求】时间" json:"request_time,omitempty"` //【请求】时间
RequestUri string `gorm:"comment:【请求】请求链接 域名+路径+参数" json:"request_uri,omitempty"` //【请求】请求链接 域名+路径+参数
RequestUrl string `gorm:"comment:【请求】请求链接 域名+路径" json:"request_url,omitempty"` //【请求】请求链接 域名+路径
RequestApi string `gorm:"index;comment:【请求】请求接口 路径" json:"request_api,omitempty"` //【请求】请求接口 路径
RequestMethod string `gorm:"index;comment:【请求】请求方式" json:"request_method,omitempty"` //【请求】请求方式
RequestProto string `gorm:"comment:【请求】请求协议" json:"request_proto,omitempty"` //【请求】请求协议
RequestUa string `gorm:"comment:【请求】请求UA" json:"request_ua,omitempty"` //【请求】请求UA
RequestReferer string `gorm:"comment:【请求】请求referer" json:"request_referer,omitempty"` //【请求】请求referer
RequestBody string `gorm:"comment:【请求】请求主体" json:"request_body,omitempty"` //【请求】请求主体
RequestUrlQuery string `gorm:"comment:【请求】请求URL参数" json:"request_url_query,omitempty"` //【请求】请求URL参数
RequestIp string `gorm:"index;comment:【请求】请求客户端Ip" json:"request_ip,omitempty"` //【请求】请求客户端Ip
RequestIpCountry string `gorm:"index;comment:【请求】请求客户端城市" json:"request_ip_country,omitempty"` //【请求】请求客户端城市
RequestIpProvince string `gorm:"index;comment:【请求】请求客户端省份" json:"request_ip_province,omitempty"` //【请求】请求客户端省份
RequestIpCity string `gorm:"index;comment:【请求】请求客户端城市" json:"request_ip_city,omitempty"` //【请求】请求客户端城市
RequestIpIsp string `gorm:"index;comment:【请求】请求客户端运营商" json:"request_ip_isp,omitempty"` //【请求】请求客户端运营商
RequestHeader string `gorm:"comment:【请求】请求头" json:"request_header,omitempty"` //【请求】请求头
ResponseTime time.Time `gorm:"index;comment:【返回】时间" json:"response_time,omitempty"` //【返回】时间
ResponseCode int `gorm:"index;comment:【返回】状态码" json:"response_code,omitempty"` //【返回】状态码
ResponseMsg string `gorm:"comment:【返回】描述" json:"response_msg,omitempty"` //【返回】描述
ResponseData string `gorm:"comment:【返回】数据" json:"response_data,omitempty"` //【返回】数据
CostTime int64 `gorm:"comment:【系统】花费时间" json:"cost_time,omitempty"` //【系统】花费时间
SystemHostName string `gorm:"index;comment:【系统】主机名" json:"system_host_name,omitempty"` //【系统】主机名
SystemInsideIp string `gorm:"index;comment:【系统】内网ip" json:"system_inside_ip,omitempty"` //【系统】内网ip
SystemOs string `gorm:"index;comment:【系统】系统类型" json:"system_os,omitempty"` //【系统】系统类型
SystemArch string `gorm:"index;comment:【系统】系统架构" json:"system_arch,omitempty"` //【系统】系统架构
SystemCpuQuantity int `gorm:"index;comment:【系统】CPU核数" json:"system_cpu_quantity,omitempty"` //【系统】CPU核数
GoVersion string `gorm:"index;comment:【程序】Go版本" json:"go_version,omitempty"` //【程序】Go版本
SdkVersion string `gorm:"index;comment:【程序】Sdk版本" json:"sdk_version,omitempty"` //【程序】Sdk版本
}
// GinGormClientConfig 框架实例配置
type GinGormClientConfig struct {
IpService *goip.Client // ip服务
GormClientFun ginGormClientFun // 日志配置
Debug bool // 日志开关
ZapLog *ZapLog // 日志服务
JsonStatus bool // json状态
}
// NewGinGormClient 创建框架实例化
@ -76,6 +43,8 @@ func NewGinGormClient(config *GinGormClientConfig) (*GinClient, error) {
c.logDebug = config.Debug
c.config.jsonStatus = config.JsonStatus
client, tableName := config.GormClientFun()
if client == nil || client.Db == nil {
@ -102,67 +71,142 @@ func NewGinGormClient(config *GinGormClientConfig) (*GinClient, error) {
c.gormConfig.insideIp = goip.GetInsideIp(ctx)
c.gormConfig.goVersion = runtime.Version()
c.log.gorm = true
return c, nil
}
// 创建模型
func (c *GinClient) gormAutoMigrate() (err error) {
err = c.gormClient.Db.Table(c.gormConfig.tableName).AutoMigrate(&ginPostgresqlLog{})
if err != nil {
c.zapLog.WithLogger().Sugar().Infof("[golog.gin.gormAutoMigrate]%s", err)
if c.config.jsonStatus {
err = c.gormClient.Db.Table(c.gormConfig.tableName).AutoMigrate(&ginPostgresqlLogJson{})
if err != nil {
c.zapLog.WithLogger().Sugar().Errorf("创建模型:%s", err)
}
} else {
err = c.gormClient.Db.Table(c.gormConfig.tableName).AutoMigrate(&ginPostgresqlLogString{})
if err != nil {
c.zapLog.WithLogger().Sugar().Errorf("创建模型:%s", err)
}
}
return err
}
// gormRecord 记录日志
func (c *GinClient) gormRecord(postgresqlLog ginPostgresqlLog) (err error) {
postgresqlLog.SystemHostName = c.gormConfig.hostname
postgresqlLog.SystemInsideIp = c.gormConfig.insideIp
postgresqlLog.GoVersion = c.gormConfig.goVersion
postgresqlLog.SdkVersion = Version
postgresqlLog.SystemOs = c.config.os
postgresqlLog.SystemArch = c.config.arch
postgresqlLog.SystemCpuQuantity = c.config.maxProCs
err = c.gormClient.Db.Table(c.gormConfig.tableName).Create(&postgresqlLog).Error
if err != nil {
c.zapLog.WithTraceIdStr(postgresqlLog.TraceId).Sugar().Errorf("[golog.gin.gormRecord]%s", err)
func (c *GinClient) gormRecord(data ginPostgresqlLogString) (err error) {
data.SystemHostName = c.gormConfig.hostname
data.SystemInsideIp = c.gormConfig.insideIp
data.GoVersion = c.gormConfig.goVersion
data.SdkVersion = Version
data.SystemOs = c.config.os
data.SystemArch = c.config.arch
if c.config.jsonStatus {
err = c.gormClient.Db.Table(c.gormConfig.tableName).Create(&ginPostgresqlLogJson{
TraceId: data.TraceId,
RequestTime: data.RequestTime,
RequestUri: data.RequestUri,
RequestUrl: data.RequestUrl,
RequestApi: data.RequestApi,
RequestMethod: data.RequestMethod,
RequestProto: data.RequestProto,
RequestUa: data.RequestUa,
RequestReferer: data.RequestReferer,
RequestBody: datatypes.JSON(data.RequestBody),
RequestUrlQuery: datatypes.JSON(data.RequestUrlQuery),
RequestIp: data.RequestIp,
RequestIpCountry: data.RequestIpCountry,
RequestIpProvince: data.RequestIpProvince,
RequestIpCity: data.RequestIpCity,
RequestIpIsp: data.RequestIpIsp,
RequestIpLongitude: data.RequestIpLongitude,
RequestIpLatitude: data.RequestIpLatitude,
RequestHeader: datatypes.JSON(data.RequestHeader),
ResponseTime: data.ResponseTime,
ResponseCode: data.ResponseCode,
ResponseMsg: data.ResponseMsg,
ResponseData: datatypes.JSON(data.ResponseData),
CostTime: data.CostTime,
SystemHostName: data.SystemHostName,
SystemInsideIp: data.SystemInsideIp,
SystemOs: data.SystemOs,
SystemArch: data.SystemArch,
GoVersion: data.GoVersion,
SdkVersion: data.SdkVersion,
}).Error
if err != nil {
c.zapLog.WithTraceIdStr(data.TraceId).Sugar().Errorf("记录日志失败:%s", err)
}
} else {
err = c.gormClient.Db.Table(c.gormConfig.tableName).Create(&ginPostgresqlLogString{
TraceId: data.TraceId,
RequestTime: data.RequestTime,
RequestUri: data.RequestUri,
RequestUrl: data.RequestUrl,
RequestApi: data.RequestApi,
RequestMethod: data.RequestMethod,
RequestProto: data.RequestProto,
RequestUa: data.RequestUa,
RequestReferer: data.RequestReferer,
RequestBody: data.RequestBody,
RequestUrlQuery: data.RequestUrlQuery,
RequestIp: data.RequestIp,
RequestIpCountry: data.RequestIpCountry,
RequestIpProvince: data.RequestIpProvince,
RequestIpCity: data.RequestIpCity,
RequestIpIsp: data.RequestIpIsp,
RequestIpLongitude: data.RequestIpLongitude,
RequestIpLatitude: data.RequestIpLatitude,
RequestHeader: data.RequestHeader,
ResponseTime: data.ResponseTime,
ResponseCode: data.ResponseCode,
ResponseMsg: data.ResponseMsg,
ResponseData: data.ResponseData,
CostTime: data.CostTime,
SystemHostName: data.SystemHostName,
SystemInsideIp: data.SystemInsideIp,
SystemOs: data.SystemOs,
SystemArch: data.SystemArch,
GoVersion: data.GoVersion,
SdkVersion: data.SdkVersion,
}).Error
if err != nil {
c.zapLog.WithTraceIdStr(data.TraceId).Sugar().Errorf("记录日志失败:%s", err)
}
}
return
}
func (c *GinClient) gormRecordJson(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string) {
func (c *GinClient) gormRecordJson(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string, requestClientIpLocationLatitude, requestClientIpLocationLongitude float64) {
if c.logDebug {
c.zapLog.WithLogger().Sugar().Infof("[golog.gin.gormRecordJson]收到保存数据要求:%s", c.gormConfig.tableName)
}
data := ginPostgresqlLog{
TraceId: traceId, //【系统】跟踪编号
RequestTime: requestTime, //【请求】时间
RequestUrl: ginCtx.Request.RequestURI, //【请求】请求链接
RequestApi: gourl.UriFilterExcludeQueryString(ginCtx.Request.RequestURI), //【请求】请求接口
RequestMethod: ginCtx.Request.Method, //【请求】请求方式
RequestProto: ginCtx.Request.Proto, //【请求】请求协议
RequestUa: ginCtx.Request.UserAgent(), //【请求】请求UA
RequestReferer: ginCtx.Request.Referer(), //【请求】请求referer
RequestUrlQuery: dorm.JsonEncodeNoError(ginCtx.Request.URL.Query()), //【请求】请求URL参数
RequestIp: clientIp, //【请求】请求客户端Ip
RequestIpCountry: requestClientIpCountry, //【请求】请求客户端城市
RequestIpProvince: requestClientIpProvince, //【请求】请求客户端省份
RequestIpCity: requestClientIpCity, //【请求】请求客户端城市
RequestIpIsp: requestClientIpIsp, //【请求】请求客户端运营商
RequestHeader: dorm.JsonEncodeNoError(ginCtx.Request.Header), //【请求】请求头
ResponseTime: gotime.Current().Time, //【返回】时间
ResponseCode: responseCode, //【返回】状态码
ResponseData: responseBody, //【返回】数据
CostTime: endTime - startTime, //【系统】花费时间
data := ginPostgresqlLogString{
TraceId: traceId, //【系统】跟踪编号
RequestTime: requestTime, //【请求】时间
RequestUrl: ginCtx.Request.RequestURI, //【请求】请求链接
RequestApi: gourl.UriFilterExcludeQueryString(ginCtx.Request.RequestURI), //【请求】请求接口
RequestMethod: ginCtx.Request.Method, //【请求】请求方式
RequestProto: ginCtx.Request.Proto, //【请求】请求协议
RequestUa: ginCtx.Request.UserAgent(), //【请求】请求UA
RequestReferer: ginCtx.Request.Referer(), //【请求】请求referer
RequestUrlQuery: dorm.JsonEncodeNoError(ginCtx.Request.URL.Query()), //【请求】请求URL参数
RequestIp: clientIp, //【请求】请求客户端Ip
RequestIpCountry: requestClientIpCountry, //【请求】请求客户端城市
RequestIpProvince: requestClientIpProvince, //【请求】请求客户端省份
RequestIpCity: requestClientIpCity, //【请求】请求客户端城市
RequestIpIsp: requestClientIpIsp, //【请求】请求客户端运营商
RequestIpLatitude: requestClientIpLocationLatitude, // 【请求】请求客户端纬度
RequestIpLongitude: requestClientIpLocationLongitude, // 【请求】请求客户端经度
RequestHeader: dorm.JsonEncodeNoError(ginCtx.Request.Header), //【请求】请求头
ResponseTime: gotime.Current().Time, //【返回】时间
ResponseCode: responseCode, //【返回】状态码
ResponseData: responseBody, //【返回】数据
CostTime: endTime - startTime, //【系统】花费时间
}
if ginCtx.Request.TLS == nil {
data.RequestUri = "http://" + ginCtx.Request.Host + ginCtx.Request.RequestURI //【请求】请求链接
@ -190,32 +234,34 @@ func (c *GinClient) gormRecordJson(ginCtx *gin.Context, traceId string, requestT
}
}
func (c *GinClient) gormRecordXml(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string) {
func (c *GinClient) gormRecordXml(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string, requestClientIpLocationLatitude, requestClientIpLocationLongitude float64) {
if c.logDebug {
c.zapLog.WithLogger().Sugar().Infof("[golog.gin.gormRecordXml]收到保存数据要求:%s", c.gormConfig.tableName)
}
data := ginPostgresqlLog{
TraceId: traceId, //【系统】跟踪编号
RequestTime: requestTime, //【请求】时间
RequestUrl: ginCtx.Request.RequestURI, //【请求】请求链接
RequestApi: gourl.UriFilterExcludeQueryString(ginCtx.Request.RequestURI), //【请求】请求接口
RequestMethod: ginCtx.Request.Method, //【请求】请求方式
RequestProto: ginCtx.Request.Proto, //【请求】请求协议
RequestUa: ginCtx.Request.UserAgent(), //【请求】请求UA
RequestReferer: ginCtx.Request.Referer(), //【请求】请求referer
RequestUrlQuery: dorm.JsonEncodeNoError(ginCtx.Request.URL.Query()), //【请求】请求URL参数
RequestIp: clientIp, //【请求】请求客户端Ip
RequestIpCountry: requestClientIpCountry, //【请求】请求客户端城市
RequestIpProvince: requestClientIpProvince, //【请求】请求客户端省份
RequestIpCity: requestClientIpCity, //【请求】请求客户端城市
RequestIpIsp: requestClientIpIsp, //【请求】请求客户端运营商
RequestHeader: dorm.JsonEncodeNoError(ginCtx.Request.Header), //【请求】请求头
ResponseTime: gotime.Current().Time, //【返回】时间
ResponseCode: responseCode, //【返回】状态码
ResponseData: responseBody, //【返回】数据
CostTime: endTime - startTime, //【系统】花费时间
data := ginPostgresqlLogString{
TraceId: traceId, //【系统】跟踪编号
RequestTime: requestTime, //【请求】时间
RequestUrl: ginCtx.Request.RequestURI, //【请求】请求链接
RequestApi: gourl.UriFilterExcludeQueryString(ginCtx.Request.RequestURI), //【请求】请求接口
RequestMethod: ginCtx.Request.Method, //【请求】请求方式
RequestProto: ginCtx.Request.Proto, //【请求】请求协议
RequestUa: ginCtx.Request.UserAgent(), //【请求】请求UA
RequestReferer: ginCtx.Request.Referer(), //【请求】请求referer
RequestUrlQuery: dorm.JsonEncodeNoError(ginCtx.Request.URL.Query()), //【请求】请求URL参数
RequestIp: clientIp, //【请求】请求客户端Ip
RequestIpCountry: requestClientIpCountry, //【请求】请求客户端城市
RequestIpProvince: requestClientIpProvince, //【请求】请求客户端省份
RequestIpCity: requestClientIpCity, //【请求】请求客户端城市
RequestIpIsp: requestClientIpIsp, //【请求】请求客户端运营商
RequestIpLatitude: requestClientIpLocationLatitude, // 【请求】请求客户端纬度
RequestIpLongitude: requestClientIpLocationLongitude, // 【请求】请求客户端经度
RequestHeader: dorm.JsonEncodeNoError(ginCtx.Request.Header), //【请求】请求头
ResponseTime: gotime.Current().Time, //【返回】时间
ResponseCode: responseCode, //【返回】状态码
ResponseData: responseBody, //【返回】数据
CostTime: endTime - startTime, //【系统】花费时间
}
if ginCtx.Request.TLS == nil {
data.RequestUri = "http://" + ginCtx.Request.Host + ginCtx.Request.RequestURI //【请求】请求链接
@ -244,14 +290,13 @@ func (c *GinClient) gormRecordXml(ginCtx *gin.Context, traceId string, requestTi
}
}
// GormQuery 查询
func (c *GinClient) GormQuery(ctx context.Context) *gorm.DB {
return c.gormClient.Db.Table(c.gormConfig.tableName)
}
// GormDelete 删除
func (c *GinClient) GormDelete(ctx context.Context, hour int64) error {
return c.gormClient.Db.Table(c.gormConfig.tableName).Where("request_time < ?", gotime.Current().BeforeHour(hour).Format()).Delete(&ginPostgresqlLog{}).Error
if c.config.jsonStatus {
return c.gormClient.Db.Table(c.gormConfig.tableName).Where("request_time < ?", gotime.Current().BeforeHour(hour).Format()).Delete(&ginPostgresqlLogJson{}).Error
} else {
return c.gormClient.Db.Table(c.gormConfig.tableName).Where("request_time < ?", gotime.Current().BeforeHour(hour).Format()).Delete(&ginPostgresqlLogString{}).Error
}
}
// GormMiddleware 中间件
@ -306,6 +351,8 @@ func (c *GinClient) GormMiddleware() gin.HandlerFunc {
var requestClientIpProvince string
var requestClientIpCity string
var requestClientIpIsp string
var requestClientIpLocationLatitude float64
var requestClientIpLocationLongitude float64
if c.ipService != nil {
if net.ParseIP(clientIp).To4() != nil {
// IPv4
@ -314,12 +361,16 @@ func (c *GinClient) GormMiddleware() gin.HandlerFunc {
requestClientIpProvince = info.Ip2regionV2info.Province
requestClientIpCity = info.Ip2regionV2info.City
requestClientIpIsp = info.Ip2regionV2info.Operator
requestClientIpLocationLatitude = info.GeoipInfo.Location.Latitude
requestClientIpLocationLongitude = info.GeoipInfo.Location.Longitude
} else if net.ParseIP(clientIp).To16() != nil {
// IPv6
info := c.ipService.Analyse(clientIp)
requestClientIpCountry = info.Ipv6wryInfo.Country
requestClientIpProvince = info.Ipv6wryInfo.Province
requestClientIpCity = info.Ipv6wryInfo.City
requestClientIpLocationLatitude = info.GeoipInfo.Location.Latitude
requestClientIpLocationLongitude = info.GeoipInfo.Location.Longitude
}
}
@ -332,12 +383,12 @@ func (c *GinClient) GormMiddleware() gin.HandlerFunc {
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.GormMiddleware]准备使用{gormRecordJson}保存数据:%s", data)
}
c.gormRecordJson(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp)
c.gormRecordJson(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp, requestClientIpLocationLatitude, requestClientIpLocationLongitude)
} else {
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.GormMiddleware]准备使用{gormRecordXml}保存数据:%s", data)
}
c.gormRecordXml(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp)
c.gormRecordXml(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp, requestClientIpLocationLatitude, requestClientIpLocationLongitude)
}
}
}()

@ -0,0 +1,42 @@
package golog
import (
"gorm.io/datatypes"
"time"
)
// 模型
type ginPostgresqlLogJson struct {
LogId uint `gorm:"primaryKey;comment:【记录】编号" json:"log_id,omitempty"` //【记录】编号
TraceId string `gorm:"index;comment:【系统】跟踪编号" json:"trace_id,omitempty"` //【系统】跟踪编号
RequestTime time.Time `gorm:"index;comment:【请求】时间" json:"request_time,omitempty"` //【请求】时间
RequestUri string `gorm:"comment:【请求】请求链接 域名+路径+参数" json:"request_uri,omitempty"` //【请求】请求链接 域名+路径+参数
RequestUrl string `gorm:"comment:【请求】请求链接 域名+路径" json:"request_url,omitempty"` //【请求】请求链接 域名+路径
RequestApi string `gorm:"index;comment:【请求】请求接口 路径" json:"request_api,omitempty"` //【请求】请求接口 路径
RequestMethod string `gorm:"index;comment:【请求】请求方式" json:"request_method,omitempty"` //【请求】请求方式
RequestProto string `gorm:"comment:【请求】请求协议" json:"request_proto,omitempty"` //【请求】请求协议
RequestUa string `gorm:"comment:【请求】请求UA" json:"request_ua,omitempty"` //【请求】请求UA
RequestReferer string `gorm:"comment:【请求】请求referer" json:"request_referer,omitempty"` //【请求】请求referer
RequestBody datatypes.JSON `gorm:"type:jsonb;comment:【请求】请求主体" json:"request_body,omitempty"` //【请求】请求主体
RequestUrlQuery datatypes.JSON `gorm:"type:jsonb;comment:【请求】请求URL参数" json:"request_url_query,omitempty"` //【请求】请求URL参数
RequestIp string `gorm:"index;comment:【请求】请求客户端Ip" json:"request_ip,omitempty"` //【请求】请求客户端Ip
RequestIpCountry string `gorm:"index;comment:【请求】请求客户端城市" json:"request_ip_country,omitempty"` //【请求】请求客户端城市
RequestIpProvince string `gorm:"index;comment:【请求】请求客户端省份" json:"request_ip_province,omitempty"` //【请求】请求客户端省份
RequestIpCity string `gorm:"index;comment:【请求】请求客户端城市" json:"request_ip_city,omitempty"` //【请求】请求客户端城市
RequestIpIsp string `gorm:"index;comment:【请求】请求客户端运营商" json:"request_ip_isp,omitempty"` //【请求】请求客户端运营商
RequestIpLongitude float64 `gorm:"index;comment:【请求】请求客户端经度" json:"request_ip_longitude,omitempty"` //【请求】请求客户端经度
RequestIpLatitude float64 `gorm:"index;comment:【请求】请求客户端纬度" json:"request_ip_latitude,omitempty"` //【请求】请求客户端纬度
//RequestIpLocation `gorm:"index;comment:【请求】请求客户端位置" json:"request_ip_location,omitempty"` //【请求】请求客户端位置
RequestHeader datatypes.JSON `gorm:"type:jsonb;comment:【请求】请求头" json:"request_header,omitempty"` //【请求】请求头
ResponseTime time.Time `gorm:"index;comment:【返回】时间" json:"response_time,omitempty"` //【返回】时间
ResponseCode int `gorm:"index;comment:【返回】状态码" json:"response_code,omitempty"` //【返回】状态码
ResponseMsg string `gorm:"comment:【返回】描述" json:"response_msg,omitempty"` //【返回】描述
ResponseData datatypes.JSON `gorm:"type:jsonb;comment:【返回】数据" json:"response_data,omitempty"` //【返回】数据
CostTime int64 `gorm:"comment:【系统】花费时间" json:"cost_time,omitempty"` //【系统】花费时间
SystemHostName string `gorm:"index;comment:【系统】主机名" json:"system_host_name,omitempty"` //【系统】主机名
SystemInsideIp string `gorm:"index;comment:【系统】内网ip" json:"system_inside_ip,omitempty"` //【系统】内网ip
SystemOs string `gorm:"index;comment:【系统】系统类型" json:"system_os,omitempty"` //【系统】系统类型
SystemArch string `gorm:"index;comment:【系统】系统架构" json:"system_arch,omitempty"` //【系统】系统架构
GoVersion string `gorm:"comment:【程序】Go版本" json:"go_version,omitempty"` //【程序】Go版本
SdkVersion string `gorm:"comment:【程序】Sdk版本" json:"sdk_version,omitempty"` //【程序】Sdk版本
}

@ -0,0 +1,39 @@
package golog
import "time"
// 模型
type ginPostgresqlLogString struct {
LogId uint `gorm:"primaryKey;comment:【记录】编号" json:"log_id,omitempty"` //【记录】编号
TraceId string `gorm:"index;comment:【系统】跟踪编号" json:"trace_id,omitempty"` //【系统】跟踪编号
RequestTime time.Time `gorm:"index;comment:【请求】时间" json:"request_time,omitempty"` //【请求】时间
RequestUri string `gorm:"comment:【请求】请求链接 域名+路径+参数" json:"request_uri,omitempty"` //【请求】请求链接 域名+路径+参数
RequestUrl string `gorm:"comment:【请求】请求链接 域名+路径" json:"request_url,omitempty"` //【请求】请求链接 域名+路径
RequestApi string `gorm:"index;comment:【请求】请求接口 路径" json:"request_api,omitempty"` //【请求】请求接口 路径
RequestMethod string `gorm:"index;comment:【请求】请求方式" json:"request_method,omitempty"` //【请求】请求方式
RequestProto string `gorm:"comment:【请求】请求协议" json:"request_proto,omitempty"` //【请求】请求协议
RequestUa string `gorm:"comment:【请求】请求UA" json:"request_ua,omitempty"` //【请求】请求UA
RequestReferer string `gorm:"comment:【请求】请求referer" json:"request_referer,omitempty"` //【请求】请求referer
RequestBody string `gorm:"comment:【请求】请求主体" json:"request_body,omitempty"` //【请求】请求主体
RequestUrlQuery string `gorm:"comment:【请求】请求URL参数" json:"request_url_query,omitempty"` //【请求】请求URL参数
RequestIp string `gorm:"index;comment:【请求】请求客户端Ip" json:"request_ip,omitempty"` //【请求】请求客户端Ip
RequestIpCountry string `gorm:"index;comment:【请求】请求客户端城市" json:"request_ip_country,omitempty"` //【请求】请求客户端城市
RequestIpProvince string `gorm:"index;comment:【请求】请求客户端省份" json:"request_ip_province,omitempty"` //【请求】请求客户端省份
RequestIpCity string `gorm:"index;comment:【请求】请求客户端城市" json:"request_ip_city,omitempty"` //【请求】请求客户端城市
RequestIpIsp string `gorm:"index;comment:【请求】请求客户端运营商" json:"request_ip_isp,omitempty"` //【请求】请求客户端运营商
RequestIpLongitude float64 `gorm:"index;comment:【请求】请求客户端经度" json:"request_ip_longitude,omitempty"` //【请求】请求客户端经度
RequestIpLatitude float64 `gorm:"index;comment:【请求】请求客户端纬度" json:"request_ip_latitude,omitempty"` //【请求】请求客户端纬度
//RequestIpLocation `gorm:"index;comment:【请求】请求客户端位置" json:"request_ip_location,omitempty"` //【请求】请求客户端位置
RequestHeader string `gorm:"comment:【请求】请求头" json:"request_header,omitempty"` //【请求】请求头
ResponseTime time.Time `gorm:"index;comment:【返回】时间" json:"response_time,omitempty"` //【返回】时间
ResponseCode int `gorm:"index;comment:【返回】状态码" json:"response_code,omitempty"` //【返回】状态码
ResponseMsg string `gorm:"comment:【返回】描述" json:"response_msg,omitempty"` //【返回】描述
ResponseData string `gorm:"comment:【返回】数据" json:"response_data,omitempty"` //【返回】数据
CostTime int64 `gorm:"comment:【系统】花费时间" json:"cost_time,omitempty"` //【系统】花费时间
SystemHostName string `gorm:"index;comment:【系统】主机名" json:"system_host_name,omitempty"` //【系统】主机名
SystemInsideIp string `gorm:"index;comment:【系统】内网ip" json:"system_inside_ip,omitempty"` //【系统】内网ip
SystemOs string `gorm:"index;comment:【系统】系统类型" json:"system_os,omitempty"` //【系统】系统类型
SystemArch string `gorm:"index;comment:【系统】系统架构" json:"system_arch,omitempty"` //【系统】系统架构
GoVersion string `gorm:"comment:【程序】Go版本" json:"go_version,omitempty"` //【程序】Go版本
SdkVersion string `gorm:"comment:【程序】Sdk版本" json:"sdk_version,omitempty"` //【程序】Sdk版本
}

@ -1,481 +0,0 @@
package golog
import (
"bytes"
"context"
"encoding/json"
"errors"
"github.com/gin-gonic/gin"
"go.dtapp.net/dorm"
"go.dtapp.net/goip"
"go.dtapp.net/gorequest"
"go.dtapp.net/gotime"
"go.dtapp.net/gotrace_id"
"go.dtapp.net/gourl"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"io/ioutil"
"net"
"os"
"runtime"
"time"
)
type ginMongoLogRequestIpLocationLocation struct {
Type string `json:"type,omitempty" bson:"type,omitempty"` // GeoJSON类型
Coordinates []float64 `json:"coordinates,omitempty" bson:"coordinates,omitempty"` // 经度,纬度
}
// 模型结构体
type ginMongoLog struct {
LogId primitive.ObjectID `json:"log_id,omitempty" bson:"_id,omitempty"` //【记录】编号
LogTime primitive.DateTime `json:"log_time,omitempty" bson:"log_time,omitempty"` //【记录】时间
TraceId string `json:"trace_id,omitempty" bson:"trace_id,omitempty"` //【记录】跟踪编号
RequestTime dorm.BsonTime `json:"request_time,omitempty" bson:"request_time,omitempty"` //【请求】时间
RequestUri string `json:"request_uri,omitempty" bson:"request_uri,omitempty"` //【请求】请求链接 域名+路径+参数
RequestUrl string `json:"request_url,omitempty" bson:"request_url,omitempty"` //【请求】请求链接 域名+路径
RequestApi string `json:"request_api,omitempty" bson:"request_api,omitempty"` //【请求】请求接口 路径
RequestMethod string `json:"request_method,omitempty" bson:"request_method,omitempty"` //【请求】请求方式
RequestProto string `json:"request_proto,omitempty" bson:"request_proto,omitempty"` //【请求】请求协议
RequestUa string `json:"request_ua,omitempty" bson:"request_ua,omitempty"` //【请求】请求UA
RequestReferer string `json:"request_referer,omitempty" bson:"request_referer,omitempty"` //【请求】请求referer
RequestBody interface{} `json:"request_body,omitempty" bson:"request_body,omitempty"` //【请求】请求主体
RequestUrlQuery interface{} `json:"request_url_query,omitempty" bson:"request_url_query,omitempty"` //【请求】请求URL参数
RequestIp string `json:"request_ip,omitempty" bson:"request_ip,omitempty"` //【请求】请求客户端Ip
RequestIpCountry string `json:"request_ip_country,omitempty" bson:"request_ip_country,omitempty"` //【请求】请求客户端国家
RequestIpProvince string `json:"request_ip_province,omitempty" bson:"request_ip_province,omitempty"` //【请求】请求客户端省份
RequestIpCity string `json:"request_ip_city,omitempty" bson:"request_ip_city,omitempty"` //【请求】请求客户端城市
RequestIpIsp string `json:"request_ip_isp,omitempty" bson:"request_ip_isp,omitempty"` //【请求】请求客户端运营商
RequestIpLocation ginMongoLogRequestIpLocationLocation `json:"request_ip_location,omitempty" bson:"request_ip_location,omitempty"` //【请求】请求客户端位置
RequestHeader interface{} `json:"request_header,omitempty" bson:"request_header,omitempty"` //【请求】请求头
ResponseTime dorm.BsonTime `json:"response_time,omitempty" bson:"response_time,omitempty"` //【返回】时间
ResponseCode int `json:"response_code,omitempty" bson:"response_code,omitempty"` //【返回】状态码
ResponseMsg string `json:"response_msg,omitempty" bson:"response_msg,omitempty"` //【返回】描述
ResponseData interface{} `json:"response_data,omitempty" bson:"response_data,omitempty"` //【返回】数据
CostTime int64 `json:"cost_time,omitempty" bson:"cost_time,omitempty"` //【系统】花费时间
SystemHostName string `json:"system_host_name,omitempty" bson:"system_host_name,omitempty"` //【系统】主机名
SystemInsideIp string `json:"system_inside_ip,omitempty" bson:"system_inside_ip,omitempty"` //【系统】内网ip
SystemOs string `json:"system_os,omitempty" bson:"system_os,omitempty"` //【系统】系统类型
SystemArch string `json:"system_arch,omitempty" bson:"system_arch,omitempty"` //【系统】系统架构
SystemCpuQuantity int `json:"system_cpu_quantity,omitempty" bson:"system_cpu_quantity,omitempty"` //【系统】CPU核数
GoVersion string `json:"go_version,omitempty" bson:"go_version,omitempty"` //【程序】Go版本
SdkVersion string `json:"sdk_version,omitempty" bson:"sdk_version,omitempty"` //【程序】Sdk版本
}
// GinMongoClientConfig 框架实例配置
type GinMongoClientConfig struct {
IpService *goip.Client // ip服务
MongoClientFun ginMongoClientFun // 日志配置
Debug bool // 日志开关
ZapLog *ZapLog // 日志服务
}
// NewGinMongoClient 创建框架实例化
// client 数据库服务
// databaseName 库名
// collectionName 表名
// ipService ip服务
func NewGinMongoClient(config *GinMongoClientConfig) (*GinClient, error) {
var ctx = context.Background()
c := &GinClient{}
c.zapLog = config.ZapLog
c.logDebug = config.Debug
client, databaseName, collectionName := config.MongoClientFun()
if client == nil || client.Db == nil {
return nil, errors.New("没有设置驱动")
}
c.mongoClient = client
if databaseName == "" {
return nil, errors.New("没有设置库名")
}
c.mongoConfig.databaseName = databaseName
if collectionName == "" {
return nil, errors.New("没有设置表名")
}
c.mongoConfig.collectionName = collectionName
c.ipService = config.IpService
hostname, _ := os.Hostname()
c.mongoConfig.hostname = hostname
c.mongoConfig.insideIp = goip.GetInsideIp(ctx)
c.mongoConfig.goVersion = runtime.Version()
c.log.mongo = true
// 创建时间序列集合
c.mongoCreateCollection(ctx)
// 创建索引
c.mongoCreateIndexes(ctx)
return c, nil
}
// 创建时间序列集合
func (c *GinClient) mongoCreateCollection(ctx context.Context) {
var commandResult bson.M
commandErr := c.mongoClient.Db.Database(c.mongoConfig.databaseName).RunCommand(ctx, bson.D{{
"listCollections", 1,
}}).Decode(&commandResult)
if commandErr != nil {
c.zapLog.WithTraceId(ctx).Sugar().Error("检查时间序列集合:", commandErr)
} else {
err := c.mongoClient.Db.Database(c.mongoConfig.databaseName).CreateCollection(ctx, c.mongoConfig.collectionName, options.CreateCollection().SetTimeSeriesOptions(options.TimeSeries().SetTimeField("log_time")))
if err != nil {
c.zapLog.WithTraceId(ctx).Sugar().Error("创建时间序列集合:", err)
}
}
}
// 创建索引
func (c *GinClient) mongoCreateIndexes(ctx context.Context) {
indexes, err := c.mongoClient.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).CreateManyIndexes(ctx, []mongo.IndexModel{
{
Keys: bson.D{{
Key: "trace_id",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "request_time",
Value: -1,
}},
}, {
Keys: bson.D{{
Key: "request_method",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "request_ip",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "request_ip_country",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "request_ip_province",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "request_ip_city",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "request_ip_isp",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "response_time",
Value: -1,
}},
}, {
Keys: bson.D{{
Key: "response_code",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "system_host_name",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "system_os",
Value: 1,
}},
}, {
Keys: bson.D{{
Key: "system_arch",
Value: -1,
}},
}, {
Keys: bson.D{{
Key: "go_version",
Value: -1,
}},
}, {
Keys: bson.D{{
Key: "sdk_version",
Value: -1,
}},
}, {
Keys: bson.D{{
Key: "request_ip_location",
Value: "2dsphere",
}},
},
})
if err != nil {
c.zapLog.WithTraceId(ctx).Sugar().Errorf("创建索引:%s", err)
}
c.zapLog.WithTraceId(ctx).Sugar().Infof("创建索引:%s", indexes)
}
// 记录日志
func (c *GinClient) mongoRecord(ctx context.Context, mongoLog ginMongoLog) (err error) {
mongoLog.SystemHostName = c.mongoConfig.hostname //【系统】主机名
mongoLog.SystemInsideIp = c.mongoConfig.insideIp //【系统】内网ip
mongoLog.GoVersion = c.mongoConfig.goVersion //【程序】Go版本
mongoLog.SdkVersion = Version //【程序】Sdk版本
mongoLog.SystemOs = c.config.os //【系统】系统类型
mongoLog.SystemArch = c.config.arch //【系统】系统架构
mongoLog.SystemCpuQuantity = c.config.maxProCs //【系统】CPU核数
mongoLog.LogId = primitive.NewObjectID() //【记录】编号
_, err = c.mongoClient.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).InsertOne(ctx, mongoLog)
if err != nil {
c.zapLog.WithTraceIdStr(mongoLog.TraceId).Sugar().Errorf("[golog.gin.mongoRecord]%s", err)
}
return err
}
func (c *GinClient) mongoRecordJson(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string, requestClientIpLocationLatitude, requestClientIpLocationLongitude float64) {
var ctx = gotrace_id.SetGinTraceIdContext(context.Background(), ginCtx)
if c.logDebug {
c.zapLog.WithLogger().Sugar().Infof("[golog.gin.mongoRecordJson]收到保存数据要求:%s,%s", c.mongoConfig.databaseName, c.mongoConfig.collectionName)
}
data := ginMongoLog{
TraceId: traceId, //【记录】跟踪编号
LogTime: primitive.NewDateTimeFromTime(requestTime), //【记录】时间
RequestTime: dorm.NewBsonTimeFromTime(requestTime), //【请求】时间
RequestUrl: ginCtx.Request.RequestURI, //【请求】请求链接
RequestApi: gourl.UriFilterExcludeQueryString(ginCtx.Request.RequestURI), //【请求】请求接口
RequestMethod: ginCtx.Request.Method, //【请求】请求方式
RequestProto: ginCtx.Request.Proto, //【请求】请求协议
RequestUa: ginCtx.Request.UserAgent(), //【请求】请求UA
RequestReferer: ginCtx.Request.Referer(), //【请求】请求referer
RequestUrlQuery: ginCtx.Request.URL.Query(), //【请求】请求URL参数
RequestIp: clientIp, //【请求】请求客户端Ip
RequestIpCountry: requestClientIpCountry, //【请求】请求客户端国家
RequestIpProvince: requestClientIpProvince, //【请求】请求客户端省份
RequestIpCity: requestClientIpCity, //【请求】请求客户端城市
RequestIpIsp: requestClientIpIsp, //【请求】请求客户端运营商
RequestHeader: ginCtx.Request.Header, //【请求】请求头
ResponseTime: dorm.NewBsonTimeCurrent(), //【返回】时间
ResponseCode: responseCode, //【返回】状态码
ResponseData: c.jsonUnmarshal(responseBody), //【返回】数据
CostTime: endTime - startTime, //【系统】花费时间
}
if ginCtx.Request.TLS == nil {
data.RequestUri = "http://" + ginCtx.Request.Host + ginCtx.Request.RequestURI //【请求】请求链接
} else {
data.RequestUri = "https://" + ginCtx.Request.Host + ginCtx.Request.RequestURI //【请求】请求链接
}
if len(requestBody) > 0 {
data.RequestBody = dorm.JsonDecodeNoError(requestBody) //【请求】请求主体
} else {
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.mongoRecordJson.len]%s%s", data.RequestUri, requestBody)
}
}
if requestClientIpLocationLatitude != 0 && requestClientIpLocationLongitude != 0 {
data.RequestIpLocation = ginMongoLogRequestIpLocationLocation{
Type: "Point",
Coordinates: []float64{requestClientIpLocationLongitude, requestClientIpLocationLatitude},
}
}
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.mongoRecordJson.data]%+v", data)
}
err := c.mongoRecord(ctx, data)
if err != nil {
c.zapLog.WithTraceIdStr(traceId).Sugar().Errorf("[golog.gin.mongoRecordJson]%s", err)
}
}
func (c *GinClient) mongoRecordXml(ginCtx *gin.Context, traceId string, requestTime time.Time, requestBody []byte, responseCode int, responseBody string, startTime, endTime int64, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp string, requestClientIpLocationLatitude, requestClientIpLocationLongitude float64) {
var ctx = gotrace_id.SetGinTraceIdContext(context.Background(), ginCtx)
if c.logDebug {
c.zapLog.WithLogger().Sugar().Infof("[golog.gin.mongoRecordXml]收到保存数据要求:%s,%s", c.mongoConfig.databaseName, c.mongoConfig.collectionName)
}
data := ginMongoLog{
TraceId: traceId, //【记录】跟踪编号
LogTime: primitive.NewDateTimeFromTime(requestTime), //【记录】时间
RequestTime: dorm.NewBsonTimeFromTime(requestTime), //【请求】时间
RequestUrl: ginCtx.Request.RequestURI, //【请求】请求链接
RequestApi: gourl.UriFilterExcludeQueryString(ginCtx.Request.RequestURI), //【请求】请求接口
RequestMethod: ginCtx.Request.Method, //【请求】请求方式
RequestProto: ginCtx.Request.Proto, //【请求】请求协议
RequestUa: ginCtx.Request.UserAgent(), //【请求】请求UA
RequestReferer: ginCtx.Request.Referer(), //【请求】请求referer
RequestUrlQuery: ginCtx.Request.URL.Query(), //【请求】请求URL参数
RequestIp: clientIp, //【请求】请求客户端Ip
RequestIpCountry: requestClientIpCountry, //【请求】请求客户端国家
RequestIpProvince: requestClientIpProvince, //【请求】请求客户端省份
RequestIpCity: requestClientIpCity, //【请求】请求客户端城市
RequestIpIsp: requestClientIpIsp, //【请求】请求客户端运营商
RequestHeader: ginCtx.Request.Header, //【请求】请求头
ResponseTime: dorm.NewBsonTimeCurrent(), //【返回】时间
ResponseCode: responseCode, //【返回】状态码
ResponseData: c.jsonUnmarshal(responseBody), //【返回】数据
CostTime: endTime - startTime, //【系统】花费时间
}
if ginCtx.Request.TLS == nil {
data.RequestUri = "http://" + ginCtx.Request.Host + ginCtx.Request.RequestURI //【请求】请求链接
} else {
data.RequestUri = "https://" + ginCtx.Request.Host + ginCtx.Request.RequestURI //【请求】请求链接
}
if len(requestBody) > 0 {
data.RequestBody = dorm.XmlDecodeNoError(requestBody) //【请求】请求主体
} else {
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.mongoRecordXml.len]%s%s", data.RequestUri, requestBody)
}
}
if requestClientIpLocationLatitude != 0 && requestClientIpLocationLongitude != 0 {
data.RequestIpLocation = ginMongoLogRequestIpLocationLocation{
Type: "Point",
Coordinates: []float64{requestClientIpLocationLongitude, requestClientIpLocationLatitude},
}
}
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.mongoRecordXml.data]%+v", data)
}
err := c.mongoRecord(ctx, data)
if err != nil {
c.zapLog.WithTraceIdStr(traceId).Sugar().Errorf("[golog.gin.mongoRecordXml]%s", err)
}
}
// MongoQuery 查询
func (c *GinClient) MongoQuery(ctx context.Context) *mongo.Collection {
return c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName)
}
// MongoDelete 删除
func (c *GinClient) MongoDelete(ctx context.Context, hour int64) (*mongo.DeleteResult, error) {
filter := bson.D{{"log_time", bson.D{{"$lt", primitive.NewDateTimeFromTime(gotime.Current().BeforeHour(hour).Time)}}}}
return c.mongoClient.Db.Database(c.mongoConfig.databaseName).Collection(c.mongoConfig.collectionName).DeleteMany(ctx, filter)
}
// MongoMiddleware 中间件
func (c *GinClient) MongoMiddleware() gin.HandlerFunc {
return func(ginCtx *gin.Context) {
// 开始时间
startTime := gotime.Current().TimestampWithMillisecond()
requestTime := gotime.Current().Time
// 获取
data, _ := ioutil.ReadAll(ginCtx.Request.Body)
if c.logDebug {
c.zapLog.WithLogger().Sugar().Infof("[golog.gin.MongoMiddleware] %s", data)
}
// 复用
ginCtx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data))
blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: ginCtx.Writer}
ginCtx.Writer = blw
// 处理请求
ginCtx.Next()
// 响应
responseCode := ginCtx.Writer.Status()
responseBody := blw.body.String()
//结束时间
endTime := gotime.Current().TimestampWithMillisecond()
go func() {
var dataJson = true
// 解析请求内容
var jsonBody map[string]interface{}
// 判断是否有内容
if len(data) > 0 {
err := json.Unmarshal(data, &jsonBody)
if err != nil {
dataJson = false
}
}
clientIp := gorequest.ClientIp(ginCtx.Request)
var requestClientIpCountry string
var requestClientIpProvince string
var requestClientIpCity string
var requestClientIpIsp string
var requestClientIpLocationLatitude float64
var requestClientIpLocationLongitude float64
if c.ipService != nil {
if net.ParseIP(clientIp).To4() != nil {
// IPv4
info := c.ipService.Analyse(clientIp)
requestClientIpCountry = info.Ip2regionV2info.Country
requestClientIpProvince = info.Ip2regionV2info.Province
requestClientIpCity = info.Ip2regionV2info.City
requestClientIpIsp = info.Ip2regionV2info.Operator
requestClientIpLocationLatitude = info.GeoipInfo.Location.Latitude
requestClientIpLocationLongitude = info.GeoipInfo.Location.Longitude
} else if net.ParseIP(clientIp).To16() != nil {
// IPv6
info := c.ipService.Analyse(clientIp)
requestClientIpCountry = info.Ipv6wryInfo.Country
requestClientIpProvince = info.Ipv6wryInfo.Province
requestClientIpCity = info.Ipv6wryInfo.City
requestClientIpLocationLatitude = info.GeoipInfo.Location.Latitude
requestClientIpLocationLongitude = info.GeoipInfo.Location.Longitude
}
}
// 记录
if c.mongoClient != nil && c.mongoClient.Db != nil {
var traceId = gotrace_id.GetGinTraceId(ginCtx)
if dataJson {
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.MongoMiddleware]准备使用{mongoRecordJson}保存数据:%s", data)
}
c.mongoRecordJson(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp, requestClientIpLocationLatitude, requestClientIpLocationLongitude)
} else {
if c.logDebug {
c.zapLog.WithTraceIdStr(traceId).Sugar().Infof("[golog.gin.MongoMiddleware]准备使用{mongoRecordXml}保存数据:%s", data)
}
c.mongoRecordXml(ginCtx, traceId, requestTime, data, responseCode, responseBody, startTime, endTime, clientIp, requestClientIpCountry, requestClientIpProvince, requestClientIpCity, requestClientIpIsp, requestClientIpLocationLatitude, requestClientIpLocationLongitude)
}
}
}()
}
}

@ -11,9 +11,8 @@ require (
go.dtapp.net/gotime v1.0.5
go.dtapp.net/gotrace_id v1.0.6
go.dtapp.net/gourl v1.0.0
go.mongodb.org/mongo-driver v1.10.2
go.uber.org/zap v1.23.0
gorm.io/gorm v1.23.9
gorm.io/datatypes v1.0.7
)
require (
@ -74,6 +73,7 @@ require (
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
go.dtapp.net/gorandom v1.0.1 // indirect
go.dtapp.net/gostring v1.0.10 // indirect
go.mongodb.org/mongo-driver v1.10.2 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
@ -87,6 +87,7 @@ require (
gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/driver/mysql v1.3.6 // indirect
gorm.io/driver/postgres v1.3.9 // indirect
gorm.io/gorm v1.23.9 // indirect
mellium.im/sasl v0.3.0 // indirect
modernc.org/libc v1.16.19 // indirect
modernc.org/sqlite v1.18.0 // indirect

@ -3,6 +3,9 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE=
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
@ -60,9 +63,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/denisenkom/go-mssqldb v0.12.0 h1:VtrkII767ttSPNRfFekePK3sctr+joXgO58stqQbtUA=
github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
@ -114,6 +120,10 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 h1:+eHOFJl1BaXrQxKX+T06f78590z4qA2ZzBTqahsKSE4=
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -313,6 +323,7 @@ github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peK
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
@ -331,6 +342,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/montanaflynn/stats v0.6.6 h1:Duep6KMIDpY4Yo11iFsvyqJDyfzLF9+sndUKT+v64GQ=
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
@ -374,6 +386,7 @@ github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaF
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -554,12 +567,14 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
@ -595,6 +610,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI=
golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
@ -722,16 +738,27 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/datatypes v1.0.7 h1:8NhJN4+annFjwV1WufDhFiPjdUvV1lSGUdg1UCjQIWY=
gorm.io/datatypes v1.0.7/go.mod h1:l9qkCuy0CdzDEop9HKUdcnC9gHC2sRlaFtHkTzsZRqg=
gorm.io/driver/mysql v1.3.2/go.mod h1:ChK6AHbHgDCFZyJp0F+BmVGb06PSIoh9uVYKAlRbb2U=
gorm.io/driver/mysql v1.3.6 h1:BhX1Y/RyALb+T9bZ3t07wLnPZBukt+IRkMn8UZSNbGM=
gorm.io/driver/mysql v1.3.6/go.mod h1:sSIebwZAVPiT+27jK9HIwvsqOGKx3YMPmrA3mBJR10c=
gorm.io/driver/postgres v1.3.4/go.mod h1:y0vEuInFKJtijuSGu9e5bs5hzzSzPK+LancpKpvbRBw=
gorm.io/driver/postgres v1.3.9 h1:lWGiVt5CijhQAg0PWB7Od1RNcBw/jS4d2cAScBcSDXg=
gorm.io/driver/postgres v1.3.9/go.mod h1:qw/FeqjxmYqW5dBcYNBsnhQULIApQdk7YuuDPktVi1U=
gorm.io/driver/sqlite v1.3.1 h1:bwfE+zTEWklBYoEodIOIBwuWHpnx52Z9zJFW5F33WLk=
gorm.io/driver/sqlite v1.3.1/go.mod h1:wJx0hJspfycZ6myN38x1O/AqLtNS6c5o9TndewFbELg=
gorm.io/driver/sqlserver v1.3.1 h1:F5t6ScMzOgy1zukRTIZgLZwKahgt3q1woAILVolKpOI=
gorm.io/driver/sqlserver v1.3.1/go.mod h1:w25Vrx2BG+CJNUu/xKbFhaKlGxT/nzRkhWCCoptX8tQ=
gorm.io/gorm v1.23.1/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.6/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.7/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.23.9 h1:NSHG021i+MCznokeXR3udGaNyFyBQJW8MbjrJMVCfGw=

21
vendor/gorm.io/datatypes/License generated vendored

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-NOW Jinzhu <wosmvp@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -0,0 +1,94 @@
# GORM Data Types
## JSON
sqlite, mysql, postgres supported
```go
import "gorm.io/datatypes"
type UserWithJSON struct {
gorm.Model
Name string
Attributes datatypes.JSON
}
DB.Create(&User{
Name: "json-1",
Attributes: datatypes.JSON([]byte(`{"name": "jinzhu", "age": 18, "tags": ["tag1", "tag2"], "orgs": {"orga": "orga"}}`)),
}
// Check JSON has keys
datatypes.JSONQuery("attributes").HasKey(value, keys...)
db.Find(&user, datatypes.JSONQuery("attributes").HasKey("role"))
db.Find(&user, datatypes.JSONQuery("attributes").HasKey("orgs", "orga"))
// MySQL
// SELECT * FROM `users` WHERE JSON_EXTRACT(`attributes`, '$.role') IS NOT NULL
// SELECT * FROM `users` WHERE JSON_EXTRACT(`attributes`, '$.orgs.orga') IS NOT NULL
// PostgreSQL
// SELECT * FROM "user" WHERE "attributes"::jsonb ? 'role'
// SELECT * FROM "user" WHERE "attributes"::jsonb -> 'orgs' ? 'orga'
// Check JSON extract value from keys equal to value
datatypes.JSONQuery("attributes").Equals(value, keys...)
DB.First(&user, datatypes.JSONQuery("attributes").Equals("jinzhu", "name"))
DB.First(&user, datatypes.JSONQuery("attributes").Equals("orgb", "orgs", "orgb"))
// MySQL
// SELECT * FROM `user` WHERE JSON_EXTRACT(`attributes`, '$.name') = "jinzhu"
// SELECT * FROM `user` WHERE JSON_EXTRACT(`attributes`, '$.orgs.orgb') = "orgb"
// PostgreSQL
// SELECT * FROM "user" WHERE json_extract_path_text("attributes"::json,'name') = 'jinzhu'
// SELECT * FROM "user" WHERE json_extract_path_text("attributes"::json,'orgs','orgb') = 'orgb'
```
NOTE: SQlite need to build with `json1` tag, e.g: `go build --tags json1`, refer https://github.com/mattn/go-sqlite3#usage
## Date
```go
import "gorm.io/datatypes"
type UserWithDate struct {
gorm.Model
Name string
Date datatypes.Date
}
user := UserWithDate{Name: "jinzhu", Date: datatypes.Date(time.Now())}
DB.Create(&user)
// INSERT INTO `user_with_dates` (`name`,`date`) VALUES ("jinzhu","2020-07-17 00:00:00")
DB.First(&result, "name = ? AND date = ?", "jinzhu", datatypes.Date(curTime))
// SELECT * FROM user_with_dates WHERE name = "jinzhu" AND date = "2020-07-17 00:00:00" ORDER BY `user_with_dates`.`id` LIMIT 1
```
## Time
MySQL, PostgreSQL, SQLite, SQLServer are supported.
Time with nanoseconds is supported for some databases which support for time with fractional second scale.
```go
import "gorm.io/datatypes"
type UserWithTime struct {
gorm.Model
Name string
Time datatypes.Time
}
user := UserWithTime{Name: "jinzhu", Time: datatypes.NewTime(1, 2, 3, 0)}
DB.Create(&user)
// INSERT INTO `user_with_times` (`name`,`time`) VALUES ("jinzhu","01:02:03")
DB.First(&result, "name = ? AND time = ?", "jinzhu", datatypes.NewTime(1, 2, 3, 0))
// SELECT * FROM user_with_times WHERE name = "jinzhu" AND time = "01:02:03" ORDER BY `user_with_times`.`id` LIMIT 1
```
NOTE: If the current using database is SQLite, the field column type is defined as `TEXT` type
when GORM AutoMigrate because SQLite doesn't have time type.

42
vendor/gorm.io/datatypes/date.go generated vendored

@ -0,0 +1,42 @@
package datatypes
import (
"database/sql"
"database/sql/driver"
"time"
)
type Date time.Time
func (date *Date) Scan(value interface{}) (err error) {
nullTime := &sql.NullTime{}
err = nullTime.Scan(value)
*date = Date(nullTime.Time)
return
}
func (date Date) Value() (driver.Value, error) {
y, m, d := time.Time(date).Date()
return time.Date(y, m, d, 0, 0, 0, 0, time.Time(date).Location()), nil
}
// GormDataType gorm common data type
func (date Date) GormDataType() string {
return "date"
}
func (date Date) GobEncode() ([]byte, error) {
return time.Time(date).GobEncode()
}
func (date *Date) GobDecode(b []byte) error {
return (*time.Time)(date).GobDecode(b)
}
func (date Date) MarshalJSON() ([]byte, error) {
return time.Time(date).MarshalJSON()
}
func (date *Date) UnmarshalJSON(b []byte) error {
return (*time.Time)(date).UnmarshalJSON(b)
}

280
vendor/gorm.io/datatypes/json.go generated vendored

@ -0,0 +1,280 @@
package datatypes
import (
"context"
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
)
// JSON defined JSON data type, need to implements driver.Valuer, sql.Scanner interface
type JSON json.RawMessage
// Value return json value, implement driver.Valuer interface
func (j JSON) Value() (driver.Value, error) {
if len(j) == 0 {
return nil, nil
}
return string(j), nil
}
// Scan scan value into Jsonb, implements sql.Scanner interface
func (j *JSON) Scan(value interface{}) error {
if value == nil {
*j = JSON("null")
return nil
}
var bytes []byte
switch v := value.(type) {
case []byte:
if len(v) > 0 {
bytes = make([]byte, len(v))
copy(bytes, v)
}
case string:
bytes = []byte(v)
default:
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
}
result := json.RawMessage(bytes)
*j = JSON(result)
return nil
}
// MarshalJSON to output non base64 encoded []byte
func (j JSON) MarshalJSON() ([]byte, error) {
return json.RawMessage(j).MarshalJSON()
}
// UnmarshalJSON to deserialize []byte
func (j *JSON) UnmarshalJSON(b []byte) error {
result := json.RawMessage{}
err := result.UnmarshalJSON(b)
*j = JSON(result)
return err
}
func (j JSON) String() string {
return string(j)
}
// GormDataType gorm common data type
func (JSON) GormDataType() string {
return "json"
}
// GormDBDataType gorm db data type
func (JSON) GormDBDataType(db *gorm.DB, field *schema.Field) string {
switch db.Dialector.Name() {
case "sqlite":
return "JSON"
case "mysql":
return "JSON"
case "postgres":
return "JSONB"
}
return ""
}
func (js JSON) GormValue(ctx context.Context, db *gorm.DB) clause.Expr {
if len(js) == 0 {
return gorm.Expr("NULL")
}
data, _ := js.MarshalJSON()
switch db.Dialector.Name() {
case "mysql":
if v, ok := db.Dialector.(*mysql.Dialector); ok && !strings.Contains(v.ServerVersion, "MariaDB") {
return gorm.Expr("CAST(? AS JSON)", string(data))
}
}
return gorm.Expr("?", string(data))
}
// JSONQueryExpression json query expression, implements clause.Expression interface to use as querier
type JSONQueryExpression struct {
column string
keys []string
hasKeys bool
equals bool
equalsValue interface{}
extract bool
path string
}
// JSONQuery query column as json
func JSONQuery(column string) *JSONQueryExpression {
return &JSONQueryExpression{column: column}
}
// Extract extract json with path
func (jsonQuery *JSONQueryExpression) Extract(path string) *JSONQueryExpression {
jsonQuery.extract = true
jsonQuery.path = path
return jsonQuery
}
// HasKey returns clause.Expression
func (jsonQuery *JSONQueryExpression) HasKey(keys ...string) *JSONQueryExpression {
jsonQuery.keys = keys
jsonQuery.hasKeys = true
return jsonQuery
}
// Keys returns clause.Expression
func (jsonQuery *JSONQueryExpression) Equals(value interface{}, keys ...string) *JSONQueryExpression {
jsonQuery.keys = keys
jsonQuery.equals = true
jsonQuery.equalsValue = value
return jsonQuery
}
// Build implements clause.Expression
func (jsonQuery *JSONQueryExpression) Build(builder clause.Builder) {
if stmt, ok := builder.(*gorm.Statement); ok {
switch stmt.Dialector.Name() {
case "mysql", "sqlite":
switch {
case jsonQuery.extract:
builder.WriteString("JSON_EXTRACT(")
builder.WriteQuoted(jsonQuery.column)
builder.WriteByte(',')
builder.AddVar(stmt, jsonQuery.path)
builder.WriteString(")")
case jsonQuery.hasKeys:
if len(jsonQuery.keys) > 0 {
builder.WriteString("JSON_EXTRACT(")
builder.WriteQuoted(jsonQuery.column)
builder.WriteByte(',')
builder.AddVar(stmt, jsonQueryJoin(jsonQuery.keys))
builder.WriteString(") IS NOT NULL")
}
case jsonQuery.equals:
if len(jsonQuery.keys) > 0 {
builder.WriteString("JSON_EXTRACT(")
builder.WriteQuoted(jsonQuery.column)
builder.WriteByte(',')
builder.AddVar(stmt, jsonQueryJoin(jsonQuery.keys))
builder.WriteString(") = ")
if value, ok := jsonQuery.equalsValue.(bool); ok {
builder.WriteString(strconv.FormatBool(value))
} else {
stmt.AddVar(builder, jsonQuery.equalsValue)
}
}
}
case "postgres":
switch {
case jsonQuery.hasKeys:
if len(jsonQuery.keys) > 0 {
stmt.WriteQuoted(jsonQuery.column)
stmt.WriteString("::jsonb")
for _, key := range jsonQuery.keys[0 : len(jsonQuery.keys)-1] {
stmt.WriteString(" -> ")
stmt.AddVar(builder, key)
}
stmt.WriteString(" ? ")
stmt.AddVar(builder, jsonQuery.keys[len(jsonQuery.keys)-1])
}
case jsonQuery.equals:
if len(jsonQuery.keys) > 0 {
builder.WriteString(fmt.Sprintf("json_extract_path_text(%v::json,", stmt.Quote(jsonQuery.column)))
for idx, key := range jsonQuery.keys {
if idx > 0 {
builder.WriteByte(',')
}
stmt.AddVar(builder, key)
}
builder.WriteString(") = ")
if _, ok := jsonQuery.equalsValue.(string); ok {
stmt.AddVar(builder, jsonQuery.equalsValue)
} else {
stmt.AddVar(builder, fmt.Sprint(jsonQuery.equalsValue))
}
}
}
}
}
}
// JSONOverlapsExpression JSON_OVERLAPS expression, implements clause.Expression interface to use as querier
type JSONOverlapsExpression struct {
column clause.Expression
val string
}
// JSONOverlaps query column as json
func JSONOverlaps(column clause.Expression, value string) *JSONOverlapsExpression {
return &JSONOverlapsExpression{
column: column,
val: value,
}
}
// Build implements clause.Expression
// only mysql support JSON_OVERLAPS
func (json *JSONOverlapsExpression) Build(builder clause.Builder) {
if stmt, ok := builder.(*gorm.Statement); ok {
switch stmt.Dialector.Name() {
case "mysql":
builder.WriteString("JSON_OVERLAPS(")
json.column.Build(builder)
builder.WriteString(",")
builder.AddVar(stmt, json.val)
builder.WriteString(")")
}
}
}
type columnExpression string
func Column(col string) columnExpression {
return columnExpression(col)
}
func (col columnExpression) Build(builder clause.Builder) {
if stmt, ok := builder.(*gorm.Statement); ok {
switch stmt.Dialector.Name() {
case "mysql", "sqlite", "postgres":
builder.WriteString(stmt.Quote(string(col)))
}
}
}
const prefix = "$."
func jsonQueryJoin(keys []string) string {
if len(keys) == 1 {
return prefix + keys[0]
}
n := len(prefix)
n += len(keys) - 1
for i := 0; i < len(keys); i++ {
n += len(keys[i])
}
var b strings.Builder
b.Grow(n)
b.WriteString(prefix)
b.WriteString(keys[0])
for _, key := range keys[1:] {
b.WriteString(".")
b.WriteString(key)
}
return b.String()
}

@ -0,0 +1,96 @@
package datatypes
import (
"context"
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"strings"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
)
// JSONMap defined JSON data type, need to implements driver.Valuer, sql.Scanner interface
type JSONMap map[string]interface{}
// Value return json value, implement driver.Valuer interface
func (m JSONMap) Value() (driver.Value, error) {
if m == nil {
return nil, nil
}
ba, err := m.MarshalJSON()
return string(ba), err
}
// Scan scan value into Jsonb, implements sql.Scanner interface
func (m *JSONMap) Scan(val interface{}) error {
if val == nil {
*m = make(JSONMap)
return nil
}
var ba []byte
switch v := val.(type) {
case []byte:
ba = v
case string:
ba = []byte(v)
default:
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", val))
}
t := map[string]interface{}{}
err := json.Unmarshal(ba, &t)
*m = t
return err
}
// MarshalJSON to output non base64 encoded []byte
func (m JSONMap) MarshalJSON() ([]byte, error) {
if m == nil {
return []byte("null"), nil
}
t := (map[string]interface{})(m)
return json.Marshal(t)
}
// UnmarshalJSON to deserialize []byte
func (m *JSONMap) UnmarshalJSON(b []byte) error {
t := map[string]interface{}{}
err := json.Unmarshal(b, &t)
*m = JSONMap(t)
return err
}
// GormDataType gorm common data type
func (m JSONMap) GormDataType() string {
return "jsonmap"
}
// GormDBDataType gorm db data type
func (JSONMap) GormDBDataType(db *gorm.DB, field *schema.Field) string {
switch db.Dialector.Name() {
case "sqlite":
return "JSON"
case "mysql":
return "JSON"
case "postgres":
return "JSONB"
case "sqlserver":
return "NVARCHAR(MAX)"
}
return ""
}
func (jm JSONMap) GormValue(ctx context.Context, db *gorm.DB) clause.Expr {
data, _ := jm.MarshalJSON()
switch db.Dialector.Name() {
case "mysql":
if v, ok := db.Dialector.(*mysql.Dialector); ok && !strings.Contains(v.ServerVersion, "MariaDB") {
return gorm.Expr("CAST(? AS JSON)", string(data))
}
}
return gorm.Expr("?", string(data))
}

@ -0,0 +1,10 @@
#!/bin/bash -e
dialects=("postgres" "postgres_simple" "mysql" "mssql" "sqlite")
for dialect in "${dialects[@]}" ; do
if [ "$GORM_DIALECT" = "" ] || [ "$GORM_DIALECT" = "${dialect}" ]
then
GORM_DIALECT=${dialect} go test --tags "json1"
fi
done

123
vendor/gorm.io/datatypes/time.go generated vendored

@ -0,0 +1,123 @@
package datatypes
import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"gorm.io/gorm"
"gorm.io/gorm/schema"
)
// Time is time data type.
type Time time.Duration
// NewTime is a constructor for Time and returns new Time.
func NewTime(hour, min, sec, nsec int) Time {
return newTime(hour, min, sec, nsec)
}
func newTime(hour, min, sec, nsec int) Time {
return Time(
time.Duration(hour)*time.Hour +
time.Duration(min)*time.Minute +
time.Duration(sec)*time.Second +
time.Duration(nsec)*time.Nanosecond,
)
}
// GormDataType returns gorm common data type. This type is used for the field's column type.
func (Time) GormDataType() string {
return "time"
}
// GormDBDataType returns gorm DB data type based on the current using database.
func (Time) GormDBDataType(db *gorm.DB, field *schema.Field) string {
switch db.Dialector.Name() {
case "mysql":
return "TIME"
case "postgres":
return "TIME"
case "sqlserver":
return "TIME"
case "sqlite":
return "TEXT"
default:
return ""
}
}
// Scan implements sql.Scanner interface and scans value into Time,
func (t *Time) Scan(src interface{}) error {
switch v := src.(type) {
case []byte:
t.setFromString(string(v))
case string:
t.setFromString(v)
case time.Time:
t.setFromTime(v)
default:
return errors.New(fmt.Sprintf("failed to scan value: %v", v))
}
return nil
}
func (t *Time) setFromString(str string) {
var h, m, s, n int
fmt.Sscanf(str, "%02d:%02d:%02d.%09d", &h, &m, &s, &n)
*t = newTime(h, m, s, n)
}
func (t *Time) setFromTime(src time.Time) {
*t = newTime(src.Hour(), src.Minute(), src.Second(), src.Nanosecond())
}
// Value implements driver.Valuer interface and returns string format of Time.
func (t Time) Value() (driver.Value, error) {
return t.String(), nil
}
// String implements fmt.Stringer interface.
func (t Time) String() string {
if nsec := t.nanoseconds(); nsec > 0 {
return fmt.Sprintf("%02d:%02d:%02d.%09d", t.hours(), t.minutes(), t.seconds(), nsec)
} else {
// omit nanoseconds unless any value is specified
return fmt.Sprintf("%02d:%02d:%02d", t.hours(), t.minutes(), t.seconds())
}
}
func (t Time) hours() int {
return int(time.Duration(t).Truncate(time.Hour).Hours())
}
func (t Time) minutes() int {
return int((time.Duration(t) % time.Hour).Truncate(time.Minute).Minutes())
}
func (t Time) seconds() int {
return int((time.Duration(t) % time.Minute).Truncate(time.Second).Seconds())
}
func (t Time) nanoseconds() int {
return int((time.Duration(t) % time.Second).Nanoseconds())
}
// MarshalJSON implements json.Marshaler to convert Time to json serialization.
func (t Time) MarshalJSON() ([]byte, error) {
return json.Marshal(t.String())
}
// UnmarshalJSON implements json.Unmarshaler to deserialize json data.
func (t *Time) UnmarshalJSON(data []byte) error {
// ignore null
if string(data) == "null" {
return nil
}
t.setFromString(strings.Trim(string(data), `"`))
return nil
}

66
vendor/gorm.io/datatypes/url.go generated vendored

@ -0,0 +1,66 @@
package datatypes
import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"net/url"
"strings"
"gorm.io/gorm"
"gorm.io/gorm/schema"
)
type URL url.URL
func (u URL) Value() (driver.Value, error) {
return u.String(), nil
}
func (u *URL) Scan(value interface{}) error {
var us string
switch v := value.(type) {
case []byte:
us = string(v)
case string:
us = v
default:
return errors.New(fmt.Sprint("Failed to parse URL:", value))
}
uu, err := url.Parse(us)
if err != nil {
return err
}
*u = URL(*uu)
return nil
}
func (URL) GormDataType() string {
return "url"
}
func (URL) GormDBDataType(db *gorm.DB, field *schema.Field) string {
return "TEXT"
}
func (u *URL) String() string {
return (*url.URL)(u).String()
}
func (u URL) MarshalJSON() ([]byte, error) {
return json.Marshal(u.String())
}
func (u *URL) UnmarshalJSON(data []byte) error {
// ignore null
if string(data) == "null" {
return nil
}
uu, err := url.Parse(strings.Trim(string(data), `"'`))
if err != nil {
return err
}
*u = URL(*uu)
return nil
}

@ -401,6 +401,9 @@ google.golang.org/protobuf/runtime/protoiface
# gopkg.in/yaml.v2 v2.4.0
## explicit; go 1.15
gopkg.in/yaml.v2
# gorm.io/datatypes v1.0.7
## explicit; go 1.14
gorm.io/datatypes
# gorm.io/driver/mysql v1.3.6
## explicit; go 1.14
gorm.io/driver/mysql

Loading…
Cancel
Save