I'm writing a Python script to retrieve data from Flickr. For logging purposes, I have the following setup function:
def init_log(logfile):
format = '%(asctime)s - %(levelname)s - %(message)s'
logging.basicConfig(filename=logfile,level=logging.DEBUG,format=format)
I've tested this using the python shell and it works as expected, creating a file if one doesn't already exist. But calling it from within my program is where it stops working. The function is definitely being called, and the logfile parameter is working properly – logging.basicConfig just isn't creating any file. I'm not even getting any errors or warnings.
My use of the Python Flickr API may be the culprit, but I doubt it. Any ideas?
The logging.basicConfig function only does anything if the root logger has no handlers configured. If called when there are already some handlers attached to the root, it's basically a no-op (as is documented).
Possibly the Python Flickr API does some logging, in which case you may find that basicConfig should be called earlier in your code.
Related
Hi this is hopefully a basic question. I have a python library with a lot of logger messages such as this:
log = logging.getLogger(__name__)
log.info("blah")
log.warning("blah")
...
Then I have a separate code that imports and runs this library. In that code, I added this, thinking it would cause all logging messages to go to this file:
log = logging.getLogger(__name__)
fh = logging.FileHandler("/some/file/location/log.txt")
log.addHandler(fh)
This does successfully pass all log messages in that script to direct to that file, but the logging messages from the library aren't being passed along. I don't want to specify the file path from within the library, that doesn't make much sense, I want it specified in the code that runs the library. Most of the examples I'm seeing show imports happening with parent/child modules, but what about one module that calls a completely different module? Does my library need to accept a logger as an argument to use, or can I use the logging module to handle this?
Thanks.
Looks like you are creating two instances of the Logger class. Only the instance in your script is being configured to write to the file location.
Each time the 'getLogger' method is called, it provides a reference to the Logger with the specified name. If a Logger with that name doesn't exist, a new one is created. Note that in Python, __name__ specifies the module name. Since you are calling the library from a script, I'd assume you have two separate modules, hence two different Loggers.
For a quick-and-dirty approach, you can use:
import my_library
log = logging.getLogger(my_library.__name__)
fh = logging.FileHandler("/some/file/location/log.txt")
log.addHandler(fh)
Where my_library is your newly defined library. This will provide the logger which the library instantiated, instead of creating a new one.
Another approach would be to define a module-level function like this:
# In your script
import my_library
log_location = "/some/file/location/log.txt"
my_library.set_log_location(log_location)
# In your newly defined library
def set_log_location(path):
log = logging.getLogger(__name__)
fh = logging.FileHandler("/some/file/location/log.txt")
log.addHandler(fh)
The second approach wouldn't require the user knowing that your library uses the logging module.
In your application, e.g. in the if __name__ == '__main__' clause, configure the root logger with the handlers you want, using e.g.
logging.basicConfig(level=logging.DEBUG,
filename='/some/file/location/log.txt',
filemode='w',
format='%(asctime)s %(message)s')
and then all logging from your application, your libraries and third-party libraries should write log messages to the file. The sources of logged events (application or libraries) don't need to know or care where the events they log end up - that's taken care of by the configuration. If you need more involved configuration than basicConfig() provides, you can use logging's dictConfig() API to configure logging.
I have a python script with an error handling using the logging module. Although this python script works when imported to google colab, it doesn't log the errors in the log file.
As an experiment, I tried this following script in google colab just to see if it writes log at all
import logging
logging.basicConfig(filename="log_file_test.log",
filemode='a',
format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
datefmt='%H:%M:%S',
level=logging.DEBUG)
logging.info("This is a test log ..")
To my dismay, it didn't even create a log file named log_file_test.log. I tried running the same script locally and it did produce a file log_file_test.log with the following text
13:20:53,441 root INFO This is a test log ..
What is it that I am missing here?
For the time being, I am replacing the error logs with print statements, but I assume that there must be a workaround to this.
Perhaps you've reconfigured your environment somehow? (Try Runtime menu -> Reset all runtimes...) Your snippets works exactly as written for me --
logging.basicConfig can be run just once*
Any subsequent call to basicConfig is ignored.
* unless you are in Python 3.8 and use the flag force=True
logging.basicConfig(filename='app.log',
level=logging.DEBUG,
force=True, # Resets any previous configuration
)
Workarounds (2)
(1) You can easily reset the Colab workspace with this command
exit
Wait for it to come back and try your commands again.
(2) But, if you plan to do the reset more than once and/or are learning to use logging, maybe it is better to use %%python magic to run the entire cell in a subprocess. See photo below.
What is it that I am missing here?
Deeper understanding of how logging works. It is a bit tricky, but there are many good webs explaining the gotchas.
In Colab
https://realpython.com/python-logging
[This answer][1] cover the issue.
You have to:
Clear your log handlers from the environment with logging.root.removeHandler
Set log level with logging.getLogger('RootLogger').setLevel(logging.DEBUG).
Setting level with logging.basicConfig only did not work for me.
I have a problem with my logging in my python script. I run the same script multiple times (to have several simulations) using Pool for increased performance. In my script I'm using a logger with MemoryHandler, defined as below:
capacity=5000000000
filehandler_name = SOME_NAME
logger = logging.getLogger(logger_name)
logger.setLevel(logging.DEBUG)
filehandler = logging.FileHandler(filehandler_name)
memoryhandler = logging.handlers.MemoryHandler(
capacity=capacity,
flushLevel=logging.ERROR,
target=filehandler
)
logger.addHandler(memoryhandler)
and I log information using logger.info(...). However, I noticed that the logging is not always working. When I check different log files (I have one log sile per simulation), some log files contain data, the others are empty. There is not particular pattern in which are empty and which are not, usually it happens at random. I tried many things but it seems like I'm missing something. Does anyone has any suggestion on why Python logger might not be always working corretly?
Without a code snippet I would guess it is caused by the multiprocessing, you mention:
using Pool for increased performance..
You can check the official documentation on how to use logging module while multiprocessing.
I'm using Advanced Python Scheduler in a Python script. The main program defines a log by calling logging.basicConfig with the file name of the log that I want. This log is also set to "DEBUG" as the logging level, since that's what I need at present for my script.
Unfortunately, because logging.basicConfig has been set up in this manner, apscheduler writes its log entries to the same log file. There are an awful lot of these, especially since I have one scheduled task that runs every minute.
Is there any way to redirect apscheduler's log output to another log file (without changing apscheduler's code) while using my log file for my own script? I.e. is there a way to change the file name for each module's output within my script?
I tried reading the module page and the HOWTO for logging, but could not find an answer to this.
Set the logger level for apscheduler to your desired value (e.g. WARNING to avoid seeing DEBUG and INFO messages from apscheduler like this:
logging.getLogger('apscheduler').setLevel(logging.WARNING)
You will still get messages for WARNING and higher severities. To direct messages from apscheduler into a separate file, use
aplogger = logging.getLogger('apscheduler')
aplogger.propagate = False
aplogger.setLevel(logging.WARNING) # or whatever
aphandler = logging.FileHandler(...) # as per what you want
aplogger.addHandler(aphandler)
Ensure the above code is only called once (otherwise you will add multiple FileHandler instances - probably not what you want).
maybe you want to call logging.getLogger("apscheduler") and setup its log file in there? see this answer https://stackoverflow.com/a/2031557/782168
In python unittest, can how do i define a custom unittest.TextTestRunner class? I need to use the Python logger module and ensure that all logs go to the log file created by the Python logger module. Especially when exceptions and assert errors are thrown up they need to go to this log file. I need to be able to user the logger.info() and logger.warning() functions and so on.
Can anyone give me some sample code or link to sample code or steps to do so.