go如何使用日志

众所周知,在一个项目中,日志是非常非常重要的,因为有时候我们找错误,发现问题,处理问题等等,其中最重要的一点就是依靠日志,所以一般一个项目完善不完善,从日志的设置上就可以大概有所判断,日志好不好,我想大家心知肚明.好了,废话不多说,我们来看下Go语言中的日志情况.(本文在翻译zap日志库中结合自己写的代码测试而出)

    Go语言提供的默认日志包是https://golang.org/pkg/log/,默认的使用Go Logger,下面 我们就来实现一个Go Logger

初始化一个日志记录器

func InitLoggerUtil() {
	locationlFile, _ := os.OpenFile("/Users/csq/Desktop/csq.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0744)
	log.SetOutput(locationlFile)
}

参数:  1. os.O_CREATE|os.O_APPEND|os.O_RDWR  这个我们可以进去看看,会发现:


2.perm:0744 它代表的是一个写文件的权限定义

      大概去源码看了下,这里就简单说一下,后面会专门讲一下这个.主要看我的部分截图:

    读,写,执行代表的数字,权限是他们的相加

一般都文件属性标识如下: 

-rwxrwxrwx

第1位:文件属性,一般常用的是"-",表示是普通文件;"d"表示是一个目录。

第2~4位:文件所有者的权限rwx (可读/可写/可执行)。

第5~7位:文件所属用户组的权限rwx (可读/可写/可执行)。

第8~10位:其他人的权限rwx (可读/可写/可执行)。

在golang中,可以使用os.FileMode(perm).String()来查看权限标识:

os.FileMode(0777).String()    //返回 -rwxrwxrwx

os.FileMode(0666).String()   //返回 -rw-rw-rw-

例子:

0777表示:创建了一个普通文件,所有人拥有所有的读、写、执行权限

0666表示:创建了一个普通文件,所有人拥有对该文件的读、写权限,但是都不可执行

好啦,回到我们刚才的代码中来

创建一个方法:

func GetIrisDemo(url string) {
	resp, err := http.Get(url)
	if err != nil {
		log.Printf("Error fetching url %s : %s", url, err.Error())
	} else {
		log.Printf("Status Code for %s : %s", url, resp.Status)
		resp.Body.Close()
	}
}

main方法调用:

func main() {
   InitLoggerUtil()
   GetIrisDemo("http://localhost:8848/api/user/list")//正确的接口
   GetIrisDemo("localhost:8848/api/user/list")//错误接口
}

在执行这main方法之前 我们打开上个项目的 iris框架搭建的demo,然后启动之后 我们去对应位置会发现:

桌面多了一个我们之前命名的文件,里面追加了两个日志记录.

demo整体:

import (
	"go.uber.org/zap"
	"log"
	"net/http"
	"os"
)
var logger *zap.Logger
func main() {
	InitLoggerUtil()
	GetIrisDemo("http://localhost:8848/api/user/list")//正确的接口
	GetIrisDemo("localhost:8848/api/user/list")//错误接口
}
func InitLoggerUtil() {
	locationlFile, _ := os.OpenFile("/Users/csq/Desktop/csq.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0744)
	log.SetOutput(locationlFile)
}
func GetIrisDemo(url string) {
	resp, err := http.Get(url)
	if err != nil {
		log.Printf("Error fetching url %s : %s", url, err.Error())
	} else {
		log.Printf("Status Code for %s : %s", url, resp.Status)
		resp.Body.Close()
	}
}

为什么Go Logger在项目中有时候用的少?

  1. 其实Go Logger的优点在于它的使用是非常之简单,只要你向里面写,它就会被写入到指定的日志文件中去.

  2.但是它的日志级别只有一个Print,这显然是不够的,因为我们项目中常用的是INFO/DEBUG等多个级别.

  3.对于错误日志的处理,有FatalPanic,一般Fatal日志通过调用os.Exit(1)来结束程序,而Panic日志在写入日志消息之后抛出       一个panic,最重要的ERROR日志级别,恰恰是在不抛出panic或退出程序的情况下记录错误,而它没有.

  4.不提供日志切割的能力.

所以一般我们使用Zap ,Zap是非常快的、结构化的,分日志级别的Go日志库。   

安装

运行下面的命令安装zap

go get -u go.uber.org/zap

配置Zap Logger

Zap提供了两种类型的日志记录器—Sugared LoggerLogger

在性能很好但不是很关键的上下文中,使用SugaredLogger。它比其他结构化日志记录包快4-10倍,并且支持结构化和printf风格的日志记录。

在每一微秒和每一次内存分配都很重要的上下文中,使用Logger。它甚至比SugaredLogger更快,内存分配次数也更少,但它只支持强类型的结构化日志记录。

Logger

  • 通过调用zap.NewProduction()/zap.NewDevelopment()或者zap.Example()创建一个Logger。
  • 上面的每一个函数都将创建一个logger。唯一的区别在于它将记录的信息不同。例如production logger默认记录调用函数信息、日期和时间等。
  • 通过Logger调用Info/Error等。
  • 默认情况下日志都会打印到应用程序的console界面。

接下来,我们使用zap日志来修改我们的代码:

package main

import (
	"go.uber.org/zap"
	"net/http"

)
var logger *zap.Logger

func main(){
	InitLoggerUtil()
	defer logger.Sync()
	GetIrisDemo("http://localhost:8848/api/user/list")
	GetIrisDemo("localhost:8848/api/user/list")
}
func InitLoggerUtil() {
	logger, _ = zap.NewProduction()
}

func GetIrisDemo(url string) {
	resp, err := http.Get(url)
	if err != nil {
		logger.Error(
			"<---错误输出--->",
			zap.String("url", url),
			zap.Error(err))
	} else {
		logger.Info("<---成功输出--->",
			zap.String("code", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

查看控制台:

Sugared Logger

现在让我们使用Sugared Logger来实现相同的功能。

  • 大部分的实现基本都相同。
  • 惟一的区别是,我们通过调用主logger的. Sugar()方法来获取一个SugaredLogger
  • 然后使用SugaredLoggerprintf格式记录语句 
package main

import (
	"go.uber.org/zap"
	"net/http"

)
var logger *zap.Logger
var sugarLogger *zap.SugaredLogger

func main(){
	InitLoggerUtil()
	//defer logger.Sync()
	defer sugarLogger.Sync()
	GetIrisDemo("http://localhost:8848/api/user/list")
	GetIrisDemo("localhost:8848/api/user/list")
}
func InitLoggerUtil() {
	logger, _ := zap.NewProduction()
	sugarLogger = logger.Sugar()
}

func GetIrisDemo(url string) {
	resp, err := http.Get(url)
	if err != nil {
		sugarLogger.Errorf(
			"<---错误输出--->",
			zap.String("url", url),
			zap.Error(err))

	} else {
		sugarLogger.Info("<---成功输出--->",
			zap.String("code", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

查看控制台:

定制logger

将日志写入文件而不是终端

我们要做的第一个更改是把日志写入文件,而不是打印到应用程序控制台。

  • 我们将使用zap.New(…)方法来手动传递所有配置,而不是使用像zap.NewProduction()这样的预置方法来创建logger。
func New(core zapcore.Core, options ...Option) *Logger

zapcore.Core需要三个配置——EncoderWriteSyncerLogLevel

1.Encoder:编码器(如何写入日志)。我们将使用开箱即用的NewJSONEncoder(),并使用预先设置的ProductionEncoderConfig()

   zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())

2.WriterSyncer :指定日志将写到哪里去。我们使用zapcore.AddSync()函数并且将打开的文件句柄传进去。

3.Log Level:哪种级别的日志将被写入。

我们将修改上述部分中的Logger代码

package main

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"net/http"
	"os"
)
var logger *zap.Logger
var sugarLogger *zap.SugaredLogger

func main(){
	InitLoggerUtil()
	//defer logger.Sync()
	defer sugarLogger.Sync()
	GetIrisDemo("http://localhost:8848/api/user/list")
	GetIrisDemo("localhost:8848/api/user/list")
}
func InitLoggerUtil() {
	//logger, _ := zap.NewProduction()
	//sugarLogger = logger.Sugar()
	writeSyncer := getLogWriter()
	encoder := getEncoder()
	core := zapcore.NewCore(encoder, writeSyncer, zapcore.DebugLevel)

	logger := zap.New(core)
	sugarLogger = logger.Sugar()

}
func getEncoder() zapcore.Encoder {
	return zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
}

func getLogWriter() zapcore.WriteSyncer {
	file, _ := os.Create("/Users/csq/Desktop/csq02.log")
	return zapcore.AddSync(file)
}




func GetIrisDemo(url string) {
	resp, err := http.Get(url)
	if err != nil {
		sugarLogger.Errorf(
			"<---错误输出--->",
			zap.String("url", url),
			zap.Error(err))

	} else {
		sugarLogger.Info("<---成功输出--->",
			zap.String("code", resp.Status),
			zap.String("url", url))
		resp.Body.Close()
	}
}

去对应位置查看,可以发现我们之前打印在控制台的日志都写到具体的文件里面去了.

从日志内容可以看出,这是一个json形势的,要是改为普通的Log Encoder,只需要将上述代码中的

  return zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())

 修改为:

 return zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig())就ok 了.

未完待续....     

猜你喜欢

转载自blog.csdn.net/FindHuni/article/details/105723857