Logging is a very important part in the software development because, it can help us to find bugs in our code and it is very helpful in case of application crashing.
To be honest, it is a common practice using, especially during the development, the command Print() in order to find bugs, instead to use Logging.
But this, it isn’t a good solution especially when the code is in Production where, we need to have the history of the errors and where, many times, we don’t have a direct access.
In this post, we will develop a simple calculator application and we will see how Logging can be very helpful to manage bugs.
We start creating a file called ‘calculator.py’ that it will be our UI and then, we will create a module called ‘core.py’ that it will be our Business Layer:
[CORE.PY]
1 2 3 4 5 6 7 8 9 10 11 | def Addition(val1, val2): return val1 + val2 def Subtraction(val1, val2): return val1 - val2 def Multiplication(val1, val2): return val1 * val2 def Division(val1, val2): return val1 / val2 |
[CALCULATOR.PY]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import core isRunning = True # we use this while for running the application while (isRunning): values = input ( "Please, insert 2 numbers separated with a comma: \n" ) operations = input ( "Please, select one of this possible operations: '+', '-', '*', '/' => " ) result = 0 val1 = int ((values.split( ',' ))[ 0 ]) val2 = int ((values.split( ',' ))[ 1 ]) isOperationValid = True # match was introduced by Python 3.10 match operations: case '+' : result = core.Addition(val1, val2) case '-' : result = core.Subtraction(val1, val2) case '/' : result = core.Division(val1,val2) case '*' : result = core.Multiplication(val1, val2) case _: print ( "Attention! The selected operation isn't valid" ) isOperationValid = False if (isOperationValid): print (f "The result of the operation {val1}{operations}{val2} is {result}" ) print () quitApplication = input ( "Press 'q' to quit the application " ) if (quitApplication = = 'q' ): isRunning = False |
If we run the application, this will be the result:
![](https://www.zoneofdevelopment.com/wp-content/uploads/2022/11/Screenshot-2022-11-18-at-18.52.24-1024x721.png)
The application works fine but, what would happen in case of errors?
![](https://www.zoneofdevelopment.com/wp-content/uploads/2022/11/Screenshot-2022-11-18-at-19.01.45-1024x794.png)
We can see that the application crashed many times and, if it is in Production, it would be a big problem.
In order to fix these problems, we can put many try/except to avoid these errors:
[CALCULATOR.PY]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import core isRunning = True # we use this while for running the application while (isRunning): values = input ( "Please, insert 2 numbers separated with a comma: \n" ) operations = input ( "Please, select one of this possible operations: '+', '-', '*', '/' => " ) result = 0 try : val1 = int ((values.split( ',' ))[ 0 ]) val2 = int ((values.split( ',' ))[ 1 ]) isOperationValid = True except Exception as error: print ( "Attention! Insert only numbers in input." ) isOperationValid = False if (isOperationValid): # match was introduced by Python 3.10 match operations: case '+' : result = core.Addition(val1, val2) case '-' : result = core.Subtraction(val1, val2) case '/' : result = core.Division(val1,val2) case '*' : result = core.Multiplication(val1, val2) case _: print ( "Attention! The selected operation isn't valid" ) isOperationValid = False print (f "The result of the operation {val1}{operations}{val2} is {result}" ) print () quitApplication = input ( "Press 'q' to quit the application " ) if (quitApplication = = 'q' ): isRunning = False |
[CORE.PY]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def Addition(val1, val2): return val1 + val2 def Subtraction(val1, val2): return val1 - val2 def Multiplication(val1, val2): return val1 * val2 def Division(val1, val2): try : return val1 / val2 except Exception as error: print (f "Attention! {error}" ) return 0 |
if we run the application, this will be the result:
![](https://www.zoneofdevelopment.com/wp-content/uploads/2022/11/Screenshot-2022-11-18-at-19.22.26-1024x875.png)
Everything works fine but this solution, in a Production environment, cannot be used because we will lose the history of all errors.
In order to avoid this problem, as we said above, we can use Logging.
First of all, we create a module called log.py where we will write the code for managing the logs:
[LOG.PY]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import logging # we define our custom logger: logger = logging.getLogger( "Logs" ) # Overriding the default severity of logging logger.setLevel( 'DEBUG' ) # definition of the file that the application will create and # where it will save the logs filename = "AppLogs.log" # Creation of a handler # Handlers are used to configure logger # We define a file as output of the log # The filemode='a', means append. typeLog_handler = logging.FileHandler(filename = filename) # Log format definition: datetime - error level - message f_format = logging.Formatter( '%(asctime)s - %(levelname)s - %(message)s' ) typeLog_handler.setFormatter(f_format) # We add the handler at the our log logger.addHandler(typeLog_handler) |
Then, we add this module in core.py and calculator.py:
[CORE.PY]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # we import the module log import log def Addition(val1, val2): return val1 + val2 def Subtraction(val1, val2): return val1 - val2 def Multiplication(val1, val2): return val1 * val2 def Division(val1, val2): try : return val1 / val2 except Exception as error: log.logger.error(error) return 0 |
[CALCULATOR.PY]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import core # we import the module "log" import log isRunning = True # we use this while for running the application while (isRunning): values = input ( "Please, insert 2 numbers separated with a comma: \n" ) operations = input ( "Please, select one of this possible operations: '+', '-', '*', '/' => " ) result = 0 try : val1 = int ((values.split( ',' ))[ 0 ]) val2 = int ((values.split( ',' ))[ 1 ]) isOperationValid = True except Exception as error: print ( "Attention! Insert only numbers in input." ) isOperationValid = False log.logger.error(f "Input non valid. Error message: {error}" ) if (isOperationValid): # match was introduced by Python 3.10 match operations: case '+' : result = core.Addition(val1, val2) case '-' : result = core.Subtraction(val1, val2) case '/' : result = core.Division(val1,val2) case '*' : result = core.Multiplication(val1, val2) case _: print ( "Attention! The selected operation isn't valid" ) # we save this information in the log log.logger.warning(f "A wrong type of operation was inserted: {operations}" ) isOperationValid = False if (isOperationValid): print (f "The result of the operation {val1}{operations}{val2} is {result}" ) log.logger.info(f "The result of the operation {val1}{operations}{val2} is {result}" ) print () quitApplication = input ( "Press 'q' to quit the application " ) if (quitApplication = = 'q' ): isRunning = False |
We have done and now, if we run the application, this will be the result:
![](https://www.zoneofdevelopment.com/wp-content/uploads/2022/11/Screenshot-2022-11-20-at-21.07.57-1024x546.png)
And, if we open the file AppLogs.log, these will be the logs created by the application:
[APPLOGS.LOG]
1 2 3 | 2022-11-20 21:07:11,133 - ERROR - Input non valid. Error message: invalid literal for int() with base 10: 's' 2022-11-20 21:07:17,848 - INFO - The result of the operation 1+2 is 3 2022-11-20 21:07:29,640 - WARNING - A wrong type of operation was inserted: } |