For those creating their own CLI tool

If you have played around with any command line interface tools, such as Particle CLI or Git UI, you’ll notice that they oftentimes will have a —verbose or -v option with their commands. This allows you to change log levels within the program, outputting as little or as much as you desire.

This example CLI tool makes use of the Click library for Python. If you are having trouble getting started, check out my first blog on making a professional-looking CLI tool or Click’s documentation.

Why Do I Need the Verbose Option?

When using your CLI tool, users may have a variety of reasons for wanting to change how much information is displayed.

If a user is debugging a process or needs to know a little more about the error being thrown, they may want to use the verbose option to dump out more logs and information to nail down their issue.

On the other side, a user may just want to be quickly using the CLI commands and does not want or need to see the multitudes of code on every successful run. Some users may not have a firm grasp on functionality behind your CLI tool and it’ll look messy and confusing to them.

verbose option
What your user sees when you print out everything

Logging Levels

Here’s how I set up my ‘cool_logger’ in mysupercoolscript from the last blog post.

First off, click.option is added. This will add the option —verbose or -v. Both of these options will dump out the same log, one just being longer and the other quicker to type out. Secondly, we want to edit the mysupercoolscript definition. Before, the only parameter was self. Now, it will take in the parameters self and verbose. Then, the if/else statement will set the log level to either DEBUG or INFO depending on if the verbose option was given or not.

@click.group()
@click.option('--verbose', '-v', is_flag=True, help="Will print more logging messages.")
@click.pass_context
def mysupercoolscript(self, verbose):
  if verbose:
    cool_logger.setLevel(logging.DEBUG)
  else:
    cool_logger.setLevel(logging.INFO)
  pass

The next step and easiest way to implement the verbose option is to set logging levels. If you are a bit confused on how python’s logging works, lay your confusion to rest here. This is in “main” in mysupercoolscript.py file, which you can find a link to at the bottom of this post.

import logging

cool_logger = logging.getLogger('cool_logger')
cl = logging.StreamHandler()
cl.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(message)s')
cl.setFormatter(formatter)
cool_logger.addHandler(cl)

Adding the above code snippit with your own logger name (or you could keep cool_logger 😎) will initialize your logger. Now, we need to add a bit to our main function in mysupercoolscript.py to allow the option to work. In the initialization of our group, we will add:

Now on to the final piece of the puzzle. Instead of using the print or another function, we will use cool_logger.debug and cool_logger.info based on when we want our information printed. With the current setup, when you want something printed all the time, you want to use cool_logger.info. When you want a line to print only when the verbose option is used, you want to use cool_logger.debug.

Guide on Where and When to Use Different Levels

Now Python’s logger actually has six different levels for you to utilize, but I’ll only be showing off two of them: DEBUG and INFO.

Here at Dojo Five, we try to keep our CLI tool’s logger to a guideline so we keep it nice and tidy.

Generally, keeping your reporting short and sweet, especially on successful runs. Only mention important parts, and be descriptive but short.

For failures, we will want to give one error line. It should be short and to the point, but readable.

For example, say you have a command build that compiles a script, then stores the output into a folder named outputs.

Running build may yield:

Compiled Successfully.

ERROR: Output not stored. 
Message: Directory outputs not found

Whereas if you ran build --verbose, it may yield a more-inclusive:

Building test.cpp...
Building test2.cpp...
WARNING: Variable A is delcared but not used.

Compiled Successfully.

Error during output stage:
ERROR: Output not stored. 
Directory: outputs not found.
Output files will not be saved.

The Dry Stuff (Code)

Just in case you’re a bit confused about how everything is being implemented, you can find my source code for these examples on gitlab: source code.

There you can find both setup.py and supercoolscript.py

What are some things you’re struggling with on your CLI? Feel free to email me directly at cole.spear@dojofive.com if you would like help. Good luck with your future CLI endeavors!

And if you have questions about an embedded project you’re working on, Dojo Five can help you with all aspects of your devops for embedded journey! We are always happy to hear about cool projects or interesting problems to solve, so don’t hesitate to reach out and chat with us on LinkedIn or through email!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.