This is a creation in Article, where the information may have evolved or changed.
API ' s-logging
In the previous section, we solved the problem that API's could be accessed arbitrarily, so we now have one more question.
It is our log, which is output to the console, which is obviously unreasonable for a project, so this section simply encapsulates the library so that log
it supports a simple file log!
New logging
Package
We are pkg
under new logging
directory, new file.go
and log.go
file, write content:
- 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 to 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
: Returns the file information structure description file. If an error occurs, it returns*PathError
type PathError struct { Op string Path string Err error}
os.IsNotExist
: ErrNotExist
syscall
A number of errors that can be accepted, it returns a Boolean value to know that the file does not exist or that the directory does not exist
os.IsPermission
: Some errors that can be accepted, ErrPermission
syscall
it returns a Boolean value that can tell if the permission is satisfied
os.OpenFile
: The method that calls the file, supports the incoming file name, specifies the mode call file, the file permission, and the returned file can be used for I/O. If an error occurs, the *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
: Returns the root path name corresponding to the current directory
os.MkdirAll
: creates the corresponding directory and the desired subdirectory, or returns if successful nil
error
os.ModePerm
: const
DefineModePerm FileMode = 0777
- 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) Lo Gger = 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: Create a fresh logger.
out
defines a handle to write to the log data IO
. prefix
defines the beginning of each generated journal line. flag
defines the logging properties
func New(out io.Writer, prefix string, flag int) *Logger { return &Logger{out: out, prefix: prefix, flag: flag}}
- Log. Lstdflags: One of the formatting attributes of the logging, the remaining options are as follows
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)
Current directory structure:
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
Our custom logging
package has been basically completed, then let it be connected to our project!
We open log
the code that contains the package earlier,
- Open
routers
the directory, article.go
tag.go
auth.go
log
Delete the package reference, modify the reference to our own log package asgin-blog/pkg/logging
- Change the original to
log.Println(...)
log.Info(...)
For example auth.go
, what the file modifies:
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, })}
Validation features
After modifying the file, restart the service, let's try it!
After getting the token to the API, we deliberately pass the error URL parameter to the interface, such as:http://127.0.0.1:8000/api/v1/articles?tag_id=0&state=9999999&token=eyJhbG..
Then we go to $GOPATH/gin-blog/runtime/logs
check the log:
$ 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]
Log structure all normal, our record mode is Info
, so the prefix is right, and we are into the problem, but also recorded the error, so the wrong is very convenient!
At this point, this section is complete, this is just a simple extension, actually our online project to use the file log, is more complicated, to start your brain extrapolate it!
Reference
Sample code for this series