这是我参与「第五届青训营」伴学笔记创作活动的第9天。
log
- golang内置了
log包,实现简单的日志服务。通过调用log包的函数,可以实现简单的日志打印功能。 log包中有3个系列的日志打印函数,分别print系列、panic系列、fatal系列。
| 函数系列 | 作用 |
|---|---|
| 单纯打印日志 | |
| panic | 打印日志,抛出panic异常 |
| fatal | 打印日志,强制结束程序(os.Exit(1)),defer函数不会执行 |
log配置
标准log配置
- 默认情况下log只会打印出时间,但是实际情况下可能还需要获取文件名,行号等信息,
log包提供定制的接口。log包提供两个标准log配置的相关方法:
func Flags() int // 返回标准log输出配置
func SetFlags(flag int) // 设置标准log输出配置
- flag参数
const (
// 控制输出日志信息的细节,不能控制输出的顺序和格式。
// 输出的日志在每一项后会有一个冒号分隔:例如2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
Ldate = 1 << iota // 日期:2009/01/23
Ltime // 时间:01:23:23
Lmicroseconds // 微秒级别的时间:01:23:23.123123(用于增强Ltime位)
Llongfile // 文件全路径名+行号: /a/b/c/d.go:23
Lshortfile // 文件名+行号:d.go:23(会覆盖掉Llongfile)
LUTC // 使用UTC时间
LstdFlags = Ldate | Ltime // 标准logger的初始值
)
- 标准日志配置
package main
import (
"fmt"
"log"
)
func main() {
i := log.Flags()
fmt.Printf("i: %v\n", i)
log.SetFlags(log.Ldate | log.Ltime | log.Llongfile)
log.Print("my log")
}
日志前缀配置
log包提供两个日志前缀配置的相关函数:
func Prefix() string // 返回日志的前缀配置
func SetPrefix(prefix string) // 设置日志前缀
package main
import (
"fmt"
"log"
)
func main() {
s := log.Prefix()
fmt.Printf("s: %v\n", s)
log.SetPrefix("MyLog: ")
s = log.Prefix()
fmt.Printf("s: %v\n", s)
log.Print("my log...")
}
日志输出位置配置
- golang的
log包支持将日志输出到文件中。log包提供了func SetOutput(w io.Writer)函数,将日志输出到文件中。
package main
import (
"log"
"os"
)
func main() {
f, err := os.OpenFile("a.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
log.Panic("打开日志文件异常")
}
log.SetOutput(f)
log.Print("my log...")
}
自定义logger
- log包中提供了func New(out io.Writer, prefix string, flag int) *Logger函数来实现自定义logger。
var logger *log.Logger
func init() {
logFile, err := os.OpenFile("a.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
log.Panic("打开日志文件异常")
}
logger = log.New(logFile, "success", log.Ldate | log.Ltime | log.Lshortfile)
}
func main() {
logger.Println("自定义logger")
}
builtin
- 提供了一些类型声明、变量和常量声明,还有一些函数,builtin包不需要导入,相关变量和函数就可以直接使用。
常用函数
- append
func append(slice []Type, elems ...Type) []Type
slice = append(slice, elem1, elem2) //直接在slice后面添加单个元素,添加元素类型可以和slice相同,也可以不同
slice = append(slice, anotherSlice...) //直接将另外一个slice添加到slice后面,但其本质还是将anotherSlice中的元素一个一个添加到slice中,和第一种方式类似.(...表示将数组元素打散)
- len:返回数组、切片、字符串、通道的长度
- print、println:打印输出到控制台
- panic:抛出一个panic异常
- new和make
- 区别:
- make只能用来分配及初始化类型为slice,map,chan的数据;new可以分配任意类型的数据
- new分配返回的是指针,即类型*T;make返回引用,即T;
- new分配的空间被清零,make分配后,会进行初始化。
- 区别:
bytes
- bytes包提供了对字节切片进行读写操作的一系列函数,字节切片处理的函数分为基本处理函数、比较函数、后缀检查函数、索引函数、分割函数、大小写处理函数和子切片处理函数等.
- Contains:是否包含目标切片
- Count:计数出现数量
- Repeat:重复指定次数
- Replace:指定位置替换
- Runes:将中文等特殊符号进行转换
- Join:拼接字符串
Buffer类型
- 声明一个Buffer的四种方法:
var b bytes.Buffer // 直接定义一个Buffer变量,不用初始化,可以直接使用
b := new(bytes.Buffer) //使用New返回Buffer变量
b := bytes.NewBuffer(s []byte) //从一个[]byte切片,构造一个Buffer
b := bytes.NewBufferString(s string) //从一个string变量,构造一个Buffer
- 相关操作
b.Write(d []byte) //将切片d写入Buffer尾部
b.WriteString(s string) //将字符串s写入Buffer尾部
b.WriteByte(c byte) //将字符c写入Buffer尾部
b.WriteRune(r rune) //将一个rune类型的数据放到缓冲器的尾部
b.WriteTo(w io.Writer) //将Buffer中的内容输出到实现了io.Writer接口的可写入对象中
b.ReadFrom(i io.Reader) //将文件中的内容写入Buffer
c := make([]byte,8)
b.Read(c) //一次读取8个byte到c容器中,每次读取新的8个byte覆盖c中原来的内容
b.ReadByte() //读取第一个byte,b的第1个byte被拿掉,赋值给 a => a, _ := b.ReadByte()
b.ReadRune() //读取第一个rune,b的第1个rune被拿掉,赋值给 r => r, _ := b.ReadRune()
b.ReadBytes(delimiter byte) //需要一个 byte作为分隔符 ,读的时候从缓冲器里找第一个出现的分隔符(delim),找到后,把从缓冲器头部开始到分隔符之间的所有byte进行返回,作为byte类型的slice,返回后,缓冲器也会空掉一部分
b.ReadString(delimiter byte) // 需要一个byte作为分隔符,读的时候从缓冲器里找第一个出现的分隔符(delim),找到后,把从缓冲器头部开始到分隔符之间的所有byte进行返回, 作为字符串返回 ,返回后,缓冲器也会空掉一部分 b.ReadForm(i io.Reader) // 从一个实现io.Reader接口的r,把r里的内容读到缓冲器里 ,n 返回读的数量
Reader类型
- Reader实现了
io.Reader, io.ReaderAt, io.WriterTo, io.Seeker,io.ByteScanner, io.RuneScanner接口,Reader是只读的、可以seek。
errors
- errors包实现了操作错误的函数。使用 error 类型来返回函数执行过程中遇到的错误,如果返回的 error 值为
nil,则表示未遇到错误,否则 error 会返回一个字符串,用于说明遇到了什么错误。 - error接口
type error interface {
Error() string
}
- 可以用任何类型去实现此接口,只要添加一个 Error() 方法即可。即 error 可以是任何类型。
- error 不一定表示一个错误,它可以表示任何信息,比如 io 包中就用 error 类型的
io.EOF表示数据读取结束,而不是遇到了错误。 - errors 包实现了一个最简单的 error 类型,只包含一个字符串,它可以记录大多数情况下遇到的错误信息。errors 包的用法也很简单,只有一个
New函数,用于生成一个最简单的 error 对象:
func New(text string) error
package main
import (
"errors"
"fmt"
)
func check(s string) error {
if s == "" {
return errors.New("字符串不能为空")
} else {
return nil
}
}
func main() {
check("hello")
err := check("")
fmt.Printf("err: %v\n", err.Error())
}
自定义错误
package main
import (
"fmt"
"time"
)
// MyError is an error implementation that includes a time and message.
type MyError struct {
When time.Time
What string
}
func (e MyError) Error() string {
return fmt.Sprintf("%v: %v", e.When, e.What)
}
func oops() error {
return MyError{
time.Date(1989, 3, 15, 22, 30, 0, 0, time.UTC),
"the file system has gone away",
}
}
func main() {
if err := oops(); err != nil {
fmt.Println(err)
}
}