Exception Logging
Exception Logging
HANDLING
by Liubov Koliasa
Agenda
• Errors vs Exceptions
• Exception inheritance tree
• List of standart exception
• Handling exceptions
• Handling many exceptions
• Raising Exceptions
• Logging
Errors vs Exceptions
There are (at least) two distinguishable kinds of errors:
syntax errors and logical errors (exceptions).
The first type is syntax error. They result from a violation of the programming language
syntax when writing source code. If there are such errors, the program cannot be
compiled. When working in any development environment, for example, in PyCharm, the
IDE itself can track syntax errors and allocate them in some way.
The second type of errors are runtime errors. They appear in the already compiled
program during its execution. Such errors are also called exceptions. When that error
occurs, Python generate an exception that can be handled, which avoids your program to
crash.
Errors vs Exceptions
Syntax errors occur when the parser detects an incorrect statement.
>>> print( 0 / 0 ))
File “<stdin>”, line 1
print( 0 / 0 ))
^
SyntaxError: invalid syntax
An exception is an error that happens during execution of a program. When that error occurs, a Python
script raises exception (it creates an Exception object) that can be handled, which avoids your program to
crash. >>> print( 0 / 0)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
Exception inheritance tree
List of System & Standard Exceptions
BaseException The base class for all built-in exceptions. It is not meant to be directly inherited by user-defined classes.
SystemExit Raised by the sys.exit() function.
KeyboardInterrupt Raised when the user interrupts program execution, usually by pressing Ctrl+С.
GeneratorExit Raised when a generator is closed (with the close() method)
Exception All built-in, non-system-exiting exceptions are derived from this class. All user-defined exceptions should
also be derived from this class.
ArithmeticError The base class for those built-in exceptions that are raised for various arithmetic errors.
ZeroDivisionError Raised when division or modulo by zero takes place for all numeric types.
IndexError Raised when an index is not found in a sequence.
KeyError Raised when the specified key is not found in the dictionary.
List of Standard Exceptions
NameError Raised when an identifier is not found in the local or global namespace.
TypeError Raised when an operation or function is attempted that is invalid for he specified data type.
ValueError Raised when the built-in function for a data type has the valid type of arguments, but the arguments
have invalid values specified.
AttributeError Raised in case of failure of attribute reference or assignment.
IdentationError Raised when identation is not correct.
StopIteration Raised when the next() method of an iterator does not point to any object.
SyntaxError Raised when a syntax error is encountered by the parser.
ImportError Raised when python cannot find the module.
EOFError Raised when one of the built-in functions (input() or raw_input()) hits an end-of-file condition (EOF)
without reading any data.
IOError Raised when an input/ output operation fails, such as the print statement or the open() function when
trying to open a file that does not exist.
List of Standard Exceptions
a = [5, 6, 7,8]
try:
print("Second element = {}".format(a[1]))
# Throws error since there are only 4 elements in array
print("Fifth element = {}".format(a[4]))
except IndexError as e:
print(e)
Handling Many Exceptions
if a >= 4:
print("Value of b = ", b) # throws NameError
if a >= 4:
print("Value of b = ", b) # throws NameError
We can use the else keyword to define a block of code to be executed if no errors were raised:
try:
f = open("newfile.txt")
f.write("Second element: ")
except:
print("Something went wrong when writing to the file")
else:
print("Nothing went wrong")
Handling Exceptions
The finally block, if specified, will be executed regardless if the try block raises an error or not:
try:
f = open("newfile.txt")
f.write("Second element: ")
except:
print("Something went wrong when writing to the file")
else:
print("Nothing went wrong")
finaly:
f.close()
print("The 'try except' is finished")
Raising Exceptions
In Python programming, exceptions are raised when corresponding errors occur at run time, but we
can forcefully raise it using the keyword raise.
The raise statement allows the programmer to force a specific exception to occur. The sole argument
in raise indicates the exception to be raised. This must be either an exception instance or an exception
class (a class that derives from Exception).
try:
value = int(input("Enter a positive integer: "))
if value <= 0:
raise ValueError("That is not a positive number!")
except ValueError as e:
print(e)
Custom exception class
class CustomError(Exception):
def __init__(self, data):
self.data = data
def __str__(self):
return repr(self.data)
try:
num_of_group = int(input("Enter number of your group: "))
if num_of_group < 1:
raise CustomError("Number of your group can't be less than 1")
except CustomError as e:
print("We obtain error:", e.data)
Logging
Adding logging to your Python program is as easy as this:import logging
With the logging module imported, you can use something called a “logger” to log messages that you
want to see. By default, there are 5 standard levels indicating the severity of events. Each has a
corresponding method that can be used to log events at that level of severity. The defined levels, in
order of increasing severity, are the following: DEBUG, INFO, WARNING, ERROR, CRITICAL
import logging
logging.debug('This is a debug message')
logging.info('This is an info message')
logging.warning('This is a warning message')
logging.error('This is an error message')
logging.critical('This is a critical message')
Basic Configurations
You can use the basicConfig (**kwargs) method to configure the logging.
Some of the commonly used parameters for basicConfig () are the following:
•level: The root logger will be set to the specified severity level.
•filename: This specifies the file.
•filemode: If filename is given, the file is opened in this mode. The default is a, which means
append.
•format: This is the format of the log message.
import logging import logging
logging.basicConfig(filename='app.log',filemode='w',
logging.basicConfig(level=logging.DEBUG)
format='%(name)s - %(levelname)s - %(message)s')
logging.debug('This will get logged')
logging.warning('This will get logged to a file')
Formatting the Output
While you can pass any variable that can be represented as a string from your program as a message to your logs,
there are some basic elements that are already a part of the LogRecord and can be easily added to the output
format. If you want to log the process ID along with the level, the date, time info and message, you can do
something like this:
import logging
logging.basicConfig(format='%(process)d-%(levelname)s-%(asctime)s-%(message)s', level=logging.INFO)
logging.info('Admin logged in')
logging.warning('This is a Warning')
Logging Variable Data
In most cases, you would want to include dynamic information from your application in the
logs. You have seen that the logging methods take a string as an argument. The arguments
passed to the method would be included as variable data in the message.
import logging
item = 'Process'
logging.warning(f'{item} raised an error')
Capturing Stack Traces
The logging module also allows you to capture the full stack traces in an application. Exception information can be captured if
the exc_info parameter is passed as True
import logging import logging
a = 5; b = 0 a = 5; b = 0
try: try:
c = a / b c = a / b
except Exception as e: except Exception as e:
logging.error("Exception occurred", exc_info=True) logging.exception("Exception occurred")
Classes and Functions
So far, we have seen the default logger named root, which is used by the logging module whenever its functions are
called directly like this: logging.debug(). You can (and should) define your own logger by creating an object of
the Logger class, especially if your application has multiple modules.
The most commonly used classes defined in the logging module are the following:
•Logger: This is the class whose objects will be used in the application code directly to call the functions.
•LogRecord: Loggers automatically create LogRecord objects that have all the information related to the event being
logged, like the name of the logger, the function, the line number, the message, and more.
•Handler: Handlers send the LogRecord to the required output destination, like the console or a file. Handler is a
base for subclasses like StreamHandler, FileHandler, SMTPHandler, HTTPHandler, and more. These subclasses
send the logging outputs to corresponding destinations, like sys.stdout or a disk file.
•Formatter: This is where you specify the format of the output by specifying a string format that lists out the
attributes that the output should contain.
Classes and Functions
Out of these, we mostly deal with the objects of the Logger class, which are instantiated using the module-level
function logging.getLogger(name). Multiple calls to getLogger() with the same name will return a reference to the
same Logger object, which saves us from passing the logger objects to every part where it’s needed.
import logging
logger=logging.getLogger('Example_logger')
logger.warning('This is a warning')
Unlike the root logger, a custom logger can’t be configured using basicConfig(). You have to configure it using
Handlers and Formatters
Using Handlers
Useful Link
Built-in Exceptions
https://docs.python.org/3/library/exceptions.html
Logging
https://docs.python.org/3/library/logging.html
SoftServe Confidential