Log File Component
The Log File Component is a small set of VI's that can be used for logging errors, events, alarms, and notes for LabVIEW programs. It is particularly useful for autonomous, unattended programs. Additional error handling may (probably should) be included in the program, but this component is an easy way to make sure that each error or event gets archived with a timestamp into a common log file. This document provides some information on how the Log File Component can be used.
The design of this component is similar to the design practice outlined in A Software Engineering Approach to LabVIEW by Conway and Watts. This implementation was developed mostly in parallel with the LabVIEW Component Oriented Design (LCOD) proposed by Conway and Watts, with some later features added directly from their suggestions. As such, it is very modular and reusable, and it should be fairly easy to integrate into existing projects.
The main VI in this component is named the Log File Component.vi. This VI can be placed throughout your program, wherever an error or message can be generated, or it can be placed within an error handling routine where errors from throughout the program are handled. It has three inputs, Command, Log Message, and Error To Log. The Command input can often be left unwired, as it defaults to the Write Error command. Simply wire the error output of any sub-vi to the Error To Log input and the VI will parse the error, look up its description, time stamp it, open the log file, write the error, and close the log file. To write a message, alarm, event, or note to the log file, wire the Command input with a Write Message constant, programmatically create the desired alarm, event, or message string, and wire it to the Log Message input.
Besides Write Error and Write Message, the Command input has No-Op, Initialize, and Close commands. The No-Op command takes no action on the log file or the inputs. Besides writing to the Log File, this component keeps a running memory of the last 10 entries that it has written. Thus the No-Op command can be used within a user-interface to acquire and display these most-recent log file entries without having to access the log file on disk. The Initialize command determines the name and path of the log file and initializes the component (e.g. sets the memory of the last 10 log items to an empty array). This command can be called explicitly at the beginning of your program. However, this component is self-initializing, so if it is called with a Write Error or Write Message command without having been first initialized, it will run its initialization procedure before executing the desired command. The Close command should be called when the main program finishes. This clears the component so that it will be forced to reinitialize when the program next runs.
The Log File Component Caller.vi is an additional feature of my component design. This is not an example of how the component is used, but is a tool that can be incorporated into the main program if desired. It is used mostly for debugging. It is intended to be called dynamically as a top-level independent VI from the main program upon operator request. It provides access to all the functionality of the component, so that individual commands can be executed at will. For more complex components that may depend on other components or on complex inputs, this Caller may have limited utility, but for the simple Log File Component, it can effectively be used. Note that due to the way the Log File Component initializes in this distribution, the Re-Initialize function of this Caller has little utility.
Several changes should be made to the Log File Component package before it is used in an application. Most importantly, the initialization has been simplified from how it should be handled for a real application. In this example distribution, the parameters (Simulate/Use and Log File Path) are determined programmatically or statically in the Log File Component diagram. (The Log File Path is a date-stamped folder in the root directory of C:.) This is merely for ease of distribution. Normally, these parameters would be read from a configuration file. (See the Configuration Files section on my website (www.originalcode.com, under Programs) for an example of a flexible, robust configuration file architecture.)
Another item to update before using these VI's is how the Log File Component Caller is terminated. It has its own Done button that will cause it to close. It is also recommended that it close automatically if the main program quits. The main program could communicate this to all such Callers via a global, shared variable, or some other mechanism.
The Simulate/Use parameter is of little functionality in this Component, but is a general feature I include in all my components. If it is set to Simulate, many of the commands that would normally operate on the component's hardware (for a hardware driver component, e.g.) would be either re-routed to the No-Op command or would execute a subset of the functionality that did not attempt to communicate with the hardware. This can be useful for testing the component or even the larger application with the specific hardware used by the component is not available.
The Custom Error Parser.vi included with this distribution is used to parse the status, error code, source, and description into a single string that can be written to the log file. This VI uses the same error code database that General Error Handler uses. It does not incorporate exception handling. Custom error codes and descriptions can be added to the Custom Error Parser.vi by putting them into the related front panel controls and then saving those contents as defaults.
The Initialize command of the Log File Component uses the Create Directory Structure.vi (also available separately on my website) to ensure that the desired path for the log file actually exists before the log file is created or written to. Also note that each time this component writes to the log file, it opens the file, writes, and closes the file. This is relatively inefficient, but in most cases, the performance hit is negligible. (Your mileage may vary, especially if you start logging lots of errors or tend to log many, many messages.) The reason for always opening and closing the file is to help ensure that the log file is as up-to-date as possible in the case of a system crash. One of the main reasons for logging errors is to diagnose problems after they occur, so losing all or part of the log file during a system crash would be less than ideal. Also note that if this VI is called after another VI that can potentially generate errors, but no error has been generated, then the Write Error command is automatically diverted to the No-Op command. The No-Op command does not access the log file, so in the (frequent) case where no error was generated, there is no significant performance penalty incurred by this component.