{"id":2399,"date":"2023-08-24T22:31:52","date_gmt":"2023-08-24T22:31:52","guid":{"rendered":"https:\/\/www.danielpradilla.info\/blog\/?p=2399"},"modified":"2023-08-24T22:32:02","modified_gmt":"2023-08-24T22:32:02","slug":"my-python-logging-setup","status":"publish","type":"post","link":"https:\/\/www.danielpradilla.info\/blog\/my-python-logging-setup\/","title":{"rendered":"My Python logging setup"},"content":{"rendered":"<p>Working on various Python projects has taught me the importance of consistent logging, especially when dealing with distributed computing frameworks like Spark. Logging is not just about keeping track of errors or information; it&#8217;s about having a detailed and systematic record of the operations to understand the flow of your program and quickly diagnose issues.<\/p>\n<h3>The Essentials: Timestamp and Function Name<\/h3>\n<p>For any logging setup, two pieces of information are absolutely crucial:<\/p>\n<p><strong>Timestamp:<\/strong> especially vital in distributed systems like Spark, where tasks can run in parallel, and timing can be crucial for understanding the sequence of events.<\/p>\n<p><strong>Function Name:<\/strong> to trace back the exact point of failure or point of interest.<\/p>\n<p>&nbsp;<\/p>\n<h3>My Python Logging Setup<\/h3>\n<p>Here\u2019s a basic setup I use to ensure both the timestamp and the function name are always logged:<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nimport logging\r\n\r\nlogging.basicConfig(\r\n    level=logging.INFO, \r\n    format=&#039;%(asctime)s &#x5B;%(levelname)s] - %(funcName)s: %(message)s&#039;,\r\n    datefmt=&#039;%Y-%m-%d %H:%M:%S&#039;\r\n)\r\n\r\nlogger = logging.getLogger(__name__)\r\n\r\ndef sample_function():\r\n    logger.info(&quot;This is a sample log entry.&quot;)\r\n\r\n\r\n<\/pre>\n<p>The above code will produce an output like this:<\/p>\n<pre>2023-08-19 14:30:25 [INFO] - sample_function: This is a sample log entry.<\/pre>\n<p>Different stages of development or different scenarios might require varying levels of log detail. Sometimes, you want to capture every single event (debug mode), other times just informational messages, and on certain occasions, only errors. Having the ability to dynamically adjust the log level provides this flexibility.<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\n\r\ndef setup_logger(level=&#039;INFO&#039;):\r\n    numeric_level = getattr(logging, level.upper(), None)\r\n    if not isinstance(numeric_level, int):\r\n        raise ValueError(f&#039;Invalid log level: {level}&#039;)\r\n\r\n    logging.basicConfig(\r\n        level=numeric_level, \r\n        format=&#039;%(asctime)s &#x5B;%(levelname)s] - %(funcName)s: %(message)s&#039;,\r\n        datefmt=&#039;%Y-%m-%d %H:%M:%S&#039;\r\n    )\r\n    return logging.getLogger(__name__)\r\n\r\n# Example usage:\r\nlogger = setup_logger(&#039;DEBUG&#039;)\r\n\r\ndef sample_function():\r\n    logger.debug(&quot;This is a debug message.&quot;)\r\n    logger.info(&quot;This is an info message.&quot;)\r\n    logger.error(&quot;This is an error message.&quot;)\r\n\r\n<\/pre>\n<p>Whenever I use AWS Glue, I can configure a parameter called LOG_LEVEL which I can set to the desired value depending on the development stage I&#8217;m at. the logging module in Python accepts text values for log levels, such as &#8216;DEBUG&#8217;, &#8216;INFO&#8217;, &#8216;WARNING&#8217;, &#8216;ERROR&#8217;, and &#8216;CRITICAL&#8217;<\/p>\n<pre class=\"brush: python; title: ; notranslate\" title=\"\">\r\nimport sys\r\nimport logging\r\nfrom awsglue.utils import getResolvedOptions\r\n\r\ndef setup_logger(level=&#039;INFO&#039;):\r\n    numeric_level = getattr(logging, level.upper(), None)\r\n    if not isinstance(numeric_level, int):\r\n        raise ValueError(f&#039;Invalid log level: {level}&#039;)\r\n\r\n    logging.basicConfig(\r\n        level=numeric_level, \r\n        format=&#039;%(asctime)s &#x5B;%(levelname)s] - %(funcName)s: %(message)s&#039;,\r\n        datefmt=&#039;%Y-%m-%d %H:%M:%S&#039;\r\n    )\r\n    return logging.getLogger(__name__)\r\n\r\n# Read log level from the job arguments\r\nargs = getResolvedOptions(sys.argv, &#x5B;&#039;LOG_LEVEL&#039;])\r\nlog_level = args&#x5B;&#039;LOG_LEVEL&#039;]\r\n\r\nlogger = setup_logger(log_level)\r\n\r\ndef sample_function():\r\n    logger.debug(&quot;This is a debug message.&quot;)\r\n    logger.info(&quot;This is an info message.&quot;)\r\n    logger.error(&quot;This is an error message.&quot;)\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Working on various Python projects has taught me the importance of consistent logging, especially when dealing with distributed computing frameworks like Spark. Logging is not just about keeping track of errors or information; it&#8217;s about having a detailed and systematic record of the operations to understand the flow of your program and quickly diagnose issues.&hellip; <a class=\"more-link\" href=\"https:\/\/www.danielpradilla.info\/blog\/my-python-logging-setup\/\">Continue reading <span class=\"screen-reader-text\">My Python logging setup<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":2400,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[331],"tags":[341],"class_list":["post-2399","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software-development-en-en","tag-python","entry"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2023\/08\/5aadc010-b913-4eb0-9388-cd8d6c743271.jpg","jetpack_shortlink":"https:\/\/wp.me\/p1tlzy-CH","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":2302,"url":"https:\/\/www.danielpradilla.info\/blog\/aws-lambda-python\/","url_meta":{"origin":2399,"position":0},"title":"10 things I learned while deploying my first python function to AWS Lambda","author":"Daniel Pradilla","date":"04\/01\/2019","format":false,"excerpt":"I spent a few days on and off trying to deploy a Flask REST service to AWS Lambda, just to experience what the cool kids were talking about. These are some of the things I learned along the way: \u00a0 Zappa is the easiest packager\/deployer for python (as of December\u2026","rel":"","context":"In &quot;Software Dev.&quot;","block_context":{"text":"Software Dev.","link":"https:\/\/www.danielpradilla.info\/blog\/category\/software-development-en-en\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2019\/01\/AWS-Lambda-290x300.png?resize=350%2C200&ssl=1","width":350,"height":200},"classes":[]},{"id":2224,"url":"https:\/\/www.danielpradilla.info\/blog\/pentaho-is-slow-for-servers-with-too-many-home-directories\/","url_meta":{"origin":2399,"position":1},"title":"Pentaho is slow for servers with too many home directories","author":"Daniel Pradilla","date":"28\/04\/2018","format":false,"excerpt":"Over the course of two years, browsing solutions on our Pentaho 5.4 server became progressively slow. It came to a point in which you had to wait 2-3 minutes to see the list of solutions in the Pentaho User Console. The catalina log didn't say much and we didn't have\u2026","rel":"","context":"In &quot;Software Dev.&quot;","block_context":{"text":"Software Dev.","link":"https:\/\/www.danielpradilla.info\/blog\/category\/software-development-en-en\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":2416,"url":"https:\/\/www.danielpradilla.info\/blog\/echotree\/","url_meta":{"origin":2399,"position":2},"title":"EchoTree","author":"Daniel Pradilla","date":"03\/02\/2026","format":false,"excerpt":"For years now I kept some of my social accounts alive with a Python script. It read from a collection of RSS feeds and shared at random times. It worked, my feeds stayed active, and people asked me what was I doing reading at 3am. The script had a bit\u2026","rel":"","context":"In &quot;Best of&quot;","block_context":{"text":"Best of","link":"https:\/\/www.danielpradilla.info\/blog\/category\/bestof\/"},"img":{"alt_text":"EchoTree","src":"https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2026\/02\/echotree.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2026\/02\/echotree.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2026\/02\/echotree.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2026\/02\/echotree.jpg?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":2205,"url":"https:\/\/www.danielpradilla.info\/blog\/linear-optimization-with-or-tools\/","url_meta":{"origin":2399,"position":3},"title":"Linear Optimization with or-tools","author":"Daniel Pradilla","date":"07\/06\/2017","format":false,"excerpt":"\u00a0 Getting started Over the last couple of months I've been getting my feet wet with linear programming and mathematical optimisation. I got a sense of how it all worked from this Discrete Optimisation course in Coursera and googling around I discovered that there are a ton of tools out\u2026","rel":"","context":"In &quot;Best of&quot;","block_context":{"text":"Best of","link":"https:\/\/www.danielpradilla.info\/blog\/category\/bestof\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2017\/06\/grocery_bag_brown_bag.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2017\/06\/grocery_bag_brown_bag.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2017\/06\/grocery_bag_brown_bag.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2017\/06\/grocery_bag_brown_bag.jpg?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":2229,"url":"https:\/\/www.danielpradilla.info\/blog\/linear-optimization-with-or-tools-containerizing-a-gunicorn-web-application\/","url_meta":{"origin":2399,"position":4},"title":"Linear optimization with or-tools: containerizing a gunicorn web application","author":"Daniel Pradilla","date":"15\/05\/2018","format":false,"excerpt":"Previously, we left our app working with our local python+gunicorn+nginx installation. In order to get there we had to do quite a bit of configuration and if we wanted to deploy this in a server or send it to a friend, we would have to go through a very error-prone\u2026","rel":"","context":"In &quot;Software Dev.&quot;","block_context":{"text":"Software Dev.","link":"https:\/\/www.danielpradilla.info\/blog\/category\/software-development-en-en\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2018\/05\/docker.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2018\/05\/docker.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2018\/05\/docker.jpg?resize=525%2C300&ssl=1 1.5x"},"classes":[]},{"id":2212,"url":"https:\/\/www.danielpradilla.info\/blog\/linear-optimization-with-or-tools-building-a-web-front-end-with-falcon-and-gunicorn\/","url_meta":{"origin":2399,"position":5},"title":"Linear Optimization with or-tools \u00e2\u20ac\u201d building a web front-end with falcon and gunicorn","author":"Daniel Pradilla","date":"14\/11\/2017","format":false,"excerpt":"In a previous post, I put together a script for solving a linear optimisation problem using Google's OR-tools. This python script is callable from the command line and you kinda need to know what you are doing and how to organize the parameters. So, in order to address this difficulty,\u2026","rel":"","context":"In &quot;Software Dev.&quot;","block_context":{"text":"Software Dev.","link":"https:\/\/www.danielpradilla.info\/blog\/category\/software-development-en-en\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2017\/11\/groceryshopping.gif?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2017\/11\/groceryshopping.gif?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2017\/11\/groceryshopping.gif?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/www.danielpradilla.info\/blog\/wp-content\/uploads\/2017\/11\/groceryshopping.gif?resize=700%2C400&ssl=1 2x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.danielpradilla.info\/blog\/wp-json\/wp\/v2\/posts\/2399","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.danielpradilla.info\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.danielpradilla.info\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.danielpradilla.info\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.danielpradilla.info\/blog\/wp-json\/wp\/v2\/comments?post=2399"}],"version-history":[{"count":0,"href":"https:\/\/www.danielpradilla.info\/blog\/wp-json\/wp\/v2\/posts\/2399\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.danielpradilla.info\/blog\/wp-json\/wp\/v2\/media\/2400"}],"wp:attachment":[{"href":"https:\/\/www.danielpradilla.info\/blog\/wp-json\/wp\/v2\/media?parent=2399"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.danielpradilla.info\/blog\/wp-json\/wp\/v2\/categories?post=2399"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.danielpradilla.info\/blog\/wp-json\/wp\/v2\/tags?post=2399"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}