Are you an addon developer? Ever wished you could easily get in-the-moment feedback from your users? Unsure of what errors your users are encountering most often (how would you even know?). It doesn’t have to be difficult. This tutorial will show you how to use an example repository for integrating user error reporting inside blender addons with a simple “backend” that anyone can use – Google Spreadsheets!
Why implement user error reporting inside an addon?
- Users are more likely to report rarer issues with a lower barrier (fewer clicks) to report. Things like registering for a GitHub account or describing an issue or checking for duplicates may all lead to a report not filed.
- Higher duplication of common reports. While this may sound like a negative, it helps prioritize errors that are affecting the most users with the most current reports. This helps you prioritize your time as a developer.
- It helps confirm issues are resolved. With error reports captured consistently, you can detect whether prominent issues were truly resolved by checking that the errors no longer show up in newer releases.
Or check out one of these resources
Video tutorial
The above video is the live presentation from the 2020 World Blender Meetup Day. The video might show slightly outdated documentation, but follows the same steps as below.
Add user error reporting to your addon
Follow the steps below to implement this simple reporting utility into any existing addon. Code is referenced from this repository.
1) Copy the user_reporting.py file into your addon
This contains the mostly pure python code for user reporting. If you wanted to customize for connecting to a database, you would also make these changes here.
2) Register the new module and set bl_idname
Edit your addon’s __init__.py
file to import the module and run it’s register/unregister functions.
Take note: unlike typical register functions, the user_reporting.py
register function requires passing in the addon’s bl_info
dictionary. This is used to set the active addon’s version so that it is directly logged in the error reports.
__init__.py
from . import user_reporting def register(): user_reporting.register(bl_info)
3) Create a Google form
Now we jump over to creating a google form, which later we connect the questions fields to the Blender addon.
Most likely, these are the key fields your Google Form should have:
- Addon Version
- Blender Version
- Platform (operating system)
- Error Message
- Optional (default blank) field for more information
The exact names do not matter, just make sure one field exists for each of the above. It does not hurt to add more, if appropriate.
Key note: Deleting a field (in an already live-used form) is NOT a good idea unless really needed. As you will see in the next step, each question gets a unique ID. Re-ordering, renaming, etc is all fine, but don’t delete a question once you start using it in production unless you are sure you never want it back. Deleting and adding questions doesn’t break the form itself in any way, it just severs the link to the blender addon so it is no longer automatically filled out when the page is opened from Blender.
See the live form used in this repository’s example, noting the one optional question added and the arbitrary question order.
4) Generate a pre-filled form link
In order for this system to work, we need to deep link the user into a form that already fills out all of the required questions. To do this, we need to get the backend field IDs for each question.
The the convenient way to get these unique IDs is by generating a “prefilled link”, and extracting the IDs from there. To make it easy, consider entering the plain lower case, no-spaces name of each question into the fields you want to pre-populate. Example below
Example pre-filled form output (test it out in a new window!):
https://docs.google.com/forms/d/e/1FAIpQLSdHTA6aOJCbNsTCpRoWDWheWuQjci1d6gxnxHb1FdAnXvRHdw/viewform?usp=pp_url&entry.391369946=addon_version&entry.1215866813=blender_version&entry.1023948975=error_message&entry.286196237=platform
user_reporting.py
5) Update global variables in Update each of the following three areas:
IDNAME
should just be a unique, lowercase prefix to use in the report popup operator’sbl_idname
.FORM_ID
should be set to Google Form’s ID. For example,1FAIpQLSdHTA6aOJCbNsTCpRoWDWheWuQjci1d6gxnxHb1FdAnXvRHdw
is the ID you would get from the sample link above. Be sure to grab the ID from the actual prefilled link, and note it does not include any slashes.FORM_FIELDS
, which maps individual question IDs in the form with the value we populate from Blender.
From the prefilled url in the previous step, we can see entry.1215866813=blender_version
is one of the encoded parameters. In this case, blender_version
was manually typed into the question which was named “Blender Version”. In the URL, this “Blender Version” question is represented with the ID entry.1215866813
. Thus, the blender_version key should be listed as 1215866813
in user_reporting.py
file (ignore the entry.
part). Replace all IDs found in the FORM_FIELDS
accordingly.
You can add more if you like, but this only makes sense if you think you can prefill the values of the given field inside blender. Any fields requiring manual user entry can be ignored in the URLs the addon generates.
5b) [Optional, more advanced] Async integration to submit to form instead of open link
Just to call this out, if you want to make the process even more seamless, you could directly log the data into a spreadsheet instead of using Forms as a middle-man.
Caution: This would require generating a Google API key for spreadsheets, and this would be public in your addon (and thus potentially abused). If you’re going down this route, consider taking it a step further and actually integrate with a live database service instead of forms, but that’s your own call.
6) Decorate all execute functions
Now add function decorators to every operator function you want to have user error reporting. Or at least the ones you want user reporting for, though there’s no particular reason why you would not use it for all operators your addon defines.
This is done using the @user_reporting.wrapper
decorator around the execute function. Full example below.
File where operator is defined
from . import user_reporting ... class URW_OT_no_error(bpy.types.Operator): """An operator which has no errors""" bl_idname = "object.userreport_no_error" bl_label = "Demo No Error" @user_reporting.wrapper def execute(self, context): return {'FINISHED'}
7) Test it!
Force an operator to fail by throwing an Exception
in one of the decorated execute functions of an operator. When next running this operator, you should get a popup. On pressing OK, as browser page should open with questions prefilled.
Not working? Some troubleshooting steps:
- I am not getting a popup: Make sure your addon operator is raising an intentional exception, and that the execute function (not draw function or anything else) was properly added. Try restarting blender to fully reload the python modules, as a simple in-session refresh may not work.
- A browser window is not opening when I press OK: There may be an error happening in the decorator code, double check your blender console to find out what.
- A browser window opens, but shows a broken link (“resource unavailable): Double check to make sure you updated the correct form id. Start with a working (prefilled) link, grab the ID from this. Do not grab the ID from the “edit form” url.
- The form loads, but none or only some of the auto-filled questions are actually auto-filled: Double check the question IDs coming from the prefilled link. This is also a good place to reiterate: deleting questions will remove the question’s ID, which cannot be undone.
8) (Optional) Add a direct user error reporting function
If you want, you can also add buttons to panels or menus to directly open the reporting Form in a browser. This being said, this would require a user to fill out “error” section of the form, which then won’t be in the same format as normal traceback errors like other issues, but is a way to put it all in one place. They still get their blender version, addon version, and platform auto filled out.
To use this, use the sample below in a panel or menu draw function.
# directly open form in browser, prefilling all but the error message field ops = col.operator("wm.url_open", text="Report error") ops.url = user_reporting.Reporter.default_form_url
9) User error reporting and analysis
This section is a bit looser as there is any number of ways to then manager the stream of reports coming through. Some key suggestions though:
- Add a custom column to the right of the raw form answers, which reduces all errors to just the last e.g. 64 characters via a formula. Add another column to the right after that which counts the number of times this consolidated error message appears, to help give weight to the most common errors.
- Build a pivot table off of the raw data, and pivot by version number or count of errors (again, the “consolidated” error is helpful here to group things together)
- Keep the raw data the raw data, import the responses elsewhere if you need to transform the values more significantly or it gets to be too large and slow to load.
See this sample spreadsheet showing some of these basic layers of analysis, including custom formulas. The key themes of analysis is to group similar error reports or users, and help prioritize the most impacted users. In this sense, there are a couple good ways to pivot the data to view the situation:’
- Pivot by error reports: Will show the most common error reports
- Pivot by platform: You can see which operating system reports more errors; maybe you develop on one OS, and users of another keep running into path-based issues?
- Pivot by version: Either blender version or addon version. Check your homework that you actually fixed prior errors by seeing they don’t pop up in newer versions of your addon!
Further thoughts
The above workflow is the tip of the iceberg for error reporting possibilities, but hopefully demonstrates that it does not need to be complex in order to be useful. Some thoughts on extensions:
- Replace the Google Form interface with a direct API call. This avoids asking the user to ever leave blender – any friction will result in a loss of responses!. See the MCprep addon, which uses the Firebase realtime database for this purpose. Be sure to make put your internet calls inside an asynchronous thread!
- Detect whether a user’s error has been reported before, or even solved.
- To do this, consider making a hash of the error report and then reading from a published place a list of reported or solved errors. This could even be the same spreadsheet that raw errors are reported to, although that would require making that entire spreadsheet publicly viewable. Better would be to make another public read-only spreadsheet that imports only the precomputed hash and then whatever supporting information for the given bug report hash (canonical issue links, fix status, etc)
- Can direct the user to install the latest version, or even redirect them to a thread with more details on the issue (e.g. a canonical issue thread)
- Weird bonus: Auto detect if a new version of the addon is out, simply by querying whether bug reports from a newer version exist! (OK, but really this is what features like the Addon Updater module are for)