就是我们的日志,都是输出到控制台上的,这显然对于一个项目来说是不合理的,因此我们这一节简单封装log库,使其支持简单的文件日志!

项目地址:


我们在pkg下新建logging目录,新建file.golog.go文件,写入内容:

1、 file.go:

  • os.Stat:返回文件信息结构描述文件。如果出现错误,会返回*PathError

    1. type PathError struct {
    2. Op string
    3. Path string
    4. Err error
    5. }
  • os.IsNotExist:能够接受ErrNotExistsyscall的一些错误,它会返回一个布尔值,能够得知文件不存在或目录不存在
  • os.IsPermission:能够接受ErrPermissionsyscall的一些错误,它会返回一个布尔值,能够得知权限是否满足
    1. const (
    2. // Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.
    3. O_RDONLY int = syscall.O_RDONLY // 以只读模式打开文件
    4. O_WRONLY int = syscall.O_WRONLY // 以只写模式打开文件
    5. O_RDWR int = syscall.O_RDWR // 以读写模式打开文件
    6. // The remaining values may be or'ed in to control behavior.
    7. O_APPEND int = syscall.O_APPEND // 在写入时将数据追加到文件中
    8. O_CREATE int = syscall.O_CREAT // 如果不存在,则创建一个新文件
    9. O_EXCL int = syscall.O_EXCL // 使用O_CREATE时,文件必须不存在
    10. O_SYNC int = syscall.O_SYNC // 同步IO
    11. O_TRUNC int = syscall.O_TRUNC // 如果可以,打开时
    12. )
  • :创建对应的目录以及所需的子目录,若成功则返回nil,否则返回error
  • os.ModePermconst定义ModePerm FileMode = 0777

2、 log.go

  • log.New:创建一个新的日志记录器。out定义要写入日志数据的IO句柄。prefix定义每个生成的日志行的开头。flag定义了日志记录属性

    1. func New(out io.Writer, prefix string, flag int) *Logger {
    2. return &Logger{out: out, prefix: prefix, flag: flag}
    3. }
  • log.LstdFlags:日志记录的格式属性之一,其余的选项如下

    1. const (
    2. Ldate = 1 << iota // the date in the local time zone: 2009/01/23
    3. Ltime // the time in the local time zone: 01:23:23
    4. Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
    5. Llongfile // full file name and line number: /a/b/c/d.go:23
    6. Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
    7. LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone
    8. LstdFlags = Ldate | Ltime // initial values for the standard logger
    9. )

当前目录结构:

我们打开先前包含log包的代码,

  1. 打开routers目录下的article.gotag.goauth.go
  2. log包的引用删除,修改引用我们自己的日志包为gin-blog/pkg/logging
  3. 将原本的log.Println(...)改为log.Info(...)

例如auth.go文件的修改内容:

  1. package api
  2. "net/http"
  3. "github.com/gin-gonic/gin"
  4. "github.com/astaxie/beego/validation"
  5. "gin-blog/pkg/util"
  6. "gin-blog/models"
  7. "gin-blog/pkg/logging"
  8. )
  9. ...
  10. func GetAuth(c *gin.Context) {
  11. ...
  12. code := e.INVALID_PARAMS
  13. if ok {
  14. ...
  15. } else {
  16. for _, err := range valid.Errors {
  17. logging.Info(err.Key, err.Message)
  18. }
  19. }
  20. c.JSON(http.StatusOK, gin.H{
  21. "code" : code,
  22. "msg" : e.GetMsg(code),
  23. "data" : data,
  24. })
  25. }

修改文件后,重启服务,我们来试试吧!

获取到API的Token后,我们故意传错误URL参数给接口,如:http://127.0.0.1:8000/api/v1/articles?tag_id=0&state=9999999&token=eyJhbG..

然后我们到$GOPATH/gin-blog/runtime/logs查看日志:

  1. $ tail -f log20180216.log
  2. [INFO][article.go:79]2018/02/16 18:33:12 [state 状态只允许01]
  3. [INFO][article.go:79]2018/02/16 18:33:42 [state 状态只允许01]
  4. [INFO][article.go:79]2018/02/16 18:33:42 [tag_id 标签ID必须大于0]
  5. [INFO][article.go:79]2018/02/16 18:38:39 [state 状态只允许01]

至此,本节就完成了,这只是一个简单的扩展,实际上我们线上项目要使用的文件日志,是更复杂一些,开动你的大脑 举一反三吧!