Thursday Mornings with Python, Part 10 - The Last One! (Finishing Friday)
Thursday Mornings with Python, Part 10 - The Last One! (Finishing Friday)
As I have completed my intermediate course and my database operations module from the advanced course the only module that remains that we have agreed for me to do is Logging from the advanced module.
I miss nature.
I miss nature and I miss the trees and I miss the forests.
I miss the secret valley near where I love which I lived next to for 10 years before I discovered it. Proof that it is always worth exploring.
I long for the forests and long for the woods.
I have worked so hard this year. I am so happy I have a good break at the end of this year to try and recover from this all. I want to go back deep in the woods again to try and find my purpose. To try and find the internet towers deep in the woods.
Try and find the meaning and the magic.
Logging
The logging module provides several formatting options.
This is very good to know, that means we can format our outputs.
Cleanly formatted log messages can help troubleshoot issues in the application.
The course has gotten me to look at the outputs of two files - one with print statements and one with logging. The output difference is unreal. The logging file is so much cleaner and more readable. So much more processable.
Creating a Logger
I learned about import logging, creating a logger, and passing in a parameter called "name" to the logger creation method to create the logger. I am not blogging as much because I get it. The blogs are only really useful to me if I don't get something initially at first glance.
If you try to call a logger again with the same name it will just return the same logger object. Python also has a pre-built predefined variable called __name__. What does this one do please? Thanks.
What this one does:
It sets the name of the logger to the name of the module, which is cool. I wrote out some code to create a basic logger. Here we go:
import logging
import sys
logger = logging.getLogger(__name__)
stream_handler = logging.StreamHandler(sys.stdout)
logger.addHandler(stream_handler)
So then that's the basic code for setting up a logger in Python!
Log Levels
This allows us to log the severity of logs. I have definitely come across this before so it is all familiar. In fact all of this lesson is familiar. I've seen it all before! This is really interesting.
I am not sure if I am meant to remember them all. Anyway I logged them all out. They should be easy enough to search.
Here's the code I wrote for them anyway:
import logging
print(logging.NOTSET)
print(logging.DEBUG)
print(logging.INFO)
print(logging.WARNING)
print(logging.ERROR)
print(logging.CRITICAL)
And here is the output:
0
10
20
30
40
50
So these are the little levels.
Logging Errors and Messages
"The logging module has several methods that we can use to log messages and errors with an assigned severity level." They are aligned with the logging levels of severity.
We put the desired logger message as the parameter. It can be any string or just the caught contents of a caught error or exception even.
There is also a logger.log(level, msg) method. This one allows us to log the specific level as well as the message. We have to pass in the numeric value to use for the level as the input parameter. Right now I am back to thinking about how to write a general logging error message. I can see there are two ways to do this.
logger.error('This is an error message'.')
OR
logger.info(logging.ERROR, 'This is an error message.')
So yeah... thanks.
Similarly, logging a critical message can be done in two ways:
logger.critical('This is a critical message.')
OR
logger.log(logging.CRITICAL, 'This is a critical message.')
So yes I see... what's next?
Setting the Log Level
Each logger object has a default set of log levels that will output unless a different log level is explicitly set. When we set a log level for a logger, any log message that ha s this log level and higher will output. The default log level is WARNING.
To change the default log level for a logger, we can use a method called setLevel(level)
The level parameter represents the numeric value of the log level we should use
So we can do logger.setLevel(logging.DEBUG)
And that will represent a numeric value...
We can then filter so that we only see the most essential messages that are most crucial to our program...
Logging to a File
Writing logs to a saved file makes our logs persistable after program execution
We can use the logging module class FileHandler(filename) to write our logs to a saved file.
"The filename initialization parameter is a string value that represents the filename for the written log file."
So I wrote these two lines of code:
file_handler = logging.FileHandler("output.log")
logger.addHandler(file_handler)
And this is what it could look like in full:
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
file_handler = logging.FileHandler("output.log")
logger.addHandler(file_handler)
Thank you.
Logging to Console and File
You can ADD SEVERAL HANDLERS TO A SINGLE LOGGER OBJECT!! We can log to both a console AND a file.
We can do this by adding multiple addHandler(hdlr) calls for each handler object. An example of this in the code would be:
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
What is a stream_handler? Hmm.
Okay so apparently this just sends output to the console.
It is important to define the file_handler beforehand though - like this:
file_handler = logging.FileHandler("calculator.log")
logger.addHandler(file_handler)
And the stream handler can be defined like this:
stream_handler = logging.StreamHandler(sys.stdout)
logger.addHandler(stream_handler)
Formatting the Logs
A crucial benefit of using the logging module is the ability to format log messages.
Logging has a custom Formatter class.
It accepts a formatted string as its first input variable.
This can allow you to create custom logging messages.
There is also a setFormatter method that will work on various different types of Handler classes. DIFFERENT TYPES OF HANDLERS CAN HAVE DIFFERENT TYPES OF FORMATS.
Using basicConfig()
This is a method. It allows for the configuration of some components in one easy step. It allows for the basic configuration of the logger object by configuring the log level, any handlers, log message formatting options, and more
All in just one line of code.
Okay, right, for the first time in this course. I feel overwhelmed. That's convenient cos it's the last lesson lol. And the last lesson of this course.
And the last Codecademy lesson that I will ever do.
I mean if I switch to the frontend maybe there'll be some upskilling to do.
But maybe I can just learn on the job. I mean it's better. Right? I think this will be all that I need. Anyway back to configs:
- It adds the file handler object
- It sets the level of the logger
- AND allows us to format the message.
Amazing huh? Here's the example:
logging.basicConfig(filename='calculator.log', level=logging.DEBUG, format='[%(asctime)s] %(levelname)s - %(message)s')
Quiz
I did the quiz
I am too exhausted for words.
My lowest ever score
Not a bad score
Logging is hard
I love logging
OMG
OMG TESSELATE BY ALT-J Just came on in the coffee shop where I am working
This is one of the best songs ever omg
This is one of my favourite songs ever omg
I now have hope again
Hope for my future, hope for my career, hope for my frontend work and for my backend work
I will thrive wherever I end up please - thanks.
"TRIANGLES ARE MY FAVOURITE SHAPE."
"THREE POINTS WHERE TWO LINES MEET."
now all that remains is the final project on logging
then I will be 100% done with python modules and I can focus on problem solving and work and debugging and REST yayyyyy
p.s. Loggers are tricky.
Comments
Post a Comment