WRY

Where Are You?
You are on the brave land,
To experience, to remember...

0%

Fission改动第一步:优化CLI的日志输出

在Fission的基础上,自定义开发

Fission 官网开发介绍,其中详细介绍了源码结构和各个组件的功能以及编译方法,大大减少了自己摸索的成本。(只可惜我是折腾了一段时间才想起来看官网文档的。

完善Fission Cli 的日志模块

需求分析

在使用Fission查看日志消息的时候,发现日志会全部输出,并且存在冗余的时间信息,日志中也会携带很多\,影响直观的阅读。因此有了一个精简Cli输出的小需求,具体如下:

  • 可以选择从当前时间开始打印日志,而不是从头开始打印。
  • 可以选择是否输出日志时间戳,简化展示,并且展示时间戳的时候,使用对国人友好的北京时区时间。
  • 规范日志中的信息,尽量少的携带转义符

分析上述三点需求,其中前两点,可以不操作原始日志的情况下进行操作,因此适合将功能完善在Fission CLI中,而更加友好的日志格式输出,会随着日志的输出方式不同的而差异巨大,因此适合在env的镜像中制定统一的方便阅读的格式。

CLI 参数管理

从需求分析中,我们需要给Fission fn log子命令添加两个参数:

  • FnLogFromNow:只输出从当前时间之后的日志
  • FnLogWithTime:输出信息中是否携带日志的时间戳信息

那么Fission Cli是如何管理参数的呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 在cmd/fission-cli/app/app.go:40 App 中将fission子命令组合起来了
groups := helptemplate.CommandGroups{}
groups = append(groups, helptemplate.CreateCmdGroup("Basic Commands", environment.Commands(), _package.Commands(), function.Commands()))

// 在pkg/fission-cli/cmd/function/command.go:26 中给出了fn下子命令的组成
logsCmd := &cobra.Command{
Use: "log",
Aliases: []string{"logs"},
Short: "Display function logs",
RunE: wrapper.Wrapper(Log), // 具体的执行函数
}
wrapper.SetFlags(logsCmd, flag.FlagSet{ // 设置该命令需要的参数
Required: []flag.Flag{flag.FnName},
Optional: []flag.Flag{
flag.FnLogFollow, flag.FnLogReverseQuery, flag.FnLogCount,
flag.FnLogDetail, flag.FnLogPod, flag.NamespaceFunction, flag.FnLogDBType},
})
// 在pkg/fission-cli/flag/flag.go:69 中定义了所有的参数,例如这条flag,包含了类型,参数说明以及简写,其中FnLogFollow是定义的一个string类型的常量,在读取参数的时候会根据这个常量读取flag的信息。
FnLogFollow = Flag{Type: Bool, Name: flagkey.FnLogFollow, Short: "f", Usage: "Specify if the logs should be streamed"}
// 在pkg/fission-cli/cmd/function/log.go:38 中就是打印日志的具体函数了
// 读取参数的方式如下,其中flagkey.FnLogFollow和flag定义中所使用的常量是一样的。
input.Bool(flagkey.FnLogFollow)

需求开发

这里我们只关心前两个需求的开发,根据CLI管理命令的逻辑,首先创建需要的那两个布尔类型的flag,并在Log函数中,读取我们需要的参数,更改读取日志的开始时间和是否需要输出时间戳,这就比较简单了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
go func(ctx context.Context, requestChan, responseChan chan struct{}) {
// from now to output log
var t time.Time // 根据参数,对开始时间赋值
if input.Bool(flagkey.FnLogFromNow) {
t = time.Now()
} else {
t = time.Unix(0, 0*int64(time.Millisecond))
}
var cstSh, _ = time.LoadLocation("Asia/Shanghai") //上海,定义时区
for {
select {
case <-requestChan:
logFilter := logdb.LogFilter{
Pod: fnPod,
Function: f.ObjectMeta.Name,
FuncUid: string(f.ObjectMeta.UID),
Since: t, // 此处使用了开始时间
Reverse: logReverseQuery,
RecordLimit: recordLimit,
}
logEntries, err := logDB.GetLogs(logFilter)
if err != nil {
fmt.Printf("Error querying logs: %v", err)
responseChan <- struct{}{}
return
}
for _, logEntry := range logEntries {
if input.Bool(flagkey.FnLogDetail) { // 根据需求选择是否输出时间
if input.Bool(flagkey.FnLogWithTime) {
fmt.Printf("Timestamp: %s\nNamespace: %s\nFunction Name: %s\nFunction ID: %s\nPod: %s\nContainer: %s\nStream: %s\nLog: %s\n---\n",
logEntry.Timestamp.In(cstSh).Format("2006-01-02 15:04:05"), logEntry.Namespace, logEntry.FuncName, logEntry.FuncUid, logEntry.Pod, logEntry.Container, logEntry.Stream, logEntry.Message)
} else {
fmt.Printf("Namespace: %s\nFunction Name: %s\nFunction ID: %s\nPod: %s\nContainer: %s\nStream: %s\nLog: %s\n---\n",
logEntry.Namespace, logEntry.FuncName, logEntry.FuncUid, logEntry.Pod, logEntry.Container, logEntry.Stream, logEntry.Message)
}
} else {
if input.Bool(flagkey.FnLogWithTime) { // 根据需求选择是否输出时间
fmt.Printf("[%s] %s\n", logEntry.Timestamp.In(cstSh).Format("2006-01-02 15:04:05"), logEntry.Message)
} else {
fmt.Printf("%s\n", logEntry.Message)
}

}
t = logEntry.Timestamp
}
responseChan <- struct{}{}
case <-ctx.Done():
return
}
}
}(ctx, requestChan, responseChan)

测试无误之后,编译新的CLI。

1
2
# 根据官网的教程操作
~/repos/fission/cmd/fission-cli$ go build -o $GOPATH/bin/fission

测试结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
~/repos/fission/cmd/fission-cli$ $GOPATH/bin/fission fn log -h
Display function logs

Aliases:
log, logs

Options:
--name='' Function name
--follow=false (-f) Specify if the logs should be streamed
--reverse=false (-r) Specify the log reverse query base on time, it will be invalid if the
'follow' flag is specified
--recordcount=20 Get N most recent log records
--fromnow=false (-n) Show message from now
--withtime=false (-t) Show message with time
--detail=false (-d) Display detailed information
--pod='' Function pod name (use the latest pod name if unspecified)
--fnNamespace='default' (--fns) Namespace for function object
--dbtype='influxdb' Log database type, e.g. influxdb (currently only influxdb is
supported)

Global Options:
--server='' Server URL
--verbosity=1 (-v) CLI verbosity (0 is quiet, 1 is the default, 2 is verbose)
--kube-context='' Kubernetes context to be used for the execution of Fission commands

Usage:

已经可以看到新添加的两个参数fromnowwithtime,实际测试功能正常。完工!

总结

通过在Fission的CLI模块中补充开发的过程中,学的有两点:

  • 折腾之前,先看官网文档,官网文档才是学习一门技术应该看的东西。他人的博客,速成还行,深入很难,并且容易被带偏。(实际上也没有搜到有帮助的相关的博客
  • 看懂了CLI模块的组织方式之后,十分佩服作者的工程组织能力,让我一个小白也十分轻松的在框架上完成了我需要的功能,并且没有破坏框架的原有结构。

此外在开发完成之后,发现一个小细节,添加的withtime参数对之前的fission命令产生了影响,这个实际上不推荐的,更友好的方法是添加notwithtime的参数,只有添加参数的时候再忽略掉时间戳,如此可以兼容之前的使用。emmm,有点懒,偷偷改下代码,就不更新博客了。(太懒了,最后代码也没改。