|A crash reporting system for Windows applications|
bindirectory and type crprober.exe in the command line.
binfolder and do not compile it yourself, you might experience some problems if Visual C++ 2010 Redistributable files are not installed on your machine. There may be error messages like 'The application configuration is incorrect' and so on. If you do not have Visual C++ 2010 Redistributable on your machine and do not want to install it, please compile the solution yourself as described in Compiling CrashRpt.
The tool can be used to open error report files generated by any version of CrashRpt. However it works the best with reports created by version 1.1 and higher.
Typically an error report file contains an associated MD5 hash file. The crprober tool can perform integrity check using the MD5 hash file. When you receive a report using HTTP connection, the MD5 hash can be retrieved from 'md5' script argument. When you receive a report using E-mail, the hash is attached to the mail message. For more information, see Sending Error Reports.
The tool extracts information about the error report (its GUID, version of CrashRpt that generated the report, creation time in UTC format), the information about the application that sent the report (name, version, path to executable file, the list of loaded modules), information about the operating system (name, version, service pack, CPU info), and information about the exception (exception address, exception code, stack trace). It presents the extracted information in text form (creates a text file or writes to the terminal).
The error report can't be processed properly without symbol files (*.PDB) generated by Visual Studio for your application. You typically store the symbol files locally when preparing to software release. For more information, see Preparing to Software Release.
The crprober.exe is a console tool. It accepts several command line arguments. The arguments are listed in the table below:
|/?||Prints the usage help.|
|/f <input_file>||Required. Absolute or relative path to input ZIP file name.|
|/fmd5 <md5_file_or_dir>||Optional. Path to .md5 file containing MD5 hash for the <input_file> or directory name where to search for the .md5 file. If this parameter is omitted, the .md5 file is searched in the directory where <input_file> is located.|
|/o <out_file_or_dir>||Optional. Output file name or directory name. Or use empty name "" to direct output to terminal. If this parameter is omitted, output is not generated.|
|/sym <sym_search_dirs>||Optional. Symbol files search directory or list of directories separated with semicolon. If this parameter is omitted, symbol files are searched using the default search sequence.|
|/ext <extract_dir>||Optional. Specifies the directory where to extract all files contained in error report. If this parameter is omitted, files are not extracted.|
|/get <table_id> <column_id> <row_id>||Optional. Specifies the table ID, column ID and row index of the property to retrieve. If this parameter specified, the property is written to the output file or to terminal, as defined by /o parameter. For the list of properties you can retrieve, see Using CrashRptProbe API.|
The crprober tool can return one of the following return codes:
|Return Code||Meaning |
|2||Invalid command line argument. Ensure you pass correct parameters.|
|3||Integrity check failed (MD5 hash mismatch)|
|4||Error extracting file. Ensure the extraction path is correct.|
crprober.exe /f error_report.zip /o "" /sym "D:\Symbol Files"
The following example opens 'error_report.zip' file located in the current directory, performs integrity check using 'error_report.zip.md5' file and writes output to the 'error_report.zip.txt' file. Symbol files are assumed to be located in 'D:\Symbol Files' or in 'D:\MyApp\sym' directory.
crprober.exe /f error_report.zip /md5 error_report.zip.md5 /o error_report.zip.txt /sym "D:\Symbol Files;D:\MyApp\sym"
The following example retrieves the application name from the error report and writes it to terminal:
crprober.exe /f error_report.zip /o "" /sym "D:\Symbol Files;D:\MyApp\sym" /get XmlDescMisc AppName 0
The following example retrieves the count of rows in the MdmpModules table and writes it to terminal:
crprober.exe /f error_report.zip /o "" /sym "D:\Symbol Files;D:\MyApp\sym" /get MdmpModules RowCount 0
When you have ZIP and MD5 files stored in the directory, you may want to process them all at once. You may want to process reports from the latest version of your application, ignoring all others. You may want to group similar error reports, for example, by stack trace of the exception thread. You may want to copy processed reports to some other directory, leaving not processed reports where they are. You also may want to move corrupted error reports to some folder, to move error reports not having exception information to another folder, and error reports not having symbols loaded for any stack frame to the third folder. You can automate this task using a batch (BAT) script.
Below an example batch script is presented (you can find the script in processing\scripts\postprocess.bat file).
@echo off rem Process a group of ZIP error report files set INPUT_DIR="E:\ErrorReports" set INPUT_FILE_PATTERN="*.zip" set ACCEPTABLE_APPNAME="CrashRpt Tests" set ACCEPTABLE_APPVERSION="1.2.0" set SYM_SEARCH_DIRS="D:\Projects\CrashRpt\CrashRptSaved\1.2.0" set SAVE_RESULTS_TO_DIR="valid_reports\" set SAVE_INVALID_REPORTS_TO_DIR="invalid_reports\" set CRPROBER_PATH="D:\Projects\CrashRpt\bin\crprober.exe" mkdir %SAVE_RESULTS_TO_DIR% for /R %INPUT_DIR% %%f in ( %INPUT_FILE_PATTERN% ) do call :process_report "%%f" erase temp.txt exit :process_report echo Processing file: %1 if %ACCEPTABLE_APPNAME%=="" goto appname_ok rem Get application name from the crash report file and write it to "temp.txt" %CRPROBER_PATH% /f %1 /o "temp.txt" /get XmlDescMisc AppName 0 if not %errorlevel%==0 goto failed set /p app_name=<temp.txt if "%app_name%"==%ACCEPTABLE_APPNAME% goto appname_ok goto done :appname_ok if %ACCEPTABLE_APPVERSION%=="" goto appversion_ok rem Get application version from the crash report file and write it to "temp.txt" %CRPROBER_PATH% /f %1 /o "temp.txt" /get XmlDescMisc AppVersion 0 if not %errorlevel%==0 goto failed set /p app_version=<temp.txt if "%app_version%"==%ACCEPTABLE_APPVERSION% goto appversion_ok goto done :appversion_ok set stack_md5=NoExceptionInfo %CRPROBER_PATH% /f %1 /o "temp.txt" /sym %SYM_SEARCH_DIRS% /get MdmpMisc ExceptionThreadStackMD5 0 if not %errorlevel%==0 goto save_results set /p stack_md5=<temp.txt erase temp.txt if %stack_md5%=="" set stack_md5=NoSymbolsLoaded :save_results mkdir %SAVE_RESULTS_TO_DIR%%stack_md5% rem Process report and write results to text file %CRPROBER_PATH% /f %1 /o %1.txt /sym %SYM_SEARCH_DIRS% echo Return code=%errorlevel% if not %errorlevel%==0 goto failed :ok move %1 %SAVE_RESULTS_TO_DIR%%stack_md5% move %1.txt %SAVE_RESULTS_TO_DIR%%stack_md5% goto done :failed mkdir %SAVE_INVALID_REPORTS_TO_DIR% move %1 %SAVE_INVALID_REPORTS_TO_DIR% :done rem Return from subroutine goto :eof
When the script finishes, you will have similar error reports groupped in subfolders. The question is what group to start to analyze first? What groups contain the reports of errors occurring most often? The following simple Python script (you can find the script in processing\scripts\basic_stats.py file) can help you to answer this question by getting the count of .txt files in each subfolder and outputting the results into the text file.
# This script calculates how many error reports are in each subdirectory # and how many error reports are in total. # Edit in_dir and out_file parameters as you need. import os in_dir = "D:/Projects/CrashRpt/valid_reports" out_file = "stats.txt" f = open(out_file, "w") def get_txt_file_count(dirname): count = 0 for root, dirs, files in os.walk(dirname, True): for file in files: if file[-4:] != ".txt": continue; count += 1 break; return count multimap = dict() for root, dirs, files in os.walk(in_dir): for dir in dirs: dir_name = os.path.join(root, dir) report_count_in_dir = get_txt_file_count(dir_name) if report_count_in_dir in multimap.keys(): multimap[report_count_in_dir].append(dir) else: multimap[report_count_in_dir] = [dir] ordered_list = list(multimap.keys()) ordered_list.sort() ordered_list.reverse() total_count = 0 total_groups = 0 for count in ordered_list: total_groups += len(multimap[count]); total_count += count * len(multimap[count]) f.write("Total %d reports (100%%) in %d directories\n"%(total_count, total_groups)) n = 1 for key in ordered_list: for dir in multimap[key]: percent = key/total_count*100 f.write("%d. %d reports (%0.1f%%) in '%s'\n"%(n, key, percent, dir)) n = n+1 f.close()
The expected script output:
207 error reports in total 105 error reports in 'subdir1' 50 error reports in 'subdir2' 30 error reports in 'subdir3' 20 error reports in 'subdir4' 2 error reports in 'subdir5'
So, the 'subdir1' contains the reports about an error reported the most often. And the 'subdir5' contains the reports about an error reported the most rare.