Logging#

to be refined

This page was taken over from my private library as is and needs refinement which is planned in scope of #79 

Basic Logging#

Logging during development shows progress and hints you left in your messages. Any log you issue will be printed to the console. When your application is shipped out of your hands, you rely on logging written to a file. Once log files are written, some log rotation and cleanup of storage would be nice: appxc starts a new log file for each application session (log rotation) and will only keep the last five log files (cleanup).

Assumption is that your application structures code into one top-level package. The __init__.py of this top-level package is the place to activate logging:

from appxc import logging

logging.activate_logging(__name__)

The function activate_logging() must only be called once within your application.

Each module from which you want to log will then use:

from appxc import logging

log = logging.getLogger(__name__)

Note that getLogger() is the same getLogger() from python’s logging module such that all logging functions from there apply. The above log would be used like:

def some_function():

log.debug('')
log.info('For state changes')
log.warning('Unexpected but OK')
log.error('Definitely wrong but you can fail safely')

and produce log lines like the following, the number (12) being the code line in the module:

09:56:40.407 INFO app_package.module.some_function(12): For state changes

Note that date is part of the file name (./data/logging_yyyyMMdd_00.log) and, therefore, not printed.

Logging Classes#

If you are working with classes, you likely want to have the class name contained in the log lines. In this case, you can setup logging like:

from appxc import logging


class YourClass():
	log = logging.getLogger(__name__ + '.YourClass')

Logging Other Modules#

Warnings and Errors of other modules are logged to console and file just like logs of appxc and your application. What would be missing is uncought exceptions. For that reason, you should embed your main code into:

from appxc import logging

import your_application

log = logging.getLogger(__name__)

try:
   # your main application code, like:
   your_application.run()
except Exception:
   log.exception('Uncought exception.')

Note the logger log in your main file is NOT in the scope of your application package and will only log WARNING level or above. It’s scope will be __main__.

Logging GUI command errors (tkinter)#

If you are running a tkinter GUI, your command callbacks might throw exceptions which tkinter only prints to stderr by default. To change this behavior, you need to add this bit to your main application.

# ... wherever you start your main GUI ...
gui_root = tkinter.Tk()
# This line replaces the default behavior with the function below
gui_root.report_callback_exception = _handle_gui_exception

def _handle_gui_exception(exception, value, traceback):
	log.exception("GUI callback with exception:")

Logging to GUI (not yet implemented)#

Some of your logging is relevant as feedback to the user, like: “Password is too short” or “Process finished OK”. For this, you can embed a logging frame. This will show a single line with the latest info message showing progress and showing the latest INFO message. Because you will sometimes need to allow the user accessing more lines of such logging (like for: “Process finished with 4 warnings (see above)”) the logging frame can extend to 5 lines of scrollable log lines.

from appxc.logging.gui import LoggingFrame

# ... other code that generates your gui

log_frame = LoggingFrame(parent)

# you still need to place the frame via, e.g., grid()

Pop-Up-Messages#

No feature is provided here to link pop up warnings/errors with logging. Just forward the message also to the appxc logging module.

Extentions (not yet implemented)#

  • Sending bug report via Email. Automatically sends all available log files.