处理Golang的Logrus和Cobra CLI

发布于 2025-02-10 12:59:22 字数 2099 浏览 1 评论 0原文

我对Golang的Cobra和Logrus的包装相对较新,在整合它们方面,我需要寻求帮助。我正在研究一个新的Golang眼镜蛇CLI,其中包含多个命令/子命令。我想使用logrus在子命令中登录,但是我找不到在记录器中添加新字段并将其全部传递给我的子命令的好方法。 这就是我到目前为止所拥有的(我简化了我的代码以更好地解释目的):

├──pkg/
    ├──logger/
    |  ├──logger.go
├──cmd/
    ├── root.go
    ├──scmd/
    |  ├──scmd.go

// root.go

package cmd

func ExecuteRoot() {
    rootCmd := getRootCmd()
    err := rootCmd.Execute()
    if err != nil {
        os.Exit(1)
    }
}

func getRootCmd() *cobra.Command {
    rootCmd := &cobra.Command{
        Use:   "mycli",
        PersistentPreRun: enableLogs,
    }

    rootCmd.AddCommand(scmd.Getscmd())

    return rootCmd
}


func enableLogs(cmd *cobra.Command, args []string) {
    logger.ConfigureLogger(cmd.Flag("log-level").Value.String())
}

// logger.go
package logger

import (
    "github.com/sirupsen/logrus"
)


var MyCli *logrus.Entry


func ConfigureLogger(d string) {
    lv, err := logrus.ParseLevel(d)
    if err != nil {
        logrus.Fatal(err)
    }
    logrus.SetLevel(lv)

    logrus.SetFormatter(&logrus.TextFormatter{
        DisableQuote: true,
        ForceColors:  true,
    })

    MyCli = logrus.WithFields(logrus.Fields{"foo1": "bar1", "foo2": "bar2"})
}
// scmd.go

package scmd

import (
   "pkg/logger"
   "github.com/spf13/cobra"
)

func Getscmd() *cobra.Command {
    serviceUpdateCmd := &cobra.Command{
        Use:   "scmd",
        Run:   runServiceUpdateCmd,
    }

    return serviceUpdateCmd
}

func runServiceUpdateCmd(cmd *cobra.Command, args []string) {
    logger.MyCli.Info("start scmd")
    
    // here what the command does ...
}

如果运行它,我会得到我的期望:我的子命令(在这种情况下为scmd)在级别我设置了我的标志log-level和我的软件包中定义的字段logger已传递(“ foo1”:“ bar1”“ foo2”:“ bar2”)。但是,我觉得这不是正确的方法,并且在创建单元测试时可能会成为问题,因为我从我的logger package使用全局变量var mycli。此外,我应该将其导入并将其用作logger.mycli在我要记录的每个信息,错误,警告等行中。

我的问题是,在我创建的所有子命令上,是否有更好的方法可以通过Logrus的字段?还是我在我唯一的选择上解释的方式?

I am relatively new to the packages Cobra and Logrus in Golang and there is one little thing I would to ask for help when it comes to integrating them. I am working on a new Golang Cobra CLI which contains several commands/sub-commands. I'd like to use Logrus for logging inside my subcommands but I cannot find a good way to add new fields to the logger and pass them all to my subcommands.
This is what I have so far (I simplified my code for better explanation of my purpose):

├──pkg/
    ├──logger/
    |  ├──logger.go
├──cmd/
    ├── root.go
    ├──scmd/
    |  ├──scmd.go

// root.go

package cmd

func ExecuteRoot() {
    rootCmd := getRootCmd()
    err := rootCmd.Execute()
    if err != nil {
        os.Exit(1)
    }
}

func getRootCmd() *cobra.Command {
    rootCmd := &cobra.Command{
        Use:   "mycli",
        PersistentPreRun: enableLogs,
    }

    rootCmd.AddCommand(scmd.Getscmd())

    return rootCmd
}


func enableLogs(cmd *cobra.Command, args []string) {
    logger.ConfigureLogger(cmd.Flag("log-level").Value.String())
}

// logger.go
package logger

import (
    "github.com/sirupsen/logrus"
)


var MyCli *logrus.Entry


func ConfigureLogger(d string) {
    lv, err := logrus.ParseLevel(d)
    if err != nil {
        logrus.Fatal(err)
    }
    logrus.SetLevel(lv)

    logrus.SetFormatter(&logrus.TextFormatter{
        DisableQuote: true,
        ForceColors:  true,
    })

    MyCli = logrus.WithFields(logrus.Fields{"foo1": "bar1", "foo2": "bar2"})
}
// scmd.go

package scmd

import (
   "pkg/logger"
   "github.com/spf13/cobra"
)

func Getscmd() *cobra.Command {
    serviceUpdateCmd := &cobra.Command{
        Use:   "scmd",
        Run:   runServiceUpdateCmd,
    }

    return serviceUpdateCmd
}

func runServiceUpdateCmd(cmd *cobra.Command, args []string) {
    logger.MyCli.Info("start scmd")
    
    // here what the command does ...
}

If I run it, I get what I am expecting: My subcommands (in this case scmd) logs at the level I set my flag log-level and the fields defined in my package logger are passed ("foo1": "bar1", "foo2": "bar2"). However, I feel it is not the right way and could become problematic when creating unit test as I am using the global variable var MyCli from my logger package. Moreover, I should import it and use it as logger.MyCli in every Info, error, warn, etc line I want to log.

My question is whether there is a better approach to pass fields in Logrus on all subcommands I create? Or is the way I explained above my only option?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文