Separating Errors from Output in a Deployed Application
Guest blogger Peter Webb returns with another in an occasional series of postings about application deployment.
Contents
Errors are Different!
By default, standalone applications display both ordinary output and and errors via the same channel. This can be convenient, as it makes capturing all the output relatively simple. With this simplicity comes a hidden danger: error messages may get lost if the application prints out a lot of messages. In this final installment of my series of posts about redirecting program output, I'm going to show you how to treat errors differently than other types of messages. One reason for doing so is to make error messages more obvious, so they are easier to find. When I'm looking through a long listing of program output, I'm often scanning primarily for error messages, because errors indicate some intervention is necessary. I'd like the errors to be emphasized or decorated so I'll spot them quickly.
Applications and shared libraries created by MATLAB Compiler split the output from MATLAB functions, into two streams, one for errors and one for all other types of output, including warnings. Since MATLAB Compiler-generated components allow you to install a separate handler for each of these streams, it is conceptually simple to emphasize error messages.
A Brief Review of the Application
monitor is a C program that calls a single MATLAB function, sendmessages. The MATLAB function displays three kinds of output: some informational text, a warning message and an error message. monitor.c relies on three monitoring functions, StartMonitoring, MonitorHandler and StopMonitoring, to redirect its output to a user-visible window. Separate, platform-specific files contain different sets of monitoring functions.
Download the source code for the monitor program from MATLAB Central. See the monitorREADME in the ZIP file for a description of each of the downloaded files and complete directions for building the application.
Splitting the Error and Output Streams
The generated library initialization function libmsgfcnInitializeWithHandlers takes two input arguments: an error message handler and a print message handler. The example monitor.c I discussed in last week's post installs the same handler, the function MonitorHandler, for both the error and the print output streams:
if (!libmsgfcnInitializeWithHandlers(MonitorHandler, MonitorHandler))
Change the first parameter to a specialized error handler, the ErrorHandler function, and the monitor program decorates the error messages it displays, making them easier to see.
if (!libmsgfcnInitializeWithHandlers(ErrorHandler, MonitorHandler))
Emphasizing Error Messages
I've chosen to emphasize error messages in two different ways. On UNIX the monitor window displays error messages in red. The UNIX ErrorHandler function uses X terminal escape codes to set the color of the displayed text. ErrorHandler sends the sequence ESC [ 1;31m to set the text to red, outputs the error message, and then restores the foreground color to black with the sequence ESC [ 1;30m.
int ErrorHandler(const char *s) { const int csi = 0x9b; const char *redOn = "1;31m"; const char *redOff = "1;30m";
time_t now = time(NULL); char nowIsTheHour[128]; fwrite(&csi, sizeof(int), 1, tmpLog); fprintf(tmpLog, "%s", redOn); sprintf(nowIsTheHour, "%s", ctime(&now)); fprintf(tmpLog, nowIsTheHour); fprintf(tmpLog, "%s\n", s); fwrite(&csi, sizeof(int), 1, tmpLog); fprintf(tmpLog, "%s", redOff); return strlen(s)+strlen(nowIsTheHour)+1; }
The UNIX monitoring mechanism sends its output to a temporary file, the contents of which are displayed in an X terminal running tail -f. Refer to the previous post in this series for complete details of the implementation.
The monitoring mechanism in the Windows program monitorWinDialog uses a dialog box containing a ListBox. The DialogProc function (the function that handles events directed at the dialog box), prefixes a line of five asterixes to error messages before displaying them:
case ERROR_MESSAGE: strcpy(buffer, "***** "); strcat(buffer, (const char *)lParam); ListBox_AddString(GetDlgItem(box, IDC_LIST1), (const char *)buffer); break;
The error handler function ErrorHandler in the Microsoft Windows event log version, monitorWinEvents calls ReportEvent with an event type of EVENTLOG_ERROR_TYPE.
if (!ReportEvent(hEventLog, EVENTLOG_ERROR_TYPE, EXAMPLE_CATEGORY, INFORMATIONAL_MESSAGE, NULL, 1, 0, (LPCSTR*)pInsertStrings, NULL))
In response, the event log viewer displays a stop-sign icon next to the event. The print handler MonitorHandler creates events with an event type of EVENTLOG_INFORMATION_TYPE, causing the event logger to display a "talk bubble" icon next to the event.
Seeing the Differences
Once you've changed monitor.c to install separate handlers on the error and print message streams, build and run the application.
First use MATLAB Compiler to create the shared library containing sendmessages:
>> mcc -W lib:libmsgfcn -T link:lib sendmessages.m
Then, use mbuild to build the main program and link it with the shared library:
(UNIX): mbuild -g monitor.c monitorUNIX.c -L. -lmsgfcn
(Windows) -- two commands because there are two programs:
mbuild -g monitorWinDialog.c monitor.c WinLogger.rc libmsgfcn.lib
mbuild -g monitorWinEvents.c monitor.c libmsgfcn.lib
The first command builds the dialog box version (monitorWinDialog.exe) and the second command builds the event log version (monitorWinEvents.exe).
Now run it. The program takes three input arguments: the informational message, the warning and the error message.
(UNIX): ./monitor information "look out!" oops
(Windows): monitorWinDialog.exe information "look out!" oops
It should be easy to pick out the error message in the program output.
That's all I've got to say about managing errors and output in a deployed application. Do your applications do things differently? Are any of these ideas going to be useful to you? What would you like to see the Compiler do differently? Let me know.
- Category:
- Deployment