Go Web实战之创建项目及增加日志功能
宇宙之一粟 人气:0从本文开始,我们来看一下如何从零搭建一个 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
接口,并具体声明了具体的日志消息的具体方法,分别有着不同的日志级别,LogLevel
从 Trace
到 Fatal
。值得注意的是也有一个无级别的 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()
函数创建一个具有最小严重程度日志 DefaultLogger
和 log.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
,这意味着更低的日志级别(Trace
和 Debug
)将被忽略,再次编译和执行 sports
项目,就会看到本地的日志输出,可能你按照我的操作只会时间戳不同,如下:
$ go run . 11:46:55 INFO Let's Go, logger
终端结果如图所示:
总结
到了本文的总结时刻了,为了学习 Go Web 项目,本文先回顾了一下 Go 项目的初始化构建和运行过程,然后往我们的 sports
项目中添加了一个日志功能,逐步完善日志接口和实现,最后在主函数中进行了一个简单的日志输出测试。
加载全部内容