{"id":10745,"date":"2026-01-13T21:06:39","date_gmt":"2026-01-13T21:06:39","guid":{"rendered":"https:\/\/techtrendfeed.com\/?p=10745"},"modified":"2026-01-13T21:06:39","modified_gmt":"2026-01-13T21:06:39","slug":"the-full-information-to-logging-for-python-builders","status":"publish","type":"post","link":"https:\/\/techtrendfeed.com\/?p=10745","title":{"rendered":"The Full Information to Logging for Python Builders"},"content":{"rendered":"<p> <br \/>\n<\/p>\n<div id=\"post-\">\n<p>    <center><img decoding=\"async\" alt=\"The Complete Guide to Logging for Python Developers\" width=\"100%\" class=\"perfmatters-lazy\" src=\"https:\/\/www.kdnuggets.com\/wp-content\/uploads\/bala-python-logging-guide.png\"\/><img decoding=\"async\" src=\"https:\/\/www.kdnuggets.com\/wp-content\/uploads\/bala-python-logging-guide.png\" alt=\"The Complete Guide to Logging for Python Developers\" width=\"100%\"\/><br \/><span>Picture by Creator<\/span><\/center><br \/>\n\u00a0<\/p>\n<h2><span>#\u00a0<\/span>Introduction<\/h2>\n<p>\u00a0<br \/>Most Python builders deal with logging as an afterthought. They throw round <code style=\"background: #F5F5F5;\">print()<\/code> statements throughout growth, perhaps swap to primary logging later, and assume that&#8217;s sufficient. However when points come up in manufacturing, they be taught they&#8217;re lacking the context wanted to diagnose issues effectively.<\/p>\n<p>Correct logging strategies provide you with visibility into software habits, efficiency patterns, and error situations. With the precise method, you may hint consumer actions, establish bottlenecks, and debug points with out reproducing them domestically. Good logging turns debugging from guesswork into systematic problem-solving.<\/p>\n<p>This text covers the important logging patterns that Python builders can use. You&#8217;ll discover ways to construction log messages for searchability, deal with exceptions with out shedding context, and configure logging for various environments. We&#8217;ll begin with the fundamentals and work our method as much as extra superior logging methods that you need to use in tasks immediately. We will likely be utilizing solely the <strong><a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/docs.python.org\/3\/library\/logging.html\" target=\"_blank\">logging module<\/a><\/strong>.<\/p>\n<p><strong><a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/github.com\/balapriyac\/python-basics\/tree\/main\/logging-for-python-devs\" target=\"_blank\">You could find the code on GitHub<\/a><\/strong>.<\/p>\n<p>\u00a0<\/p>\n<h2><span>#\u00a0<\/span>Setting Up Your First Logger<\/h2>\n<p>\u00a0<br \/>As a substitute of leaping straight to complicated configurations, allow us to perceive what a logger really does. We&#8217;ll create a primary logger that writes to each the console and a file.<br \/>\u00a0<\/p>\n<div style=\"width: 98%; overflow: auto; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background: #F5F5F5;\">\n<pre><code>import logging&#13;\n&#13;\nlogger = logging.getLogger('my_app')&#13;\nlogger.setLevel(logging.DEBUG)&#13;\n&#13;\nconsole_handler = logging.StreamHandler()&#13;\nconsole_handler.setLevel(logging.INFO)&#13;\n&#13;\nfile_handler = logging.FileHandler('app.log')&#13;\nfile_handler.setLevel(logging.DEBUG)&#13;\n&#13;\nformatter = logging.Formatter(&#13;\n    '%(asctime)s - %(title)s - %(levelname)s - %(message)s'&#13;\n)&#13;\nconsole_handler.setFormatter(formatter)&#13;\nfile_handler.setFormatter(formatter)&#13;\n&#13;\nlogger.addHandler(console_handler)&#13;\nlogger.addHandler(file_handler)&#13;\n&#13;\nlogger.debug('It is a debug message')&#13;\nlogger.information('Utility began')&#13;\nlogger.warning('Disk house operating low')&#13;\nlogger.error('Failed to hook up with database')&#13;\nlogger.crucial('System shutting down')<\/code><\/pre>\n<\/div>\n<p>\u00a0<\/p>\n<p>Here&#8217;s what every bit of the code does.<\/p>\n<p>The <code style=\"background: #F5F5F5;\">getLogger()<\/code> perform creates a named logger occasion. Consider it as making a channel on your logs. The title &#8216;my_app&#8217; helps you establish the place logs come from in bigger purposes.<\/p>\n<p>We set the logger stage to <code style=\"background: #F5F5F5;\">DEBUG<\/code>, which implies it can course of all messages. Then we create two handlers: one for console output and one for file output. Handlers management the place logs go.<\/p>\n<p>The console handler solely exhibits <code style=\"background: #F5F5F5;\">INFO<\/code> stage and above, whereas the file handler captures all the things, together with <code style=\"background: #F5F5F5;\">DEBUG<\/code> messages. That is helpful since you need detailed logs in recordsdata however cleaner output on display screen.<\/p>\n<p>The formatter determines how your log messages look. The format string makes use of placeholders like <code style=\"background: #F5F5F5;\">%(asctime)s<\/code> for the timestamp and <code style=\"background: #F5F5F5;\">%(levelname)s<\/code> for severity.<\/p>\n<p>\u00a0<\/p>\n<h2><span>#\u00a0<\/span>Understanding Log Ranges and When to Use Every<\/h2>\n<p>\u00a0<br \/>Python&#8217;s <strong><a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/docs.python.org\/3\/library\/logging.html\" target=\"_blank\">logging module<\/a><\/strong> has 5 commonplace ranges, and figuring out when to make use of every one is necessary for helpful logs.<\/p>\n<p>Right here is an instance:<br \/>\u00a0<\/p>\n<div style=\"width: 98%; overflow: auto; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background: #F5F5F5;\">\n<pre><code>logger = logging.getLogger('payment_processor')&#13;\nlogger.setLevel(logging.DEBUG)&#13;\n&#13;\nhandler = logging.StreamHandler()&#13;\nhandler.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))&#13;\nlogger.addHandler(handler)&#13;\n&#13;\ndef process_payment(user_id, quantity):&#13;\n    logger.debug(f'Beginning fee processing for consumer {user_id}')&#13;\n&#13;\n    if quantity &lt;= 0:&#13;\n        logger.error(f'Invalid fee quantity: {quantity}')&#13;\n        return False&#13;\n&#13;\n    logger.information(f'Processing ${quantity} fee for consumer {user_id}')&#13;\n&#13;\n    if quantity &gt; 10000:&#13;\n        logger.warning(f'Giant transaction detected: ${quantity}')&#13;\n&#13;\n    attempt:&#13;\n        # Simulate fee processing&#13;\n        success = charge_card(user_id, quantity)&#13;\n        if success:&#13;\n            logger.information(f'Cost profitable for consumer {user_id}')&#13;\n            return True&#13;\n        else:&#13;\n            logger.error(f'Cost failed for consumer {user_id}')&#13;\n            return False&#13;\n    besides Exception as e:&#13;\n        logger.crucial(f'Cost system crashed: {e}', exc_info=True)&#13;\n        return False&#13;\n&#13;\ndef charge_card(user_id, quantity):&#13;\n    # Simulated fee logic&#13;\n    return True&#13;\n&#13;\nprocess_payment(12345, 150.00)&#13;\nprocess_payment(12345, 15000.00)<\/code><\/pre>\n<\/div>\n<p>\u00a0<\/p>\n<p>Allow us to break down when to make use of every stage:<\/p>\n<ul>\n<li><strong>DEBUG<\/strong> is for detailed info helpful throughout growth. You&#8217;d use it for variable values, loop iterations, or step-by-step execution traces. These are often disabled in manufacturing.\n<\/li>\n<li><strong>INFO<\/strong> marks regular operations that you just need to report. Beginning a server, finishing a process, or profitable transactions go right here. These verify your software is working as anticipated.\n<\/li>\n<li><strong>WARNING<\/strong> alerts one thing sudden however not breaking. This contains low disk house, deprecated API utilization, or uncommon however dealt with conditions. The applying continues operating, however somebody ought to examine.\n<\/li>\n<li><strong>ERROR<\/strong> means one thing failed however the software can proceed. Failed database queries, validation errors, or community timeouts belong right here. The particular operation failed, however the app retains operating.\n<\/li>\n<li><strong>CRITICAL<\/strong> signifies critical issues which may trigger the applying to crash or lose information. Use this sparingly for catastrophic failures that want quick consideration.\n<\/li>\n<\/ul>\n<p>Whenever you run the above code, you&#8217;ll get:<br \/>\u00a0<\/p>\n<div style=\"width: 98%; overflow: auto; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background: #F5F5F5;\">\n<pre><code>DEBUG: Beginning fee processing for consumer 12345&#13;\nDEBUG:payment_processor:Beginning fee processing for consumer 12345&#13;\nINFO: Processing $150.0 fee for consumer 12345&#13;\nINFO:payment_processor:Processing $150.0 fee for consumer 12345&#13;\nINFO: Cost profitable for consumer 12345&#13;\nINFO:payment_processor:Cost profitable for consumer 12345&#13;\nDEBUG: Beginning fee processing for consumer 12345&#13;\nDEBUG:payment_processor:Beginning fee processing for consumer 12345&#13;\nINFO: Processing $15000.0 fee for consumer 12345&#13;\nINFO:payment_processor:Processing $15000.0 fee for consumer 12345&#13;\nWARNING: Giant transaction detected: $15000.0&#13;\nWARNING:payment_processor:Giant transaction detected: $15000.0&#13;\nINFO: Cost profitable for consumer 12345&#13;\nINFO:payment_processor:Cost profitable for consumer 12345&#13;\nTrue<\/code><\/pre>\n<\/div>\n<p>\u00a0<\/p>\n<p>Subsequent, allow us to proceed to grasp extra about logging exceptions.<\/p>\n<p>\u00a0<\/p>\n<h2><span>#\u00a0<\/span>Logging Exceptions Correctly<\/h2>\n<p>\u00a0<br \/>When exceptions happen, you want extra than simply the error message; you want the complete stack hint. Right here is learn how to seize exceptions successfully.<br \/>\u00a0<\/p>\n<div style=\"width: 98%; overflow: auto; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background: #F5F5F5;\">\n<pre><code>import json&#13;\n&#13;\nlogger = logging.getLogger('api_handler')&#13;\nlogger.setLevel(logging.DEBUG)&#13;\n&#13;\nhandler = logging.FileHandler('errors.log')&#13;\nformatter = logging.Formatter(&#13;\n    '%(asctime)s - %(title)s - %(levelname)s - %(message)s'&#13;\n)&#13;\nhandler.setFormatter(formatter)&#13;\nlogger.addHandler(handler)&#13;\n&#13;\ndef fetch_user_data(user_id):&#13;\n    logger.information(f'Fetching information for consumer {user_id}')&#13;\n&#13;\n    attempt:&#13;\n        # Simulate API name&#13;\n        response = call_external_api(user_id)&#13;\n        information = json.hundreds(response)&#13;\n        logger.debug(f'Acquired information: {information}')&#13;\n        return information&#13;\n    besides json.JSONDecodeError as e:&#13;\n        logger.error(&#13;\n            f'Didn't parse JSON for consumer {user_id}: {e}',&#13;\n            exc_info=True&#13;\n        )&#13;\n        return None&#13;\n    besides ConnectionError as e:&#13;\n        logger.error(&#13;\n            f'Community error whereas fetching consumer {user_id}',&#13;\n            exc_info=True&#13;\n        )&#13;\n        return None&#13;\n    besides Exception as e:&#13;\n        logger.crucial(&#13;\n            f'Sudden error in fetch_user_data: {e}',&#13;\n            exc_info=True&#13;\n        )&#13;\n        elevate&#13;\n&#13;\ndef call_external_api(user_id):&#13;\n    # Simulated API response&#13;\n    return '{\"id\": ' + str(user_id) + ', \"title\": \"John\"}'&#13;\n&#13;\nfetch_user_data(123)<\/code><\/pre>\n<\/div>\n<p>\u00a0<\/p>\n<p>The important thing right here is the <code style=\"background: #F5F5F5;\">exc_info=True<\/code> parameter. This tells the logger to incorporate the complete exception traceback in your logs. With out it, you solely get the error message, which regularly is just not sufficient to debug the issue.<\/p>\n<p>Discover how we catch particular exceptions first, then have a normal <code style=\"background: #F5F5F5;\">Exception<\/code> handler. The particular handlers allow us to present context-appropriate error messages. The final handler catches something sudden and re-raises it as a result of we have no idea learn how to deal with it safely.<\/p>\n<p>Additionally discover we log at <code style=\"background: #F5F5F5;\">ERROR<\/code> for anticipated exceptions (like community errors) however <code style=\"background: #F5F5F5;\">CRITICAL<\/code> for sudden ones. This distinction helps you prioritize when reviewing logs.<\/p>\n<p>\u00a0<\/p>\n<h2><span>#\u00a0<\/span>Making a Reusable Logger Configuration<\/h2>\n<p>\u00a0<br \/>Copying logger setup code throughout recordsdata is tedious and error-prone. Allow us to create a configuration perform you may import wherever in your mission.<br \/>\u00a0<\/p>\n<div style=\"width: 98%; overflow: auto; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background: #F5F5F5;\">\n<pre><code># logger_config.py&#13;\n&#13;\nimport logging&#13;\nimport os&#13;\nfrom datetime import datetime&#13;\n&#13;\n&#13;\ndef setup_logger(title, log_dir=\"logs\", stage=logging.INFO):&#13;\n    \"\"\"&#13;\n    Create a configured logger occasion&#13;\n&#13;\n    Args:&#13;\n        title: Logger title (often __name__ from calling module)&#13;\n        log_dir: Listing to retailer log recordsdata&#13;\n        stage: Minimal logging stage&#13;\n&#13;\n    Returns:&#13;\n        Configured logger occasion&#13;\n    \"\"\"&#13;\n    # Create logs listing if it would not exist&#13;\n&#13;\n    if not os.path.exists(log_dir):&#13;\n        os.makedirs(log_dir)&#13;\n    logger = logging.getLogger(title)&#13;\n&#13;\n    # Keep away from including handlers a number of occasions&#13;\n&#13;\n    if logger.handlers:&#13;\n        return logger&#13;\n    logger.setLevel(stage)&#13;\n&#13;\n    # Console handler - INFO and above&#13;\n&#13;\n    console_handler = logging.StreamHandler()&#13;\n    console_handler.setLevel(logging.INFO)&#13;\n    console_format = logging.Formatter(\"%(levelname)s - %(title)s - %(message)s\")&#13;\n    console_handler.setFormatter(console_format)&#13;\n&#13;\n    # File handler - all the things&#13;\n&#13;\n    log_filename = os.path.be part of(&#13;\n        log_dir, f\"{title.change('.', '_')}_{datetime.now().strftime('%Ypercentmpercentd')}.log\"&#13;\n    )&#13;\n    file_handler = logging.FileHandler(log_filename)&#13;\n    file_handler.setLevel(logging.DEBUG)&#13;\n    file_format = logging.Formatter(&#13;\n        \"%(asctime)s - %(title)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s\"&#13;\n    )&#13;\n    file_handler.setFormatter(file_format)&#13;\n&#13;\n    logger.addHandler(console_handler)&#13;\n    logger.addHandler(file_handler)&#13;\n&#13;\n    return logger<\/code><\/pre>\n<\/div>\n<p>\u00a0<\/p>\n<p>Now that you&#8217;ve got arrange <code style=\"background: #F5F5F5;\">logger_config<\/code>, you need to use it in your Python script like so:<br \/>\u00a0<\/p>\n<div style=\"width: 98%; overflow: auto; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background: #F5F5F5;\">\n<pre><code>from logger_config import setup_logger&#13;\n&#13;\nlogger = setup_logger(__name__)&#13;\n&#13;\ndef calculate_discount(value, discount_percent):&#13;\n    logger.debug(f'Calculating low cost: {value} * {discount_percent}%')&#13;\n    &#13;\n    if discount_percent &lt; 0 or discount_percent &gt; 100:&#13;\n        logger.warning(f'Invalid low cost share: {discount_percent}')&#13;\n        discount_percent = max(0, min(100, discount_percent))&#13;\n    &#13;\n    low cost = value * (discount_percent \/ 100)&#13;\n    final_price = value - low cost&#13;\n    &#13;\n    logger.information(f'Utilized {discount_percent}% low cost: ${value} -&gt; ${final_price}')&#13;\n    return final_price&#13;\n&#13;\ncalculate_discount(100, 20)&#13;\ncalculate_discount(100, 150)<\/code><\/pre>\n<\/div>\n<p>\u00a0<\/p>\n<p>This setup perform handles a number of necessary issues. First, it creates the logs listing if wanted, stopping crashes from lacking directories.<\/p>\n<p>The perform checks if handlers exist already earlier than including new ones. With out this examine, calling <code style=\"background: #F5F5F5;\">setup_logger<\/code> a number of occasions would create duplicate log entries.<\/p>\n<p>We generate dated log filenames routinely. This prevents log recordsdata from rising infinitely and makes it straightforward to seek out logs from particular dates.<\/p>\n<p>The file handler contains extra element than the console handler, together with perform names and line numbers. That is invaluable when debugging however would muddle console output.<\/p>\n<p>Utilizing <code style=\"background: #F5F5F5;\">__name__<\/code> because the logger title creates a hierarchy that matches your module construction. This allows you to management logging for particular components of your software independently.<\/p>\n<p>\u00a0<\/p>\n<h2><span>#\u00a0<\/span>Structuring Logs with Context<\/h2>\n<p>\u00a0<br \/>Plain textual content logs are fantastic for easy purposes, however structured logs with context make debugging a lot simpler. Allow us to add contextual info to our logs.<br \/>\u00a0<\/p>\n<div style=\"width: 98%; overflow: auto; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background: #F5F5F5;\">\n<pre><code>import json&#13;\nfrom datetime import datetime, timezone&#13;\n&#13;\nclass ContextLogger:&#13;\n    \"\"\"Logger wrapper that provides contextual info to all log messages\"\"\"&#13;\n&#13;\n    def __init__(self, title, context=None):&#13;\n        self.logger = logging.getLogger(title)&#13;\n        self.context = context or {}&#13;\n&#13;\n        handler = logging.StreamHandler()&#13;\n        formatter = logging.Formatter('%(message)s')&#13;\n        handler.setFormatter(formatter)&#13;\n        # Examine if handler already exists to keep away from duplicate handlers&#13;\n        if not any(isinstance(h, logging.StreamHandler) and h.formatter._fmt == '%(message)s' for h in self.logger.handlers):&#13;\n            self.logger.addHandler(handler)&#13;\n        self.logger.setLevel(logging.DEBUG)&#13;\n&#13;\n    def _format_message(self, message, stage, extra_context=None):&#13;\n        \"\"\"Format message with context as JSON\"\"\"&#13;\n        log_data = {&#13;\n            'timestamp': datetime.now(timezone.utc).isoformat(),&#13;\n            'stage': stage,&#13;\n            'message': message,&#13;\n            'context': {**self.context, **(extra_context or {})}&#13;\n        }&#13;\n        return json.dumps(log_data)&#13;\n&#13;\n    def debug(self, message, **kwargs):&#13;\n        self.logger.debug(self._format_message(message, 'DEBUG', kwargs))&#13;\n&#13;\n    def information(self, message, **kwargs):&#13;\n        self.logger.information(self._format_message(message, 'INFO', kwargs))&#13;\n&#13;\n    def warning(self, message, **kwargs):&#13;\n        self.logger.warning(self._format_message(message, 'WARNING', kwargs))&#13;\n&#13;\n    def error(self, message, **kwargs):&#13;\n        self.logger.error(self._format_message(message, 'ERROR', kwargs))<\/code><\/pre>\n<\/div>\n<p>\u00a0<\/p>\n<p>You should use the <code style=\"background: #F5F5F5;\">ContextLogger<\/code> like so:<br \/>\u00a0<\/p>\n<div style=\"width: 98%; overflow: auto; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background: #F5F5F5;\">\n<pre><code>def process_order(order_id, user_id):&#13;\n    logger = ContextLogger(__name__, context={&#13;\n        'order_id': order_id,&#13;\n        'user_id': user_id&#13;\n    })&#13;\n&#13;\n    logger.information('Order processing began')&#13;\n&#13;\n    attempt:&#13;\n        gadgets = fetch_order_items(order_id)&#13;\n        logger.information('Gadgets fetched', item_count=len(gadgets))&#13;\n&#13;\n        whole = calculate_total(gadgets)&#13;\n        logger.information('Whole calculated', whole=whole)&#13;\n&#13;\n        if whole &gt; 1000:&#13;\n            logger.warning('Excessive worth order', whole=whole, flagged=True)&#13;\n&#13;\n        return True&#13;\n    besides Exception as e:&#13;\n        logger.error('Order processing failed', error=str(e))&#13;\n        return False&#13;\n&#13;\ndef fetch_order_items(order_id):&#13;\n    return [{'id': 1, 'price': 50}, {'id': 2, 'price': 75}]&#13;\n&#13;\ndef calculate_total(gadgets):&#13;\n    return sum(merchandise['price'] for merchandise in gadgets)&#13;\n&#13;\nprocess_order('ORD-12345', 'USER-789')<\/code><\/pre>\n<\/div>\n<p>\u00a0<\/p>\n<p>This <code style=\"background: #F5F5F5;\">ContextLogger<\/code> wrapper does one thing helpful: it routinely contains context in each log message. The <code style=\"background: #F5F5F5;\">order_id<\/code> and <code style=\"background: #F5F5F5;\">user_id<\/code> get added to all logs with out repeating them in each logging name.<\/p>\n<p>The <strong><a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/docs.python.org\/3\/library\/json.html\" target=\"_blank\">JSON<\/a><\/strong> format makes these logs straightforward to parse and search.<\/p>\n<p>The <code style=\"background: #F5F5F5;\">**kwargs<\/code> in every logging technique allows you to add additional context to particular log messages. This combines international context (<code style=\"background: #F5F5F5;\">order_id<\/code>, <code style=\"background: #F5F5F5;\">user_id<\/code>) with native context (<code style=\"background: #F5F5F5;\">item_count<\/code>, <code style=\"background: #F5F5F5;\">whole<\/code>) routinely.<\/p>\n<p>This sample is very helpful in internet purposes the place you need request IDs, consumer IDs, or session IDs in each log message from a request.<\/p>\n<p>\u00a0<\/p>\n<h2><span>#\u00a0<\/span>Rotating Log Recordsdata to Stop Disk Area Points<\/h2>\n<p>\u00a0<br \/>Log recordsdata develop rapidly in manufacturing. With out rotation, they&#8217;ll ultimately fill your disk. Right here is learn how to implement computerized log rotation.<br \/>\u00a0<\/p>\n<div style=\"width: 98%; overflow: auto; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background: #F5F5F5;\">\n<pre><code>from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler&#13;\n&#13;\ndef setup_rotating_logger(title):&#13;\n    logger = logging.getLogger(title)&#13;\n    logger.setLevel(logging.DEBUG)&#13;\n&#13;\n    # Dimension-based rotation: rotate when file reaches 10MB&#13;\n    size_handler = RotatingFileHandler(&#13;\n        'app_size_rotation.log',&#13;\n        maxBytes=10 * 1024 * 1024,  # 10 MB&#13;\n        backupCount=5  # Preserve 5 outdated recordsdata&#13;\n    )&#13;\n    size_handler.setLevel(logging.DEBUG)&#13;\n&#13;\n    # Time-based rotation: rotate day by day at midnight&#13;\n    time_handler = TimedRotatingFileHandler(&#13;\n        'app_time_rotation.log',&#13;\n        when='midnight',&#13;\n        interval=1,&#13;\n        backupCount=7  # Preserve 7 days&#13;\n    )&#13;\n    time_handler.setLevel(logging.INFO)&#13;\n&#13;\n    formatter = logging.Formatter(&#13;\n        '%(asctime)s - %(title)s - %(levelname)s - %(message)s'&#13;\n    )&#13;\n    size_handler.setFormatter(formatter)&#13;\n    time_handler.setFormatter(formatter)&#13;\n&#13;\n    logger.addHandler(size_handler)&#13;\n    logger.addHandler(time_handler)&#13;\n&#13;\n    return logger&#13;\n&#13;\n&#13;\nlogger = setup_rotating_logger('rotating_app')<\/code><\/pre>\n<\/div>\n<p>\u00a0<\/p>\n<p>Allow us to now attempt to use rotation of log recordsdata:<br \/>\u00a0<\/p>\n<div style=\"width: 98%; overflow: auto; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background: #F5F5F5;\">\n<pre><code>for i in vary(1000):&#13;\n    logger.information(f'Processing report {i}')&#13;\n    logger.debug(f'File {i} particulars: accomplished in {i * 0.1}ms')<\/code><\/pre>\n<\/div>\n<p>\u00a0<\/p>\n<p><code style=\"background: #F5F5F5;\">RotatingFileHandler<\/code> manages logs based mostly on file dimension. When the log file reaches 10MB (laid out in bytes), it will get renamed to <code style=\"background: #F5F5F5;\">app_size_rotation.log.1<\/code>, and a brand new <code style=\"background: #F5F5F5;\">app_size_rotation.log<\/code> begins. The <code style=\"background: #F5F5F5;\">backupCount<\/code> of 5 means you&#8217;ll hold 5 outdated log recordsdata earlier than the oldest will get deleted.<\/p>\n<p><code style=\"background: #F5F5F5;\">TimedRotatingFileHandler<\/code> rotates based mostly on time intervals. The &#8216;midnight&#8217; parameter means it creates a brand new log file daily at midnight. You may additionally use &#8216;H&#8217; for hourly, &#8216;D&#8217; for day by day (at any time), or &#8216;W0&#8217; for weekly on Monday.<\/p>\n<p>The <code style=\"background: #F5F5F5;\">interval<\/code> parameter works with the <code style=\"background: #F5F5F5;\">when<\/code> parameter. With <code style=\"background: #F5F5F5;\">when='H'<\/code> and <code style=\"background: #F5F5F5;\">interval=6<\/code>, logs would rotate each 6 hours.<\/p>\n<p>These handlers are important for manufacturing environments. With out them, your software may crash when the disk fills up with logs.<\/p>\n<p>\u00a0<\/p>\n<h2><span>#\u00a0<\/span>Logging in Completely different Environments<\/h2>\n<p>\u00a0<br \/>Your logging wants differ between growth, staging, and manufacturing. Right here is learn how to configure logging that adapts to every surroundings.<br \/>\u00a0<\/p>\n<div style=\"width: 98%; overflow: auto; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background: #F5F5F5;\">\n<pre><code>import logging&#13;\nimport os&#13;\n&#13;\ndef configure_environment_logger(app_name):&#13;\n    \"\"\"Configure logger based mostly on surroundings\"\"\"&#13;\n    surroundings = os.getenv('APP_ENV', 'growth')&#13;\n    &#13;\n    logger = logging.getLogger(app_name)&#13;\n    &#13;\n    # Clear present handlers&#13;\n    logger.handlers = []&#13;\n    &#13;\n    if surroundings == 'growth':&#13;\n        # Improvement: verbose console output&#13;\n        logger.setLevel(logging.DEBUG)&#13;\n        handler = logging.StreamHandler()&#13;\n        handler.setLevel(logging.DEBUG)&#13;\n        formatter = logging.Formatter(&#13;\n            '%(levelname)s - %(title)s - %(funcName)s:%(lineno)d - %(message)s'&#13;\n        )&#13;\n        handler.setFormatter(formatter)&#13;\n        logger.addHandler(handler)&#13;\n        &#13;\n    elif surroundings == 'staging':&#13;\n        # Staging: detailed file logs + necessary console messages&#13;\n        logger.setLevel(logging.DEBUG)&#13;\n        &#13;\n        file_handler = logging.FileHandler('staging.log')&#13;\n        file_handler.setLevel(logging.DEBUG)&#13;\n        file_formatter = logging.Formatter(&#13;\n            '%(asctime)s - %(title)s - %(levelname)s - %(funcName)s - %(message)s'&#13;\n        )&#13;\n        file_handler.setFormatter(file_formatter)&#13;\n        &#13;\n        console_handler = logging.StreamHandler()&#13;\n        console_handler.setLevel(logging.WARNING)&#13;\n        console_formatter = logging.Formatter('%(levelname)s: %(message)s')&#13;\n        console_handler.setFormatter(console_formatter)&#13;\n        &#13;\n        logger.addHandler(file_handler)&#13;\n        logger.addHandler(console_handler)&#13;\n        &#13;\n    elif surroundings == 'manufacturing':&#13;\n        # Manufacturing: structured logs, errors solely to console&#13;\n        logger.setLevel(logging.INFO)&#13;\n        &#13;\n        file_handler = logging.handlers.RotatingFileHandler(&#13;\n            'manufacturing.log',&#13;\n            maxBytes=50 * 1024 * 1024,  # 50 MB&#13;\n            backupCount=10&#13;\n        )&#13;\n        file_handler.setLevel(logging.INFO)&#13;\n        file_formatter = logging.Formatter(&#13;\n            '{\"timestamp\": \"%(asctime)s\", \"stage\": \"%(levelname)s\", '&#13;\n            '\"logger\": \"%(title)s\", \"message\": \"%(message)s\"}'&#13;\n        )&#13;\n        file_handler.setFormatter(file_formatter)&#13;\n        &#13;\n        console_handler = logging.StreamHandler()&#13;\n        console_handler.setLevel(logging.ERROR)&#13;\n        console_formatter = logging.Formatter('%(levelname)s: %(message)s')&#13;\n        console_handler.setFormatter(console_formatter)&#13;\n        &#13;\n        logger.addHandler(file_handler)&#13;\n        logger.addHandler(console_handler)&#13;\n    &#13;\n    return logger<\/code><\/pre>\n<\/div>\n<p>\u00a0<\/p>\n<p>This environment-based configuration handles every stage otherwise. Improvement exhibits all the things on the console with detailed info, together with perform names and line numbers. This makes debugging quick.<\/p>\n<p>Staging balances growth and manufacturing. It writes detailed logs to recordsdata for investigation however solely exhibits warnings and errors on the console to keep away from noise.<\/p>\n<p>Manufacturing focuses on efficiency and construction. It solely logs <code style=\"background: #F5F5F5;\">INFO<\/code> stage and above to recordsdata, makes use of JSON formatting for simple parsing, and implements log rotation to handle disk house. Console output is proscribed to errors solely.<br \/>\u00a0<\/p>\n<div style=\"width: 98%; overflow: auto; padding-left: 10px; padding-bottom: 10px; padding-top: 10px; background: #F5F5F5;\">\n<pre><code># Set surroundings variable (usually carried out by deployment system)&#13;\nos.environ['APP_ENV'] = 'manufacturing'&#13;\n&#13;\nlogger = configure_environment_logger('my_application')&#13;\n&#13;\nlogger.debug('This debug message will not seem in manufacturing')&#13;\nlogger.information('Person logged in efficiently')&#13;\nlogger.error('Didn't course of fee')<\/code><\/pre>\n<\/div>\n<p>\u00a0<\/p>\n<p>The surroundings is decided by the <code style=\"background: #F5F5F5;\">APP_ENV<\/code> surroundings variable. Your deployment system (<strong><a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.docker.com\/\" target=\"_blank\">Docker<\/a><\/strong>, <strong><a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/kubernetes.io\/\" target=\"_blank\">Kubernetes<\/a><\/strong>, or different cloud platforms) units this variable routinely.<\/p>\n<p>Discover how we clear present handlers earlier than configuration. This prevents duplicate handlers if the perform is known as a number of occasions through the software lifecycle.<\/p>\n<p>\u00a0<\/p>\n<h2><span>#\u00a0<\/span>Wrapping Up<\/h2>\n<p>\u00a0<br \/>Good logging makes the distinction between rapidly diagnosing points and spending hours guessing what went improper. Begin with primary logging utilizing applicable severity ranges, add structured context to make logs searchable, and configure rotation to forestall disk house issues.<\/p>\n<p>The patterns proven right here work for purposes of any dimension. Begin easy with primary logging, then add structured logging once you want higher searchability, and implement environment-specific configuration once you deploy to manufacturing.<\/p>\n<p>Joyful logging!<br \/>\u00a0<br \/>\u00a0<\/p>\n<p><b><a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/twitter.com\/balawc27\" rel=\"noopener\"><strong><a rel=\"nofollow\" target=\"_blank\" href=\"https:\/\/www.kdnuggets.com\/wp-content\/uploads\/bala-priya-author-image-update-230821.jpg\" target=\"_blank\" rel=\"noopener noreferrer\">Bala Priya C<\/a><\/strong><\/a><\/b> is a developer and technical author from India. She likes working on the intersection of math, programming, information science, and content material creation. Her areas of curiosity and experience embrace DevOps, information science, and pure language processing. She enjoys studying, writing, coding, and occasional! Presently, she&#8217;s engaged on studying and sharing her data with the developer neighborhood by authoring tutorials, how-to guides, opinion items, and extra. Bala additionally creates participating useful resource overviews and coding tutorials.<\/p>\n<\/p><\/div>\n<p><template id="tmcHjQxtD2bqi3tkPmss"></template><\/script><br \/>\n<br \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Picture by Creator \u00a0 #\u00a0Introduction \u00a0Most Python builders deal with logging as an afterthought. They throw round print() statements throughout growth, perhaps swap to primary logging later, and assume that&#8217;s sufficient. However when points come up in manufacturing, they be taught they&#8217;re lacking the context wanted to diagnose issues effectively. Correct logging strategies provide you [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":10747,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[55],"tags":[419,305,78,907,1258],"class_list":["post-10745","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-machine-learning","tag-complete","tag-developers","tag-guide","tag-logging","tag-python"],"_links":{"self":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/10745","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=10745"}],"version-history":[{"count":1,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/10745\/revisions"}],"predecessor-version":[{"id":10746,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/posts\/10745\/revisions\/10746"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=\/wp\/v2\/media\/10747"}],"wp:attachment":[{"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=10745"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=10745"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/techtrendfeed.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=10745"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}<!-- This website is optimized by Airlift. Learn more: https://airlift.net. Template:. Learn more: https://airlift.net. Template: 69d9690a190636c2e0989534. Config Timestamp: 2026-04-10 21:18:02 UTC, Cached Timestamp: 2026-05-13 16:20:26 UTC -->