iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > GO >Golang 中如何使用 log 包
  • 687
分享到

Golang 中如何使用 log 包

2024-04-02 19:04:59 687人浏览 八月长安
摘要

golang 中如何使用 log 包,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Golang 的 log 包主要提供了以下几个具备输出功

golang 中如何使用 log 包,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

Golang 的 log 包主要提供了以下几个具备输出功能的函数:

func Fatal(v ...interface{})  func Fatalf(fORMat string, v ...interface{})  func Fatalln(v ...interface{})  func Panic(v ...interface{})  func Panicf(format string, v ...interface{})  func Panicln(v ...interface{})  func Print(v ...interface{})  func Printf(format string, v ...interface{})  func Println(v ...interface{})

这些函数的使用方法和 fmt 包完全相同,通过查看源码可以发现,Fatal[ln|f] 和 Panic[ln|f] 实际上是调用的  Print[ln|f],而 Print[ln|f] 实际上是调用的 Output() 函数。

其中 Fatal[ln|f] 是调用 Print[ln|f] 之后,又调用了 os.Exit(1) 退出程序。

其中 Panic[ln|f] 是调用 Panic[ln|f] 之后,又调用了 panic() 函数,抛出一个恐慌。

所以,我们很有必要阅读一下 Output() 函数的源码。

函数 Output() 的源码:

func (l *Logger) Output(calldepth int, s string) error {  now := time.Now() // get this early.  var file string  var line int  l.mu.Lock()  defer l.mu.Unlock()  if l.flag&(Lshortfile|Llongfile) != 0 {   // Release lock while getting caller info - it's expensive.   l.mu.Unlock()   var ok bool   _, file, line, ok = runtime.Caller(calldepth)   if !ok {    file = "???"    line = 0   }   l.mu.Lock()  }  l.buf = l.buf[:0]  l.formatHeader(&l.buf, now, file, line)  l.buf = append(l.buf, s...)  if len(s) == 0 || s[len(s)-1] != '\n' {   l.buf = append(l.buf, '\n')  }  _, err := l.out.Write(l.buf)  return err }

通过阅读 Output() 函数的源码,可以发现使用互斥来保证多个 goroutine 写日志安全,并且在调用 runtime.Caller()  函数之前,先释放互斥锁,获取到信息后再加上互斥锁来保证安全。

使用 formatHeader() 函数来格式化日志的信息,然后保存到 buf 中,然后再把日志信息追加到 buf  的末尾,然后再通过判断,查看日志是否为空或末尾不是 \n,如果是就再把 \n 追加到 buf 的末尾,最后将日志信息输出。

函数 Output() 的源码也比较简单,其中最值得注意的是 runtime.Caller() 函数,源码如下:

func Caller(skip int) (pc uintptr, file string, line int, ok bool) {  rpc := make([]uintptr, 1)  n := callers(skip+1, rpc[:])  if n < 1 {   return  }  frame, _ := CallersFrames(rpc).Next()  return frame.PC, frame.File, frame.Line, frame.PC != 0 }

通过阅读 runtime.Caller() 函数的源码,可以发现它接收一个 int 类型的参数 skip,该参数表示跳过栈帧数,log  包中的输出功能的函数,使用的默认值都是 2,原因是什么?

举例说明,比如在 main 函数中调用 log.Print,方法调用栈为  main->log.Print->*Logger.Output->runtime.Caller,所以此时参数 skip 的值为 2,表示  main 函数中调用 log.Print 的源文件和代码行号;

参数值为 1,表示 log.Print 函数中调用 *Logger.Output 的源文件和代码行号;参数值为 0,表示 *Logger.Output  函数中调用 runtime.Caller 的源文件和代码行号。

至此,我们发现 log 包的输出功能的函数,全部都是把信息输出到控制台,那么该怎么将信息输出到文件中呢?

函数 SetOutPut 就是用来设置输出目标的,源码如下:

func SetOutput(w io.Writer) {  std.mu.Lock()  defer std.mu.Unlock()  std.out = w }

我们可以通过函数 os.OpenFile 来打开一个用于 I/O 的文件,返回值作为函数 SetOutput 的参数。

除此之外,读者应该还发现了一个问题,输出信息都是以日期和时间开头,我们该怎么记录更加丰富的信息呢?比如源文件和行号。

这就用到了函数 SetFlags,它可以设置输出的格式,源码如下:

func SetFlags(flag int) {  std.SetFlags(flag) }

参数 flag 的值可以是以下任意常量:

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  Lmsgprefix                    // move the "prefix" from the beginning of the line to before the message  LstdFlags     = Ldate | Ltime // initial values for the standard logger )

其中 Ldate、Ltime 和 Lmicroseconds 分别表示日期、时间和微秒,需要注意的是,如果设置 Lmicroseconds,那么设置  Ltime,也不会生效。

其中 Llongfile 和 Lshortfile 分别代码绝对路径、源文件名、行号,和代码相对路径、源文件名、行号,需要注意的是,如果设置  Lshortfile,那么即使设置 Llongfile,也不会生效。

其中 LUTC 表示设置时区为 UTC 时区。

其中 LstdFlags 表示标准记录器的初始值,包含日期和时间。

截止到现在,还缺少点东西,就是日志信息的前缀,比如我们需要区分日志信息为 DEBUG、INFO 和 ERROR。是的,我们还有一个函数 SetPrefix  可以实现此功能,源码如下:

func SetPrefix(prefix string) {  std.SetPrefix(prefix) }

函数 SetPrefix 接收一个 string 类型的参数,用来设置日志信息的前缀。

03、Logger

log 包定义了一个包含很多方法的类型 Logger。我们通过查看输出功能的函数,发现它们都是调用 std.Output,std 是什么?我们查看 log  包的源码。

type Logger struct {  mu     sync.Mutex // ensures atomic writes; protects the following fields  prefix string     // prefix on each line to identify the logger (but see Lmsgprefix)  flag   int        // properties  out    io.Writer  // destination for output  buf    []byte     // for accumulating text to write }  func New(out io.Writer, prefix string, flag int) *Logger {  return &Logger{out: out, prefix: prefix, flag: flag} }  var std = New(os.Stderr, "", LstdFlags)

通过阅读源码,我们发现 std 实际上是 Logger 类型的一个实例,Output 是 Logger 的一个方法。

std 通过 New 函数创建,参数分别是 os.Stderr、空字符串和 LstdFlags,分别表示标准错误输出、空字符串前缀和日期时间。

Logger 类型的字段,注释已经说明了,这里就不再赘述了。

自定义 Logger:

func main () {  logFile, err := os.OpenFile("error1.log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755)  if err != nil {   fmt.Println(err)   return  }  defer logFile.Close()  logs := DefinesLogger(logFile, "", log.LstdFlags|log.Lshortfile)  logs.Debug("message")  logs.Debugf("%s", "content") }  // 自定义 logger type Logger struct {  definesLogger *log.Logger }  type Level int8  const(  LevelDebug Level = iota  LevelInfo  LevelError )  func (l Level) String() string {  switch l {  case LevelDebug:   return " [debug] "  case LevelInfo:   return " [info] "  case LevelError:   return " [error] "  }  return "" }  func DefinesLogger(w io.Writer, prefix string, flag int) *Logger {  l := log.New(w, prefix, flag)  return &Logger{definesLogger: l} }  func (l *Logger) Debug(v ...interface{}) {  l.definesLogger.Print(LevelDebug, fmt.Sprint(v...)) }  func (l *Logger) Debugf(format string, v ...interface{}) {  l.definesLogger.Print(LevelDebug, fmt.Sprintf(format, v...)) }  func (l *Logger) Info(v ...interface{}) {  l.definesLogger.Print(LevelInfo, fmt.Sprint(v...)) }  func (l *Logger) Infof(format string, v ...interface{}) {  l.definesLogger.Print(LevelInfo, fmt.Sprintf(format, v...)) }  func (l *Logger) Error(v ...interface{}) {  l.definesLogger.Print(LevelError, fmt.Sprint(v...)) }  func (l *Logger) Errorf(format string, v ...interface{}) {  l.definesLogger.Print(LevelError, fmt.Sprintf(format, v...)) }

关于Golang 中如何使用 log 包问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注编程网GO频道了解更多相关知识。

您可能感兴趣的文档:

--结束END--

本文标题: Golang 中如何使用 log 包

本文链接: https://www.lsjlt.com/news/75420.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Golang 中如何使用 log 包
    Golang 中如何使用 log 包,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Golang 的 log 包主要提供了以下几个具备输出功...
    99+
    2022-10-19
  • golang中ssh包如何使用
    本篇文章给大家分享的是有关golang中ssh包如何使用,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、ssh包crypto的安装ssh使用的包为"golang.o...
    99+
    2023-06-06
  • GoLang context包如何使用
    本文小编为大家详细介绍“GoLang context包如何使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“GoLang context包如何使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧...
    99+
    2023-07-05
  • GoLang中的sync包Once如何使用
    这篇文章主要介绍“GoLang中的sync包Once如何使用”,在日常操作中,相信很多人在GoLang中的sync包Once如何使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”GoLang中的sync包On...
    99+
    2023-07-05
  • golang的ssh包如何使用
    这篇文章主要讲解了“golang的ssh包如何使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“golang的ssh包如何使用”吧!在使用gexpect包发现很多问题之外,这里又尝试使用ss...
    99+
    2023-06-27
  • 如何在golang中使用logger日志包
    这篇文章给大家介绍如何在golang中使用logger日志包,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。golang的优点golang是一种编译语言,可以将代码编译为机器代码,编译后的二进制文件可以直接部署到目标机器...
    99+
    2023-06-14
  • 如何在golang中使用module依赖包
    今天就跟大家聊聊有关如何在golang中使用module依赖包,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。module介绍go module是go新的依赖包管理系统,go modu...
    99+
    2023-06-14
  • 深入探究Golang中log标准库的使用
    目录使用源码使用建议Go 语言标准库中的 log 包设计简洁明了,易于上手,可以轻松记录程序运行时的信息、调试错误以及跟踪代码执行过程中的问题等。使用 log 包无需繁琐的配置即可直...
    99+
    2023-05-19
    Golang log标准库用法 Golang log标准库使用 Golang log标准库 Golang log
  • Golang httptest包测试如何使用
    这篇“Golang httptest包测试如何使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Golang&nb...
    99+
    2023-07-05
  • 如何使用golang进行打包
    golang可以通过静态编译打包或者动态链接打包。详细介绍:1、静态编译打包步骤是编写代码、静态编译和交叉编译;2、动态链接打包步骤是编写代码、引入依赖和编译生成可执行文件。总的来说,静态编译打包适合于需要分发到不同环境而且不想依赖系统环境...
    99+
    2023-12-14
    go语言 Golang
  • golang包怎么使用
    Golang是一种高效、快速和稳定的编程语言,在软件开发领域受到广泛关注和应用。相比其他语言,golang有许多优势,其中之一是它丰富的标准库,这些库提供了开发者需要的各种工具和资源。在本文中,我们将详细介绍golang的包和如何使用这些包...
    99+
    2023-05-15
  • golang中strings包的Replace使用方法
    这篇文章将为大家详细讲解有关golang中strings包的Replace使用方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。函数声明:func Trim(s string...
    99+
    2023-06-14
  • golang expect包怎么使用
    本文小编为大家详细介绍“golang expect包怎么使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“golang expect包怎么使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。这里如果使用su切换用...
    99+
    2023-06-27
  • golang包的使用方法
    使用Go语言包的步骤有以下6步:1、创建一个新的包;2、在包的目录中,编写相应的代码文件;3、以大写字母开头使其可以被其他包导入并使用;4、在需要使用包中的代码时,使用”import "<包路径>"“的形式导入当前代码文件中;5...
    99+
    2023-12-18
    golang包 go语言 Golang
  • 如何在VBS中使用Log 函数
    如何在VBS中使用Log 函数?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Log 函数返回数值的自然对数。Log(number)number 参数是任意大于 0 的有效数值表...
    99+
    2023-06-08
  • Golang常用包使用介绍
    目录sync包锁线程监听WaitGroup池Poolencoding/binary包单数值转换多数值转换encoding/gob包hash/crc32包sync包 常用的有3个功能 ...
    99+
    2022-11-11
  • golang中toolkits包怎么用
    这篇文章主要介绍了golang中toolkits包怎么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。在查看 open-falcon 项目源码时,经常会看到其引用了一个类库 ...
    99+
    2023-06-27
  • golang 中strings包的Replace的使用说明
    函数声明为: func Replace(s, old, new string, n int) string 官方描述为: 返回将s中前n个不重叠old子串都替换为new的新字符...
    99+
    2022-11-11
  • 详解Golang中time包的使用方法
    Golang作为移动互联网时代的代表性编程语言,在时间处理方面有着独具特色的实现方式。本文将介绍Golang中的time包,豁然开朗的实现方式。time包在Golang中,我们可以通过time包来进行时间相关的操作。time包提供了两种时间...
    99+
    2023-05-14
  • 如何在golang中自定义package包
    这期内容当中小编将会给大家带来有关如何在golang中自定义package包,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。golang适合做什么golang可以做服务器端开发,但golang很适合做日志处...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作