From ab26f729231eb23f38952d95a9ebbaf2149864ff Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Wed, 11 Dec 2019 17:02:09 +0800 Subject: [PATCH 01/13] =?UTF-8?q?demo=E4=B8=8D=E4=BD=BF=E7=94=A8gorm?= =?UTF-8?q?=E7=9A=84=E5=85=B3=E8=81=94=E6=93=8D=E4=BD=9C=EF=BC=8C=E4=BC=9A?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E4=B8=80=E4=BA=9B=E4=B8=8D=E5=BF=85=E8=A6=81?= =?UTF-8?q?=E7=9A=84sql=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/apis/demo.go | 6 ++--- app/apis/demo_test.go | 10 ++----- app/services/demosvc/alertsvc.go | 38 ++++++++++++++++----------- app/services/demosvc/alertsvc_test.go | 6 ++--- 4 files changed, 30 insertions(+), 30 deletions(-) diff --git a/app/apis/demo.go b/app/apis/demo.go index f347ddd..fb80c17 100644 --- a/app/apis/demo.go +++ b/app/apis/demo.go @@ -89,7 +89,7 @@ func DeleteAlertPolicy(c *gin.Context) { // ModifyAlertPolicy godoc // @Summary 更新告警策略 -// @Description 更新告警策略返回对应ID +// @Description 更新告警策略成功返回true // @Tags demo // @Accept json // @Produce json @@ -106,12 +106,12 @@ func ModifyAlertPolicy(c *gin.Context) { // 使用外层appid和uin作为告警策略的字段 p.AlertPolicy.AppID = p.AppID p.AlertPolicy.Uin = p.Uin - result, err := demosvc.ModifyAlertPolicy(c, db, p.AlertPolicy) + err := demosvc.ModifyAlertPolicy(c, db, p.AlertPolicy) if err != nil { response.ErrJSON(c, err) return } - response.JSON(c, result) + response.JSON(c, true) } // DescribeAlertPolicies godoc diff --git a/app/apis/demo_test.go b/app/apis/demo_test.go index 44dd870..5c852f3 100644 --- a/app/apis/demo_test.go +++ b/app/apis/demo_test.go @@ -154,14 +154,8 @@ func TestUpdate(t *testing.T) { if data.Get("code").ToInt() != 0 { t.Fatal("接口返回了错误信息,没有成功获取告警策略:", string(body)) } - if data.Get("data", "alert_channel").ToString() != "weixin" { - t.Fatal("修改策略表的alert_channel字段失败:", string(body)) - } - if data.Get("data", "alert_filter_rules").Size() != 0 { - t.Fatal("修改策略清空过滤条件未生效:", string(body)) - } - if data.Get("data", "alert_trigger_rules").Size() != 1 { - t.Fatal("修改策略触发条件未生效:", string(body)) + if data.Get("data").ToBool() == false { + t.Fatal("修改策略表的字段失败:", string(body)) } } diff --git a/app/services/demosvc/alertsvc.go b/app/services/demosvc/alertsvc.go index da5b61d..eb87b48 100644 --- a/app/services/demosvc/alertsvc.go +++ b/app/services/demosvc/alertsvc.go @@ -135,19 +135,19 @@ func DescribeAlertTriggerRules(c *gin.Context, db *gorm.DB, policyID int64) ([]d // ModifyAlertPolicy 更新告警策略 // 使用Association Replace来更新关联条件如果传了主键ID则更新对应记录,没有主键ID的全部新增记录,剔除了关联并不会删除记录只会把关联的id置为0 // 这里需要真实删除记录 使用事务删除全部关联 -func ModifyAlertPolicy(c *gin.Context, db *gorm.DB, policy *demomod.AlertPolicy) (*demomod.AlertPolicy, error) { +func ModifyAlertPolicy(c *gin.Context, db *gorm.DB, policy *demomod.AlertPolicy) error { // 查询被更新的记录是否存在 rawPolicy := &demomod.AlertPolicy{} if err := db.Where("appid = ? AND uin = ? AND id = ?", policy.AppID, policy.Uin, policy.ID).Find(rawPolicy).Error; err != nil { logging.CtxLogger(c).Error("ModifyAlertPolicy Find error", zap.Error(err)) - return nil, ErrAlertPolicyModifyFailed.AppendError(err) + return ErrAlertPolicyModifyFailed.AppendError(err) } // 开启事务 tx := db.Begin() if err := tx.Error; err != nil { logging.CtxLogger(c).Error("ModifyAlertPolicy Begin tx error", zap.Error(err)) - return nil, ErrAlertPolicyModifyFailed.AppendError(err) + return ErrAlertPolicyModifyFailed.AppendError(err) } defer tx.Rollback() @@ -164,36 +164,42 @@ func ModifyAlertPolicy(c *gin.Context, db *gorm.DB, policy *demomod.AlertPolicy) "callback_url": policy.CallbackURL, }).Error; err != nil { logging.CtxLogger(c).Error("ModifyAlertPolicy Updates policy error", zap.Error(err)) - return nil, ErrAlertPolicyModifyFailed.AppendError(err) + return ErrAlertPolicyModifyFailed.AppendError(err) } // 删除过滤条件 if err := tx.Where("alert_policy_id = ?", policy.ID).Delete(demomod.AlertFilterRule{}).Error; err != nil { logging.CtxLogger(c).Error("ModifyAlertPolicy Delete filter rules error", zap.Error(err)) - return nil, ErrAlertFilterRuleDeleteFailed.AppendError(err) + return ErrAlertFilterRuleDeleteFailed.AppendError(err) } // 删除触发条件 if err := tx.Where("alert_policy_id = ?", policy.ID).Delete(demomod.AlertTriggerRule{}).Error; err != nil { logging.CtxLogger(c).Error("ModifyAlertPolicy Delete trigger rules error", zap.Error(err)) - return nil, ErrAlertTriggerRuleDeleteFailed.AppendError(err) + return ErrAlertTriggerRuleDeleteFailed.AppendError(err) } - // 更新关联数据 - tx.Model(rawPolicy).Association("AlertFilterRules").Replace(policy.AlertFilterRules) - tx.Model(rawPolicy).Association("AlertTriggerRules").Replace(policy.AlertTriggerRules) - - // 保存更新 - if err := tx.Save(rawPolicy).Error; err != nil { - logging.CtxLogger(c).Error("ModifyAlertPolicy Save rules error", zap.Error(err)) - return nil, ErrAlertPolicyModifyFailed.AppendError(err) + // 插入新的关联数据 + for _, r := range policy.AlertFilterRules { + r.AlertPolicyID = policy.ID + if err := tx.Create(r).Error; err != nil { + logging.CtxLogger(c).Error(err.Error()) + return ErrAlertPolicyModifyFailed.AppendError(err) + } + } + for _, r := range policy.AlertTriggerRules { + r.AlertPolicyID = policy.ID + if err := tx.Create(r).Error; err != nil { + logging.CtxLogger(c).Error(err.Error()) + return ErrAlertPolicyModifyFailed.AppendError(err) + } } // 提交事务 if err := tx.Commit().Error; err != nil { logging.CtxLogger(c).Error("ModifyAlertPolicy Commit error", zap.Error(err)) - return nil, ErrAlertPolicyModifyFailed.AppendError(err) + return ErrAlertPolicyModifyFailed.AppendError(err) } - return rawPolicy, nil + return nil } // DescribeAlertPolicies 查询告警策略列表 diff --git a/app/services/demosvc/alertsvc_test.go b/app/services/demosvc/alertsvc_test.go index 85916c4..94eac07 100644 --- a/app/services/demosvc/alertsvc_test.go +++ b/app/services/demosvc/alertsvc_test.go @@ -304,7 +304,7 @@ func TestModifyAlertPolicy(t *testing.T) { ContinuousCycleCount: 1, } p.AlertTriggerRules = []*demomod.AlertTriggerRule{tr2, ntr} - mPolicy, err := ModifyAlertPolicy(utctx, utdb, p) + err = ModifyAlertPolicy(utctx, utdb, p) if err != nil { t.Fatal("ModifyAlertPolicy err:", err) } @@ -331,10 +331,10 @@ func TestModifyAlertPolicy(t *testing.T) { } // 检查修改返回的结果和查询修改后的结果是否一致 - if qPolicy.AlertChannel != mPolicy.AlertChannel { + if qPolicy.AlertChannel != p.AlertChannel { t.Fatal("TestModifyAlertPolicy 对比更新返回的policy和查询的policy字段失败") } - if qPolicy.AlertTriggerRules[0].Relation != mPolicy.AlertTriggerRules[0].Relation { + if qPolicy.AlertTriggerRules[0].Relation != tr2.Relation { t.Fatal("TestModifyAlertPolicy 对比更新返回的关联条件的字段失败") } } From 4129e7588732c266eeff345cefffae7a04dc901e Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Tue, 18 Feb 2020 11:36:51 +0800 Subject: [PATCH 02/13] update new proj script --- script/new-project.macos.sh | 43 ------------------- .../{new-project.linux.sh => new-project.sh} | 24 +++++++++-- ...ommit.linux.githook => pre-commit.githook} | 9 ++-- script/pre-commit.macos.githook | 15 ------- 4 files changed, 25 insertions(+), 66 deletions(-) delete mode 100755 script/new-project.macos.sh rename script/{new-project.linux.sh => new-project.sh} (64%) rename script/{pre-commit.linux.githook => pre-commit.githook} (71%) delete mode 100755 script/pre-commit.macos.githook diff --git a/script/new-project.macos.sh b/script/new-project.macos.sh deleted file mode 100755 index b77e092..0000000 --- a/script/new-project.macos.sh +++ /dev/null @@ -1,43 +0,0 @@ -#! /usr/bin/env bash -CYAN="\033[1;36m" -GREEN="\033[0;32m" -WHITE="\033[1;37m" -NOTICE_FLAG="${CYAN}❯" -QUESTION_FLAG="${GREEN}?" - -main() { - gopath=`go env GOPATH` - echo -e "${NOTICE_FLAG} New project will be create in ${WHITE}${gopath}/src/" - echo -ne "${QUESTION_FLAG} ${CYAN}Enter your new project full name${CYAN}: " - read projname - echo -ne "${QUESTION_FLAG} ${CYAN}Do you want to the demo code[${WHITE}Y/n${CYAN}]: " - read rmdemo - - # get skeleton - echo -e "${NOTICE_FLAG} Downloading the skeleton..." - git clone https://github.com/axiaoxin/pink-lady.git ${gopath}/src/${projname} - # replace project name - echo -e "${NOTICE_FLAG} Generating the project..." - cd ${gopath}/src/${projname} && rm -rf .git && cp ${gopath}/src/${projname}/app/config.toml.example ${gopath}/src/${projname}/app/config.toml - sed -i '' "s|github.com/axiaoxin/pink-lady|${projname}|g" `grep "github.com/axiaoxin/pink-lady" --include ".travis.yml" --include "*.go" --include "go.*" -rl .` - - # remove demo - if [ "${rmdemo}" == "n" ] || [ "${rmdemo}" == "N" ]; then - rm -rf app/apis/demo - rm -rf app/services/demo - rm -rf app/models/demo - sed -i '' "/demo routes start/,/demo routes end/d" ${gopath}/src/${projname}/app/apis/routes.go - sed -i '' '/app\/apis\/demo"$/d' ${gopath}/src/${projname}/app/apis/routes.go - fi - echo -e "${NOTICE_FLAG} Create project ${projname} in ${gopath}/src succeed." - - # init a git repo - echo -ne "${QUESTION_FLAG} ${CYAN}Do you want to init a git repo[${WHITE}N/y${CYAN}]: " - read initgit - if [ "${initgit}" == "y" ] || [ "${rmdemo}" == "Y" ]; then - cd ${gopath}/src/${projname} && git init && git add . && git commit -m "init project with pink-lady" - cp ${gopath}/src/${projname}/misc/pre-commit.macos.githook ${gopath}/src/${projname}/.git/hooks/pre-commit - chmod +x ${gopath}/src/${projname}/.git/hooks/pre-commit - fi -} -main diff --git a/script/new-project.linux.sh b/script/new-project.sh similarity index 64% rename from script/new-project.linux.sh rename to script/new-project.sh index 64f3f89..32bbff4 100755 --- a/script/new-project.linux.sh +++ b/script/new-project.sh @@ -5,8 +5,24 @@ WHITE="\033[1;37m" NOTICE_FLAG="${CYAN}❯" QUESTION_FLAG="${GREEN}?" +OS=`uname` +# $(replace_in_file pattern file) +function replace_in_file() { + if [ "$OS" = 'Darwin' ]; then + # for MacOS + sed -i '' -e "$1" "$2" + else + # for Linux and Windows + sed -i'' -e "$1" "$2" + fi +} + main() { gopath=`go env GOPATH` + if [ $? = 127 ]; then + echo "GOPATH not exists" + exit -1 + fi echo -e "${NOTICE_FLAG} New project will be create in ${WHITE}${gopath}/src/" echo -ne "${QUESTION_FLAG} ${CYAN}Enter your new project full name${CYAN}: " read projname @@ -19,15 +35,15 @@ main() { # replace project name echo -e "${NOTICE_FLAG} Generating the project..." cd ${gopath}/src/${projname} && rm -rf .git && cp ${gopath}/src/${projname}/app/config.toml.example ${gopath}/src/${projname}/app/config.toml - sed -i "s|github.com/axiaoxin/pink-lady|${projname}|g" `grep "github.com/axiaoxin/pink-lady" --include ".travis.yml" --include "*.go" --include "go.*" -rl .` + replace_in_file "s|github.com/axiaoxin/pink-lady|${projname}|g" `grep "github.com/axiaoxin/pink-lady" --include ".travis.yml" --include "*.go" --include "go.*" -rl .` # remove demo if [ "${rmdemo}" == "n" ] || [ "${rmdemo}" == "N" ]; then rm -rf app/apis/demo rm -rf app/services/demo rm -rf app/models/demo - sed -i "/demo routes start/,/demo routes end/d" ${gopath}/src/${projname}/app/apis/routes.go - sed -i '/app\/apis\/demo"$/d' ${gopath}/src/${projname}/app/apis/routes.go + replace_in_file "/demo routes start/,/demo routes end/d" ${gopath}/src/${projname}/app/apis/routes.go + replace_in_file '/app\/apis\/demo"$/d' ${gopath}/src/${projname}/app/apis/routes.go fi echo -e "${NOTICE_FLAG} Create project ${projname} in ${gopath}/src succeed." @@ -36,7 +52,7 @@ main() { read initgit if [ "${initgit}" == "y" ] || [ "${rmdemo}" == "Y" ]; then cd ${gopath}/src/${projname} && git init && git add . && git commit -m "init project with pink-lady" - cp ${gopath}/src/${projname}/misc/pre-commit.linux.githook ${gopath}/src/${projname}/.git/hooks/pre-commit + cp ${gopath}/src/${projname}/script/pre-commit.githook ${gopath}/src/${projname}/.git/hooks/pre-commit chmod +x ${gopath}/src/${projname}/.git/hooks/pre-commit fi } diff --git a/script/pre-commit.linux.githook b/script/pre-commit.githook similarity index 71% rename from script/pre-commit.linux.githook rename to script/pre-commit.githook index 8ea2c6f..3a94145 100755 --- a/script/pre-commit.linux.githook +++ b/script/pre-commit.githook @@ -6,12 +6,13 @@ # it wants to stop the commit. # # To enable this hook, rename this file to "pre-commit". +realpath() { + [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" +} -hooks_path=$(dirname "`readlink -f $0`") +hooks_path=$(dirname "`realpath $0`") git_path=$(dirname "$hooks_path") project_path=$(dirname "$git_path") cd $project_path/app -go fmt ./... -go vet ./... -go test ./... +go fmt ./... && go vet ./... && go test ./... diff --git a/script/pre-commit.macos.githook b/script/pre-commit.macos.githook deleted file mode 100755 index 50502f0..0000000 --- a/script/pre-commit.macos.githook +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh -# -# An example hook script to verify what is about to be committed. -# Called by "git commit" with no arguments. The hook should -# exit with non-zero status after issuing an appropriate message if -# it wants to stop the commit. -# -# To enable this hook, rename this file to "pre-commit". - -hooks_path=$(dirname "`greadlink -f $0`") -git_path=$(dirname "$hooks_path") -project_path=$(dirname "$git_path") - -cd $project_path/app -go fmt -s -w ./... && go vet ./... && go test ./... From cfab2f97bebe9d56ff79b28c916866a11d628cf1 Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Tue, 18 Feb 2020 12:39:38 +0800 Subject: [PATCH 03/13] update gen apidoc script --- script/{gen_apidoc_macos.sh => gen_apidoc.sh} | 6 +++++- script/gen_apidoc_linux.sh | 6 ------ 2 files changed, 5 insertions(+), 7 deletions(-) rename script/{gen_apidoc_macos.sh => gen_apidoc.sh} (71%) delete mode 100755 script/gen_apidoc_linux.sh diff --git a/script/gen_apidoc_macos.sh b/script/gen_apidoc.sh similarity index 71% rename from script/gen_apidoc_macos.sh rename to script/gen_apidoc.sh index 304bef0..ec65877 100755 --- a/script/gen_apidoc_macos.sh +++ b/script/gen_apidoc.sh @@ -1,6 +1,10 @@ #! /usr/bin/env bash +realpath() { + [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" +} + # 生成swag api文档 -PROJECT_PATH=$(dirname $(dirname $(greadlink -f $0))) +PROJECT_PATH=$(dirname $(dirname $(realpath $0))) MAIN_PATH=${PROJECT_PATH}/app/ # swag init必须在main.go所在的目录下执行,否则必须用--dir参数指定main.go的路径 swag init --dir ${MAIN_PATH} --generalInfo apis/apis.go --propertyStrategy camelcase --output ${MAIN_PATH}/apis/docs diff --git a/script/gen_apidoc_linux.sh b/script/gen_apidoc_linux.sh deleted file mode 100755 index d8a493c..0000000 --- a/script/gen_apidoc_linux.sh +++ /dev/null @@ -1,6 +0,0 @@ -#! /usr/bin/env bash -PROJECT_PATH=$(dirname $(dirname $(readlink -f $0))) -APP_PATH=${PROJECT_PATH}/app -cd ${APP_PATH} -swag init -g apis/init.go -cd - From be2a2f25f21fc4153d559c5ebda2ef2517bf55d9 Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Tue, 18 Feb 2020 16:29:56 +0800 Subject: [PATCH 04/13] release script update --- app/apis/docs/docs.go | 4 ++-- app/apis/docs/swagger.json | 2 +- app/apis/docs/swagger.yaml | 2 +- script/release.sh | 36 ++++++++++++++++++++++++++---------- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/app/apis/docs/docs.go b/app/apis/docs/docs.go index 1206663..77c2295 100644 --- a/app/apis/docs/docs.go +++ b/app/apis/docs/docs.go @@ -1,6 +1,6 @@ // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // This file was generated by swaggo/swag at -// 2019-12-02 18:25:14.962373 +0800 CST m=+0.059366310 +// 2020-02-18 16:28:52.636591 +0800 CST m=+0.036580649 package docs @@ -107,7 +107,7 @@ var doc = `{ } }, "put": { - "description": "更新告警策略返回对应ID", + "description": "更新告警策略成功返回true", "consumes": [ "application/json" ], diff --git a/app/apis/docs/swagger.json b/app/apis/docs/swagger.json index d7b042c..ef56ece 100644 --- a/app/apis/docs/swagger.json +++ b/app/apis/docs/swagger.json @@ -91,7 +91,7 @@ } }, "put": { - "description": "更新告警策略返回对应ID", + "description": "更新告警策略成功返回true", "consumes": [ "application/json" ], diff --git a/app/apis/docs/swagger.yaml b/app/apis/docs/swagger.yaml index 7854599..48dabe5 100644 --- a/app/apis/docs/swagger.yaml +++ b/app/apis/docs/swagger.yaml @@ -282,7 +282,7 @@ paths: put: consumes: - application/json - description: 更新告警策略返回对应ID + description: 更新告警策略成功返回true parameters: - description: 参数包含BaseParam和demomod.AlertPolicy in: body diff --git a/script/release.sh b/script/release.sh index cc8bbe0..d6f1e95 100755 --- a/script/release.sh +++ b/script/release.sh @@ -14,8 +14,12 @@ WARNING_FLAG="${YELLOW}!" ERROR_FLAG="${RED}!!" NOTICE_FLAG="${CYAN}❯" +realpath() { + [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" +} + # PATHS -PROJECT_PATH=$(dirname $(dirname $(readlink -f $0))) +PROJECT_PATH=$(dirname $(dirname $(realpath $0))) APP_PATH=${PROJECT_PATH}/app BUILD_PATH=${PROJECT_PATH}/build NOW=$(date "+%Y%m%d-%H%M%S") @@ -28,13 +32,27 @@ BUILDING_FAILED=-3 APIDOC_VERSION_PATTERN='// @version [0-9]+\.[0-9]+\.[0-9]+' CONST_VERSION_PATTERN='const VERSION = "[0-9]+\.[0-9]+\.[0-9]+"' + +OS=`uname` +# $(replace_in_file pattern file) +function replace_in_file() { + if [ "$OS" = 'Darwin' ]; then + # for MacOS + sed -i '' -E "$1" "$2" + else + # for Linux and Windows + sed -i'' "$1" "$2" + fi +} + + # Bump version bumpVersion() { lastest_commit=$(git log --pretty=format:"%h %cd %d %s" -1) # check version - current_apidoc_version_line=($(grep -oE "${APIDOC_VERSION_PATTERN}" ${APP_PATH}/apis/init.go)) + current_apidoc_version_line=($(grep -oE "${APIDOC_VERSION_PATTERN}" ${APP_PATH}/apis/apis.go)) current_apidoc_version=${current_apidoc_version_line[2]} - current_const_version_line=$(grep -oE "${CONST_VERSION_PATTERN}" ${APP_PATH}/apis/init.go) + current_const_version_line=$(grep -oE "${CONST_VERSION_PATTERN}" ${APP_PATH}/apis/apis.go) current_const_version=$(echo "${current_const_version_line}" | grep -o '".*"' | sed 's/"//g') if [ "${current_apidoc_version}" != "${current_const_version}" ]; then echo -e "${ERROR_FLAG} ${RED}apidoc version ${current_apidoc_version} is not match with const version ${current_const_version}" @@ -59,7 +77,7 @@ bumpVersion() { echo -e "${NOTICE_FLAG} Will set new version to be ${WHITE}${new_version}" # update version in apidoc and const - sed -i -r "s|${APIDOC_VERSION_PATTERN}|// @version ${new_version}|" ${APP_PATH}/apis/init.go && sed -i -r "s|${CONST_VERSION_PATTERN}|const VERSION = \"${new_version}\"|" ${APP_PATH}/apis/init.go + replace_in_file "s|${APIDOC_VERSION_PATTERN}|// @version ${new_version}|" ${APP_PATH}/apis/apis.go && replace_in_file "s|${CONST_VERSION_PATTERN}|const VERSION = \"${new_version}\"|" ${APP_PATH}/apis/apis.go } tests() { @@ -85,7 +103,7 @@ build() { if [ "${binary_name}" != "" ]; then BINARY_NAME=${binary_name} fi - APIDOC_HOST=pink-lady + APIDOC_HOST=127.0.0.1:4869 echo -ne "${QUESTION_FLAG} ${CYAN}Enter apidocs host[${WHITE}${APIDOC_HOST}${CYAN}]: " read apidoc_host if [ "${apidoc_host}" != "" ]; then @@ -93,7 +111,7 @@ build() { fi # replace apidoc host - sed -i -r "s|// @host .+?|// @host ${APIDOC_HOST}|" ${APP_PATH}/apis/init.go + replace_in_file "s|// @host .+?|// @host ${APIDOC_HOST}|" ${APP_PATH}/apis/apis.go echo -e "${NOTICE_FLAG} Will build binary name to be ${WHITE}${BINARY_NAME} ${CYAN}with apidoc host ${WHITE}${APIDOC_HOST}" @@ -104,9 +122,7 @@ build() { echo -e "${WARNING_FLAG} ${CYAN}No swag for generate API docs. You need to install it for auto generate the docs" else echo -e "${NOTICE_FLAG} Generating API docs..." - cd ${APP_PATH} - swag init -g apis/init.go - cd - + bash ${PROJECT_PATH}/script/gen_apidoc.sh fi # Building @@ -139,7 +155,7 @@ commit() { echo -ne "${QUESTION_FLAG} ${CYAN}Do you want to commit this version bump to git[${WHITE}Y/n${CYAN}]: " read do_commit if [ "${do_commit}" == "" ] || [ "${do_commit}" == "Y" ]; then - git add ${APP_PATH}/docs ${APP_PATH}/apis/init.go + git add ${APP_PATH}/docs ${APP_PATH}/apis/apis.go git commit -m "Bump version ${current_version} -> ${new_version}" echo -ne "${QUESTION_FLAG} ${CYAN}Do you want to tag this version bump to git[${WHITE}Y/n${CYAN}]: " read do_tag From d6db800b92696eeff42e73b1be55a5f0b923d8a6 Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Tue, 18 Feb 2020 17:13:15 +0800 Subject: [PATCH 05/13] add a function for gen gin context --- app/logging/ctxlogger.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/logging/ctxlogger.go b/app/logging/ctxlogger.go index 310a222..4fdd552 100644 --- a/app/logging/ctxlogger.go +++ b/app/logging/ctxlogger.go @@ -1,6 +1,9 @@ package logging import ( + "net/http" + "net/http/httptest" + "github.com/gin-gonic/gin" uuid "github.com/satori/go.uuid" "go.uber.org/zap" @@ -13,6 +16,15 @@ const ( RequestIDKey = "X-Request-Id" ) +// GenGinContext 生成gin.context +func GenGinContext(logger *zap.Logger, requestID string) *gin.Context { + c, _ := gin.CreateTestContext(httptest.NewRecorder()) + c.Request, _ = http.NewRequest("GET", "http://fake.url", nil) + SetCtxLogger(c, logger) + SetCtxRequestID(c, requestID) + return c +} + // SetCtxLogger add a logger with given field into the gin.Context // and set requestid field get from context func SetCtxLogger(c *gin.Context, ctxLogger *zap.Logger) { From e1a3f134ce13d2cd1b14fbb42cc8102681bee5c6 Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Tue, 18 Feb 2020 20:54:03 +0800 Subject: [PATCH 06/13] redis map --- app/config.toml.example | 17 +++++++++---- app/utils/redis.go | 55 ++++++++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/app/config.toml.example b/app/config.toml.example index 90ec413..e44fa20 100644 --- a/app/config.toml.example +++ b/app/config.toml.example @@ -68,11 +68,18 @@ postgres = [ ] [redis] -mode = "single-instance" -address = "localhost:6379" -password = "" -dbindex = 0 -master = "" + [redis.local0] + mode = "normal" + address = "localhost:6379" + password = "" + dbindex = 0 + master = "" + [redis.local1] + mode = "normal" + address = "localhost:6379" + password = "" + dbindex = 1 + master = "" [apidocs] rootRedirect = true diff --git a/app/utils/redis.go b/app/utils/redis.go index 53a776b..d0d20de 100644 --- a/app/utils/redis.go +++ b/app/utils/redis.go @@ -10,20 +10,18 @@ import ( // redis connection modes const ( - RedisSingleInstanceMode = "single-instance" + RedisSingleInstanceMode = "normal" RedisSentinelMode = "sentinel" RedisClusterMode = "cluster" RedisAddrsSeparator = "," ) -// redis clients +// redis clients map var ( - // Redis single instance - Redis *redis.Client - // Redis sentinel instance - RedisSentinel *redis.Client - // RedisCluster redis cluster client - RedisCluster *redis.ClusterClient + // RedisClientMap redis normal and sentinel client map + RedisClientMap = make(map[string]*redis.Client) + // RedisClusterMap redis cluster client map + RedisClusterMap = make(map[string]*redis.ClusterClient) ) // InitRedis init redis client by different mode @@ -34,23 +32,34 @@ var ( // `dbindex` is redis db number, cluster mode don't use it // `master` is redis sentinel master name, only need to be set on sentinel mode, others dont't use it func InitRedis() error { - addr := viper.GetString("redis.address") - password := viper.GetString("redis.password") - dbindex := viper.GetInt("redis.dbindex") - mode := strings.ToLower(viper.GetString("redis.mode")) - var err error - if mode == RedisSingleInstanceMode { - Redis, err = NewRedisClient(addr, password, dbindex) - } else if mode == RedisSentinelMode { - addrs := strings.Split(addr, RedisAddrsSeparator) - RedisSentinel, err = NewRedisSentinel(viper.GetString("redis.master"), addrs, password, dbindex) - } else if mode == RedisClusterMode { - addrs := strings.Split(addr, RedisAddrsSeparator) - RedisCluster, err = NewRedisCluster(addrs, password) - } else { - err = errors.New("Invalid Redis config to InitRedis") + var cli *redis.Client + var cluster *redis.ClusterClient + + redisMap := viper.GetStringMap("redis") + for name, confItf := range redisMap { + conf := confItf.(map[string]interface{}) + addr := conf["address"].(string) + password := conf["password"].(string) + dbindex := int(conf["dbindex"].(int64)) + mode := strings.ToLower(conf["mode"].(string)) + + if mode == RedisSingleInstanceMode { + cli, err = NewRedisClient(addr, password, dbindex) + RedisClientMap[name] = cli + } else if mode == RedisSentinelMode { + addrs := strings.Split(addr, RedisAddrsSeparator) + cli, err = NewRedisSentinel(viper.GetString("redis.master"), addrs, password, dbindex) + RedisClientMap[name] = cli + } else if mode == RedisClusterMode { + addrs := strings.Split(addr, RedisAddrsSeparator) + cluster, err = NewRedisCluster(addrs, password) + RedisClusterMap[name] = cluster + } else { + err = errors.New("Invalid Redis config to InitRedis") + } } + return err } From 4c3bbe0638143c24d9f23f83a9e8951411f2dbc5 Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Tue, 18 Feb 2020 20:56:08 +0800 Subject: [PATCH 07/13] testfix --- app/utils/redis_test.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/app/utils/redis_test.go b/app/utils/redis_test.go index aadae11..7b146a1 100644 --- a/app/utils/redis_test.go +++ b/app/utils/redis_test.go @@ -2,8 +2,6 @@ package utils import ( "testing" - - "github.com/spf13/viper" ) func TestNewRedisClient(t *testing.T) { @@ -42,13 +40,9 @@ func TestNewRedisClient(t *testing.T) { } func TestInitRedis(t *testing.T) { - err := InitRedis() - if err == nil { - t.Error("没有设置redis配置应该返回错误") - } - viper.SetDefault("redis.mode", "cluster") - viper.SetDefault("redis.address", "127.0.0.1:6379") - viper.SetDefault("redis.password", "") - viper.SetDefault("redis.dbindex", 0) + InitViper("..", "config", "") InitRedis() + if len(RedisClientMap) == 0 { + t.Error("RedisClientMap init failed") + } } From 4ddb8996229df523b9f42fb2c8c1b68614a7a4e9 Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Wed, 19 Feb 2020 10:50:01 +0800 Subject: [PATCH 08/13] dir rename --- README.md | 4 ++-- app/apis/demo.go | 12 ++++++------ .../alertsvc.go => handlers/demohdl/demohdl.go} | 2 +- .../demohdl/demohdl_test.go} | 2 +- app/{services/demosvc => handlers/demohdl}/errors.go | 2 +- app/handlers/handlers.go | 2 ++ app/handlers/handlers_test.go | 1 + app/services/services.go | 2 -- app/services/services_test.go | 1 - {sql => migration}/demo.sql | 0 10 files changed, 14 insertions(+), 14 deletions(-) rename app/{services/demosvc/alertsvc.go => handlers/demohdl/demohdl.go} (99%) rename app/{services/demosvc/alertsvc_test.go => handlers/demohdl/demohdl_test.go} (99%) rename app/{services/demosvc => handlers/demohdl}/errors.go (98%) create mode 100644 app/handlers/handlers.go create mode 100644 app/handlers/handlers_test.go delete mode 100644 app/services/services.go delete mode 100644 app/services/services_test.go rename {sql => migration}/demo.sql (100%) diff --git a/README.md b/README.md index 1490093..803f7ff 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ go mod ## 接口实现 在`app/apis/routes.go`中添加URL并指定你的handleFunc,handleFunc推荐在`app/apis`下按业务模块新建文件的形式组织 -可复用的代码可以在`app/services`下以目录或者文件的形式按需组织 +可复用的代码可以在`app/handlers`下以目录或者文件的形式按需组织 API版本号定义在`app/api/apis.go`中,可以手动修改值,但不要修改代码格式,自动生成API文档依赖这个格式。 @@ -45,7 +45,7 @@ API版本号定义在`app/api/apis.go`中,可以手动修改值,但不要修 - `app/apis/routes.go` - `app/apis/demo*` - `app/models/demomod/` -- `app/services/demosvc/` +- `app/handlers/demohdl/` ## 访问DB diff --git a/app/apis/demo.go b/app/apis/demo.go index fb80c17..d264a1d 100644 --- a/app/apis/demo.go +++ b/app/apis/demo.go @@ -2,8 +2,8 @@ package apis import ( "pink-lady/app/database" + "pink-lady/app/handlers/demohdl" "pink-lady/app/response" - "pink-lady/app/services/demosvc" "github.com/gin-gonic/gin" ) @@ -27,7 +27,7 @@ func CreateAlertPolicy(c *gin.Context) { // 使用外层appid和uin作为告警策略的字段 p.AlertPolicy.AppID = p.AppID p.AlertPolicy.Uin = p.Uin - result, err := demosvc.CreateAlertPolicy(c, db, p.AlertPolicy) + result, err := demohdl.CreateAlertPolicy(c, db, p.AlertPolicy) if err != nil { response.ErrJSON(c, err) return @@ -53,7 +53,7 @@ func DescribeAlertPolicy(c *gin.Context) { return } db := database.UTDB() - result, err := demosvc.DescribeAlertPolicy(c, db, p.AppID, p.Uin, p.ID) + result, err := demohdl.DescribeAlertPolicy(c, db, p.AppID, p.Uin, p.ID) if err != nil { response.ErrJSON(c, err) return @@ -79,7 +79,7 @@ func DeleteAlertPolicy(c *gin.Context) { return } db := database.UTDB() - err := demosvc.DeleteAlertPolicy(c, db, p.AppID, p.Uin, p.ID) + err := demohdl.DeleteAlertPolicy(c, db, p.AppID, p.Uin, p.ID) if err != nil { response.ErrJSON(c, err) return @@ -106,7 +106,7 @@ func ModifyAlertPolicy(c *gin.Context) { // 使用外层appid和uin作为告警策略的字段 p.AlertPolicy.AppID = p.AppID p.AlertPolicy.Uin = p.Uin - err := demosvc.ModifyAlertPolicy(c, db, p.AlertPolicy) + err := demohdl.ModifyAlertPolicy(c, db, p.AlertPolicy) if err != nil { response.ErrJSON(c, err) return @@ -140,7 +140,7 @@ func DescribeAlertPolicies(c *gin.Context) { return } db := database.UTDB() - result, count, err := demosvc.DescribeAlertPolicies(c, db, p.AppID, p.Uin, p.Offset, p.Limit, p.Order, p.ID, p.Name) + result, count, err := demohdl.DescribeAlertPolicies(c, db, p.AppID, p.Uin, p.Offset, p.Limit, p.Order, p.ID, p.Name) if err != nil { response.ErrJSON(c, err) return diff --git a/app/services/demosvc/alertsvc.go b/app/handlers/demohdl/demohdl.go similarity index 99% rename from app/services/demosvc/alertsvc.go rename to app/handlers/demohdl/demohdl.go index eb87b48..2bc16f4 100644 --- a/app/services/demosvc/alertsvc.go +++ b/app/handlers/demohdl/demohdl.go @@ -1,4 +1,4 @@ -package demosvc +package demohdl import ( "pink-lady/app/database" diff --git a/app/services/demosvc/alertsvc_test.go b/app/handlers/demohdl/demohdl_test.go similarity index 99% rename from app/services/demosvc/alertsvc_test.go rename to app/handlers/demohdl/demohdl_test.go index 94eac07..86b6189 100644 --- a/app/services/demosvc/alertsvc_test.go +++ b/app/handlers/demohdl/demohdl_test.go @@ -1,4 +1,4 @@ -package demosvc +package demohdl import ( "fmt" diff --git a/app/services/demosvc/errors.go b/app/handlers/demohdl/errors.go similarity index 98% rename from app/services/demosvc/errors.go rename to app/handlers/demohdl/errors.go index 59987b4..016fcb1 100644 --- a/app/services/demosvc/errors.go +++ b/app/handlers/demohdl/errors.go @@ -1,6 +1,6 @@ // 业务自身的错误码 (云API子错误码) -package demosvc +package demohdl import "pink-lady/app/response" diff --git a/app/handlers/handlers.go b/app/handlers/handlers.go new file mode 100644 index 0000000..5cb8845 --- /dev/null +++ b/app/handlers/handlers.go @@ -0,0 +1,2 @@ +// Package handlers save common business logic code +package handlers diff --git a/app/handlers/handlers_test.go b/app/handlers/handlers_test.go new file mode 100644 index 0000000..5ac8282 --- /dev/null +++ b/app/handlers/handlers_test.go @@ -0,0 +1 @@ +package handlers diff --git a/app/services/services.go b/app/services/services.go deleted file mode 100644 index 99961cc..0000000 --- a/app/services/services.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package services save common business logic code -package services diff --git a/app/services/services_test.go b/app/services/services_test.go deleted file mode 100644 index 5e568ea..0000000 --- a/app/services/services_test.go +++ /dev/null @@ -1 +0,0 @@ -package services diff --git a/sql/demo.sql b/migration/demo.sql similarity index 100% rename from sql/demo.sql rename to migration/demo.sql From a10a1a7cbffc6c27eb200058c7c0c88fda6011e6 Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Thu, 27 Feb 2020 19:00:14 +0800 Subject: [PATCH 09/13] exfid --- app/models/demomod/alert_policy.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/demomod/alert_policy.go b/app/models/demomod/alert_policy.go index eadacc6..84d483f 100644 --- a/app/models/demomod/alert_policy.go +++ b/app/models/demomod/alert_policy.go @@ -57,8 +57,8 @@ type AlertPolicy struct { URLScheme string `gorm:"column:url_scheme" json:"url_scheme" binding:"required" example:"http"` // 回调url的scheme CallbackURL string `gorm:"column:callback_url" json:"callback_url" binding:"required" example:"axiaoxin.com"` // 回调url 不包含scheme部分 LatestAlertTime string `gorm:"column:latest_alert_time" json:"latest_alert_time" binding:"-" example:""` // 最后告警时间(产生告警后更改该字段) - AlertFilterRules []*AlertFilterRule `json:"alert_filter_rules" binding:"dive"` // 告警过滤条件 - AlertTriggerRules []*AlertTriggerRule `json:"alert_trigger_rules" binding:"required,dive"` // 告警触发条件 + AlertFilterRules []*AlertFilterRule `gorm:"foreignkey:alert_policy_id" json:"alert_filter_rules" binding:"dive"` // 告警过滤条件 + AlertTriggerRules []*AlertTriggerRule `gorm:"foreignkey:alert_policy_id" json:"alert_trigger_rules" binding:"required,dive"` // 告警触发条件 } // TableName define tabel name From 978bdadffb5ec2aab2b907f0813b841ae67e0fa4 Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Tue, 3 Mar 2020 13:03:39 +0800 Subject: [PATCH 10/13] =?UTF-8?q?demo=E6=98=BE=E7=A4=BA=E6=98=8E=E7=A1=AE?= =?UTF-8?q?=E7=9A=84=E6=8C=87=E5=AE=9A=E5=A4=96=E6=A3=80=E5=A4=96=E9=94=AE?= =?UTF-8?q?=E5=85=B3=E8=81=94=E5=85=B3=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/demomod/alert_policy.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/app/models/demomod/alert_policy.go b/app/models/demomod/alert_policy.go index 84d483f..10e39fc 100644 --- a/app/models/demomod/alert_policy.go +++ b/app/models/demomod/alert_policy.go @@ -44,21 +44,21 @@ func (*AlertTriggerRule) TableName() string { // AlertPolicy 告警策略表 type AlertPolicy struct { models.BaseModel - AppID int `gorm:"column:appid" json:"appid" example:"1" binding:"-"` // AppID - Uin string `gorm:"column:uin" json:"uin" example:"axiaoxin" binding:"-"` // Uin - Name string `gorm:"column:name" json:"name" binding:"required" example:"swag-test-name"` // 策略名称 - MetricSetID int64 `gorm:"column:metric_set_id" json:"metric_set_id" binding:"required" example:"-1"` // 指标集ID - NoticeFrequencySec int `gorm:"column:notice_frequency_sec" json:"notice_frequency_sec" binding:"required" example:"60"` // 通知频率(通知间隔秒数) - Status int `gorm:"column:status" json:"status" binding:"required" example:"1"` // 状态 1=已开启 2=未开启 3=已失效 - AlertGroupID string `gorm:"column:alert_group_id" json:"alert_group_id" binding:"required" example:"-1,0"` // 告警接收组 逗号分隔 - AlertChannel string `gorm:"column:alert_channel" json:"alert_channel" binding:"required" example:"weixin,sms"` // 告警接收渠道 1=邮件 2=短信 3=微信 - NoticePeriodBegin int `gorm:"column:notice_period_begin" json:"notice_period_begin" binding:"-" example:"0"` // 通知时段开始时间(从00:00:00开始计算的秒数) - NoticePeriodEnd int `gorm:"column:notice_period_end" json:"notice_period_end" binding:"required" example:"86399"` // 通知时段结束时间(从00:00:00开始计算的秒数) - URLScheme string `gorm:"column:url_scheme" json:"url_scheme" binding:"required" example:"http"` // 回调url的scheme - CallbackURL string `gorm:"column:callback_url" json:"callback_url" binding:"required" example:"axiaoxin.com"` // 回调url 不包含scheme部分 - LatestAlertTime string `gorm:"column:latest_alert_time" json:"latest_alert_time" binding:"-" example:""` // 最后告警时间(产生告警后更改该字段) - AlertFilterRules []*AlertFilterRule `gorm:"foreignkey:alert_policy_id" json:"alert_filter_rules" binding:"dive"` // 告警过滤条件 - AlertTriggerRules []*AlertTriggerRule `gorm:"foreignkey:alert_policy_id" json:"alert_trigger_rules" binding:"required,dive"` // 告警触发条件 + AppID int `gorm:"column:appid" json:"appid" example:"1" binding:"-"` // AppID + Uin string `gorm:"column:uin" json:"uin" example:"axiaoxin" binding:"-"` // Uin + Name string `gorm:"column:name" json:"name" binding:"required" example:"swag-test-name"` // 策略名称 + MetricSetID int64 `gorm:"column:metric_set_id" json:"metric_set_id" binding:"required" example:"-1"` // 指标集ID + NoticeFrequencySec int `gorm:"column:notice_frequency_sec" json:"notice_frequency_sec" binding:"required" example:"60"` // 通知频率(通知间隔秒数) + Status int `gorm:"column:status" json:"status" binding:"required" example:"1"` // 状态 1=已开启 2=未开启 3=已失效 + AlertGroupID string `gorm:"column:alert_group_id" json:"alert_group_id" binding:"required" example:"-1,0"` // 告警接收组 逗号分隔 + AlertChannel string `gorm:"column:alert_channel" json:"alert_channel" binding:"required" example:"weixin,sms"` // 告警接收渠道 1=邮件 2=短信 3=微信 + NoticePeriodBegin int `gorm:"column:notice_period_begin" json:"notice_period_begin" binding:"-" example:"0"` // 通知时段开始时间(从00:00:00开始计算的秒数) + NoticePeriodEnd int `gorm:"column:notice_period_end" json:"notice_period_end" binding:"required" example:"86399"` // 通知时段结束时间(从00:00:00开始计算的秒数) + URLScheme string `gorm:"column:url_scheme" json:"url_scheme" binding:"required" example:"http"` // 回调url的scheme + CallbackURL string `gorm:"column:callback_url" json:"callback_url" binding:"required" example:"axiaoxin.com"` // 回调url 不包含scheme部分 + LatestAlertTime string `gorm:"column:latest_alert_time" json:"latest_alert_time" binding:"-" example:""` // 最后告警时间(产生告警后更改该字段) + AlertFilterRules []*AlertFilterRule `gorm:"foreignkey:alert_policy_id;association_foreignkey:id" json:"alert_filter_rules" binding:"dive"` // 告警过滤条件 + AlertTriggerRules []*AlertTriggerRule `gorm:"foreignkey:alert_policy_id;association_foreignkey:id" json:"alert_trigger_rules" binding:"required,dive"` // 告警触发条件 } // TableName define tabel name From 4b2d3501f86fe49703fb689cf5a24dfe9ed98ac6 Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Wed, 11 Mar 2020 12:54:49 +0800 Subject: [PATCH 11/13] =?UTF-8?q?=E6=8B=86=E5=88=86apidoc=E8=84=9A?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/gen_apidoc.sh | 73 +++++++++++++++++++++++++++++++++++-- script/release.sh | 87 +++++++------------------------------------- 2 files changed, 83 insertions(+), 77 deletions(-) diff --git a/script/gen_apidoc.sh b/script/gen_apidoc.sh index ec65877..03fa65c 100755 --- a/script/gen_apidoc.sh +++ b/script/gen_apidoc.sh @@ -1,10 +1,77 @@ #! /usr/bin/env bash +# 生成swag api文档 +BUMPVERSION_ERROR=-1 +APIDOC_HOST_PATTERN='// @host .+' +APIDOC_VERSION_PATTERN='// @version [0-9]+\.[0-9]+\.[0-9]+' +CONST_VERSION_PATTERN='const VERSION = "[0-9]+\.[0-9]+\.[0-9]+"' + + realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" } -# 生成swag api文档 +OS=`uname` +# $(replace_in_file pattern file) +function replace_in_file() { + if [ "$OS" = 'Darwin' ]; then + # for MacOS + sed -i '' -E "$1" "$2" + else + # for Linux and Windows + sed -i'' "$1" "$2" + fi +} + PROJECT_PATH=$(dirname $(dirname $(realpath $0))) -MAIN_PATH=${PROJECT_PATH}/app/ +APP_PATH=${PROJECT_PATH}/app + + +# Bump version +bumpVersion() { + lastest_commit=$(git log --pretty=format:"%h %cd %d %s" -1) + # check version + current_apidoc_version_line=($(grep -oE "${APIDOC_VERSION_PATTERN}" ${APP_PATH}/apis/apis.go)) + current_apidoc_version=${current_apidoc_version_line[2]} + current_const_version_line=$(grep -oE "${CONST_VERSION_PATTERN}" ${APP_PATH}/apis/apis.go) + current_const_version=$(echo "${current_const_version_line}" | grep -o '".*"' | sed 's/"//g') + if [ "${current_apidoc_version}" != "${current_const_version}" ]; then + echo -e "apidoc version ${current_apidoc_version} is not match with const version ${current_const_version}" + exit $BUMPVERSION_ERROR + fi + current_version=${current_apidoc_version} + echo -e "Current version: ${current_version}" + echo -e "Latest commit: ${lastest_commit}" + + # get new version + num_list=($(echo ${current_version} | tr '.' ' ')) + major=${num_list[0]} + minor=${num_list[1]} + patch=${num_list[2]} + patch=$((patch + 1)) + suggested_version="$major.$minor.$patch" + echo -ne "Enter a version number [${suggested_version}]: " + read new_version + if [ "${new_version}" = "" ]; then + new_version=${suggested_version} + fi + + echo -e "Will set new version to be ${new_version}" + # update version in apidoc and const + replace_in_file "s|${APIDOC_VERSION_PATTERN}|// @version ${new_version}|" ${APP_PATH}/apis/apis.go && replace_in_file "s|${CONST_VERSION_PATTERN}|const VERSION = \"${new_version}\"|" ${APP_PATH}/apis/apis.go +} + +bumpVersion + +APIDOC_HOST=127.0.0.1:4869 +echo -ne "Enter apidocs host[${APIDOC_HOST}]: " +read apidoc_host +if [ "${apidoc_host}" != "" ]; then + APIDOC_HOST=${apidoc_host} +fi + +# replace apidoc host +replace_in_file "s|${APIDOC_HOST_PATTERN}|// @host ${APIDOC_HOST}|" ${APP_PATH}/apis/apis.go + + # swag init必须在main.go所在的目录下执行,否则必须用--dir参数指定main.go的路径 -swag init --dir ${MAIN_PATH} --generalInfo apis/apis.go --propertyStrategy camelcase --output ${MAIN_PATH}/apis/docs +swag init --dir ${APP_PATH}/ --generalInfo apis/apis.go --propertyStrategy camelcase --output ${APP_PATH}/apis/docs diff --git a/script/release.sh b/script/release.sh index d6f1e95..dff9748 100755 --- a/script/release.sh +++ b/script/release.sh @@ -1,18 +1,4 @@ #! /usr/bin/env bash -# COLORS -RED="\033[1;31m" -GREEN="\033[0;32m" -YELLOW="\033[1;33m" -CYAN="\033[1;36m" -WHITE="\033[1;37m" -# BLUE="\033[1;34m" -# PURPLE="\033[1;35m" -# RESET="\033[0m" - -QUESTION_FLAG="${GREEN}?" -WARNING_FLAG="${YELLOW}!" -ERROR_FLAG="${RED}!!" -NOTICE_FLAG="${CYAN}❯" realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" @@ -25,12 +11,9 @@ BUILD_PATH=${PROJECT_PATH}/build NOW=$(date "+%Y%m%d-%H%M%S") # ERROR CODE -BUMPVERSION_ERROR=-1 TESTING_FAILED=-2 BUILDING_FAILED=-3 -APIDOC_VERSION_PATTERN='// @version [0-9]+\.[0-9]+\.[0-9]+' -CONST_VERSION_PATTERN='const VERSION = "[0-9]+\.[0-9]+\.[0-9]+"' OS=`uname` @@ -46,47 +29,13 @@ function replace_in_file() { } -# Bump version -bumpVersion() { - lastest_commit=$(git log --pretty=format:"%h %cd %d %s" -1) - # check version - current_apidoc_version_line=($(grep -oE "${APIDOC_VERSION_PATTERN}" ${APP_PATH}/apis/apis.go)) - current_apidoc_version=${current_apidoc_version_line[2]} - current_const_version_line=$(grep -oE "${CONST_VERSION_PATTERN}" ${APP_PATH}/apis/apis.go) - current_const_version=$(echo "${current_const_version_line}" | grep -o '".*"' | sed 's/"//g') - if [ "${current_apidoc_version}" != "${current_const_version}" ]; then - echo -e "${ERROR_FLAG} ${RED}apidoc version ${current_apidoc_version} is not match with const version ${current_const_version}" - exit $BUMPVERSION_ERROR - fi - current_version=${current_apidoc_version} - echo -e "${NOTICE_FLAG} Current version: ${WHITE}${current_version}" - echo -e "${NOTICE_FLAG} Latest commit: ${WHITE}${lastest_commit}" - - # get new version - num_list=($(echo ${current_version} | tr '.' ' ')) - major=${num_list[0]} - minor=${num_list[1]} - patch=${num_list[2]} - patch=$((patch + 1)) - suggested_version="$major.$minor.$patch" - echo -ne "${QUESTION_FLAG} ${CYAN}Enter a version number [${WHITE}${suggested_version}${CYAN}]: " - read new_version - if [ "${new_version}" = "" ]; then - new_version=${suggested_version} - fi - - echo -e "${NOTICE_FLAG} Will set new version to be ${WHITE}${new_version}" - # update version in apidoc and const - replace_in_file "s|${APIDOC_VERSION_PATTERN}|// @version ${new_version}|" ${APP_PATH}/apis/apis.go && replace_in_file "s|${CONST_VERSION_PATTERN}|const VERSION = \"${new_version}\"|" ${APP_PATH}/apis/apis.go -} - tests() { # Running tests - echo -e "${NOTICE_FLAG} Running tests" + echo -e "Running tests" cd ${APP_PATH} if !(go test ./...) then - echo -e "${ERROR_FLAG} ${RED}Tests failed." + echo -e "Tests failed." cd - exit ${TESTING_FAILED} fi @@ -98,46 +47,37 @@ build() { mkdir ${BUILD_PATH} fi BINARY_NAME=app - echo -ne "${QUESTION_FLAG} ${CYAN}Enter release binary name [${WHITE}${BINARY_NAME}${CYAN}]: " + echo -ne "Enter release binary name [${BINARY_NAME}]: " read binary_name if [ "${binary_name}" != "" ]; then BINARY_NAME=${binary_name} fi - APIDOC_HOST=127.0.0.1:4869 - echo -ne "${QUESTION_FLAG} ${CYAN}Enter apidocs host[${WHITE}${APIDOC_HOST}${CYAN}]: " - read apidoc_host - if [ "${apidoc_host}" != "" ]; then - APIDOC_HOST=${apidoc_host} - fi - - # replace apidoc host - replace_in_file "s|// @host .+?|// @host ${APIDOC_HOST}|" ${APP_PATH}/apis/apis.go - echo -e "${NOTICE_FLAG} Will build binary name to be ${WHITE}${BINARY_NAME} ${CYAN}with apidoc host ${WHITE}${APIDOC_HOST}" + echo -e "Will build binary name to be ${BINARY_NAME}" # Update docs echo "Updating swag docs" # check swag if !(swag > /dev/null 2>&1); then - echo -e "${WARNING_FLAG} ${CYAN}No swag for generate API docs. You need to install it for auto generate the docs" + echo -e "No swag for generate API docs. You need to install it for auto generate the docs" else - echo -e "${NOTICE_FLAG} Generating API docs..." + echo -e "Generating API docs..." bash ${PROJECT_PATH}/script/gen_apidoc.sh fi # Building - echo -e "${NOTICE_FLAG} Building..." + echo -e "Building..." go build -o ${BUILD_PATH}/${BINARY_NAME} -tags=jsoniter -v ${APP_PATH} if [ $? -ne 0 ] then - echo -e "${ERROR_FLAG} ${RED}Build failed." + echo -e "Build failed." exit ${BUILDING_FAILED} fi } tarball() { configfile=config.toml - echo -ne "${QUESTION_FLAG} ${CYAN}Enter your configfile[${WHITE}${configfile}${CYAN}]: " + echo -ne "Enter your configfile[${configfile}]: " read cf if [ "${cf}" != "" ]; then configfile=${cf} @@ -152,25 +92,24 @@ tarball() { } commit() { - echo -ne "${QUESTION_FLAG} ${CYAN}Do you want to commit this version bump to git[${WHITE}Y/n${CYAN}]: " + echo -ne "Do you want to commit this version bump to git[Y/n]: " read do_commit if [ "${do_commit}" == "" ] || [ "${do_commit}" == "Y" ]; then git add ${APP_PATH}/docs ${APP_PATH}/apis/apis.go git commit -m "Bump version ${current_version} -> ${new_version}" - echo -ne "${QUESTION_FLAG} ${CYAN}Do you want to tag this version bump to git[${WHITE}Y/n${CYAN}]: " + echo -ne "Do you want to tag this version bump to git[Y/n]: " read do_tag if [ "${do_tag}" == "" ] || [ "${do_tag}" == "Y" ]; then git tag ${new_version} if [ $? -ne 0 ]; then - echo -e "${WARNING_FLAG} ${CYAN}git tag failed" + echo -e "git tag failed" fi fi fi } main() { - echo -e "${NOTICE_FLAG} This tool will help you to release your binary app.\n It will bump the version in your code, run tests then update apidocs and build the binary app and tar it as tar.gz file.\n Last do an optional commit the changed code and tag it with then version name" - bumpVersion + echo -e "This tool will help you to release your binary app.\n It will bump the version in your code, run tests then update apidocs and build the binary app and tar it as tar.gz file.\n Last do an optional commit the changed code and tag it with then version name" tests build tarball From 81055b235a158468ea7fb623e741aef8ff374c06 Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Wed, 11 Mar 2020 16:05:21 +0800 Subject: [PATCH 12/13] sugar logging --- app/logging/logging.go | 104 ++++++++++++++++++++++++++++++----------- 1 file changed, 78 insertions(+), 26 deletions(-) diff --git a/app/logging/logging.go b/app/logging/logging.go index dfdf857..9affbd2 100644 --- a/app/logging/logging.go +++ b/app/logging/logging.go @@ -1,37 +1,89 @@ // Package logging provides ... package logging -import ( - "github.com/getsentry/sentry-go" - "go.uber.org/zap" - "go.uber.org/zap/zapcore" -) - // Debug 记录debug级别的日志 -func Debug(msg string, fields ...zap.Field) { - defer Logger.Sync() - Logger.Debug(msg, fields...) +// logging.Debug("abc", 123) +func Debug(args ...interface{}) { + slogger := Logger.Sugar() + defer slogger.Sync() + slogger.Debug(args...) } // Info 记录info级别的日志 -func Info(msg string, fields ...zap.Field) { - defer Logger.Sync() - Logger.Info(msg, fields...) +func Info(args ...interface{}) { + slogger := Logger.Sugar() + defer slogger.Sync() + slogger.Info(args...) } // Warn 记录warn级别的日志 -func Warn(msg string, fields ...zap.Field) { - defer Logger.Sync() - Logger.Warn(msg, fields...) -} - -// Error 记录Error级别的日志,如果fields中有zap.Error则上报的sentry -func Error(msg string, fields ...zap.Field) { - defer Logger.Sync() - Logger.Error(msg, fields...) - for _, field := range fields { - if field.Type == zapcore.ErrorType { - sentry.CaptureException(field.Interface.(error)) - } - } +func Warn(args ...interface{}) { + slogger := Logger.Sugar() + defer slogger.Sync() + slogger.Warn(args...) +} + +// Error 记录Error级别的日志 +func Error(args ...interface{}) { + slogger := Logger.Sugar() + defer slogger.Sync() + slogger.Error(args...) +} + +// Debugf 模板字符串记录debug级别的日志 +// logging.Debugf("str:%s", "abd") +func Debugf(template string, args ...interface{}) { + slogger := Logger.Sugar() + defer slogger.Sync() + slogger.Debugf(template, args...) +} + +// Infof 模板字符串记录info级别的日志 +func Infof(template string, args ...interface{}) { + slogger := Logger.Sugar() + defer slogger.Sync() + slogger.Infof(template, args...) +} + +// Warnf 模板字符串记录warn级别的日志 +func Warnf(template string, args ...interface{}) { + slogger := Logger.Sugar() + defer slogger.Sync() + slogger.Warnf(template, args...) +} + +// Errorf 模板字符串记录debug级别的日志 +func Errorf(template string, args ...interface{}) { + slogger := Logger.Sugar() + defer slogger.Sync() + slogger.Errorf(template, args...) +} + +// Debugw kv记录debug级别的日志 +// logging.Debugw("msg", "k1", "v1", "k2", "v2") +func Debugw(msg string, keysAndValues ...interface{}) { + slogger := Logger.Sugar() + defer slogger.Sync() + slogger.Debugw(msg, keysAndValues...) +} + +// Infow kv记录info级别的日志 +func Infow(msg string, keysAndValues ...interface{}) { + slogger := Logger.Sugar() + defer slogger.Sync() + slogger.Infow(msg, keysAndValues...) +} + +// Warnw kv记录warn级别的日志 +func Warnw(msg string, keysAndValues ...interface{}) { + slogger := Logger.Sugar() + defer slogger.Sync() + slogger.Warnw(msg, keysAndValues...) +} + +// Errorw kv记录error级别的日志 +func Errorw(msg string, keysAndValues ...interface{}) { + slogger := Logger.Sugar() + defer slogger.Sync() + slogger.Errorw(msg, keysAndValues...) } From 8ff25858e33543168aa2b051521929e53f3b8086 Mon Sep 17 00:00:00 2001 From: axiaoxin <254606826@qq.com> Date: Wed, 11 Mar 2020 20:29:21 +0800 Subject: [PATCH 13/13] logging attach sentry core --- app/{utils => logging}/sentry.go | 22 ++-- app/{utils => logging}/sentry_test.go | 6 +- app/logging/sentrycore.go | 167 ++++++++++++++++++++++++++ app/logging/zaplogger.go | 12 ++ app/router/router.go | 3 - 5 files changed, 194 insertions(+), 16 deletions(-) rename app/{utils => logging}/sentry.go (66%) rename app/{utils => logging}/sentry_test.go (79%) create mode 100644 app/logging/sentrycore.go diff --git a/app/utils/sentry.go b/app/logging/sentry.go similarity index 66% rename from app/utils/sentry.go rename to app/logging/sentry.go index a2d9b1e..290e271 100644 --- a/app/utils/sentry.go +++ b/app/logging/sentry.go @@ -1,32 +1,36 @@ -package utils +package logging import ( "net/http" - "pink-lady/app/logging" - "github.com/getsentry/sentry-go" "github.com/pkg/errors" "github.com/spf13/viper" ) -// InitSentry 初始化sentry配置 +// SentryClient godoc +var SentryClient *sentry.Client + +// InitSentry init sentry func InitSentry() error { - err := sentry.Init(sentry.ClientOptions{ + options := sentry.ClientOptions{ Dsn: viper.GetString("server.sentrydsn"), Debug: viper.GetBool("server.mode"), AttachStacktrace: true, BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event { - logger := logging.Logger.Sugar() if hint.Context != nil { if req, ok := hint.Context.Value(sentry.RequestContextKey).(*http.Request); ok { // You have access to the original Request - logger.Debug("Sentry BeforeSend req:", req) + Debug("Sentry BeforeSend req:", req) } } - logger.Debug("Sentry BeforeSend event:", event) + Debug("Sentry BeforeSend event:", event) return event }, - }) + } + err := sentry.Init(options) + + SentryClient, err = sentry.NewClient(options) + return errors.Wrap(err, "init sentry error") } diff --git a/app/utils/sentry_test.go b/app/logging/sentry_test.go similarity index 79% rename from app/utils/sentry_test.go rename to app/logging/sentry_test.go index afb98f3..958b139 100644 --- a/app/utils/sentry_test.go +++ b/app/logging/sentry_test.go @@ -1,16 +1,14 @@ -package utils +package logging import ( "testing" - "pink-lady/app/logging" - "github.com/getsentry/sentry-go" "github.com/pkg/errors" ) func TestInitSentry(t *testing.T) { - logging.InitLogger() + InitLogger() err := InitSentry() if err != nil { t.Fatal(err) diff --git a/app/logging/sentrycore.go b/app/logging/sentrycore.go new file mode 100644 index 0000000..3791cd7 --- /dev/null +++ b/app/logging/sentrycore.go @@ -0,0 +1,167 @@ +// a core for sentry capture error + +package logging + +import ( + "time" + + "github.com/getsentry/sentry-go" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +func sentryLevel(lvl zapcore.Level) sentry.Level { + switch lvl { + case zapcore.DebugLevel: + return sentry.LevelDebug + case zapcore.InfoLevel: + return sentry.LevelInfo + case zapcore.WarnLevel: + return sentry.LevelWarning + case zapcore.ErrorLevel: + return sentry.LevelError + case zapcore.DPanicLevel: + return sentry.LevelFatal + case zapcore.PanicLevel: + return sentry.LevelFatal + case zapcore.FatalLevel: + return sentry.LevelFatal + default: + return sentry.LevelFatal + } +} + +// SentryCoreConfig is a minimal set of parameters for Sentry Core. +type SentryCoreConfig struct { + Tags map[string]string + DisableStacktrace bool + Level zapcore.Level + FlushTimeout time.Duration + Hub *sentry.Hub +} + +// sentryCore the core for sentry +type sentryCore struct { + client *sentry.Client + cfg *SentryCoreConfig + zapcore.LevelEnabler + flushTimeout time.Duration + + fields map[string]interface{} +} + +// GetSentryClient return sentry client +func (c *sentryCore) GetSentryClient() *sentry.Client { + return c.client +} + +func (c *sentryCore) with(fs []zapcore.Field) *sentryCore { + // Copy our map. + m := make(map[string]interface{}, len(c.fields)) + for k, v := range c.fields { + m[k] = v + } + + // Add fields to an in-memory encoder. + enc := zapcore.NewMapObjectEncoder() + for _, f := range fs { + f.AddTo(enc) + } + + // Merge the two maps. + for k, v := range enc.Fields { + m[k] = v + } + + return &sentryCore{ + client: c.client, + cfg: c.cfg, + fields: m, + LevelEnabler: c.LevelEnabler, + } +} + +// With zap core interface +func (c *sentryCore) With(fs []zapcore.Field) zapcore.Core { + return c.with(fs) +} + +// Check zap core interface +func (c *sentryCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { + if c.cfg.Level.Enabled(ent.Level) { + return ce.AddCore(ent, c) + } + return ce +} + +// Write zap core interface +func (c *sentryCore) Write(ent zapcore.Entry, fs []zapcore.Field) error { + clone := c.with(fs) + + event := sentry.NewEvent() + event.Message = ent.Message + event.Timestamp = ent.Time.Unix() + event.Level = sentryLevel(ent.Level) + event.Platform = "pink-lady" + event.Extra = clone.fields + event.Tags = c.cfg.Tags + + if !c.cfg.DisableStacktrace { + trace := sentry.NewStacktrace() + if trace != nil { + event.Exception = []sentry.Exception{{ + Type: ent.Message, + Value: ent.Caller.TrimmedPath(), + Stacktrace: trace, + }} + } + } + + hub := c.cfg.Hub + if hub == nil { + hub = sentry.CurrentHub() + } + _ = c.client.CaptureEvent(event, nil, hub.Scope()) + + // We may be crashing the program, so should flush any buffered events. + if ent.Level > zapcore.ErrorLevel { + c.client.Flush(c.flushTimeout) + } + return nil +} + +// Sync zap core interface +func (c *sentryCore) Sync() error { + c.client.Flush(c.flushTimeout) + return nil +} + +// NewSentryCore new a sentry core +func NewSentryCore(cfg SentryCoreConfig, sentryClient *sentry.Client) zapcore.Core { + + core := sentryCore{ + client: sentryClient, + cfg: &cfg, + LevelEnabler: cfg.Level, + flushTimeout: 3 * time.Second, + fields: make(map[string]interface{}), + } + + if cfg.FlushTimeout > 0 { + core.flushTimeout = cfg.FlushTimeout + } + + return &core +} + +// SentryAttach attach sentrycore +func SentryAttach(l *zap.Logger, sentryClient *sentry.Client) *zap.Logger { + cfg := SentryCoreConfig{ + Level: zap.ErrorLevel, + Tags: map[string]string{ + "source": "zap sentry core", + }, + } + core := NewSentryCore(cfg, sentryClient) + return AttachCore(l, core) +} diff --git a/app/logging/zaplogger.go b/app/logging/zaplogger.go index 0cbcf26..16e3bd9 100644 --- a/app/logging/zaplogger.go +++ b/app/logging/zaplogger.go @@ -30,6 +30,11 @@ func InitLogger() error { viper.GetBool("logger.disableStacktrace"), ) Logger = Logger.Named("pink-lady") + err = InitSentry() + + if viper.GetString("server.sentrydsn") != "" { + Logger = SentryAttach(Logger, SentryClient) + } return err } @@ -111,3 +116,10 @@ func CloneLogger() *zap.Logger { copy := *Logger return © } + +// AttachCore godoc +func AttachCore(l *zap.Logger, c zapcore.Core) *zap.Logger { + return l.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core { + return zapcore.NewTee(core, c) + })) +} diff --git a/app/router/router.go b/app/router/router.go index 42bed87..28e9092 100644 --- a/app/router/router.go +++ b/app/router/router.go @@ -33,9 +33,6 @@ func InitDependencies(configpath, configname string) { if err := logging.InitLogger(); err != nil { log.Println("[ERROR] ", err) } - if err := utils.InitSentry(); err != nil { - log.Println("[ERROR] ", err) - } if err := database.InitGorm(); err != nil { log.Println("[ERROR] ", err) }