Commit ad9ce240 by zhengqiuyun86

初始化

parent f50bf998
package conf package conf
type Config struct { type Config struct {
ServerName string
Env string
LogLevel string LogLevel string
LogColorful bool LogColorful bool
LogResponseLength int LogResponseLength int
LogShowSql bool
//RedisAddr Redis conf
RedisAddr string
RedisPwd string
RedisDb int
//EsServerHttp
EsServerHttp string
//mysql
MysqlConf MysqlConf
} }
func BaseConfig(conf Config) { func BaseConfig(conf Config) {
LogLevel = conf.LogLevel LogLevel = conf.LogLevel
LogColorful = conf.LogColorful LogColorful = conf.LogColorful
LogResponseLength = conf.LogResponseLength LogResponseLength = conf.LogResponseLength
LogShowSql = conf.LogShowSql
RedisAddr = conf.RedisAddr
RedisPwd = conf.RedisPwd
RedisDb = conf.RedisDb
ServerName = conf.ServerName
Env = conf.Env
EsServerHttp = conf.EsServerHttp
MySql = conf.MysqlConf
} }
//Base conf
var ServerName = ""
var Env = ""
//log conf
var LogLevel = "DEBUG" var LogLevel = "DEBUG"
var LogColorful = false //日志是否开启彩色打印
var LogResponseLength = 10
var LogShowSql = true
//LogColorful 日志是否开启彩色打印 //Redis conf
var LogColorful = false var RedisAddr = "to-chengdu-office.168cad.top:50001"
var RedisPwd = "testPassevnsoo567"
var RedisDb = 0
var LogResponseLength = 10 //ES conf
var EsServerHttp = "http://192.168.1.124:9200"
//Mysql conf
type MysqlConf struct {
Host string
Port int
User string
Password string
}
var MySql = MysqlConf{}
package YorN
const (
Y string = "1"
N string = "0"
)
package es
const indexNamePrefix = "manage_client_log"
package es
import (
"context"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/conf"
"git.168cad.top/zhengqiuyun/rym-util/exception"
"git.168cad.top/zhengqiuyun/rym-util/log"
"github.com/olivere/elastic/v7"
_log "log"
"os"
)
var Client *elastic.Client
//初始化
func init() {
host := conf.EsServerHttp
var err error
errorLog := _log.New(os.Stdout, "APP", _log.LstdFlags)
Client, err = elastic.NewClient(elastic.SetErrorLog(errorLog), elastic.SetURL(host))
if err != nil {
exception.ThrowsErrS(fmt.Sprintf("ES连接失败:%s", err.Error()))
}
info, code, err := Client.Ping(host).Do(context.Background())
if err != nil {
panic(err)
}
log.Info(fmt.Sprintf("Elasticsearch connect %d", code))
log.Info(fmt.Sprintf("Elasticsearch version %s", info.Version.Number))
}
package es
import (
"context"
"encoding/json"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/exception"
"git.168cad.top/zhengqiuyun/rym-util/log"
"git.168cad.top/zhengqiuyun/rym-util/util"
"github.com/olivere/elastic/v7"
"sort"
"time"
)
func getCurrentIndex() string {
return indexNamePrefix + util.FormatDates(time.Now())
}
type ServerLogModel struct {
ServerName string `json:"serverName"`
Env string `json:"env"`
TimeStamp int64 `json:"timeStamp"`
ThreadNo string `json:"threadNo"`
ServerIp string `json:"serverIp"`
ClientIp string `json:"clientIp"`
Token string `json:"token"`
CustomerId uint32 `json:"customerId"`
ClientSource string `json:"clientSource"`
Url string `json:"url"`
Method string `json:"method"`
Request string `json:"request"`
Response string `json:"response"`
DealTimes int64 `json:"dealTimes"`
}
func InsertEsLog(logInfo interface{}) {
indexName := getCurrentIndex()
put, err := Client.Index().
Index(indexName).
BodyJson(logInfo).
Do(context.Background())
if err != nil {
log.Error(fmt.Sprintf("insert es log fail:%s", err.Error()))
} else {
log.Debug(fmt.Sprintf("insert es log success:%s", put.Id))
}
}
func GroupField(indexName, field string, size, minCount int, excludeValues []string) []byte {
if size == 0 {
size = 30
}
aggregationQuery := elastic.NewTermsAggregation().Field(field).MinDocCount(minCount).Size(size)
for _, excludeValue := range excludeValues {
aggregationQuery.ExcludeValues(excludeValue)
}
if log.IsDebug() {
source, _ := aggregationQuery.Source()
queryByte, _ := json.Marshal(source)
log.Info(fmt.Sprintf("查询条件:%s", string(queryByte)))
}
res, err := Client.Search(indexName).
Aggregation("group_field", aggregationQuery).
From(0).
Size(0).
Do(context.Background())
if err != nil {
exception.ThrowsErr(err)
}
bs, err := json.Marshal(res.Aggregations)
if err != nil {
exception.ThrowsErr(err)
}
return bs
}
func QueryLogs(indexName, filed, value string, from, size int) interface{} {
if from <= 0 {
from = 0
}
if size <= 0 {
size = 10
}
query := elastic.NewBoolQuery().Must(elastic.NewTermQuery(filed, value))
res, err := Client.Search(indexName).Query(query).
From(from).
Size(size).
Do(context.Background())
if err != nil {
exception.ThrowsErr(err)
}
return res
}
type IndexInfo struct {
Name string `json:"name"`
Count int `json:"count"`
Size string `json:"size"`
}
func AllIndex() interface{} {
res, err := Client.CatIndices().Do(context.Background())
if err != nil {
exception.ThrowsErr(err)
}
var keys []string
var sizeMap = make(map[string]IndexInfo)
for _, row := range res {
keys = append(keys, row.Index)
sizeMap[row.Index] = IndexInfo{row.Index, row.DocsCount, row.StoreSize}
}
sort.Strings(keys)
data := make([]IndexInfo, len(keys))
for i, key := range keys {
data[i] = sizeMap[key]
}
return data
}
func DeleteIndex(indexName string) interface{} {
res, err := Client.DeleteIndex(indexName).
Do(context.Background())
if err != nil {
exception.ThrowsErr(err)
}
return res
}
package exception
import (
"errors"
"git.168cad.top/zhengqiuyun/rym-util/log"
"github.com/go-playground/validator/v10"
"reflect"
)
func ThrowsErr(err error) {
if err != nil {
log.Error(err.Error())
panic(err)
}
}
func ThrowsValid(err error, r interface{}) {
if err != nil {
switch err.(type) {
case validator.ValidationErrors:
e := (err).(validator.ValidationErrors)
errMsg := getError(e, r)
panic(errors.New(errMsg))
break
default:
panic(err)
break
}
}
}
// 自定义错误消息
func getError(errs validator.ValidationErrors, r interface{}) string {
s := reflect.TypeOf(r)
for _, fieldError := range errs {
filed, _ := s.FieldByName(fieldError.Field())
// 获取统一错误消息
errText := filed.Tag.Get("msg")
if errText != "" {
return errText
}
fieldName := filed.Tag.Get("json")
if fieldName == "" {
fieldName = fieldError.Field()
}
return fieldName + ":" + fieldError.Tag()
}
return ""
}
type DError struct {
Err string
}
func (e *DError) Error() string {
return e.Err
}
func ThrowsErrS(err string) {
if &err != nil && err != "" {
log.Error(err)
panic(DError{Err: err})
}
}
package catch
import (
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/exception"
"git.168cad.top/zhengqiuyun/rym-util/getWay"
"github.com/gin-gonic/gin"
"runtime"
"strings"
)
func ExceptionCatch(c *gin.Context) {
err := recover() //获取异常
if err != nil {
switch err.(type) {
case exception.DError:
e := (err).(exception.DError)
getWay.FailAndMsg(c, e.Error())
break
case error:
e := (err).(error)
if strings.Index(e.Error(), "duplicate key") > 0 {
getWay.FailAndMsg(c, "信息重复")
} else {
var buf [1024]byte
n := runtime.Stack(buf[:], true)
fmt.Println(string(buf[:]), n)
getWay.FailAndMsg(c, e.Error())
}
break
}
}
}
package getWay
type Error struct {
Code State
}
func ThrowsGetWayErr(code State) {
if &code != nil {
panic(Error{code})
}
}
package getWay
import (
"git.168cad.top/zhengqiuyun/rym-util/exception"
"github.com/gin-gonic/gin"
)
const headerKeyToken = "token"
const headerKeyPlatformCode = "platform"
const headerKeyClientSource = "clientSource"
func getHeader(c *gin.Context, key string) string {
v := c.GetHeader(key)
return v
}
func GetToken(c *gin.Context) string {
return getHeader(c, headerKeyToken)
}
func SetToken(v string, c *gin.Context) {
c.Header(headerKeyToken, v)
}
func GetPlatformCode(c *gin.Context) string {
platformCode := getHeader(c, headerKeyPlatformCode)
if platformCode == "" {
exception.ThrowsErrS("平台错误")
}
return platformCode
}
func GetClientSource(c *gin.Context) string {
platformCode := getHeader(c, headerKeyClientSource)
return platformCode
}
package getWay
import (
"encoding/json"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/log"
"github.com/gin-gonic/gin"
"net"
"time"
)
func GetCurrentUserId(c *gin.Context) (uint32, bool) {
userId, b := c.Get(CurrentUserIdKey)
if b {
transUserId := userId.(uint32)
return transUserId, b
}
return 0, b
}
type UserInfo struct {
Id uint32
Account string
Name string
}
func GetCurrentUser(c *gin.Context) *UserInfo {
var userInfo = UserInfo{}
adminResponse, b := c.Get(CurrentUserKey)
if b {
admin := adminResponse.(Admin)
userInfo.Name = admin.Name
userInfo.Account = admin.LoginAccount
userInfo.Id = admin.Id
}
return &userInfo
}
type AdminResponse struct {
code int
msg string
Admin Admin
}
type Admin struct {
Id uint32
Name string
LoginAccount string
}
const requestBodyKey = "requestBody"
func BindRequestBody(c *gin.Context, param interface{}) error {
c.ShouldBindJSON(param)
bytes, err := json.Marshal(param)
c.Set(requestBodyKey, string(bytes))
return err
}
func GetParams(c *gin.Context) string {
rd := ""
params := c.Request.URL.Query().Encode()
if params != "" {
rd += params
}
ad := c.GetString(requestBodyKey)
if ad != "" {
rd += ad
}
return rd
}
func GetServerIP() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
return ""
}
for _, addr := range addrs {
ipAddr, ok := addr.(*net.IPNet)
if !ok {
continue
}
if ipAddr.IP.IsLoopback() {
continue
}
if !ipAddr.IP.IsGlobalUnicast() {
continue
}
return ipAddr.IP.String()
}
return ""
}
func GetClientIP(c *gin.Context) string {
ip := c.ClientIP()
return ip
}
func GetURL(c *gin.Context) string {
url := c.Request.URL.Path
return url
}
func GetMethod(c *gin.Context) string {
method := c.Request.Method
return method
}
func SetStartTime(c *gin.Context) {
c.Set(StartTimeKey, time.Now().UnixNano())
logStart(c)
}
func GetStartTime(c *gin.Context) int64 {
startTime := c.GetInt64(StartTimeKey)
return startTime
}
func logStart(c *gin.Context) {
log.Info(fmt.Sprintf("开始 %s %s %s %s", GetMethod(c), GetURL(c), GetToken(c), GetClientIP(c)))
}
package getWay
import (
"encoding/json"
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/conf"
"git.168cad.top/zhengqiuyun/rym-util/es"
"git.168cad.top/zhengqiuyun/rym-util/log"
db "git.168cad.top/zhengqiuyun/rym-util/mysql"
"git.168cad.top/zhengqiuyun/rym-util/redis"
"git.168cad.top/zhengqiuyun/rym-util/util"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
type ServerResponse struct {
Code State `json:"code"` //0为成功,其他都是失败
Msg string `json:"msg,omitempty"` //非1000情况下的错误描述
}
type ServerDataResponse struct {
ServerResponse
Data interface{} `json:"data,omitempty"`
}
func response(state State) ServerResponse {
return ServerResponse{Code: state, Msg: state.String()}
}
func FailGetWay(c *gin.Context, state State) {
resp := response(state)
c.JSON(http.StatusBadGateway, resp)
c.Abort()
logEnd(c, resp)
}
func FailAndMsg(c *gin.Context, msg string) {
db.Rollback()
resp := ServerResponse{Code: BusinessError, Msg: msg}
c.JSON(http.StatusOK, resp)
c.Abort()
logEnd(c, resp)
}
func Success(c *gin.Context) {
db.Commit()
resp := response(OK)
c.JSON(http.StatusOK, resp)
c.Abort()
logEnd(c, resp)
}
func SuccessData(c *gin.Context, data interface{}) {
db.Commit()
resp := ServerDataResponse{response(OK), data}
c.JSON(http.StatusOK, resp)
c.Abort()
logEnd(c, resp)
}
type WxResponse struct {
Code string `json:"code"`
Message string `json:"message"`
}
func WxSuccess(c *gin.Context) {
resp := WxResponse{"SUCCESS", "成功"}
c.JSON(http.StatusOK, resp)
logEnd(c, resp)
}
func AliSuccess(c *gin.Context) {
resp := "success"
c.JSON(http.StatusOK, resp)
logEnd(c, resp)
}
func logEnd(c *gin.Context, data interface{}) {
esSwitch := redis.SwitchOpen(redis.ES日志开关 + conf.ServerName)
startTime := GetStartTime(c)
endTime := time.Now().UnixNano()
var responseStr string
if data != nil {
dataJson, _ := json.Marshal(data)
rs := string(dataJson)
excludeUrl := []string{""}
if esSwitch {
if util.ArrayContains(excludeUrl, GetURL(c)) && len(rs) > conf.LogResponseLength {
responseStr = rs[0:conf.LogResponseLength] + "......"
} else {
responseStr = rs
}
} else {
if len(rs) > conf.LogResponseLength {
responseStr = rs[0:conf.LogResponseLength] + "......"
} else {
responseStr = rs
}
}
}
token := GetToken(c)
if esSwitch && token != "" {
esLog(c, responseStr)
log.Info(fmt.Sprintf("结束,耗时%d毫秒", (endTime-startTime)/1e6))
} else {
log.Info(fmt.Sprintf("返回数据:%s", responseStr))
log.Info(fmt.Sprintf("结束,耗时%d毫秒 %s %s %s %s %s", (endTime-startTime)/1e6, GetMethod(c), GetURL(c), token, GetClientIP(c), GetParams(c)))
}
}
func esLog(c *gin.Context, response string) {
log := es.ServerLogModel{
ServerName: conf.ServerName,
Env: conf.Env,
TimeStamp: util.MilSecond(time.Now()),
ThreadNo: fmt.Sprintf("%d", util.GetGID()),
ServerIp: GetServerIP(),
ClientIp: GetClientIP(c),
Token: GetToken(c),
CustomerId: GetCurrentUser(c).Id,
ClientSource: GetClientSource(c),
Url: GetURL(c),
Method: GetMethod(c),
Request: GetParams(c),
Response: response,
DealTimes: util.MilSecond(time.Now()) - GetStartTime(c)/1e6,
}
es.InsertEsLog(log)
}
package getWay
type State int16
// iota 初始化后会自动递增
const (
BusinessError State = 1001
OK State = 1000
Expire State = 1 - iota
Illegal1
Illegal2
Illegal3
Illegal4
Illegal5
Illegal6
Illegal7
Illegal8
Illegal9
)
func (t State) String() string {
switch t {
case BusinessError:
return "business error"
case OK:
return "OK"
case Expire:
return "expire request"
case Illegal1:
return "illegal request(1)"
case Illegal2:
return "illegal request(2)"
case Illegal3:
return "illegal request(3)"
case Illegal4:
return "illegal request(4)"
case Illegal5:
return "illegal request(5)"
case Illegal6:
return "illegal request(6)"
case Illegal7:
return "illegal request(7)"
case Illegal8:
return "illegal request(8)"
case Illegal9:
return "illegal request(9)"
default:
return "unknown"
}
}
package getWay
const CurrentUserKey = "userInfo"
const CurrentUserIdKey = "userID"
const StartTimeKey = "StartTime"
module git.168cad.top/zhengqiuyun/rym-util module git.168cad.top/zhengqiuyun/rym-util
go 1.16 go 1.17
require (
github.com/gin-gonic/gin v1.7.4
github.com/garyburd/redigo v1.6.3
github.com/olivere/elastic/v7 v7.0.32
gorm.io/driver/mysql v1.2.2
gorm.io/gorm v1.22.4
)
\ No newline at end of file
package db
import (
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/conf"
"git.168cad.top/zhengqiuyun/rym-util/exception"
"git.168cad.top/zhengqiuyun/rym-util/log"
"git.168cad.top/zhengqiuyun/rym-util/util"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"os"
"sync"
"time"
"gorm.io/gorm/logger"
_log "log"
)
var customerDb *gorm.DB
var customerDbMap sync.Map
var gidNeedTX sync.Map
func SetTx() {
gid := util.GetGID()
gidNeedTX.Store(gid, 1)
}
func GetPgDb() *gorm.DB {
return getDb(customerDb, &customerDbMap)
}
func getDb(db *gorm.DB, dbMap *sync.Map) *gorm.DB {
gid := util.GetGID()
_, needTx := gidNeedTX.Load(gid)
if needTx {
cacheTx, ok := dbMap.Load(gid)
if ok {
return cacheTx.(*gorm.DB)
} else {
if conf.LogShowSql {
db = db.Debug()
}
tx := db.Begin()
dbMap.Store(gid, tx)
return tx
}
} else {
if conf.LogShowSql {
db = db.Debug()
}
return db
}
}
func Rollback() {
gid := util.GetGID()
_, needTx := gidNeedTX.Load(gid)
if needTx {
rollbackTx(gid, &customerDbMap)
gidNeedTX.Delete(gid)
}
}
func Commit() {
gid := util.GetGID()
_, needTx := gidNeedTX.Load(gid)
if needTx {
commitTx(gid, &customerDbMap)
gidNeedTX.Delete(gid)
}
}
func rollbackTx(gid uint64, dbMap *sync.Map) {
cacheTx, ok := dbMap.Load(gid)
if ok {
tx := cacheTx.(*gorm.DB)
tx.Rollback()
dbMap.Delete(gid)
}
}
func commitTx(gid uint64, dbMap *sync.Map) {
cacheTx, ok := dbMap.Load(gid)
if ok {
tx := cacheTx.(*gorm.DB)
tx.Commit()
dbMap.Delete(gid)
}
}
func init() {
newLogger := logger.New(
_log.New(os.Stdout, "", _log.Lmicroseconds), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Error, // 日志级别
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
Colorful: conf.LogColorful, // 是否开启彩色打印
},
)
var err error
customerDb, err = gorm.Open(mysql.Open(fmt.Sprintf("%s:%s@tcp(%s:%d)/duocaihui_dev?charset=utf8mb4&parseTime=True&loc=Local",
conf.MySql.User, conf.MySql.Password, conf.MySql.Host, conf.MySql.Port)), &gorm.Config{
Logger: newLogger,
})
if err != nil {
exception.ThrowsErr(err)
}
log.Info(fmt.Sprintf("%s connect success", "Mysql server"))
}
package redis
import (
"fmt"
"git.168cad.top/zhengqiuyun/rym-util/conf"
"git.168cad.top/zhengqiuyun/rym-util/const/YorN"
"git.168cad.top/zhengqiuyun/rym-util/log"
"github.com/garyburd/redigo/redis"
)
var pool *redis.Pool //创建redis连接池
func init() {
pool = &redis.Pool{ //实例化一个连接池
MaxIdle: 10, //最初的连接数量
MaxActive: 0, //连接池最大连接数量,不确定可以用0(0表示自动定义),按需分配
IdleTimeout: 300, //连接关闭时间 300秒 (300秒不使用自动关闭)
Dial: func() (redis.Conn, error) { //要连接的redis数据库
c, err := redis.Dial("tcp", conf.RedisAddr)
if err != nil {
return nil, err
}
if _, err := c.Do("AUTH", conf.RedisPwd); err != nil {
c.Close()
return nil, err
}
if _, err := c.Do("SELECT", conf.RedisDb); err != nil {
c.Close()
return nil, err
}
return c, nil
},
}
}
func Incr(key string) int64 {
c := pool.Get() //从连接池,取一个链接
defer c.Close() //函数运行结束 ,把连接放回连接池
r, err := redis.Int64(c.Do("INCR", key))
if err != nil {
log.Error(err.Error())
}
return r
}
func IncrBy(key string, n int) int64 {
c := pool.Get() //从连接池,取一个链接
defer c.Close() //函数运行结束 ,把连接放回连接池
r, err := redis.Int64(c.Do("INCRBY", key, n))
if err != nil {
log.Error(err.Error())
}
return r
}
func DecrBy(key string, n int) int64 {
c := pool.Get() //从连接池,取一个链接
defer c.Close() //函数运行结束 ,把连接放回连接池
r, err := redis.Int64(c.Do("DECRBY", key, n))
if err != nil {
log.Error(err.Error())
}
return r
}
func Exists(key string) bool {
c := pool.Get() //从连接池,取一个链接
defer c.Close() //函数运行结束 ,把连接放回连接池
r, err := redis.Int64(c.Do("EXISTS", key))
if err != nil {
return false
}
return r > 0
}
//SwitchOpen 在redis中存0或1,1代表OK
func SwitchOpen(key string) bool {
r := GetString(key)
log.Debug(fmt.Sprintf("缓存[%s]数据为:%s", key, r))
return r == YorN.Y
}
func Get(key string) []byte {
c := pool.Get() //从连接池,取一个链接
defer c.Close() //函数运行结束 ,把连接放回连接池
r, err := redis.Bytes(c.Do("GET", key))
if err != nil {
return nil
}
return r
}
func GetString(key string) string {
c := pool.Get() //从连接池,取一个链接
defer c.Close() //函数运行结束 ,把连接放回连接池
r, err := redis.String(c.Do("GET", key))
if err != nil {
return ""
}
return r
}
func Set(k string, v string) {
c := pool.Get() //从连接池,取一个链接
defer c.Close() //函数运行结束 ,把连接放回连接池
r, err := c.Do("SET", k, v)
if err != nil {
log.Error(err.Error())
}
log.Debug(fmt.Sprintf("设置缓存成功:%s", r))
}
func Expire(k string, t int) {
c := pool.Get() //从连接池,取一个链接
defer c.Close()
r, err := c.Do("EXISTS", k, t)
if err != nil {
log.Error(err.Error())
}
log.Debug(fmt.Sprintf("设置缓存过期成功:%d", r))
}
package redis
const (
ES日志开关 = "es:log:switch:"
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment