{"id":1307,"date":"2016-03-21T10:52:06","date_gmt":"2016-03-21T08:52:06","guid":{"rendered":"http:\/\/www.ludovicocaldara.net\/dba\/?p=1307"},"modified":"2016-03-21T10:52:27","modified_gmt":"2016-03-21T08:52:27","slug":"bash-tips-4-use-logging-levels","status":"publish","type":"post","link":"https:\/\/www.ludovicocaldara.net\/dba\/bash-tips-4-use-logging-levels\/","title":{"rendered":"Bash tips &#038; tricks [ep. 4]: Use logging levels"},"content":{"rendered":"<p>This is the fourth epidose of a <a href=\"https:\/\/www.ludovicocaldara.net\/dba\/bash-tips-1-personal-accounts-permissions\/\">small series<\/a>.<\/p>\n<p><strong>Description:<\/strong><\/p>\n<p>Support different logging levels natively in your scripts so that your code will be more stable and maintainable.<\/p>\n<p><strong>BAD:<\/strong><\/p>\n<pre class=\"lang:sh decode:true\">#!\/bin\/bash -l\r\n...\r\n# for debug only, comment out when OK\r\necho $a \r\ndo_something $a\r\n\r\n# echo $? # sometimes does not work?<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>\u00a0GOOD:<\/strong><\/p>\n<p>Nothing to invent, there are already a few blog posts around about the best practices for log messages. I personally like the one from <a href=\"http:\/\/www.goodmami.org\/\">Michael Wayne Goodman<\/a>:<\/p>\n<p><a href=\"http:\/\/www.goodmami.org\/2011\/07\/04\/Simple-logging-in-BASH-scripts.html\">http:\/\/www.goodmami.org\/2011\/07\/04\/Simple-logging-in-BASH-scripts.html<\/a><\/p>\n<p>I have reused his code in my scripts with very few modifications to fit my needs:<\/p>\n<pre class=\"lang:sh decode:true \">### verbosity levels\r\nsilent_lvl=0\r\ncrt_lvl=1\r\nerr_lvl=2\r\nwrn_lvl=3\r\nntf_lvl=4\r\ninf_lvl=5\r\ndbg_lvl=6\r\n\r\n## esilent prints output even in silent mode\r\nfunction esilent () { verb_lvl=$silent_lvl elog \"$@\" ;}\r\nfunction enotify () { verb_lvl=$ntf_lvl elog \"$@\" ;}\r\nfunction eok ()    { verb_lvl=$ntf_lvl elog \"SUCCESS - $@\" ;}\r\nfunction ewarn ()  { verb_lvl=$wrn_lvl elog \"${colylw}WARNING${colrst} - $@\" ;}\r\nfunction einfo ()  { verb_lvl=$inf_lvl elog \"${colwht}INFO${colrst} ---- $@\" ;}\r\nfunction edebug () { verb_lvl=$dbg_lvl elog \"${colgrn}DEBUG${colrst} --- $@\" ;}\r\nfunction eerror () { verb_lvl=$err_lvl elog \"${colred}ERROR${colrst} --- $@\" ;}\r\nfunction ecrit ()  { verb_lvl=$crt_lvl elog \"${colpur}FATAL${colrst} --- $@\" ;}\r\nfunction edumpvar () { for var in $@ ; do edebug \"$var=${!var}\" ; done }\r\nfunction elog() {\r\n        if [ $verbosity -ge $verb_lvl ]; then\r\n                datestring=`date +\"%Y-%m-%d %H:%M:%S\"`\r\n                echo -e \"$datestring - $@\"\r\n        fi\r\n}\r\n<\/pre>\n<p>The edumpvar is handy to have the status of several variables at once:<\/p>\n<pre class=\"lang:sh decode:true   \">#!\/bin\/bash -l\r\n# code\r\n#...\r\n\r\nverbosity=6\r\n\r\nedumpvar ORACLE_SID ORACLE_HOME\r\n\r\n&lt;output&gt;\r\n2016-03-15 23:06:10 - DEBUG --- ORACLE_SID=orcl12c\r\n2016-03-15 23:06:10 - DEBUG --- ORACLE_HOME=\/u01\/app\/oracle\/product\/12.1.0.2\r\n&lt;\/output&gt;<\/pre>\n<p>If you couple the verbosity level with input parameters you can have something quite clever (e.g. -s for silent, -V for verbose, -G for debug). I&#8217;m putting everything into one single snippet just as example, but as you can imagine, you should seriously put all the fixed variables and functions inside an external file that you will systematically include in your scripts:<\/p>\n<pre class=\"lang:sh decode:true \">#!\/bin\/bash -l\r\n\r\ncolblk='\\033[0;30m' # Black - Regular\r\ncolred='\\033[0;31m' # Red\r\ncolgrn='\\033[0;32m' # Green\r\ncolylw='\\033[0;33m' # Yellow\r\ncolpur='\\033[0;35m' # Purple\r\ncolrst='\\033[0m'    # Text Reset\r\n\r\nverbosity=4\r\n\r\n### verbosity levels\r\nsilent_lvl=0\r\ncrt_lvl=1\r\nerr_lvl=2\r\nwrn_lvl=3\r\nntf_lvl=4\r\ninf_lvl=5\r\ndbg_lvl=6\r\n\r\n## esilent prints output even in silent mode\r\nfunction esilent () { verb_lvl=$silent_lvl elog \"$@\" ;}\r\nfunction enotify () { verb_lvl=$ntf_lvl elog \"$@\" ;}\r\nfunction eok ()    { verb_lvl=$ntf_lvl elog \"SUCCESS - $@\" ;}\r\nfunction ewarn ()  { verb_lvl=$wrn_lvl elog \"${colylw}WARNING${colrst} - $@\" ;}\r\nfunction einfo ()  { verb_lvl=$inf_lvl elog \"${colwht}INFO${colrst} ---- $@\" ;}\r\nfunction edebug () { verb_lvl=$dbg_lvl elog \"${colgrn}DEBUG${colrst} --- $@\" ;}\r\nfunction eerror () { verb_lvl=$err_lvl elog \"${colred}ERROR${colrst} --- $@\" ;}\r\nfunction ecrit ()  { verb_lvl=$crt_lvl elog \"${colpur}FATAL${colrst} --- $@\" ;}\r\nfunction edumpvar () { for var in $@ ; do edebug \"$var=${!var}\" ; done }\r\nfunction elog() {\r\n        if [ $verbosity -ge $verb_lvl ]; then\r\n                datestring=`date +\"%Y-%m-%d %H:%M:%S\"`\r\n                echo -e \"$datestring - $@\"\r\n        fi\r\n}\r\n\r\nOPTIND=1\r\nwhile getopts \":sVG\" opt ; do\r\n        case $opt in\r\n        s)\r\n                verbosity=$silent_lvl\r\n                edebug \"-s specified: Silent mode\"\r\n                ;;\r\n        V)\r\n                verbosity=$inf_lvl\r\n                edebug \"-V specified: Verbose mode\"\r\n                ;;\r\n        G)\r\n                verbosity=$dbg_lvl\r\n                edebug \"-G specified: Debug mode\"\r\n                ;;\r\n        esac\r\ndone\r\n\r\newarn \"this is a warning\"\r\neerror \"this is an error\"\r\neinfo \"this is an information\"\r\nedebug \"debugging\"\r\necrit \"CRITICAL MESSAGE!\"\r\nedumpvar ORACLE_SID\r\n<\/pre>\n<p>Example:<\/p>\n<pre class=\"lang:sh decode:true\">$ example.sh -s<\/pre>\n<pre class=\"lang:sh decode:true\">$ example.sh<\/pre>\n<p><a href=\"https:\/\/www.ludovicocaldara.net\/dba\/wp-content\/uploads\/2016\/03\/bash-colour-output-normal.png\"><img loading=\"lazy\" decoding=\"async\" class=\"  wp-image-1313 alignnone\" src=\"https:\/\/www.ludovicocaldara.net\/dba\/wp-content\/uploads\/2016\/03\/bash-colour-output-normal.png\" alt=\"bash-colour-output-normal\" width=\"392\" height=\"52\" \/><\/a><\/p>\n<pre class=\"lang:sh decode:true \">$ example.sh -V<\/pre>\n<p><a href=\"https:\/\/www.ludovicocaldara.net\/dba\/wp-content\/uploads\/2016\/03\/bash-colour-output-verbose.png\"><img loading=\"lazy\" decoding=\"async\" class=\"  wp-image-1314 alignnone\" src=\"https:\/\/www.ludovicocaldara.net\/dba\/wp-content\/uploads\/2016\/03\/bash-colour-output-verbose.png\" alt=\"bash-colour-output-verbose\" width=\"396\" height=\"64\" \/><\/a><\/p>\n<pre class=\"lang:sh decode:true \">$ example.sh -G<\/pre>\n<p><a href=\"https:\/\/www.ludovicocaldara.net\/dba\/wp-content\/uploads\/2016\/03\/bash-colour-output-debug.png\"><img loading=\"lazy\" decoding=\"async\" class=\"  wp-image-1312 alignnone\" src=\"https:\/\/www.ludovicocaldara.net\/dba\/wp-content\/uploads\/2016\/03\/bash-colour-output-debug.png\" alt=\"bash-colour-output-debug\" width=\"437\" height=\"101\" \/><\/a><\/p>\n<p>It does not take into account the output file. That will be part of the next tip \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is the fourth epidose of a small series. Description: Support different logging levels natively in your scripts so that your code will be more stable and maintainable. BAD: #!\/bin\/bash -l &#8230; # for debug only, comment out when OK &hellip; <a href=\"https:\/\/www.ludovicocaldara.net\/dba\/bash-tips-4-use-logging-levels\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,132],"tags":[],"class_list":["post-1307","post","type-post","status-publish","format-standard","hentry","category-linux","category-triblog"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.ludovicocaldara.net\/dba\/wp-json\/wp\/v2\/posts\/1307","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ludovicocaldara.net\/dba\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ludovicocaldara.net\/dba\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ludovicocaldara.net\/dba\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ludovicocaldara.net\/dba\/wp-json\/wp\/v2\/comments?post=1307"}],"version-history":[{"count":7,"href":"https:\/\/www.ludovicocaldara.net\/dba\/wp-json\/wp\/v2\/posts\/1307\/revisions"}],"predecessor-version":[{"id":1330,"href":"https:\/\/www.ludovicocaldara.net\/dba\/wp-json\/wp\/v2\/posts\/1307\/revisions\/1330"}],"wp:attachment":[{"href":"https:\/\/www.ludovicocaldara.net\/dba\/wp-json\/wp\/v2\/media?parent=1307"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ludovicocaldara.net\/dba\/wp-json\/wp\/v2\/categories?post=1307"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ludovicocaldara.net\/dba\/wp-json\/wp\/v2\/tags?post=1307"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}