Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Sébastien Le Gall
Sébastien Le Gall

Posted on • Edited on

     

Integrating logrus with cobra

You can find a working example on my GitHub:https://github.com/seblegall/blog-scripts/tree/master/logrus-cobra

I recently had to refactor the way one of my app print logs. My idea was to uselogrus as it is a very well known lib to produce logs with Go.

Logrus let you print nicely color-coded and structured logs and is completely API compatible with the standard library logger.

logrus

My first question was about log level and how to setup it once across all sub-directory/package of my project.

Under the hood, logrus instantiate a new variablelog. Once done, calling thelogrus.SetLevel() function will store the level directly in this newly instantiated struct.

Thus, we have a global struct, available across all sub-package making the level automatically shared without having to use dependency injection.

If you need to set a different level in a sub-package (for example), you just need to instantiate a new logger :

varlog=logrus.New()//...log.Debug("debug log")
Enter fullscreen modeExit fullscreen mode

More about logrus here :https://github.com/sirupsen/logrus

Then I thought about adding a flag to my binary, letting the user set its own log level.

My application is usingcobra, so I had to decided where to read the flag and where to init the logger by setting the level, depending on the flag value.

My first thought was to create aSetLevel() func which could be called in each cobra sub-command run function. But I found a better approach by looking at the source code ofSkaffold

Cobra has a cool feature called pre/post run. It's basically a function that will be executed right before the command start, or right after.

The same way you can defined "persistent" flags in cobra commands (which is a way to create inheritance between commands and sub-commands), the framework also offers aPersistentPreRun function.

That was the perfect place to put my log init as it is :

  • Defined once for all sub-commands (which is a behaviour you probably want when creating averbose flag.)
  • A place where flags are already defined and read. So I could make a good use of the flag value set by the user.

Here is how it goes :

packagecmdimport("io""os""github.com/sirupsen/logrus""github.com/spf13/cobra")//The verbose flag valuevarvstringvarrootCmd=&cobra.Command{Use:"mycmd",Short:"mycmd is a test project to integrate logrus",}//NewMyCmd return the root cobra commandfuncNewMyCmd()*cobra.Command{//Here is where we define the PreRun func, using the verbose flag value//We use the standard output for logs.rootCmd.PersistentPreRunE=func(cmd*cobra.Command,args[]string)error{iferr:=setUpLogs(os.Stdout,v);err!=nil{returnerr}returnnil}//Here is where we bind the verbose flag//Default value is the warn levelrootCmd.PersistentFlags().StringVarP(&v,"verbosity","v",logrus.WarnLevel.String(),"Log level (debug, info, warn, error, fatal, panic")returnrootCmd}//setUpLogs set the log output ans the log levelfuncsetUpLogs(outio.Writer,levelstring)error{logrus.SetOutput(out)lvl,err:=logrus.ParseLevel(level)iferr!=nil{returnerr}logrus.SetLevel(lvl)returnnil}
Enter fullscreen modeExit fullscreen mode

Once thePersistentPreRun func defined, you call easily create a sub-command which will use the logger.

varsubCmd=&cobra.Command{Use:"subcmd",Short:"subcmd is a subcommand of the main cmd",Run:func(cmd*cobra.Command,args[]string){runSubCmd()},}//...//Inside the NewMyCmd() funcrootCmd.AddCommand(NewSubCmd())//...//NewSubCmd return the a sub cobra commandfuncNewSubCmd()*cobra.Command{returnsubCmd}funcrunSubCmd(){logrus.Debug("debug log")}
Enter fullscreen modeExit fullscreen mode

This will produce :

$go run main.go subcmd-v debugDEBU[0000] debug log
Enter fullscreen modeExit fullscreen mode

By default, logrus is configured on Info level and the default value for my flag is Warn. Son the result proves it works ;-)

You are done !

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Joined

Trending onDEV CommunityHot

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp