如何从 ctrl“sigs.k8s.io/controller-runtime”模拟 zap 记录器?

Posted

技术标签:

【中文标题】如何从 ctrl“sigs.k8s.io/controller-runtime”模拟 zap 记录器?【英文标题】:How to mock zap logger from ctrl "sigs.k8s.io/controller-runtime"? 【发布时间】:2021-12-13 15:30:30 【问题描述】:
package logger

import (
    "bytes"
    . "github.com/onsi/ginkgo"
    . "github.com/onsi/gomega"
    ctrl "sigs.k8s.io/controller-runtime"
)
var _ = Describe("Logger", func() 
    It("Test Default Log Level", func() 
        buf := &bytes.Buffer
        testLog := ctrl.Log.WithName("setup")
        SetLogger()
        

        testLog.Info("This is a test")
        Expect(buf.String(),"This is a test")
    )
)

这是SetLogger 函数,也用于生产:

package logger

import (
    ctrl "sigs.k8s.io/controller-runtime"
    "sigs.k8s.io/controller-runtime/pkg/log/zap"
    ...
)

func SetLogger() 
    opts := zap.Options
        Development:     developmentFlag,
        StacktraceLevel: stacktraceLevel,
        Level:           isLevelEnabler,
        Encoder:         logFmtEncoder,
    
  ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))

如何将testLog.Info 的输出更改为缓冲区?

【问题讨论】:

【参考方案1】:

如果你只对测试日志消息感兴趣,你可以使用钩子。

特别是zap.Hooks 函数从可变数量的挂钩构造zap.Option。钩子只是一个func(entry zapcore.Entry) error,您可以使用它来拦截条目并将其消息写入缓冲区。

要将此zap.Option 设置到您的sigs.k8s.io 记录器中,请将其设置为ZapOpts 字段:

    opts := k8szap.Options
        // ...
        ZapOpts: []zap.Option
            zap.Hooks(func(entry zapcore.Entry) error 
                buf.WriteString(entry.Message)
                return nil
            ),
        ,
    

因此,由于您需要访问缓冲区,因此可以将其作为参数传递给 SetLogger 函数:

func SetLogger(buf *bytes.Buffer) 
    opts := zap.Options
        Development:     developmentFlag,
        StacktraceLevel: stacktraceLevel,
        Level:           isLevelEnabler,
        Encoder:         logFmtEncoder,

        // here 'zap' selector is 'go.uber.org/zap'
        ZapOpts: []zap.Option
            zap.Hooks(func(entry zapcore.Entry) error 
                buf.WriteString(entry.Message)
                return nil
            ),
        ,
    
    // here I call 'k8szap' selector the package 'sigs.k8s.io/controller-runtime/pkg/log/zap'
    ctrl.SetLogger(k8szap.New(k8szap.UseFlagOptions(&opts)))

然后在你的测试函数中:

    It("Test Default Log Level", func() 
        buf := &bytes.Buffer
        testLog := ctrl.Log.WithName("setup")

        // pass buffer to SetLogger
        SetLogger(buf)
        

        testLog.Info("This is a test")
        Expect(buf.String(), "This is a test")
    )

最小示例(在操场上下载包时可能会超时):https://play.golang.org/p/oBN3SHFKVC8

【讨论】:

@blackGrren - 再次感谢您的支持,我还有 2 个问题:在真实情况下(不在测试中)我需要将什么传递给 buf *bytes.Buffer 而不是在测试中?设置记录器后是否可以设置它或者它必须处于初始化阶段? @user1365697 如果您使用指针 *bytes.Buffer 从技术上讲,您可以保留变量并随时为其分配一些其他值,但是如果出现错误,这已经成熟你的程序有并发代码。在初始化期间设置它可能是一个更好的选择 @blackGrren - 真实情况下的 *bytes.Buffer 应该是什么?当我从生产调用中调用它时 @user1365697 好吧,这取决于想要做什么。为什么在生产中需要这个?如果您的目标是将输出重定向到其他地方,更好的选择可能是zapcore.NewTee,类似于here。如果这只是为了测试,你最好稍微重构一下代码,因为测试的东西不应该溢出到生产代码中......但这有点超出你的问题范围,所以很难回答 @blackGrren - 我在生产中不需要它,所以我应该将什么传递给 SetLogger,因为我向 SetLogger 添加了新的参数 buf *bytes.Buffer 所以它也在生产中

以上是关于如何从 ctrl“sigs.k8s.io/controller-runtime”模拟 zap 记录器?的主要内容,如果未能解决你的问题,请参考以下文章

在Linux中如何从字符界面进入图形界面,

如何快速从使用Eclipse转用IDEA

如何使用 C# 模拟 CTRL+V 击键(粘贴)

新手如何熟练掌握Linux终端?

如何在 CLI 应用程序中“拦截”Ctrl+C?

如何使用 Ctrl+C 输入干净地退出 QProcess?