Go标准库日志打印,以及同时输出到控制台和文件

2023-10-27

打印

在使用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 

在这里插入图片描述
最后更新时间:2022-04-21

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go标准库日志打印,以及同时输出到控制台和文件 的相关文章

  • Go的并发的退出

    有时候我们需要通知goroutine停止它正在干的事情 比如一个正在执行计算的web服务 然而它的客户端已经断开了和服务端的连接 Go语言并没有提供在一个goroutine中终止另一个goroutine的方法 由于这样会导致goroutin
  • 【Golang入门】Golang第一天心得

    生活所迫 入门一下Go 很奇葩的第一点 接口 package main import fmt 定义一个接口 type Shape interface Area float64 定义一个矩形类型 type Rectangle struct W
  • golang之跨语言ipc通信

    1 golang之跨语言ipc通信 文章目录 1 golang之跨语言ipc通信 1 1 unix domain Socket unix域套接字 介绍 1 2 IPC SOCKET通信 1 2 1 函数及地址定义介绍 1 2 2 UNIX
  • go-zero使用Etcd进行服务注册代码分析

    代码分析 github com tal tech go zero v1 2 3 core discov publisher go package discov import github com tal tech go zero core
  • go Cobra命令行工具入门

    简介 Github https github com spf13 cobra Star 26 5K Cobra是一个用Go语言实现的命令行工具 并且现在正在被很多项目使用 例如 Kubernetes Hugo和Github CLI等 通过使
  • 权重实现随机抽奖

    一般抽奖是怎么实现的 在实习期间学会了一种通用的写法 在这里记录一下 最近在学Golang语法基础 这里就用Golang来写 package main import fmt time math rand func main r rand N
  • Go中 Redis Client的使用

    文章目录 常见操作 List 操作 Pipeline 使用 在 Go 语言中使用 Redis 时 可以使用第三方库实现 Redis Client 的封装 本文介绍如何使用 Go 语言的 redisClient 去连接 Redis 服务器 并
  • goland环境配置

    goland modules环境配置 下载和安装goland 环境配置 配置环境变量GOPATH 配置go modules GOPROXY代理的系统变量 工程目录中新建三个工作目录 goland中启用go modules 新建一个go程序
  • 为什么最近听说 Go 岗位很少很难?

    大家好 我是煎鱼 其实这个话题已经躺在我的 TODO 里很久了 近来很多社区的小伙伴都私下来交流 也有在朋友圈看到朋友吐槽 Go 上海的大会没什么人 还不如 Rust 大会 比较尴尬 今天主要是看看为什么 Go 岗位看起来近来很难的样子 也
  • 有哪些不错的 Golang 开源项目?

    目前人在字节做 Go 开发 寻找 Golang 开源项目学习目的可能是 想学习或者提高自己对 Go 项目的组织和编排能力 想学习 Go 项目的框架设计 想在一些 Go 语法上细节的优化和进阶 我推荐两个项目 一 tinode 这是一个开源的
  • go-zero 开发入门-加法客服端示例

    定义 RPC 接口文件 接口文件 add proto 的内容如下 syntax proto3 package add 当 protoc gen go 版本大于 1 4 0 时需加上 go package 否则编译报错 unable to d
  • go-zero开发入门之网关往rpc服务传递数据2

    go zero 的网关服务实际是个 go zero 的 API 服务 也就是一个 http 服务 或者说 rest 服务 http 转 grpc 使用了开源的 grpcurl 库 当网关需要往 rpc 服务传递额外的数据 比如鉴权数据的时候
  • go-zero开发入门-API网关开发示例

    开发一个 API 网关 代理 https blog csdn net Aquester article details 134856271 中的 RPC 服务 网关完整源代码 file main go package main import
  • GoLong的学习之路,进阶,Viper(yaml等配置文件的管理)

    本来有今天是继续接着上一章写微服务的 但是这几天有朋友说 再写Web框架的时候 遇到一个问题 就是很多的中间件 redis 微信 mysql mq 的配置信息写的太杂了 很不好管理 希望我能写一篇有管理配置文件的 所以这篇就放到今天写吧 微
  • go语言实现文件夹上传前后端代码案例

    go语言实现文件夹上传前后端代码案例 前端用于上传的测试界面 如果上传的文件夹有子文件要遍历子文件夹创建出子文件夹再进行拷贝 需要获取文件名和对应的路径 将文件的相对路径和文件对象添加到FormData中 这几行代码很关键 for let
  • Golang拼接字符串性能对比

    g o l a n g golang g o l an g
  • [每周一更]-(第55期):Go的interface

    参考地址 https juejin cn post 6978322067775029261 https gobyexample com interfaces https go dev tour methods 9 介绍下Go的interfa
  • Golang拼接字符串性能对比

    g o l a n g golang g o l an g
  • go-carbon v2.3.4 发布,轻量级、语义化、对开发者友好的 Golang 时间处理库

    carbon 是一个轻量级 语义化 对开发者友好的 golang 时间处理库 支持链式调用 目前已被 awesome go 收录 如果您觉得不错 请给个 star 吧 github com golang module carbon gite
  • 【go语言】AST抽象语法树详解&实践之扫描代码生成错误码文档

    背景 为了能识别出代码中抛出错误码的地址和具体的错误码值 再根据错误码文件获取到错误码的具体值和注释 方便后续的排错 这里使用AST进行语法分析获取到代码中的目标对象 一 编译过程 在开始解析代码之前先补充了解一下编译过程 编译过程是将高级

随机推荐

  • Unity PackageManager一直加载不到信息的解决方法

    关闭unity 断开网络连接 打开unity 这时候会加载出来 连接网络开始install
  • 牛客网——两数之和

    题目描述 给出一个整数数组 请在数组中找出两个加起来等于目标值的数 你给出的函数twoSum 需要返回这两个数字的下标 index1 index2 需要满足 index1 小于index2 注意 下标是从1开始的 假设给出的数组中只存在唯一
  • 解决error: subprocess-exited-with-error

    运行 pip install upgrade setuptools 即可解决
  • Playwright解决永久保存下载文件

    Playwright默认在浏览器关闭的时候 所有的临时文件都将删除 无论你是自定义位置还是默认位置 那么如何正确下载对应的文件呢 废话不多说 大家直接看以下代码即可 这里还是告诫大家一下 多研究官网的API文档 别学我慌慌张张去搞了 啥都没
  • QTP的那些事--项目实践操作案例代码--查询操作

    1 一下的代码记录的是我对于一个查询操作的自动化的思路 遗憾的是预期的结果可能需要手动输入到datatable中 以后逐步完善 将所有的预期值都自动输入到excel中 登陆系统 2 3 RunAction login loginsystem
  • HDS 存储名词解释

    DKU 扩展柜 DKC 控制柜 DKA 后端端口 CHA 前端端口 CSW 交换卡 SVP 内置服务PC 另一个含义是服务程序 CM Cache Memory数据内存 SM Share Memory共享内存 HDU Hard Disk Un
  • npoi全国计算机编程,NPOI 导入Excel

    NPOI 导入Excel public static List GetExcelToList string excelfileName List list new List ISheet sheet null PropertyInfo pr
  • Nginx进程管理

    Nginx进程管理 1 Nginx进程管理之master进程 监控进程充当整个进程组与用户的交互接口 同时对进程进行监护 它不需要处理网络事件 不负责业务的执行 只会通过管理worker进程来实现重启服务 平滑升级 更换日志文件 配置文件实
  • 利用lda对文本进行分类_使用lda进行文本分类

    利用lda对文本进行分类 LDA or Latent Dirichlet Allocation is one of the most widely used topic modelling algorithms It is scalable
  • Linux——gcc/g++以及make/Makefile的使用

    简介 在Linux的系统中 想要完成代码编译 gcc g 是不可缺少的工具 而make Makefile能否熟练应用则从一个侧面体现出一个人是否有能力独自完成一个大型工程 而本篇文章就带领大家了解一些gcc g 和make Makefile
  • 层叠上下文(stacking context)

    一 什么是层叠式上下文 层叠上下文 是HTML中的一个三维概念 如果元素具备以下任何一个条件 则该元素会创建一个新的层叠上下文 根元素 z index不为auto的定位元素 二 什么是层叠级别 同一个层叠上下文的背景色以及内部元素 谁在上谁
  • IPsec SA 创建步骤——IKE协议

    IPsec SA 创建步骤概述 IPsec SA creation steps There are two steps on the IPsec SA creation phase 1 is to creat IKE SA and phas
  • 为什么重写equals方法时必须重写hashcode方法

    文章目录 1 与 equals的区别 2 重写equals 3 为什么重写equals方法时必须重写hashcode方法 3 1 Hash算法 3 2 HashCode 相关文章 为什么重写equals方法时必须重写hashcode方法 J
  • 在vue页面中,直接展示代码及样式高亮(vue 中使用 highlight)

    参考链接 https blog csdn net u011364720 article details 90417302 前言 效果如下 想要在前端页面中 直接展示代码的样式 就像一些开发文档的源码展示一样 使用插件 highlight j
  • C++智能指针 shared_ptr,unique_ptr和weak_ptr

    1 智能指针为什么存在 因为C 没有自动回收内存的机制 因此每一次new出来的动态内存必须手动delete回去 因此智能指针可以解决这个问题 2 智能指针的大致描述是什么 智能指针 自动负责释放所指向的对象 实际上它利用了栈的机制 每一个智
  • Go语言基础知识4——依赖管理

    依赖 别人写的库 依赖其进行编译 依赖管理的三个阶段 GOPATH GOVENDOR go mod GOPATH和GOVENDOR正在向go mod迁移 一 GOPATH GOPATH是一个环境 就是一个目录 默认在 go unix lin
  • spring-boot集成spring-brick实现动态插件

    spring boot集成spring brick实现动态插件 spring boot集成spring brick实现动态插件 项目结构 需求实现 spring boot集成spring brick 环境说明 1 主程序集成spring b
  • GnosisSafeProxyFactory合约学习

    GnosisSafe是以太坊区块链上最流行的多签钱包 它的最初版本叫 MultiSigWallet 现在新的钱包叫Gnosis Safe 意味着它不仅仅是钱包了 它自己的介绍为 以太坊上的最可信的数字资产管理平台 The most trus
  • UTXO的定义(交易,输入输出)-1

    在比特币系统中并没有账户的概念 有的是遍布全网区块链的UTXO 所谓UTXO是指关联比特币地址的比特币金额的集合 是一个包含数据和可执行代码的数据结构 一个UTXO的基本单位是 聪 聪 是比特币的最小计量单位 一个比特币等于10 8聪 一个
  • Go标准库日志打印,以及同时输出到控制台和文件

    打印 在使用go写一些小程序时 我们没必要引入额外的包 直接使用fmt标准包打印即可 import fmt func main fmt Println line1 fmt Print line2 fmt Printf line d n 3