36

一个快速上手、轻量级 Golang 公共类库 (golang_common)

 4 years ago
source link: https://www.tuicool.com/articles/mQjimaa
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

目录

定位

功能

安装及使用

其他功能举例

思考

定位

配置 Golang 基础服务(mysql、redis、http.client、log)比较繁琐,如果想 快速接入 基础服务可以使用本类库。

没有多余复杂的功能,方便你拓展其他功能。

你可以 import 引入直接使用,也可以拷贝代码到自己项目中使用,也可以用于构建自己的基础类库。

项目地址: https://github.com/e421083458/golang_common

功能

多套配置环境设置,比如:dev、prod。

mysql、redis 多套数据源配置。

支持默认和自定义日志实例,自动滚动日志。

支持 mysql(基于gorm的二次开发支持ctx功能,不影响gorm原功能使用)、redis(redigo)、http.client 请求链路日志输出。

安装及使用

需要确保已经安装了 Go 1.8+,然后执行以下命令

go get -v github.com/e421083458/golang_common

将配置文件拷贝到你的项目中,配置文件请参考: https://github.com/e421083458/golang_common/tree/master/conf/dev

其实只需要base.toml即可,mysql.toml、redis.toml 根据实际需要再配置。

log消息打印代码举例:

package main

import (

"github.com/e421083458/golang_common/lib"

"log"

"time"

)

func main(){

if err:=lib.Init("./conf/dev/");err!=nil{

log.Fatal(err)

}

defer lib.Destroy()

//todo sth
lib.Log.TagInfo(lib.NewTrace(), lib.DLTagUndefind, map[string]interface{}{"message": "todo sth"})
time.Sleep(time.Second)

}

运行代码

go run main.go

输出:

2019/05/21 10:31:08 ------------------------------------------------------------------------

2019/05/21 10:31:08 [INFO] config=./conf/dev/

2019/05/21 10:31:08 [INFO] start loading resources.

2019/05/21 10:31:08 [INFO] success loading resources.

2019/05/21 10:31:08 ------------------------------------------------------------------------

2019-05-21T10:31:08.667 [INFO] log.go:58 _undef||traceid=ac182a1c5ce362ecf9280618104dc7b0||cspanid=||spanid=f0fb48f0380704bb||message=todo sth

2019/05/21 10:31:09 ------------------------------------------------------------------------

2019/05/21 10:31:09 [INFO] start destroy resources.

2019/05/21 10:31:09 [INFO] success destroy resources.

其他功能举例

初始化当前运行环境

//初始化测试用例

func InitTest() {

initOnce.Do(func() {

if err:=lib.Init("../conf/dev/");err!=nil{

log.Fatal(err)

}

})

}

获取当前运行环境

//获取 程序运行环境 dev prod

func Test_GetConfEnv(t *testing.T) {

InitTest()

fmt.Println(lib.GetConfEnv())

DestroyTest()

}

加载自定义配置文件

type HttpConf struct {

ServerAddr string toml:"server_addr"
ReadTimeout int toml:"read_timeout"
WriteTimeout int toml:"write_timeout"
MaxHeaderBytes int toml:"max_header_bytes"
AllowHost []string toml:"allow_host"

}

// 加载自定义配置文件

func Test_ParseLocalConfig(t *testing.T) {

InitTest()

httpProfile := &HttpConf{}

err:=lib.ParseLocalConfig("http.toml",httpProfile)

if err!=nil{

t.Fatal(err)

}

fmt.Println(httpProfile)

DestroyTest()

}

测试PostJson请求

//测试PostJson请求

func TestJson(t *testing.T) {

InitTestServer()

//首次scrollsId不传递

jsonStr := "{\"source\":\"control\",\"cityId\":\"12\",\"trailNum\":10,\"dayTime\":\"2018-11-21 16:08:00\",\"limit\":2,\"andOperations\":{\"cityId\":\"eq\",\"trailNum\":\"gt\",\"dayTime\":\"eq\"}}"

url := " http://"+addr+"/postjson "

_, res, err := lib.HttpJSON(lib.NewTrace(), url, jsonStr, 1000, nil)

fmt.Println(string(res))

if err != nil {

fmt.Println(err.Error())

}

}

测试Get请求

//测试Get请求

func TestGet(t *testing.T) {

InitTestServer()

a := url.Values{

"city

id": {"12"},

}

url := " http://"+addr+"/get "

, res, err := lib.HttpGET(lib.NewTrace(), url, a, 1000, nil)

fmt.Println("city_id="+string(res))

if err != nil {

fmt.Println(err.Error())

}

}

测试Post请求

//测试Post请求

func TestPost(t *testing.T) {

InitTestServer()

a := url.Values{

"city

id": {"12"},

}

url := " http://"+addr+"/post "

, res, err := lib.HttpPOST(lib.NewTrace(), url, a, 1000, nil, "")

fmt.Println("city_id="+string(res))

if err != nil {

fmt.Println(err.Error())

}

}

测试默认日志打点

//测试日志打点

func TestDefaultLog(t *testing.T) {

InitTest()

lib.Log.TagInfo(lib.NewTrace(), lib.DLTagMySqlSuccess, map[string]interface{}{

"sql": "sql",

})

time.Sleep(time.Second)

DestroyTest()

}

测试自定义日志实例打点

//测试日志实例打点

func TestLogInstance(t *testing.T) {

nlog:= log.NewLogger()

logConf:= log.LogConfig{

Level:"trace",

FW: log.ConfFileWriter{

On:true,

LogPath:"./log_test.log",

RotateLogPath:"./log_test.log",

WfLogPath:"./log_test.wf.log",

RotateWfLogPath:"./log_test.wf.log",

},

CW: log.ConfConsoleWriter{

On:true,

Color:true,

},

}

log.SetupLogInstanceWithConf(logConf,nlog)

nlog.Info("test message")

nlog.Close()

time.Sleep(time.Second)

}

测试mysql普通sql

var (

createTableSQL = "CREATE TABLE test1 ( id int(12) unsigned NOT NULL AUTO_INCREMENT" +

" COMMENT '自增id', name varchar(255) NOT NULL DEFAULT '' COMMENT '姓名'," +

" created_at datetime NOT NULL,PRIMARY KEY ( id )) ENGINE=InnoDB " +

"DEFAULT CHARSET=utf8"

insertSQL = "INSERT INTO test1 ( id , name , created_at ) VALUES (NULL, '111', '2018-08-29 11:01:43');"

dropTableSQL = "DROP TABLE test1 "

beginSQL = "start transaction;"

commitSQL = "commit;"

rollbackSQL = "rollback;"

)

func Test_DBPool(t *testing.T) {

InitTest()

//获取链接池
dbpool, err := lib.GetDBPool("default")
if err != nil {
    t.Fatal(err)
}
//开始事务
trace := lib.NewTrace()
if _, err := lib.DBPoolLogQuery(trace, dbpool, beginSQL); err != nil {
    t.Fatal(err)
}

//创建表
if _, err := lib.DBPoolLogQuery(trace, dbpool, createTableSQL); err != nil {
    lib.DBPoolLogQuery(trace, dbpool, rollbackSQL)
    t.Fatal(err)
}

//插入数据
if _, err := lib.DBPoolLogQuery(trace, dbpool, insertSQL); err != nil {
    lib.DBPoolLogQuery(trace, dbpool, rollbackSQL)
    t.Fatal(err)
}

//循环查询数据
current_id := 0
table_name := "test1"
fmt.Println("begin read table ", table_name, "")
fmt.Println("------------------------------------------------------------------------")
fmt.Printf("%6s | %6s\n", "id", "created_at")
for {
    rows, err := lib.DBPoolLogQuery(trace, dbpool, "SELECT id,created_at FROM test1 WHERE id>? order by id asc", current_id)
    defer rows.Close()
    row_len := 0
    if err != nil {
        lib.DBPoolLogQuery(trace, dbpool, "rollback;")
        t.Fatal(err)
    }
    for rows.Next() {
        var create_time string
        if err := rows.Scan(&current_id, &create_time); err != nil {
            lib.DBPoolLogQuery(trace, dbpool, "rollback;")
            t.Fatal(err)
        }
        fmt.Printf("%6d | %6s\n", current_id, create_time)
        row_len++
    }
    if row_len == 0 {
        break
    }
}
fmt.Println("------------------------------------------------------------------------")
fmt.Println("finish read table ", table_name, "")

//删除表
if _, err := lib.DBPoolLogQuery(trace, dbpool, dropTableSQL); err != nil {
    lib.DBPoolLogQuery(trace, dbpool, rollbackSQL)
    t.Fatal(err)
}

//提交事务
lib.DBPoolLogQuery(trace, dbpool, commitSQL)
DestroyTest()

}

测试Gorm

func Test_GORM(t *testing.T) {

InitTest()

//获取链接池
dbpool, err := lib.GetGormPool("default")
if err != nil {
    t.Fatal(err)
}
db := dbpool.Begin()
traceCtx := lib.NewTrace()

//设置trace信息
db = db.SetCtx(traceCtx)
if err := db.Exec(createTableSQL).Error; err != nil {
    db.Rollback()
    t.Fatal(err)
}郑    州    妇 科   医 院    :https://yyk.familydoctor.com.cn/21521/

//插入数据
t1 := &Test1{Name: "test_name", CreatedAt: time.Now()}
if err := db.Save(t1).Error; err != nil {
    db.Rollback()
    t.Fatal(err)
}

//查询数据
list := []Test1{}
if err := db.Where("name=?", "test_name").Find(&list).Error; err != nil {
    db.Rollback()
    t.Fatal(err)
}
fmt.Println(list)

//删除表数据
if err := db.Exec(dropTableSQL).Error; err != nil {
    db.Rollback()
    t.Fatal(err)
}
db.Commit()
DestroyTest()

}

测试redis查询

func Test_Redis(t *testing.T) {

InitTest()

c, err := lib.RedisConnFactory("default")
if err != nil {
    t.Fatal(err)
}
defer c.Close()

// 调用SET
trace := lib.NewTrace()
redisKey := "test_key1"
lib.RedisLogDo(trace, c, "SET", redisKey, "test_dpool")
lib.RedisLogDo(trace, c, "expire", "test_key1", 10)

// 调用GET
v, err := redis.String(lib.RedisLogDo(trace, c, "GET", redisKey))
fmt.Println(v)
if v != "test_dpool" || err != nil {
    t.Fatal("test redis get fatal!")
}

DestroyTest()

}

销毁当前运行环境

//销毁测试用例

func DestroyTest() {

Destroy()

}思考

怎么样才能让类库做的更通用?

有人说简洁才是golang特性,不需要做通用类库。如果你想加一个功能直接引一个包用即可。比如:日志那就引日志包、redis就引redis包。

我赞同此观点,但是引入包后要面临的问题是功能改造和代码适配,并且每做一个项目都要搞上一套。这意味着需要耗费一定的时间在重复的工作上。

我感觉类库应该有一下特点:

轻量级,没有太多依赖,否则容易有类库依赖冲突。

只封装重复使用率高的功能。

拓展性强。

作者:e421083458

来源:CSDN

原文: https://blog.csdn.net/e421083458/article/details/90346968

版权声明:本文为博主原创文章,转载请附上博文链接!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK