Gin實踐 連載六 搭建Blog API's(五)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

API's - logging

在上一節中,我們解決了API's可以任意訪問的問題,那麼我們現在還有一個問題。

就是我們的日誌,都是輸出到控制台上的,這顯然對於一個項目來說是不合理的,因此我們這一節簡單封裝log庫,使其支援簡單的檔案日誌!

建立logging

我們在pkg下建立logging目錄,建立file.golog.go檔案,寫入內容:

  1. file.go:
package loggingimport (    "os"    "time"    "fmt"    "log")var (    LogSavePath = "runtime/logs/"    LogSaveName = "log"    LogFileExt = "log"    TimeFormat = "20060102")func getLogFilePath() string {    return fmt.Sprintf("%s", LogSavePath)}func getLogFileFullPath() string {    prefixPath := getLogFilePath()    suffixPath := fmt.Sprintf("%s%s.%s", LogSaveName, time.Now().Format(TimeFormat), LogFileExt)    return fmt.Sprintf("%s%s", prefixPath, suffixPath)}func openLogFile(filePath string) *os.File {    _, err := os.Stat(filePath)    switch {        case os.IsNotExist(err):            mkDir(getLogFilePath())        case os.IsPermission(err):            log.Fatalf("Permission :%v", err)    }    handle, err := os.OpenFile(filePath, os.O_APPEND | os.O_CREATE | os.O_WRONLY, 0644)    if err != nil {        log.Fatalf("Fail to OpenFile :%v", err)    }    return handle}func mkDir(filePath string) {    dir, _ := os.Getwd()    err := os.MkdirAll(dir + "/" + getLogFilePath(), os.ModePerm)    if err != nil {        panic(err)    }}
  • os.Stat:返迴文件資訊結構描述檔案。如果出現錯誤,會返回*PathError
type PathError struct {    Op   string    Path string    Err  error}
  • os.IsNotExist:能夠接受ErrNotExistsyscall的一些錯誤,它會返回一個布爾值,能夠得知檔案不存在或目錄不存在
  • os.IsPermission:能夠接受ErrPermissionsyscall的一些錯誤,它會返回一個布爾值,能夠得知許可權是否滿足
  • os.OpenFile:調用檔案,支援傳入檔案名稱、指定的模式調用檔案、檔案許可權,返回的檔案的方法可以用於I/O。如果出現錯誤,則為*PathError
const (    // Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.    O_RDONLY int = syscall.O_RDONLY // 以唯讀模式開啟檔案    O_WRONLY int = syscall.O_WRONLY // 以唯寫模式開啟檔案    O_RDWR   int = syscall.O_RDWR   // 以讀寫入模式開啟檔案    // The remaining values may be or'ed in to control behavior.    O_APPEND int = syscall.O_APPEND // 在寫入時將資料追加到檔案中    O_CREATE int = syscall.O_CREAT  // 如果不存在,則建立一個新檔案    O_EXCL   int = syscall.O_EXCL   // 使用O_CREATE時,檔案必須不存在    O_SYNC   int = syscall.O_SYNC   // 同步IO    O_TRUNC  int = syscall.O_TRUNC  // 如果可以,開啟時)
  • os.Getwd:返回與目前的目錄對應的根路徑名
  • os.MkdirAll:建立對應的目錄以及所需的子目錄,若成功則返回nil,否則返回error
  • os.ModePermconst定義ModePerm FileMode = 0777
  1. log.go
package loggingimport (    "log"    "os"    "runtime"    "path/filepath"    "fmt")type Level intvar (    F *os.File    DefaultPrefix = ""    DefaultCallerDepth = 2    logger *log.Logger    logPrefix = ""    levelFlags = []string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"})const (    DEBUG Level = iota    INFO    WARNING    ERROR    FATAL)func init() {    filePath := getLogFileFullPath()    F = openLogFile(filePath)    logger = log.New(F, DefaultPrefix, log.LstdFlags)}func Debug(v ...interface{}) {    setPrefix(DEBUG)    logger.Println(v)}func Info(v ...interface{}) {    setPrefix(INFO)    logger.Println(v)}func Warn(v ...interface{}) {    setPrefix(WARNING)    logger.Println(v)}func Error(v ...interface{}) {    setPrefix(ERROR)    logger.Println(v)}func Fatal(v ...interface{}) {    setPrefix(FATAL)    logger.Fatalln(v)}func setPrefix(level Level) {    _, file, line, ok := runtime.Caller(DefaultCallerDepth)    if ok {        logPrefix = fmt.Sprintf("[%s][%s:%d]", levelFlags[level], filepath.Base(file), line)    } else {        logPrefix = fmt.Sprintf("[%s]", levelFlags[level])    }        logger.SetPrefix(logPrefix)}
  • log.New:建立一個新的日誌記錄器。out定義要寫入日誌資料的IO控制代碼。prefix定義每個產生的日誌行的開頭。flag定義了日誌記錄屬性
func New(out io.Writer, prefix string, flag int) *Logger {    return &Logger{out: out, prefix: prefix, flag: flag}}
  • log.LstdFlags:日誌記錄的格式屬性之一,其餘的選項如下
const (    Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23    Ltime                         // the time in the local time zone: 01:23:23    Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.    Llongfile                     // full file name and line number: /a/b/c/d.go:23    Lshortfile                    // final file name element and line number: d.go:23. overrides Llongfile    LUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zone    LstdFlags     = Ldate | Ltime // initial values for the standard logger)

目前的目錄結構:

gin-blog/├── conf│   └── app.ini├── main.go├── middleware│   └── jwt│       └── jwt.go├── models│   ├── article.go│   ├── auth.go│   ├── models.go│   └── tag.go├── pkg│   ├── e│   │   ├── code.go│   │   └── msg.go│   ├── logging│   │   ├── file.go│   │   └── log.go│   ├── setting│   │   └── setting.go│   └── util│       ├── jwt.go│       └── pagination.go├── routers│   ├── api│   │   ├── auth.go│   │   └── v1│   │       ├── article.go│   │       └── tag.go│   └── router.go├── runtime

我們自訂的logging包,已經基本完成了,接下來讓它接入到我們的項目之中吧!

我們開啟先前包含log包的代碼,

  1. 開啟routers目錄下的article.gotag.goauth.go
  2. log包的引用刪除,修改引用我們自己的日誌包為gin-blog/pkg/logging
  3. 將原本的log.Println(...)改為log.Info(...)

例如auth.go檔案的修改內容:

package apiimport (    "net/http"    "github.com/gin-gonic/gin"    "github.com/astaxie/beego/validation"    "gin-blog/pkg/e"    "gin-blog/pkg/util"    "gin-blog/models"    "gin-blog/pkg/logging")...func GetAuth(c *gin.Context) {    ...    code := e.INVALID_PARAMS    if ok {        ...    } else {        for _, err := range valid.Errors {            logging.Info(err.Key, err.Message)        }    }    c.JSON(http.StatusOK, gin.H{        "code" : code,        "msg" : e.GetMsg(code),        "data" : data,    })}

驗證功能

修改檔案後,重啟服務,我們來試試吧!

擷取到API的Token後,我們故意傳錯誤URL參數給介面,如:http://127.0.0.1:8000/api/v1/articles?tag_id=0&state=9999999&token=eyJhbG..

然後我們到$GOPATH/gin-blog/runtime/logs查看日誌:

$ tail -f log20180216.log [INFO][article.go:79]2018/02/16 18:33:12 [state 狀態只允許0或1][INFO][article.go:79]2018/02/16 18:33:42 [state 狀態只允許0或1][INFO][article.go:79]2018/02/16 18:33:42 [tag_id 標籤ID必須大於0][INFO][article.go:79]2018/02/16 18:38:39 [state 狀態只允許0或1][INFO][article.go:79]2018/02/16 18:38:39 [tag_id 標籤ID必須大於0]

日誌結構一切正常,我們的記錄模式都為Info,因此首碼是對的,並且我們是入參有問題,也把錯誤記錄下來了,這樣排錯就很方便了!

至此,本節就完成了,這隻是一個簡單的擴充,實際上我們線上項目要使用的檔案日誌,是更複雜一些,開動你的大腦 舉一反三吧!

參考

本系列範例程式碼

  • go-gin-example

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.