Go 實現 自動檢索 API 錯誤碼代碼行 並 打印成文檔,例 markDown 形式等


作者:林冠宏 / 指尖下的幽靈

掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8

博客:http://www.cnblogs.com/linguanh/

GitHub : https://github.com/af913337456/

騰訊雲專欄: https://cloud.tencent.com/developer/user/1148436/activities


源碼--GitHub:https://github.com/af913337456/ErrorDocAutoPrinter

如果你是一個后端Server程序開發人員。你應該知道,在你寫完API之后,是需要給客戶端的同學提供調用文檔的。

例如下面一個api handler創建一個用戶

func HandleCreateUser(w http.ResponseWriter,r *http.Request) map[string]interface{} {
    if r.Body == nil {
        return util.GetCommonErr(23,"create user req body is fucking null?")
    }
    ....
    ....
    return util.GetCommonSuccess("success")
}

上面有一行錯誤信息輸出的代碼

util.GetCommonErr(23,"create user req body is fucking null?")

假設我們要寫成markDown風格的文檔,上面的可能是這樣一種對應

錯誤碼 含義 提示
23 create user req body is fucking null? 暫無

Ok,這只是一個錯誤信息的情況,我們很輕松就手動寫完了。

如果有幾百上千個呢?一個完整的服務端程序,肯定會有很多這種錯誤信息輸出的代碼。在幾百上千個的時候,還要手動寫?這是多么低效率,且浪費時間令人窒息的操作。

而我這篇文章要介紹的就是一個幫你自動檢索並生成API輸出錯誤信息文檔開源程序

ErrorDocAutoPrinter

它,具備下面的特點

  • 自定義代碼文件夾路徑
  • Json 配置文件形式導入設置,避免反復編譯程序
  • 按照給定的代碼方法名稱自動檢索對應的代碼行
  • 按照給定的切割參數規則,自動切割組合
  • 按照給定的列名描述,自動組合成新的文字
  • 接口化的設計邏輯,高度自定義
  • 自動按照code 從小到大排序輸出,可控!
  • 自動提示重復出現過的錯誤信息。
  • 自動按照設定生成輸出文件
  • 可設置符合目標的文件后綴
  • 可設置需要過濾的文件名,符合就不處理
  • 自定義輸出風格,markDown?txt?html?
  • 自行定義輸出的邏輯,可以映射到很多情況的文字玩法
  • 總之:‘為所欲為’

我,提供了兩種風格的輸出

  • 簡單文本 風格
  • markDown 風格

使用步驟

  1. 配置好json文件 DefaultConfig.json
{
  "TargetFileSuffix":[".go"],
  "TargetErrorFuncName":["util.GetCommonErr","util.GetErrWithTips"],
  "FilterFileName":["core"],
  "ParamsColumnNames":[" 錯 誤 碼 "," 含 義 ","提 示"],
  "ParamsSplitChar":","
}
  1. 輸入你的代碼文件夾路徑並運行程序
func TestDocPrinter(t *testing.T) {
    p := NewDefaultErrorDocPrinter(NewDefaultMarkDownErrorDocPrinter())
    if p == nil {
        return
    }
    fmt.Println(p.printErrorDoc("../../errorDocPrinter"))
}
  1. 復制粘貼結果
錯誤碼 含義 提示
-9 invalid create user --空缺--
-4 invalid create user --空缺--
-1 create user failed 創建用戶失敗
88 創建評論失敗 --空缺--
3110 error params --空缺--
3111 update failed --空缺--
3112 yellow 內容涉黃 --空缺--
3113 forbid 禁止訪問 --空缺--
3114 empty id --空缺--
3115 服務端開啟事務失敗 --空缺--
3116 服務端事務提交失敗 --空缺--
3117 update effect row <= 0 --空缺--
3118 RowsAffected 失敗 --空缺--
3119 更新只有部分成功 --空缺--
3120 empty userId --空缺--
3121 too lager --空缺--
3122 user not exits --空缺--
3123 非法更新 --空缺--
3124 參數個數長度限制 --空缺--
3126 服務端事務提交失敗 --空缺--
3127 invalid money --空缺--
3128 money not enough --空缺--
3129 創建消費記錄失敗 --空缺--
基本說完了,源碼見上面的開源鏈接,去玩吧。

簡單分析下 markDown 風格的生成

接口

type IErrorDocPrinter interface {
    FindLines(printer *ErrorDocPrinter,reader *bufio.Reader,fileName,currentSuffix string,handleLine func(line string)) []string
    BuildACell(printer ErrorDocPrinter,columns,size int,prefixName,param string) string
    ResultLine(line string)
    EndOfAFile(printer ErrorDocPrinter,aFileRetLines []string)
    EndOfAllFile(printer ErrorDocPrinter,allRetLines []string)
}

找到一個文件所有行

func (p MarkDownErrorDocPrinter) FindLines(
    printer *ErrorDocPrinter,reader *bufio.Reader,fileName,currentSuffix string,handleLine func(line string)) []string {
    // 正則匹配 todo
    var lines []string
    printer.currentLineNum = 0
    for {
        byt, _, err := reader.ReadLine()
        if err != nil {
            // 讀完一個文件
            break
        }
        line := string(byt)
        // 排除注釋
        printer.currentLineNum++
        if startWith(line,"//") {
            continue
        }
        if startWith(line,"/*") {
            continue
        }
        if startWith(line,"*") {
            continue
        }
        for _,value := range printer.TargetErrorFuncName {
            if strings.Contains(line,value) {
                // hit,准備生成
                handleLine(line)
                lines = append(lines,line)
            }
        }
    }
    return lines
}

處理一個單元格

func (p MarkDownErrorDocPrinter) BuildACell(
printer ErrorDocPrinter,columns,size int,prefixName,param string) string {
    /**
    | Name | Academy | score |
    | - | - | - |
    | Harry Potter | Gryffindor| 90 |
    | Hermione Granger | Gryffindor | 100 |
    | Draco Malfoy | Slytherin | 90 |
    */
    if columns == 0 {
        code,err := strconv.ParseInt(param,10,64)
        if err == nil {
            codeArr = append(codeArr,code)
        }
        return "|" + param
    }
    count := tipsMap[param]
    if columns == 1 {
        // 保存提示列
        if count != 0 {
            count++
            diffMap[fmt.Sprintf("param: -- %s -- times:%d",param,count-1)] =
                fmt.Sprintf(" 與 %s 的第 %d 行提示重復",printer.currentFileName,printer.currentLineNum)
        }else{
            count = 1
        }
        tipsMap[param] = count
    }
    if columns == size - 1 {
        return "|" + param + "|"
    }
    // 找出提示一樣,但是 code 不一樣的
    return "|" + param
}

從小到大排序--code

func quickSort(arr *[]int64,left,right int) {
    if arr == nil {
        return
    }
    if right == len(*arr) {
        right--
    }
    if left < 0 || left >= len(*arr) {
        return
    }
    hight := right
    low   := left
    base  := (*arr)[left]
    if low < hight {
        for ;low < hight; {
            for ;low < hight && base <= (*arr)[hight]; {
                hight--
                break
            }
            (*arr)[low] = (*arr)[hight]
            for ;low < hight && base >= (*arr)[low]; {
                low++
                break
            }
            (*arr)[hight] = (*arr)[low]
        }
        (*arr)[low] = base
        quickSort(arr,left,low-1)
        quickSort(arr,low+1,right)
    }
}

組裝


quickSort(&codeArr,0,len(codeArr))
codeArrSize := len(codeArr)
for i:=0; i<codeArrSize ;i++ {
    codeAtr := strconv.Itoa((int)(codeArr[i]))
    index := 0
    for _,line := range allRetLines {
        if strings.Contains(line,"|"+codeAtr+"|") {
            final = append(final,line)
            // 減去一個,減少循環次數
            //retLines = append(retLines[:index],retLines[index+1:]...)
            index--
            break
        }
        index++
    }
}

// 生成文件
fileName := "errorInfo.md"
file,err := os.Create(fileName)
defer file.Close()
if err!=nil {
    fmt.Println(err)
}
for _,line := range final {
    fmt.Println(line)
    file.WriteString(line+"\n")
}

如果編程不是為了讓復雜的問題簡單化,那和機械學習有什么區別?


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com