Linux 在许多方面相对于 Windows 来说都是独特的,在 Linux 中编写程序也不例外。标准输出,标准 err 和 null devices 的使用不仅是一个好主意,也是一个原则。如果您的程序将记录日志信息,则最好遵循目标约定。这样,您的程序将兼容所有 Mac/Linux 工具和托管环境。

Go 在标准库中有一个 log 包和 logger 类型。使用 log 包将为您提供成为优秀公民 (译注:指 log 包兼容性非常好) 所需的一切。您将能够写入所有标准设备,自定义文件或支持 io.Writer 接口的任何目标。

我提供了一个非常简单的示例,它将帮助您开始使用 logger :

 package main

 import (
"io"
"io/ioutil"
"log"
"os"
) var (
Trace *log.Logger
Info *log.Logger
Warning *log.Logger
Error *log.Logger
) func Init(
traceHandle io.Writer,
infoHandle io.Writer,
warningHandle io.Writer,
errorHandle io.Writer) { Trace = log.New(traceHandle,
"TRACE: ",
log.Ldate|log.Ltime|log.Lshortfile) Info = log.New(infoHandle,
"INFO: ",
log.Ldate|log.Ltime|log.Lshortfile) Warning = log.New(warningHandle,
"WARNING: ",
log.Ldate|log.Ltime|log.Lshortfile) Error = log.New(errorHandle,
"ERROR: ",
log.Ldate|log.Ltime|log.Lshortfile)
} func main() {
Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr) Trace.Println("I have something standard to say")
Info.Println("Special Information")
Warning.Println("There is something you need to know about")
Error.Println("Something has failed")
}

运行此程序时,您将获得以下输出:

 INFO: // :: main.go:: Special Information
WARNING: // :: main.go:: There is something you need to know about
ERROR: // :: main.go:: Something has failed

您会注意到没有显示 Trace logging (译注:跟踪记录器)。让我们看看代码,找出原因。

查看 Trace logging 部分的代码:

var Trace *log.Logger

Trace = log.New(traceHandle,
"TRACE: ",
log.Ldate|log.Ltime|log.Lshortfile) Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr) Trace.Println("I have something standard to say")

该代码创建一个名为 Trace 的包级变量,它是一个指向 log.Logger 对象的指针。然后在 Init 函数内部创建一个新的 log.Logger 对象。log.New 函数的参数如下:

func New(out io.Writer, prefix string, flag int) *Logger
out: The out variable sets the destination to which log data will be written. // 译注 out 变量设置将写入日志数据的目标
prefix: The prefix appears at the beginning of each generated log line. // 译注 前缀出现在每个生成的日志行的开头。
flags: The flag argument defines the logging properties. // 译注 flag 参数定义日志记录属性
Flags: const (
// Bits or’ed together to control what’s printed. There is no control over the
// order they appear (the order listed here) or the format they present (as
// described in the comments). A colon appears after these items:
// 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
Ldate = << iota // the date: 2009/01/23
Ltime // the time: 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
LstdFlags = Ldate | Ltime // initial values for the standard logger
)

在此示例程序中,Trace 的目标是 ioutil.Discard 。这是一个 null device (译注:对应 /dev/null 相当于垃圾桶,消息直接丢弃),所有写入调用都可以成功而不做任何事情。因此,使用 Trace 写入时,终端窗口中不会显示任何内容。

再来看看 Info 的代码:

var Info *log.Logger

Info = log.New(infoHandle,
"INFO: ",
log.Ldate|log.Ltime|log.Lshortfile) Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr) Info.Println("Special Information")

  

对于 Info (译注:消息记录器),os.Stdout 传入到 init 函数给了 infoHandle 。这意味着当您使用 Info 写消息时,消息将通过标准输出显示在终端窗口中。

最后,看下 Error 的代码:

var Error *log.Logger

Error = log.New(errorHandle,
"ERROR: ", // 译注: 原文是 INFO 与原始定义不同,应该是笔误,故直接修改
log.Ldate|log.Ltime|log.Lshortfile) Init(ioutil.Discard, os.Stdout, os.Stdout, os.Stderr) Error.Println("Something has failed") // 译注: 原文是 Special Information 与原始定义不同,应该是笔误,故直接修改

这次 os.Stderr 传入到 Init 函数给了 errorHandle 。这意味着当您使用 Error 写消息时,该消息将通过标准错误显示在终端窗口中。但是,将这些消息传递给 os.Stderr 允许运行程序的其他应用程序知道发生了错误。

由于支持 io.Writer 接口的任何目标都可以接受,因此您可以创建和使用文件:

 file, err := os.OpenFile("file.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, )
if err != nil {
log.Fatalln("Failed to open log file", output, ":", err)
} MyFile = log.New(file,
"PREFIX: ",
log.Ldate|log.Ltime|log.Lshortfile)

在示例代码中,打开一个文件,然后将其传递给 log.New 函数。现在,当您使用 MyFile 进行写入时,数据将写到 file.txt 里。

您还可以让 logger (译注:记录器) 同时写入多个目标。

 file, err := os.OpenFile("file.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, )
if err != nil {
log.Fatalln("Failed to open log file", output, ":", err)
} multi := io.MultiWriter(file, os.Stdout) MyFile := log.New(multi,
"PREFIX: ",
log.Ldate|log.Ltime|log.Lshortfile)

这里数据将写入到文件和标准输出里。

注意在处理 OpenFile 的任何错误时使用 log.Fatalln 方法。 log 包提供了一个可以配置的初始 logger。以下是使用具有标准配置的日志的示例程序:

package main

import (
"log"
) func main() {
log.Println("Hello World")
}

以下是输出:

2013/11/05 18:42:26 Hello World

如果想要删除或更改输出格式,可以使用 log.SetFlags 方法:

package main

import (
"log"
) func main() {
log.SetFlags()
log.Println("Hello World")
}

以下是输出:

Hello World

现在所有格式都已删除。如果要将输出发送到其他目标,请使用 log.SetOutput :

package main

import (
"io/ioutil"
"log"
) func main() {
log.SetOutput(ioutil.Discard)
log.Println("Hello World")
}

现在终端窗口上不会显示任何内容。您可以使用任何支持io.Writer 接口的目标。

基于这个例子,我为我的所有程序编写了一个新的日志包:

go get github.com/goinggo/tracelog

我希望在开始编写Go程序时我就知道 log 和 loggers 。期待将来能够看到我写的更多日志包。


via: https://www.ardanlabs.com/blog/2013/11/using-log-package-in-go.html

作者:William Kennedy  译者:chaoshong  校对:polaris1119

本文由 GCTT 原创编译,Go语言中文网 荣誉推出

在 Go 语言中使用 Log 包--转自GCTT的更多相关文章

  1. R语言中的数据处理包dplyr、tidyr笔记

    R语言中的数据处理包dplyr.tidyr笔记   dplyr包是Hadley Wickham的新作,主要用于数据清洗和整理,该包专注dataframe数据格式,从而大幅提高了数据处理速度,并且提供了 ...

  2. R语言中的机器学习包

    R语言中的机器学习包   Machine Learning & Statistical Learning (机器学习 & 统计学习)  网址:http://cran.r-project ...

  3. 在Go语言中记录log:seelog包

    前两周调bug调的吐血,虽然解决了但是还是挺浪费时间的.跟同事聊了聊,觉得我们现在项目中的日志记录太少了,导致出了问题不知道怎么下手,还得自己改代码记录日志,然后排查问题.这样如果将来还有bug的话还 ...

  4. go 语言中常用的包

    来自学习go语言.pdf 译者刑星 ==== fmt 包fmt实现了格式化IO函数,这与c的printf和scanf类似,格式化短语派生于c %v 默认格式的值.当打印结构时,加号(%+v)会增加字段 ...

  5. r语言,安装外部包 警告: 无法将临时安装

    安装R语言中的外部包时,出现错误提示 试开URL’https://mirrors.tuna.tsinghua.edu.cn/CRAN/bin/windows/contrib/3.3/ggplot2_2 ...

  6. Go语言中的并发编程

    并发是编程里面一个非常重要的概念,Go语言在语言层面天生支持并发,这也是Go语言流行的一个很重要的原因. Go语言中的并发编程 并发与并行 并发:同一时间段内执行多个任务(你在用微信和两个女朋友聊天) ...

  7. go标准库-log包源码学习

    log包是go语言提供的一个简单的日志记录功能,其中定义了一个结构体类型 Logger,是整个包的基础部分,包中的其他方法都是围绕这整个结构体创建的. Logger结构 Logger结构的定义如下: ...

  8. 如何使用T-SQL备份还原数据库及c#如何调用执行? C#中索引器的作用和实现。 jquery控制元素的隐藏和显示的几种方法。 localStorage、sessionStorage用法总结 在AspNetCore中扩展Log系列 - 介绍开源类库的使用(一) span<T>之高性能字符串操作实测

    如何使用T-SQL备份还原数据库及c#如何调用执行? 准备材料:Microsoft SQL Server一部.需要还原的bak文件一只 一.备份 数据库备份语句:user master backup ...

  9. node.js中模块和包

    node.js中模块和包 什么是模块 如何创建并加载模块 1. 创建模块 2. 单次加载 3. 覆盖 exports 如何创建一个包 1. 作为文件夹的模块 2. package.json 如何使用包 ...

随机推荐

  1. python virtualenv环境安装(ubuntu)

    测试系统ubantu16.04 该系统已经默认安装了python3.5, 当然了python2.7也同时存在着. 可以用如下命令安装pip(如下命令会默认安装pip到python2.7库中) $ su ...

  2. 状态模式c#(状态流转例子吃饭)

    using System;using System.Collections.Generic;using System.Linq;using System.Text; namespace 状态模式{   ...

  3. 小程序报错Do not have xx handler in current page的解决方法

    看到小程序这一大串的“Do not have bindName handler in current page: pages/card/card. Please make sure that bind ...

  4. PV对第三方存储的访问模式支持

    访问模式 PV可以使用存储资源提供商支持的任何方法来映射到host中.如下的表格中所示,提供商有着不同的功能,每个PV的访问模式被设置为卷支持的指定模式.比如,NFS可以支持多个读/写的客户端,但可以 ...

  5. Linux中逻辑卷(LVM)管理基本操作

    1.创建逻辑卷 原文:https://linux.cn/article-3965-1.html

  6. Oracle学习笔记(十)

    光标(游标)概念引入 就是一个结果集(查询或者其他操作返回的结果是多个时使用)定义一个光标 cursor c1 is select ename from emp: 从光标中取值 打开光标: --ope ...

  7. 用Swift实现一款天气预报APP(二)

    这个系列的目录: 用Swift实现一款天气预报APP(一) 用Swift实现一款天气预报APP(二) 用Swift实现一款天气预报APP(三) 上篇中主要讲了界面的一些内容,这篇主要讨论网络请求,获得 ...

  8. 字符串匹配的KMP算法(转载)

    字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD" ...

  9. 我的"gethup"(GitHub)注册之旅

    大家好,我叫张琪琪,来自网络工程143(学号1413042062),.平时喜欢运动,也喜欢看电视尤其是动漫.其实对于自己的编程能力没有多大自信,如果看着题目回忆课本内容写下的程序也算的话,那是敲过不少 ...

  10. 【JAVA 学习笔记1】代码注释

    在JAVA中支持单行注释和多行注释 1.单行注释,只要在注释的一行代码中加上双斜杠即可 例如: // int a=2,b=4,c=8; 2.多行注释,在开始位置加上/* 结束位置加上*/ 例如 /* ...