介绍 Golang 日志处理

介绍 Golang 日志处理

本文介绍Go语言的Log包及其API,通过示例让你轻松掌握日志处理。

1. 概述

日志文件一般用于记录操作系统或其他软件运行时发生的事件,或通信软件不同用户之间的消息。日志记录是一种记录日志的行为,在最简单的情况下,信息被写入单个日志文件。

很多分布式应用使用Go语言,主要利用其并发特性,如:channel、goroutine等。如果你也复杂构建或支持Go应用,那良好的日志策略可以帮助你理解用户行为、本地错误、监控应用性能等。

在GoLang的log包中,实现了简单的日志功能。定义了Logger类型及格式化输出方法,如:Print[f|ln], Fatal[f|ln], Panic[f|ln] ,这些方法使用起来很方便。

Golang Log提供了丰富的选项,下面我们将讨论其中的几个。

2. 使用Go标准日志库

Golang内置了标准日志库log,缺省的logger无需任何配置就能够写错误信息及时间戳。在实际开发中通常需要通过简单的日志快速获得反馈,而不是需要丰富的结构化日志。如果需要更强大的库,需引入第三方包。

2.1. 在控制台输出日志

下面通过示例进行说明。

// testLog.go

package main

import (
    "errors"
    "fmt"
    "log"
)

func division(x float32, y float32) (float32, error) {
    if y == 0 {
        return 0, errors.New("can't divide by zero")
    }

    return x / y, nil
}

func main() {

    var x float32 = 11
    var y float32

    res, err := division(x, y)

    if err != nil {
        log.Print(err)
    }

    fmt.Println(res)
}

输出结果如下,第一行是错误信息,第二行是res的默认值为0.

2019/11/28 18:50:19 can't divide by zero
0

上面代码首先引入三个包:errors,fmt,log。然后定义division函数,其接收两个参数,函数体中检查除数是否为0,如何是返回错误信息。

在函数调用时,我们设定y作为除数,但没有赋值缺省为0,因此生成错误信息并打印在控制台上。

标准日志信息包括消息的发生日期和时间,标准错误信息。每个日志信息在单独一行显示,如果错误消息没有以换行符结尾,标准日志会增加换行符。

Fatal函数写日志信息后调用os.Exit(1)。Painic函数在写日志信息后调用painc函数。

2.2. 文件存储日志

上面示例日志在控制台中打印。实际应用中日志一般需存储在文件中,下面看示例:

package main

import (
	"errors"
	"fmt"
	"log"
	"os"
)

func division(x float32, y float32) (float32, error) {
	if y == 0 {
		return 0, errors.New("can't divide by zero")
	}

	return x / y, nil
}

func main() {
	var x float32 = 11
	var y float32 

	res, exception := division(x, y)
	file, err := os.OpenFile("info.log", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	log.SetOutput(file)

	if err != nil {
		log.Fatal(err)
	}

	if exception != nil {
		log.Print(exception)
	}

	defer file.Close()

	fmt.Println(res)
}

这回控制台仅输出0,错误日志在当前目录中文件info.log中。打开文件能看到内容:

2020/04/25 14:38:41 can't divide by zero

Go中的os包意在统一所有操作系统的访问接口,对于不通用的特性在特定系统包syscall中。如果打开文件代码几乎能够自解释,创建日志文件并写入日志。最后关闭文件。

3. Github 包logrus格式化日志

logrus
是为结构化日志设计的日志包,非常适合JSON中进行日志记录。JSON格式使机器能够快速解析您的Golang日志。

Json格式是标准格式,增加新增的字段,解析器也很容易解析。使用logrus包可以通过WithFields方法定义标准至json日志。其提供了不同的日志级别,如: Info(), Warn(), and Error()。

logrus库自动在json中插入标准字段及你的自定义字段。要使用受限要现在并安装,命令如下:

go get github.com/Sirupsen/logrus

现在在代码中导入包进行测试:

package main

import (
    log "github.com/sirupsen/logrus"
)

func main() {
    log.WithFields(log.Fields{
        "Best Song": "Sunflower",
    }).Info("One of the best song")
}

输出为:

level=info msg="One of the best song" Best Song=Sunflower

请注意,它与stdlib日志记录器完全兼容,因此您可以在任何地方用日志“github.com/sirupsen/logrus”替换您的日志导入,重复利用其Logrus的灵活性。你可以定制你想要的一切:

package main

import (
	"os"

	log "github.com/sirupsen/logrus"
)

func init() {
	// Log as JSON instead of the default ASCII formatter.
	log.SetFormatter(&log.JSONFormatter{})

	// Output to stdout instead of the default stderr
	// Can be any io.Writer, see below for File example
	log.SetOutput(os.Stdout)

	// Only log the warning severity or above.
	log.SetLevel(log.WarnLevel)
}

func main() {
	log.WithFields(log.Fields{
		"animal": "walrus",
		"size":   10,
	}).Info("A group of walrus emerges from the ocean")

	log.WithFields(log.Fields{
		"omg":    true,
		"number": 122,
	}).Warn("The group's number increased tremendously!")

	log.WithFields(log.Fields{
		"omg":    true,
		"number": 100,
	}).Fatal("The ice breaks!")

	// A common pattern is to re-use fields between logging statements by re-using
	// the logrus.Entry returned from WithFields()
	contextLogger := log.WithFields(log.Fields{
		"common": "this is a common field",
		"other":  "I also should be logged always",
	})

	contextLogger.Info("I'll be logged with common and other field")
	contextLogger.Info("Me too")
}

输出:

{"level":"warning","msg":"The group's number increased tremendously!","number":1
22,"omg":true,"time":"2020-04-25T15:24:07+08:00"}
{"level":"fatal","msg":"The ice breaks!","number":100,"omg":true,"time":"2020-04
-25T15:24:07+08:00"}

总结

写日志首要任务是先找一个合适库,然后计划在哪里调用日志代码,如何存储,存储多久,如何分析日志。最佳实践:

  1. 一般建议应用程序的主流程中调用日志,不要在goroutine中使用。
  2. 最好把日志写在本地,即使后面要集中至中央服务进行处理。
  3. 可以使用预定义的消息使日志信息更加标准、规范。
  4. 发送日志至中央平台进行集中分析处理。
  5. 使用HTTP头和唯一ID记录用户访问微服务的行为。

本文通过示例介绍了Go的标准库log包,以及第三方库logrus。通过示例说明如何使用日志,最后顺便总结下使用日志最佳实践。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Go 语言,错误处理是一种非常重要的机制,可以帮助我们在程序运行时检测到错误,并采取相应的措施来解决问题。Go 语言的错误类型是内置的 error 接口类型,其定义如下: ```go type error interface { Error() string } ``` 可以看到,这个接口只有一个方法 Error(),它返回一个字符串,表示错误的描述信息。因此,如果你想定义一个错误类型,只需要实现 error 接口的 Error() 方法即可。 在 Go 语言,我们通常会使用函数返回值来传递错误信息。如果函数执行成功,通常会返回一个 nil 错误;如果函数执行失败,通常会返回一个非空的错误值,表示出错的具体信息。 例如,下面的代码演示了如何在打开一个文件时进行错误处理: ```go file, err := os.Open("test.txt") if err != nil { // 处理错误 fmt.Println("打开文件失败:", err.Error()) return } // 文件打开成功,进行操作 ``` 在这个代码,我们使用 os.Open 函数打开一个文件。如果函数执行失败,会返回一个非空的错误值 err;否则,函数返回一个文件对象 file。我们可以使用 if err != nil 来检查 err 是否为空,如果不为空,表示函数执行失败,我们需要采取相应的措施来解决问题,例如打印错误信息并返回。如果 err 为空,则表示函数执行成功,我们可以继续操作文件对象。 除了使用 if err != nil 来检查错误之外,Go 语言还提供了一个更加简洁的语法,即使用 defer 和 panic 函数来处理错误。例如,下面的代码演示了如何在除数为零时触发 panic: ```go func divide(x, y int) int { defer func() { if err := recover(); err != nil { fmt.Println("出现了一个错误:", err) } }() if y == 0 { panic("除数不能为零") } return x / y } ``` 在这个代码,我们使用 defer 和匿名函数来定义一个错误处理函数。在 divide 函数,如果除数为零,我们会使用 panic 函数触发一个 panic,表示程序遇到了无法处理的错误。此时,defer 语句会立即执行匿名函数,该函数调用 recover 函数来捕获 panic,并打印错误信息。注意,在 defer 函数使用 recover 函数可以避免程序崩溃,并返回一个错误信息。 总的来说,Go 语言提供了多种方式来处理错误,可以根据实际情况选择适合自己的方式。在实际开发,我们通常会将错误信息记录到日志,或者通过 HTTP 接口返回给客户端。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值