Handle Logrus and Cobra CLI in Golang

1.5k views Asked by At

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 the way I explained above is my only option.

Any help or idea to improve my code is really welcome.

Thanks!

0

There are 0 answers