Moin 1.3 has a new user friendly error messages, that show up when you make a configuration mistake or known internal error happens. The problem with these nice errors is that they hide the real exceptions, making debugging harder.
In general we should not have fatal errors. We should recover from most errors in a sane way, with a friendly error message in the page itself, for example, like too long file names is treated. But sometimes we have errors that we can't recover from - like configuration errors. In these cases, FatalError sub classes are useful.
Different types of users
Users, wiki administrators and developers need different error messages:
Developers
- Want a full detailed traceback, showing local variables at each point
- Need full traceback always
- When checking other people errors, need the system and moin details
Wiki admin
- Want simple error message, that will tell how to fix the problem if it can be fixed
- May want to see the full traceback, and may be able to fix code
- Some would like to get tracebacks always, some would like simple errors as default
- May want to report a bug using the full traceback
Users
- Usually don't care about errors, they can't fix them anyway.
Default error report
- Show simple clear error message
- Help - suggest what to do:
- How to fix configuration if relevant e.g wrong permissions on data dir
- How to trace the problem e.g check some config options
Point to relevant documentation e.g. HelpOnConfiguration
Point to places where you can get more support e.g. mailing list, #moin, MoinMoinQuestions
- Point to our bug system
- Show full debugging information on demand
Full tracebacks, including all tracebacks happened e.g AttributeError that raised InternalError.
- Show system details
Debug mode error message
Full tracebacks, including all tracebacks happened e.g AttributeError that raised InternalError.
- Show system details
How to set debug mode
Moin uses environment variables or query:
Set MOIN_DEBUG environment variable, for example, in moin.cgi:
import os os.environ['MOIN_DEBUG'] = '1'
Or call with debug e.g http://www.example.com/wiki/FrontPage?action=edit&debug
Use the query to debug quickly, and the environment variable when developing.
Planning
Improve logging
currently we print the error message to the log, without the traceback.
Save html traceback to a log dir
cgitb has already support for logdir. We can easily add this feature:
Each traceback will save in the logdir directory if you define MOIN_DEBUG_LOGDIR. Each traceback is saved as tmpxxxxxx.html.
os.environ['MOIN_DEBUG_LOGDIR'] = '/path/to/logdir'
Those random names suck - names like traceback--yyyy-mm-dd--hh-mm-ss--nn.html is much better. I think it can be a useful feature for any user of cgitb.
This can be useful to read detailed tracebacks in a browser without showing sensitive information to the world.
Traceback log
Have a special log for tracebacks, containing full tracebacks in text format.
Before we load the config, we can't access the wiki error log, so this should go to separate log. For example, <server script>.log in the same directory as the server script
After we loaded the config, we can print the tracebacks to the wiki error.log.
Privacy issues
Don't show sensitive information:
- Operating system and version, might be useful to use known exploits
- Web server version
Location of wiki directory or MoinMoin installation
- user id, shown either in variables on in path in IOError
- user hashed password
- more?
Problem: some data is needed for debugging. If we filter sensitive data in tracebacks, we might get bug reports with missing information.
Alternatives:
Filtering data in traceback
We can add a filter fuction to cgitb.Frame that filter values of certain names.
Problems:
- Hard to lookup values, e.g. value may be a dict that displayed by repr(dict). We have to lookup into the dict to find sensitive names.
- Each time we change a name we will have to change the filtering function.
I don't think it will work, be very fragile and make debugging harder.
Don't display tracebacks for non local requests
In very early stage, it may be hard to tell if this is a local request.
We can use this feature anyway, together with debug levels.
Use debug levels
- 0 - don't show tracebacks, only log
- 1 - show collapsed tracebacks (this is the current default)
- 2 - show always tracebacks - for developers
To implement this, we have to add 2 lines of code, check debug level, and create cgitb.Hook with the proper display and logdir values.
I think that this is the way to go.
- You don't show sensitive data to the world
- You have a complete debugging information for yourself or for us
- Robust
- Easy to implement
2.0
- Rafactor all error code out of request: fail will ask error.handleError to do everything, send headers, log, show error view.
- Have one point that catch errors instead of 7
- request sub classes should not do any work on init, just set their variables
__init__ should not do any work, just set default values, so it will not need error handler.
- All work should be done in run(), inside one try: except:
When catching errors inside moin, raise InternalError with a simple explanation of the error