Go标准库日志打印及同时输出到控制台与文件
作者:Go和分布式IM 发布时间:2024-04-26 17:22:40
打印
在使用go写一些小程序时,我们没必要引入额外的包,直接使用fmt标准包打印即可:
import "fmt"
func main() {
fmt.Println("line1")
fmt.Print("line2")
fmt.Printf("line%d \n", 3)
str1 := fmt.Sprintln("hello", 3)
str2 := fmt.Sprint("hello ", 1, " 2")
str3 := fmt.Sprintf("hello %d", 1)
fmt.Print(str1, str2, str3)
}
line1
line2line3
hello 3
hello 1 2hello 1
那么,有些场景下,我们希望能同时打印到日志文件中要怎么办呢?
log包
标准库提供了log组件,用法和fmt一致,有3种方式:
import “log"
func main() {
log.Println("line1")
log.Print("line2")
log.Printf("line%d \n", 3)
}
和fmt的区别就是多了时间:
2021/08/25 17:23:47 line1
2021/08/25 17:23:47 line2
2021/08/25 17:23:47 line3
我们通过SetFlag函数,可以设置打印的格式:
// For example, flags Ldate | Ltime (or LstdFlags) produce,
// 2009/01/23 01:23:23 message
// while flags Ldate | Ltime | Lmicroseconds | Llongfile produce,
// 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
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
)
比如,我们只需要时间和文件名:
import “log"
func main() {
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
log.Println("line1")
log.Print("line2")
log.Printf("line%d \n", 3)
}
此时,再次运行,则会打印文件和行号:
2021/08/25 17:27:56 mod_unread_redis.go:32: line1
2021/08/25 17:27:56 mod_unread_redis.go:33: line2
2021/08/25 17:27:56 mod_unread_redis.go:34: line3
如何输出日志到文件?
log包使用非常简单,默认情况下,只会输出到控制台。
我们可以使用SetOutput改变输出流,比如输出到文件。
先来看一下函数原型,其接收一个io.Writer接口:
// SetOutput sets the output destination for the standard logger.
func SetOutput(w io.Writer) {
// ...
}
那么,我们就可以创建一个文件流设置一下就行了。
// 创建、追加、读写,777,所有权限
f, err := os.OpenFile("log.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
if err != nil {
return
}
defer func() {
f.Close()
}()
log.SetOutput(f)
此时,在运行,我们发现日志会输出到文件,但是控制台没有任何东西输出了。
如何同时输出到控制台和文件?
标准库io包中,有一个MultiWriter,可以把文件流和控制台标准输出流整合到一个io.Writer上,其实现上就是一个数组,在执行写操作时,遍历数组:
// MultiWriter creates a writer that duplicates its writes to all the
// provided writers, similar to the Unix tee(1) command.
//
// Each write is written to each listed writer, one at a time.
// If a listed writer returns an error, that overall write operation
// stops and returns the error; it does not continue down the list.
func MultiWriter(writers ...Writer) Writer {
allWriters := make([]Writer, 0, len(writers))
for _, w := range writers {
if mw, ok := w.(*multiWriter); ok {
allWriters = append(allWriters, mw.writers...)
} else {
allWriters = append(allWriters, w)
}
}
return &multiWriter{allWriters}
}
// 重写io.Writer的Write函数函数,本质上就是遍历数组,比较巧妙
func (t *multiWriter) Write(p []byte) (n int, err error) {
for _, w := range t.writers {
n, err = w.Write(p)
if err != nil {
return
}
if n != len(p) {
err = ErrShortWrite
return
}
}
return len(p), nil
}
使用方式如下:
func main() {
f, err := os.OpenFile("log.log", os.O_CREATE|os.O_APPEND|os.O_RDWR, os.ModePerm)
if err != nil {
return
}
defer func() {
f.Close()
}()
// 组合一下即可,os.Stdout代表标准输出流
multiWriter := io.MultiWriter(os.Stdout, f)
log.SetOutput(multiWriter)
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
log.Println("line1")
log.Print("line2")
log.Printf("line%d \n", 3)
}
此时,再运行,则会同时输出到控制台和文件中。
2021/08/25 17:38:02 mod_unread_redis.go:42: line1
2021/08/25 17:38:02 mod_unread_redis.go:43: line2
2021/08/25 17:38:02 mod_unread_redis.go:44: line3
附:日志切割(按文件大小切割、按日期切割)
其实就是每次记录文件的大小,超过了就重新写一个文件。
通过Stat()函数拿到文件的一些信息
open, _:= os.Open("文件名")
stat, _, := open.Stat()
stat.Size()//拿到文件大小
日期切割:
拿到文件的名称或者检查下有没有当天的日志文件,没有就创建新增。
来源:https://blog.csdn.net/xmcy001122/article/details/119916227


猜你喜欢
- reader.html<html><head><meta http-equiv=&quo
- 1.scrapy基本了解Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。可以应用在包括数据挖掘, 信息处理或存储历史数据
- 一般情况下,网站的图片代码是这样的。<img src="./images/test.jpg"
- 之前使用beego的http库的时候,有的情况需要下载文件。beego是能实现,但就是有点问题:不支持回调,没法显示下载速度,这在日常开发中
- 本文记录了PyCharm安装的图文教程,供大家参考,具体内容如下PyCharm的官网 1.在官网下载安装包2.选择Windows系
- 本文实例讲解了4种JavaScript实现简单tab选项卡切换的方法,分享给大家供大家参考,具体内容如下效果图: 方法一:for循
- Explain工具介绍使用Explain关键字可以模拟优化器执行SQL语句,分析你的查询语句或是结构的性能瓶颈。在select语句之前增加e
- 1:masterha_check_repl 副本集方面报错 replicates is not defined in
- 简单了解多子图学习matplotlib的时候,有人肯定会觉得为啥不用Excel,为啥不用origin,为啥不直接使用软件,其实matplot
- 本文将对python中多个时间储存方式、时间模块(如time、datetime、timeit)以及他们之间的转换关系进行详细的梳理和总结。整
- 日期包常用函数time.Now(): 获取当前时间package mainimport ( "fmt&q
- 前几天光耀童鞋喷了一篇《谈网站注册、登录过程》,今天我们在与小爬童鞋梳理购买流程的时候也谈到了这部分内容。其实注册作为一个网站基本功能再普通
- 因为系统的一个Bug,导致数据库表中出现重复数据,需要做的是删除重复数据且只保留最新的一条数据。具体场景是这样的有张订单关联额外费用表,而且
- 案例一 导入图片思路: 1.导入库 2.加载图片 3.创建窗口 4.显示图片 5.暂停窗口 6.关闭窗口# 1.导入库import cv2#
- 之前写了一篇flask开发环境搭建,今天继续,进行一个实战小项目-blog系统。blog系统很简单,只有一个页面,然后麻雀虽小五脏俱全。这里
- 本文实例讲述了python实现线程池的方法。分享给大家供大家参考。具体如下:原理:建立一个任务队列,然多个线程都从这个任务队列中取出任务然后
- go-cqhttp安装一、 简介1、 介绍官方文档地址:https://docs.go-cqhttp.org/各种框架都只是机器人的各种实现
- Pandas 处理数据的效率还是很优秀的,相对于大规模的数据集只要掌握好正确的方法,就能让在数据处理时间上节省很多很多的时间。Pandas
- 本文实例为大家分享了python实现名片管理系统的具体代码,供大家参考,具体内容如下名片管理系统前提:实现名片管理系统,首先要创建两个pyt
- 本文实例讲述了Python使用正则表达式抓取网页图片的方法。分享给大家供大家参考,具体如下:#!/usr/bin/pythonimport