Go Web 实战:如何创建项目及增加日志功能

举报
宇宙之一粟 发表于 2022/10/27 13:40:30 2022/10/27
【摘要】 本文先回顾了一下 Go 项目的初始化构建和运行过程,然后往我们的 sports 项目中添加了一个日志功能,逐步完善日志接口和实现,最后在主函数中进行了一个简单的日志输出测试。

Go Web 实战:如何创建项目及增加日志功能

从本文开始,我们来看一下如何从零搭建一个 Go 项目。

回顾一下基础的 Go 项目运行过程

首先,新建一个 sports 的文件,然后键入此文件目录下,选择在终端中打开,使用如下命令初始化项目:


go mod init sports



然后,我们创建一个 main.go 的文件,写入如下代码:


package main

import "fmt"

func writeMessage() {
  fmt.Println("Let's Go")
}

func main() {
  writeMessage()
}


回到终端,编译并执行我们的项目:


go run .


就像之前第一次写一个 HelloWorld 项目一样,run 命令会成功编译并执行我们的 Println() 内的字符串 Let's Go,输出结果如下:


$ go run .
Let's Go

创建一些基本的项目功能

众所周知,Web 应用有一些基础的服务和功能如日志、文件配置等等。所以我们可以为 sports 项目提供一些基本的服务,这些服务将为运行网络应用程序提供基础。

创建日志接口 Logger

先来实现第一个服务器功能——日志。Go 标准库中的 log 包为创建日志提供了一套非常用户友好的基本功能,但在实际开发过程中,仍需要一些额外的功能来筛选一些信息详情。


创建 sports/logging 文件夹,然后在这个文件夹下面创建一个 logging.go 文件,然后写入如下代码:


package logging

type LogLevel int

const (
	Trace LogLevel = iota
	Debug
	Information
	Warning
	Fatal
	None
)

type Logger interface {
	Trace(string)
	Tracef(string, ...interface{})

	Debug(string)
	Debugf(string, ...interface{})

	Info(string)
	Infof(string, ...interface{})

	Warn(string)
	Warnf(string, ...interface{})

	Panic(string)
	Panicf(string, ...interface{})
}


上面的代码定义了 Logger 接口,并具体声明了具体的日志消息的具体方法,分别有着不同的日志级别,LogLevelTraceFatal 。值得注意的是也有一个无级别的 None, 意味着没有日志输出。


对于每个级别的重要性,Logger 接口定义两个方法:


  • 一个用于接受简单字符串的方法,如 Debug

  • 一个用于接收模板字符串和占位符值的方法,如 Debugf


将日志功能定义为接口的好处是:在需要更改或替换功能时,只需要更改实现,我们的调用接口并不需要改变;接口也使得功能作为服务提供给应用程序。


Logger 接口的具体实现

日志接口定义好了之后,我们来创建具体的 Logger 接口的实现。


创建一个 logger_default.go 的文件,然后写入如下的代码:


package logging

import (
	"fmt"
	"log"
)

type DefaultLogger struct {
	minLevel     LogLevel
	loggers      map[LogLevel]*log.Logger
	triggerPanic bool
}

func (l *DefaultLogger) MinLogLevel() LogLevel {
	return l.minLevel
}

func (l *DefaultLogger) write(level LogLevel, message string) {
	if l.minLevel <= level {
		l.loggers[level].Output(2, message)
	}
}

func (l *DefaultLogger) Trace(msg string) {
	l.write(Trace, msg)
}

func (l *DefaultLogger) Tracef(template string, vals ...interface{}) {
	l.write(Trace, fmt.Sprintf(template, vals...))
}

func (l *DefaultLogger) Debug(msg string) {
	l.write(Debug, msg)
}

func (l *DefaultLogger) Debugf(template string, vals ...interface{}) {
	l.write(Debug, fmt.Sprintf(template, vals...))
}

func (l *DefaultLogger) Info(msg string) {
	l.write(Information, msg)
}

func (l *DefaultLogger) Infof(template string, vals ...interface{}) {
	l.write(Information, fmt.Sprintf(template, vals...))
}

func (l *DefaultLogger) Warn(msg string) {
	l.write(Warning, msg)
}

func (l *DefaultLogger) Warnf(template string, vals ...interface{}) {
	l.write(Warning, fmt.Sprintf(template, vals...))
}

func (l *DefaultLogger) Panic(msg string) {
	l.write(Fatal, msg)
	if l.triggerPanic {
		panic(msg)
	}
}

func (l *DefaultLogger) Panicf(template string, vals ...interface{}) {
	formattedMsg := fmt.Sprintf(template, vals...)
	l.write(Fatal, formattedMsg)
	if l.triggerPanic {
		panic(formattedMsg)
	}
}


NewDefaultLogger() 函数创建一个具有最小严重程度日志 DefaultLoggerlog.Loggers 将消息写入标准输出。


最终我们的目录结构如下:


测试日志功能

为了做一个简单的测试,我们可以修改最开始的 main() 函数,以便查看日志功能是否能成功打印出日志消息,回到 main.go ,写入如下代码:

package main

import (
	// "fmt"
	"sports/logging"
)

func writeMessage(logger logging.Logger) {
	// fmt.Println("Let's Go")
	logger.Info("Let's Go, logger")
}

func main() {

	var logger logging.Logger = logging.NewDefaultLogger(logging.Information)
	writeMessage(logger)
}

NewDefaultLogger 创建的最小日志级别被设置为 Information,这意味着更低的日志级别(TraceDebug)将被忽略,再次编译和执行 sports 项目,就会看到本地的日志输出,可能你按照我的操作只会时间戳不同,如下:

$ go run .
11:46:55 INFO Let's Go, logger

终端结果如图所示:


总结

到了本文的总结时刻了,为了学习 Go Web 项目,本文先回顾了一下 Go 项目的初始化构建和运行过程,然后往我们的 sports 项目中添加了一个日志功能,逐步完善日志接口和实现,最后在主函数中进行了一个简单的日志输出测试。


希望本文能对你有所帮助,如果喜欢本文,可以点个关注。

这里是宇宙之一粟,下一篇文章见!

宇宙古今无有穷期,一生不过须臾,当思奋争。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。