{"id":10035,"date":"2016-01-11T14:11:20","date_gmt":"2016-01-11T12:11:20","guid":{"rendered":"http:\/\/www.webcodegeeks.com\/?p=10035"},"modified":"2018-01-09T09:49:45","modified_gmt":"2018-01-09T07:49:45","slug":"python-logging-example","status":"publish","type":"post","link":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/","title":{"rendered":"Python Logging Example"},"content":{"rendered":"<p>Logging is a process through which an application pushes strings to a handler. That string should be a line containing information about the piece of code from which it was sent and the context in that moment.<\/p>\n<p>It is a feature every application must have, and it&#8217;s as important as any other functionality you add to the application in question. It is the easiest way to know what your application is doing, how, how long does it take, etc.<\/p>\n<p>Any application which is not logging, will be a real pain to maintain, for there is no easy way to tell if it&#8217;s working or not, and if it&#8217;s not, why.<\/p>\n<p>Through the log, we should be able to know a lot of useful information about our application:<\/p>\n<ul>\n<li>What is it doing?<\/li>\n<li>How is it doing it?<\/li>\n<li>How long does it take it?<\/li>\n<li>Is it failing? Why?<\/li>\n<\/ul>\n<p>[ulp id=&#8217;R7QVpFMZmjosABLC&#8217;]<\/p>\n<h2>1. The Theory<\/h2>\n<p>Python provides a module called <code>logging<\/code> which has some really useful tools and configurations. But before we jump into the code, let&#8217;s look around some concepts.<\/p>\n<h3>1.1. Log Levels<\/h3>\n<p>Log levels are the levels of severity of each log line. Is a good solution to differentiate errors from common information in our log files.<\/p>\n<p>The <code>logging<\/code> module provides 5 levels of severity: <code>DEBUG, INFO, WARNING, ERROR, CRITICAL<\/code>. Python&#8217;s logging documentations defines each of them as:<\/p>\n<ul>\n<li><strong>DEBUG<\/strong>: Detailed information, typically of interest only when diagnosing problems.<\/li>\n<li><strong>INFO<\/strong>: Confirmation that things are working as expected.<\/li>\n<li><strong>WARNING<\/strong>: An indication that something unexpected happened, or indicative of some problem in the near future (e.g. \u2018disk space low\u2019). The software is still working as expected.<\/li>\n<li><strong>ERROR<\/strong>: Due to a more serious problem, the software has not been able to perform some function.<\/li>\n<li><strong>CRITICAL<\/strong>: A serious error, indicating that the program itself may be unable to continue running.<\/li>\n<\/ul>\n<p>Loggers can be configured to output only lines above a threshold, which is configured as the global log level of that logger.<\/p>\n<h3>1.2. Handlers<\/h3>\n<p>As we said, a logger is an object which outputs strings to a handler. The handler receives the record and processes it, which means, in some cases, output to a file, console or even by UDP.<\/p>\n<p>The <code>logging<\/code> module provides some useful handlers, and of course you can extend them and create your own. A list with handlers provided by Python below:<\/p>\n<ul>\n<li><strong>StreamHandler<\/strong>: instances send messages to streams (file-like objects).<\/li>\n<li><strong>FileHandler<\/strong>: instances send messages to disk files.<\/li>\n<li><strong>BaseRotatingHandler<\/strong>: is the base class for handlers that rotate log files at a certain point. It is not meant to be instantiated directly. Instead, use RotatingFileHandler or TimedRotatingFileHandler.<\/li>\n<li><strong>RotatingFileHandler<\/strong>: instances send messages to disk files, with support for maximum log file sizes and log file rotation.<\/li>\n<li><strong>TimedRotatingFileHandler<\/strong>: instances send messages to disk files, rotating the log file at certain timed intervals.<\/li>\n<li><strong>SocketHandler<\/strong>: instances send messages to TCP\/IP sockets. Since 3.4, Unix domain sockets are also supported.<\/li>\n<li><strong>DatagramHandler<\/strong>: instances send messages to UDP sockets. Since 3.4, Unix domain sockets are also supported.<\/li>\n<li><strong>SMTPHandler<\/strong>: instances send messages to a designated email address.<\/li>\n<li><strong>SysLogHandler<\/strong>: instances send messages to a Unix syslog daemon, possibly on a remote machine.<\/li>\n<li><strong>NTEventLogHandler<\/strong>: instances send messages to a Windows NT\/2000\/XP event log.<\/li>\n<li><strong>MemoryHandler<\/strong>: instances send messages to a buffer in memory, which is flushed whenever specific criteria are met.<\/li>\n<li><strong>HTTPHandler<\/strong>: instances send messages to an HTTP server using either GET or POST semantics.<\/li>\n<li><strong>WatchedFileHandler<\/strong>: instances watch the file they are logging to. If the file changes, it is closed and reopened using the file name. This handler is only useful on Unix-like systems; Windows does not support the underlying mechanism used.<\/li>\n<li><strong>QueueHandler<\/strong>: instances send messages to a queue, such as those implemented in the queue or multiprocessing modules.<\/li>\n<li><strong>NullHandler<\/strong>: instances do nothing with error messages. They are used by library developers who want to use logging, but want to avoid the \u2018No handlers could be found for logger XXX\u2019 message which can be displayed if the library user has not configured logging.<\/li>\n<\/ul>\n<p>The NullHandler, StreamHandler and FileHandler classes are defined in the core logging package. The other handlers are defined in a sub-module, logging.handlers.<\/p>\n<h3>1.3. Format<\/h3>\n<p>There is some data that we want to be present in every line of log. Context information such as the thread name, time, severity, module and method. Python provides a way to format every message appending this information without explicitly having to add it to the message.<\/p>\n<p>This is done by providing a format to the logger&#8217;s configuration. This format consists of attribute names that represent that context data. Below is the list of every available attribute:<\/p>\n<ul>\n<li><strong>args<\/strong> (You shouldn\u2019t need to format this yourself): The tuple of arguments merged into msg to produce message, or a dict whose values are used for the merge (when there is only one argument, and it is a dictionary).<\/li>\n<li><strong>asctime<\/strong> (<code>%(asctime)s<\/code>): Human-readable time when the LogRecord was created. By default this is of the form \u20182003-07-08 16:49:45,896\u2019 (the numbers after the comma are millisecond portion of the time).<\/li>\n<li><strong>created<\/strong> (<code>%(created)f<\/code>): Time when the LogRecord was created (as returned by time.time()).<\/li>\n<li><strong>exc_info<\/strong> (You shouldn\u2019t need to format this yourself): Exception tuple or, if no exception has occurred, None.<\/li>\n<li><strong>filename<\/strong> (<code>%(filename)s<\/code>): Filename portion of pathname.<\/li>\n<li><strong>funcName<\/strong> (<code>%(funcName)s<\/code>): Name of function containing the logging call.<\/li>\n<li><strong>levelname<\/strong> (<code>%(levelname)s<\/code>): Text logging level for the message (&#8216;DEBUG&#8217;, &#8216;INFO&#8217;, &#8216;WARNING&#8217;, &#8216;ERROR&#8217;, &#8216;CRITICAL&#8217;).<\/li>\n<li><strong>levelno<\/strong> (<code>%(levelno)s<\/code>): Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).<\/li>\n<li><strong>lineno<\/strong> (<code>%(lineno)d<\/code>): Source line number where the logging call was issued (if available).<\/li>\n<li><strong>module<\/strong> (<code>%(module)s<\/code>): Module (name portion of filename).<\/li>\n<li><strong>msecs<\/strong> (<code>%(msecs)d<\/code>): Millisecond portion of the time when the LogRecord was created.<\/li>\n<li><strong>message<\/strong> (<code>%(message)s<\/code>): The logged message, computed as msg % args. This is set when Formatter.format() is invoked.<\/li>\n<li><strong>msg<\/strong> (You shouldn\u2019t need to format this yourself): The format string passed in the original logging call. Merged with args to produce message, or an arbitrary object.<\/li>\n<li><strong>name<\/strong> (<code>%(name)s<\/code>): Name of the logger used to log the call.<\/li>\n<li><strong>pathname<\/strong> (<code>%(pathname)s<\/code>): \tFull pathname of the source file where the logging call was issued (if available).<\/li>\n<li><strong>process<\/strong> (<code>%(process)d<\/code>): Process ID (if available).<\/li>\n<li><strong>processName<\/strong> (<code>%(processName)s<\/code>): Process name (if available).<\/li>\n<li><strong>relativeCreated<\/strong> (<code>%(relativeCreated)d<\/code>): Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.<\/li>\n<li><strong>stack_info<\/strong> (You shouldn\u2019t need to format this yourself): Stack frame information (where available) from the bottom of the stack in the current thread, up to and including the stack frame of the logging call which resulted in the creation of this record.<\/li>\n<li><strong>thread<\/strong> (<code>%(thread)d<\/code>): Thread ID (if available).<\/li>\n<li><strong>threadName<\/strong> (<code>%(threadName)s<\/code>): Thread name (if available).<\/li>\n<\/ul>\n<p>A pretty useful and common format would look like: <code>'%(asctime)s - [%(levelname)s] [%(threadName)s] (%(module)s:%(lineno)d) %(message)s'<\/code>.<\/p>\n<h2>2. The Practice<\/h2>\n<p>So, let&#8217;s experiment a little bit. Let&#8217;s create a file called <code>basic.py<\/code> and make a logging example in it.<\/p>\n<p>Let&#8217;s start with checking the behavior of the default logger, without modifying any of its configuration.<\/p>\n<p><span style=\"text-decoration: underline\"><em>basic.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\nimport logging\r\n\r\nlogging.debug('Some additional information')\r\nlogging.info('Working...')\r\nlogging.warning('Watch out!')\r\nlogging.error('Oh NO!')\r\nlogging.critical('x.x')\r\n<\/pre>\n<p>Here we are just importing logging, and logging a line for each severity, to see the format and the threshold. When we run it we see:<\/p>\n<pre class=\"brush:bash\">\r\nWARNING:root:Watch out!\r\nERROR:root:Oh NO!\r\nCRITICAL:root:x.x\r\n<\/pre>\n<p>So, the default format would be something like <code>'%(levelname)s:%(name)s:%(message)s'<\/code>. And the threshold is warning, as our info and warn lines are not being logged. Let&#8217;s make it a little nicer:<\/p>\n<p><span style=\"text-decoration: underline\"><em>basic.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\nimport logging\r\n\r\nlogging.basicConfig(level=logging.INFO,\r\n                    format=\"%(asctime)s - [%(levelname)s] [%(threadName)s] (%(module)s:%(lineno)d) %(message)s\", )\r\n\r\nlogging.debug('Some additional information')\r\nlogging.info('Working...')\r\nlogging.warning('Watch out!')\r\nlogging.error('Oh NO!')\r\nlogging.critical('x.x')\r\n<\/pre>\n<p>And the output:<\/p>\n<pre class=\"brush:bash\">\r\n2015-12-30 16:43:39,600 - [INFO] [MainThread] (basic:7) Working...\r\n2015-12-30 16:43:39,600 - [WARNING] [MainThread] (basic:8) Watch out!\r\n2015-12-30 16:43:39,600 - [ERROR] [MainThread] (basic:9) Oh NO!\r\n2015-12-30 16:43:39,600 - [CRITICAL] [MainThread] (basic:10) x.x\r\n<\/pre>\n<p>We&#8217;ve declared a threshold of <code>INFO<\/code> and a format which gives a lot of useful information. We now have the time, the severity, the thread, the module and the line in every log record.<\/p>\n<p>Let&#8217;s make a tiny application which would save a contact list to a CSV file and then retrieve them, and then let&#8217;s add some useful log to it:<\/p>\n<p><span style=\"text-decoration: underline\"><em>contacts.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\nimport csv\r\nimport os.path\r\n\r\n\r\nclass Repository:\r\n    def __init__(self, full_file_path):\r\n        self.full_file_path = full_file_path\r\n\r\n    def add(self, contact):\r\n        headers = [h for h in contact]\r\n        headers.sort()\r\n        write_headers = not os.path.isfile(\r\n            self.full_file_path)  # let's assume no one will go and erase the headers by hand\r\n        with open(self.full_file_path, 'a+') as file:\r\n            writer = csv.DictWriter(file, fieldnames=headers)\r\n            if write_headers:\r\n                writer.writeheader()\r\n            writer.writerow(contact)\r\n\r\n    def names(self):\r\n        with open(self.full_file_path, 'r+') as file:\r\n            names = list(map(lambda r: r['name'], csv.DictReader(file)))\r\n            return names\r\n\r\n    def full_contact(self, name):\r\n        with open(self.full_file_path, 'r+') as file:\r\n            for contact in list(csv.DictReader(file)):\r\n                if contact['name'] == name:\r\n                    return contact\r\n            return\r\n\r\n\r\nclass Main:\r\n\r\n    def __init__(self, contacts_file):\r\n        self.repo = Repository(contacts_file)\r\n\r\n    def create(self):\r\n        name = input(\"name: \")\r\n        number = input(\"number: \")\r\n        contact = {\"name\": name, \"number\": number}\r\n        self.repo.add(contact)\r\n        print(\"----------------\")\r\n\r\n    def names(self):\r\n        names = self.repo.names()\r\n        if len(names) &gt; 0:\r\n            for n in names:\r\n                print(\"- {}\".format(n))\r\n        else:\r\n            print(\"no contacts were found\")\r\n        print(\"----------------\")\r\n\r\n    def full_contact(self):\r\n        name = input(\"name: \")\r\n        contact = self.repo.full_contact(name)\r\n        if contact is not None:\r\n            print(\"name: {}\".format(contact[\"name\"]))\r\n            print(\"number: {}\".format(contact[\"number\"]))\r\n        else:\r\n            print(\"contact not found.\")\r\n        print(\"----------------\")\r\n\r\n    def menu(self):\r\n        actions = {\"1\": self.create, \"2\": self.names, \"3\": self.full_contact}\r\n        options = [\"1) Create Contact\", \"2) All Contacts\", \"3) Detail of a contact\", \"0) Exit\"]\r\n        for o in options:\r\n            print(o)\r\n        selected = input(\"What do you want to do? \")\r\n        if selected in actions:\r\n            actions[selected]()\r\n            self.menu()\r\n\r\nMain(\"\/tmp\/contacts.csv\").menu()\r\n\r\n\r\n<\/pre>\n<p>So now we run it and create two contacts: Michael and Sarah.<\/p>\n<pre class=\"brush:bash\">\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 1\r\nname: Michael\r\nnumber: 1234-5678\r\nDone!\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 2\r\n- Michael\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 1\r\nname: Sarah\r\nnumber: 9876-5432\r\nDone!\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 2\r\n- Michael\r\n- Sarah\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 3\r\nname: Sarah\r\nname: Sarah\r\nnumber: 9876-5432\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 0\r\n<\/pre>\n<p>What if we add some logging to know what&#8217;s going on there?<\/p>\n<p><span style=\"text-decoration: underline\"><em>contacts.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\nimport csv\r\nimport os.path\r\nimport logging\r\n\r\nlogging.basicConfig(level=logging.INFO,\r\n                    format=\"%(asctime)s - [%(levelname)s] [%(threadName)s] (%(module)s:%(lineno)d) %(message)s\", )\r\n\r\n\r\nclass Repository:\r\n    def __init__(self, full_file_path):\r\n        logging.info(\"initializing contacts repository with file at: {}\".format(full_file_path))\r\n        self.full_file_path = full_file_path\r\n\r\n    def add(self, contact):\r\n        logging.info(\"creating contact: {}\".format(contact))\r\n        headers = [h for h in contact]\r\n        headers.sort()\r\n        write_headers = not os.path.isfile(\r\n            self.full_file_path)  # let's assume no one will go and erase the headers by hand\r\n        with open(self.full_file_path, 'a+') as file:\r\n            writer = csv.DictWriter(file, fieldnames=headers)\r\n            if write_headers:\r\n                logging.debug(\"this is the first contact in the given file. writing headers.\")\r\n                writer.writeheader()\r\n            writer.writerow(contact)\r\n\r\n    def names(self):\r\n        logging.info(\"retrieving all contact names\")\r\n        with open(self.full_file_path, 'r+') as file:\r\n            names = list(map(lambda r: r['name'], csv.DictReader(file)))\r\n            logging.debug(\"found {} contacts\".format(len(names)))\r\n            return names\r\n\r\n    def full_contact(self, name):\r\n        logging.info(\"retrieving full contact for name: {}\".format(name))\r\n        with open(self.full_file_path, 'r+') as file:\r\n            for contact in list(csv.DictReader(file)):\r\n                if contact['name'] == name:\r\n                    logging.debug(\"contact was found\")\r\n                    return contact\r\n            logging.warning(\"contact was not found for name: {}\".format(name))\r\n            return\r\n\r\n\r\nclass Main:\r\n\r\n    def __init__(self, contacts_file):\r\n        self.repo = Repository(contacts_file)\r\n\r\n    def create(self):\r\n        name = input(\"name: \")\r\n        number = input(\"number: \")\r\n        contact = {\"name\": name, \"number\": number}\r\n        self.repo.add(contact)\r\n        print(\"----------------\")\r\n\r\n    def names(self):\r\n        names = self.repo.names()\r\n        if len(names) &gt; 0:\r\n            for n in names:\r\n                print(\"- {}\".format(n))\r\n        else:\r\n            print(\"no contacts were found\")\r\n        print(\"----------------\")\r\n\r\n    def full_contact(self):\r\n        name = input(\"name: \")\r\n        contact = self.repo.full_contact(name)\r\n        if contact is not None:\r\n            print(\"name: {}\".format(contact[\"name\"]))\r\n            print(\"number: {}\".format(contact[\"number\"]))\r\n        else:\r\n            print(\"contact not found.\")\r\n        print(\"----------------\")\r\n\r\n    def menu(self):\r\n        actions = {\"1\": self.create, \"2\": self.names, \"3\": self.full_contact}\r\n        options = [\"1) Create Contact\", \"2) All Contacts\", \"3) Detail of a contact\", \"0) Exit\"]\r\n        for o in options:\r\n            print(o)\r\n        selected = input(\"What do you want to do? \")\r\n        if selected in actions:\r\n            actions[selected]()\r\n            self.menu()\r\n\r\nMain(\"\/tmp\/contacts.csv\").menu()\r\n\r\n\r\n<\/pre>\n<p>So, now doing the exact same thing we&#8217;ll see:<\/p>\n<pre class=\"brush:bash\">\r\n2015-12-30 17:32:15,788 - [INFO] [MainThread] (contacts:11) initializing contacts repository with file at: \/tmp\/contacts.csv\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 1\r\nname: Michael\r\nnumber: 1234-5678\r\n2015-12-30 17:32:33,732 - [INFO] [MainThread] (contacts:15) creating contact: {'number': '1234-5678', 'name': 'Michael'}\r\n----------------\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 1\r\nname: Sarah\r\nnumber: 9876-5432\r\n2015-12-30 17:32:41,828 - [INFO] [MainThread] (contacts:15) creating contact: {'number': '9876-5432', 'name': 'Sarah'}\r\n----------------\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 2\r\n2015-12-30 17:32:45,140 - [INFO] [MainThread] (contacts:28) retrieving all contact names\r\n- Michael\r\n- Sarah\r\n----------------\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 3\r\nname: Sarah\r\n2015-12-30 17:32:48,532 - [INFO] [MainThread] (contacts:35) retrieving full contact for name: Sarah\r\nname: Sarah\r\nnumber: 9876-5432\r\n----------------\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 0\r\n<\/pre>\n<p>Now, there is our logging, but there is also a new problem. The user of our script doesn&#8217;t care about our log lines, they actually bothers him. Let&#8217;s log to a file modifying only the configuration of the logger:<\/p>\n<p><span style=\"text-decoration: underline\"><em>contacts.py<\/em><\/span><\/p>\n<pre class=\"brush:python\">\r\n...\r\nlogging.basicConfig(level=logging.INFO,\r\n                    format=\"%(asctime)s - [%(levelname)s] [%(threadName)s] (%(module)s:%(lineno)d) %(message)s\",\r\n                    filename=\"\/tmp\/contacts.log\")\r\n...\r\n<\/pre>\n<p>So, now in the output we see everything normal again:<\/p>\n<pre class=\"brush:bash\">\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 2\r\n- Michael\r\n- Sarah\r\n----------------\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 3\r\nname: Michael\r\nname: Michael\r\nnumber: 1234-5678\r\n----------------\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 3\r\nname: Qwerty\r\ncontact not found.\r\n----------------\r\n1) Create Contact\r\n2) All Contacts\r\n3) Detail of a contact\r\n0) Exit\r\nWhat do you want to do? 0\r\n<\/pre>\n<p>No log lines for the world to see. Not our script is actually usable again. So with a simple <code>cat \/tmp\/contacts.log<\/code> we can see what happened there:<\/p>\n<pre class=\"brush:bash\">\r\n2015-12-30 17:34:54,112 - [INFO] [MainThread] (contacts:12) initializing contacts repository with file at: \/tmp\/contacts.csv\r\n2015-12-30 17:34:56,219 - [INFO] [MainThread] (contacts:29) retrieving all contact names\r\n2015-12-30 17:35:01,819 - [INFO] [MainThread] (contacts:36) retrieving full contact for name: Michael\r\n2015-12-30 17:35:06,827 - [INFO] [MainThread] (contacts:36) retrieving full contact for name: Qwerty\r\n2015-12-30 17:35:06,827 - [WARNING] [MainThread] (contacts:42) contact was not found for name: Qwerty\r\n<\/pre>\n<h2>3. Download the Code Project<\/h2>\n<p>This was an example on Python Logging.<\/p>\n<div class=\"download\"><strong>Download<\/strong><br \/> You can download the full source code of this example here: <a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2015\/12\/logging-example.zip\"><strong>python-logging<\/strong><\/a><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Logging is a process through which an application pushes strings to a handler. That string should be a line containing information about the piece of code from which it was sent and the context in that moment. It is a feature every application must have, and it&#8217;s as important as any other functionality you add &hellip;<\/p>\n","protected":false},"author":109,"featured_media":1651,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[53],"tags":[306],"class_list":["post-10035","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-python","tag-logging"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Python Logging Example - Web Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"Logging is a process through which an application pushes strings to a handler. That string should be a line containing information about the piece of code\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Python Logging Example - Web Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"Logging is a process through which an application pushes strings to a handler. That string should be a line containing information about the piece of code\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webcodegeeks\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/sgvinci\" \/>\n<meta property=\"article:published_time\" content=\"2016-01-11T12:11:20+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-01-09T07:49:45+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Sebastian Vinci\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@sebastianvinci_\" \/>\n<meta name=\"twitter:site\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Sebastian Vinci\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/\"},\"author\":{\"name\":\"Sebastian Vinci\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/06a43c63e373dff2e159bbc029b405aa\"},\"headline\":\"Python Logging Example\",\"datePublished\":\"2016-01-11T12:11:20+00:00\",\"dateModified\":\"2018-01-09T07:49:45+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/\"},\"wordCount\":1391,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"keywords\":[\"logging\"],\"articleSection\":[\"Python\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/\",\"name\":\"Python Logging Example - Web Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"datePublished\":\"2016-01-11T12:11:20+00:00\",\"dateModified\":\"2018-01-09T07:49:45+00:00\",\"description\":\"Logging is a process through which an application pushes strings to a handler. That string should be a line containing information about the piece of code\",\"breadcrumb\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#primaryimage\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.webcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Python\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/python\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Python Logging Example\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"name\":\"Web Code Geeks\",\"description\":\"Web Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.webcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webcodegeeks\",\"https:\/\/x.com\/webcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/06a43c63e373dff2e159bbc029b405aa\",\"name\":\"Sebastian Vinci\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/12d0233b49dd2a282330a987b16e81c3fbd4a8a8f5d5338348a6edd47cfff99e?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/12d0233b49dd2a282330a987b16e81c3fbd4a8a8f5d5338348a6edd47cfff99e?s=96&d=mm&r=g\",\"caption\":\"Sebastian Vinci\"},\"description\":\"Sebastian is a full stack programmer, who has strong experience in Java and Scala enterprise web applications. He is currently studying Computers Science in UBA (University of Buenos Aires) and working a full time job at a .com company as a Semi-Senior developer, involving architectural design, implementation and monitoring. He also worked in automating processes (such as data base backups, building, deploying and monitoring applications).\",\"sameAs\":[\"http:\/\/www.webcodegeeks.com\/\",\"https:\/\/www.facebook.com\/sgvinci\",\"https:\/\/x.com\/sebastianvinci_\"],\"url\":\"https:\/\/www.webcodegeeks.com\/author\/sebastian-vinci\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Python Logging Example - Web Code Geeks - 2026","description":"Logging is a process through which an application pushes strings to a handler. That string should be a line containing information about the piece of code","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/","og_locale":"en_US","og_type":"article","og_title":"Python Logging Example - Web Code Geeks - 2026","og_description":"Logging is a process through which an application pushes strings to a handler. That string should be a line containing information about the piece of code","og_url":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/","og_site_name":"Web Code Geeks","article_publisher":"https:\/\/www.facebook.com\/webcodegeeks","article_author":"https:\/\/www.facebook.com\/sgvinci","article_published_time":"2016-01-11T12:11:20+00:00","article_modified_time":"2018-01-09T07:49:45+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","type":"image\/jpeg"}],"author":"Sebastian Vinci","twitter_card":"summary_large_image","twitter_creator":"@sebastianvinci_","twitter_site":"@webcodegeeks","twitter_misc":{"Written by":"Sebastian Vinci","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#article","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/"},"author":{"name":"Sebastian Vinci","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/06a43c63e373dff2e159bbc029b405aa"},"headline":"Python Logging Example","datePublished":"2016-01-11T12:11:20+00:00","dateModified":"2018-01-09T07:49:45+00:00","mainEntityOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/"},"wordCount":1391,"commentCount":0,"publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","keywords":["logging"],"articleSection":["Python"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/","url":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/","name":"Python Logging Example - Web Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#primaryimage"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","datePublished":"2016-01-11T12:11:20+00:00","dateModified":"2018-01-09T07:49:45+00:00","description":"Logging is a process through which an application pushes strings to a handler. That string should be a line containing information about the piece of code","breadcrumb":{"@id":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#primaryimage","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/11\/python-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.webcodegeeks.com\/python\/python-logging-example\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.webcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Python","item":"https:\/\/www.webcodegeeks.com\/category\/python\/"},{"@type":"ListItem","position":3,"name":"Python Logging Example"}]},{"@type":"WebSite","@id":"https:\/\/www.webcodegeeks.com\/#website","url":"https:\/\/www.webcodegeeks.com\/","name":"Web Code Geeks","description":"Web Developers Resource Center","publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.webcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.webcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.webcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webcodegeeks","https:\/\/x.com\/webcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/06a43c63e373dff2e159bbc029b405aa","name":"Sebastian Vinci","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/12d0233b49dd2a282330a987b16e81c3fbd4a8a8f5d5338348a6edd47cfff99e?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/12d0233b49dd2a282330a987b16e81c3fbd4a8a8f5d5338348a6edd47cfff99e?s=96&d=mm&r=g","caption":"Sebastian Vinci"},"description":"Sebastian is a full stack programmer, who has strong experience in Java and Scala enterprise web applications. He is currently studying Computers Science in UBA (University of Buenos Aires) and working a full time job at a .com company as a Semi-Senior developer, involving architectural design, implementation and monitoring. He also worked in automating processes (such as data base backups, building, deploying and monitoring applications).","sameAs":["http:\/\/www.webcodegeeks.com\/","https:\/\/www.facebook.com\/sgvinci","https:\/\/x.com\/sebastianvinci_"],"url":"https:\/\/www.webcodegeeks.com\/author\/sebastian-vinci\/"}]}},"_links":{"self":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/10035","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/users\/109"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/comments?post=10035"}],"version-history":[{"count":0,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/10035\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media\/1651"}],"wp:attachment":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media?parent=10035"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/categories?post=10035"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/tags?post=10035"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}