衔接上文,继续开发。这一章主要是解决日志输出的问题。
我们使用logging包对log库进行封装。
新建logging包
在pkg下新建logging目录,新建file.go 和 log.go文件
file.go文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
package logging import ( "fmt" "log" "os" "time" ) var ( strLogSavePath = "runtime/logs/" strLogSaveName = "log" strLogFileExt = "log" strTimeFormat = "20060102" ) func getLogFilePath() string { return fmt.Sprintf("%s", strLogSavePath) } func getLogFileFullPath() string { prefixPath := getLogFilePath() suffixPath := fmt.Sprintf("%s%s.%s", strLogSaveName, time.Now().Format(strTimeFormat), strLogFileExt, ) 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("Failed to OpenFile :%v", err) } return handle } func mkDir(strFilePath string) { dir, _ := os.Getwd() err := os.MkdirAll(dir+"/"+strFilePath, os.ModePerm) if err != nil { panic(err) } } |
关键知识点:
os.Stat 函数返回文件信息结构描述结构体,如果出现错误,则会返回一个PathError的结构体。
os.IsNotExist 返回一个bool,得知文件不存在或者目录不存在的错误。
os.IsPermission 返回一个bool,得知权限是否满足的问题。
OpenFile 调用文件,传入参数:文件名称、调用模式、权限。如果出现错误则返回PathError结构体。
调用模式参数如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// 底层系统文件的OpenFile标志。 const ( // 必须指定O_RDONLY、 O_WRONLY、 O_RDWR三个中的一个 O_RDONLY int = syscall.O_RDONLY // 以只读模式打开文件 O_WRONLY int = syscall.O_WRONLY // 以只写模式打开文件 O_RDWR int = syscall.O_RDWR // 以读写模式打开文件 // 下面的值可以用来控制行为 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 // 同步I/O O_TRUNC int = syscall.O_TRUNC // 打开时文件长度截取为0 ) |
os.Getwd 函数返回与当前目录对应的根路径名。
os.ModePerm 是Unix权限位,定义是:ModePerm FileMode = 0777
log.go文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
package logging import ( "fmt" "log" "os" "path/filepath" "runtime" ) var ( fileHadle *os.File strDefaultPrefix = "" //默认调用栈深度 nDefaultCallerDepth = 2 logger *log.Logger logPrefix = "" levelFlags = []string{"DEBUG", "INFO", "WARN", "ERROR", "FATAL"} ) //Level Log信息等级 type Level int const ( //DEBUG 调试 DEBUG Level = iota //INFO 信息 INFO //WARN 警告 WARN //ERROR 错误 ERROR //FATAL 致命错误 FATAL ) func init() { filePath := getLogFileFullPath() fileHadle = openLogFile(filePath) logger = log.New(fileHadle, strDefaultPrefix, log.LstdFlags) } //Debug 调试 func Debug(v ...interface{}) { setPrefix(DEBUG) logger.Println(v...) } //Info 信息 func Info(v ...interface{}) { setPrefix(INFO) logger.Println(v...) } //Warn 警告 func Warn(v ...interface{}) { setPrefix(WARN) logger.Println(v...) } //Error 错误 func Error(v ...interface{}) { setPrefix(ERROR) logger.Println(v...) } //Fatal 致命错误 func Fatal(v ...interface{}) { setPrefix(FATAL) logger.Println(v...) } func setPrefix(level Level) { _, file, line, ok := runtime.Caller(nDefaultCallerDepth) 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 定义日志记录属性
日志记录属性的定义可以自己定位进去看。
使用logging包
完成了logging包之后,我们需要修改大多数代码,只要项目中用到了其他log包的地方,全部要修改。
比如routers目录下的 article.go 、 tag.go 、 auth.go 三个文件。
还有models目录下的 models.go文件
package/setting目录下的 setting.go文件。
将原本的log包引用删除,改为我们自己的 ginBlog/pkg/logging
然后将原来的 log.Println替换为 logging.Info() 函数,log.Fatalf 替换为 logging.Fatal函数。其他的Log按照对应Level替换。
但是logging包里面的是不能替换的…哈哈哈。
验证Logging包
先启动服务,然后请求文章,故意传递错误参数:
GET 192.168.1.101:8000/api/v1/articles?tag_id=0&token=eyJhbGciOi…
这里记得先获取Token,然后再请求就会给出错误信息。
然后我们查看日志:ginBlog/runtime/logs 文件夹内
1 2 |
[xiong@AMDServer logs]$ tail -f log20200906.log [INFO][article.go:76]2020/09/06 02:02:35 tag_id 标签ID必须大于0 |
然后到这里就算完成了。