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]
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]
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:
The application works fine but, what would happen in case of errors?
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]
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]
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:
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]
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]
# 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]
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:
And, if we open the file AppLogs.log, these will be the logs created by the application:
[APPLOGS.LOG]
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: }