-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updates to the python logging system for the AB #1011
Updates to the python logging system for the AB #1011
Conversation
commits for corrections to the uncertainty distributions that were included within the same branch. Improves thread safety in logging increasing stability in the multi-threaded processes.
… to correct for use of logging over the standard console. Adds the .logs to .gitignore.
Hi @marc-vdm I put you in here as this is related to one or two issues that you have had previously. These changes are based on what I have read in the PyQt documentation, regarding the use of thread safe methods (the consequence of which is to avoid the standard print function). The motivation for this was the messages from @mixib with the database import issues #614, @mixib has already tested this with a simple commenting out of the print statements, which worked (also for me) in improving the stability. These updates are to provide a longer term solution. What I think is the most important aspect to review is the handling of files and the locations of the logs. |
Will do a review soon, this week for sure. Just one question already:
What do we do that is multithreaded during imports? I thought BW took care of importing? |
Brightway does perform the actual imports but with the different import types and strategies used there is input from AB. The really dumb part is that the problem is with the logging, because this has been done with the ordinary Python print() function that is not safe with threaded processes. Unfortunately, this is also the case in Brightway, so we need to raise an issue in BW to use the python logging library instead. In line 854 in db_import_wizard of this PR there is the log statement for when linking exchanges, in Linux this contributed significantly to instabilities when using Pythons print() function (sorry for all the edits) |
Whoops, to answer your first question the import procedures are run from a separate thread, it is during the local imports that we use the print function to producing the logs that caused the instability |
…as published on the python docs for logging), improving the stability of logging.\n2) Changes the generation of the logging object that is more compatible with pytest, supporting the existing test procedures.
Alright thanks for the explanation! Some more questions:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See attached comments
activity_browser/logger.py
Outdated
if Logger.file_handler is None: | ||
dir_path = os.getcwd() + "/.logs" | ||
os.makedirs(dir_path, exist_ok=True) | ||
Logger.cleanDirectory(dir_path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it not be better to actually store the logfile (perhaps with sessions <timestamp>
as name?) And perhaps we store the files for a year instead of a week? These files should not be larger than a few kB, so storing them forever should not even become a problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you are right on these points, I've extended the period to a year. I've also provided a timestamp for the file names, although I haven't changed the stem of the name (ab_logs). This might not be required however, it might be useful to have some separation if people start going crazy with plugins
activity_browser/logger.py
Outdated
name = name + "_" + Logger.uniqueString(8) + '.log' | ||
file_path = dir_path + "/" + name | ||
Logger.file_handler = logging.FileHandler(file_path) | ||
Logger.file_handler.setLevel(logging.WARNING) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean we only store WARNING
level items in the log? I'd advocate to actually store everything, it's not really big anyway. And is there a place where I can see the different levels of logging? I'm thinking it could be useful to actually log way more detailed info to the logfile than we show in the terminal/debug -though this last sentence is a problem for later and more a new feature than it has to do with these bugs-.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you are right, the log files generally hold a lot more than the console or window streams. I've changed the file level to include everything (well almost, it's set to DEBUG, which is lower than INFO)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So there are 4 tiers by default?
debug
, info
, warning
and error
?
That could work for us I think. We can just start writing relevant debug data to the logfiles, and perhaps in some cases provide less data to the user, as it was previously all wrapped into print
of course.
Again though, this is something for later. Lets first get this working in general haha
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a critical level, which is one level higher than an error. Plus one "lower" level, the lower level is basically a signal to turn on the turn on the logger for the dependencies too.
@@ -330,14 +330,14 @@ def perform_MonteCarlo_LCA(project='default', cs_name=None, iterations=10): | |||
mc = perform_MonteCarlo_LCA(project='ei34', cs_name='kraft paper', iterations=15) | |||
|
|||
# test the get_results_by() method | |||
print('\nTesting the get_results_by() method') | |||
# print('\nTesting the get_results_by() method') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are all these commented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well for no particular reason really, I didn't put the logger here because it serves no purpose. I could just as well have left these lines the same though, I admit it doesn't make a difference
@@ -142,7 +143,7 @@ def database_and_key_check(data: pd.DataFrame) -> None: | |||
msg = "Error in importing file with activity {} and {}".format(ds[4], ds[5]) | |||
raise IncompatibleDatabaseNamingError() | |||
except IncompatibleDatabaseNamingError as e: | |||
print(msg) | |||
log.error(msg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it log.error(msg)
here instead of log.error(e)
like here? Not saying either is right or wrong, just curious why this is the case? Would it be better to log.error("{}: {}".format(e, msg))
?
Same for the 2 instances below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Part of the reason is that this error doesn't actually contain any information. The decision I made previously was to provide a statement of what caused the error when and where it happened and to raise an error that could be captured at a higher level for managing what should happen. This will be redundant when I push up the changes for scenario files soon, for the sake of doing things properly this should probably take the Exception, however for the sake of expediency I'm going to avoid this for now
@@ -108,7 +109,7 @@ def closeEvent(self, event): | |||
event.accept() | |||
|
|||
def cancel_thread(self): | |||
print('\nDatabase import interrupted!') | |||
log.info('\nDatabase import interrupted!') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should make this a warning?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm, this is a user initiated cause so I think it's not warranting a warning, pesonally
Hey Marc, so for the 1st point I have changed this to use the appdirs location for log files. On my distro its in –/.cache/Activity-Browser/ I'm not sure where this is in windows, before it was stupid. As for your second point, this has been quite sticky for me today, after trying too many ways to get this to work I've now resorted to using a dirty approach. I'll have a go through the python logging documentation to find a proper way to get this done, but this won't alter anything for the user. It will just be a bit cleaner from the code perspective |
…le, corrects for deletion of impact assessment methods. Updates the routine to the lca_setup module for calling the logger.
…to ABHandler. The module now contains the formats and settings for the Stream handlers. Calling of the methods in the other AB modules requires passing a logging.Logger instance and the name of the calling module. These are then incorporated into the wrapping routines in the class. Additions:\n 1) An error wrapper is provided and also explicitly provides a trace of the error.\n 2) A timestamp routine is provided and used for providing the file names for log files.\n 3) A standard location based on appdirs is provided and used for log file locations.
…that improves support for trace backs. Additional changes have been made to instances calling the logger module, including in the testing suite where the calls have been updated to reflect the changed logger interface.
…es a printout of the log file location.\n2) Formatting of the console streams is changed to provide a simpler, easier to read structure avoiding the time and location stamps.\n3) The extra argument from the logging module is used to pass the actual modules where the logs are created
Adds a module logger that provides a logging facility for outputting messages to the standard output, the AB debug window and a file (for upload).
Checklist
bug
,feature
,ui
,change
,documentation
,breaking
,ci
as they show up in the changelog