;+ ; NAME: ; ErrorLogger__Define ; ; PURPOSE: ; ; The purpose of this program is to log program errors or text messages during ; program execution as an aid to debugging such a program at a later date. The ; ErrorLogger program is written as an object so that it will persist in the IDL ; session until it is destroyed. ; ; AUTHOR: ; ; FANNING SOFTWARE CONSULTING ; David Fanning, Ph.D. ; 1645 Sheely Drive ; Fort Collins, CO 80526 USA ; Phone: 970-221-0438 ; E-mail: david@idlcoyote.com ; Coyote's Guide to IDL Programming: http://www.idlcoyote.com ; ; CATEGORY: ; ; Utilities ; ; CALLING SEQUENCE: ; ; errorLogger = Obj_New("ErrorLogger") ; ; ARGUMENTS: ; ; filename: The name of the error log file. If not provided, a default name ; will be created, based on the current system time. (Optional) ; ; KEYWORDS: ; ; ALERT: The default behavior of the error logger is simply to write text to a file. ; But if the ALERT keyword is set, the program will alert the user via a ; message dialog that an error has occurred when using the AddError method. ; Default is 0. (Input) ; ; DELETE_ON_DESTROY: If this keyword is set, the error log file will be deleted when the ; ErrorLogger object is destroyed, but only if the ErrorLogger object is not ; in an error state at that time (error status = 2). Default is 0. (Input) ; ; NOCLUTTER: Believe it or not, some people who use an ErrorLogger prefer that an error log ; file is never left behind. (They prefer that the program act like cgErrorMsg.) ; For those people, the NOCLUTTER keyword provides a way for them to automatically ; set the ALERT and DESTROY_ON_DELETE keywords to 1. It also prevents the error ; logger from ever setting the error status to 2. Thus, when the ErrorLogger is ; destroyed, the file is always deleted. Default is 0. When set, overrides ALERT ; and DELETE_ON_DESTROY settings. (Input) ; ; NOTRACEBACK: Set this keyword to suppress traceback information in the error log output ; and in any alerts issued by the program. Default is 0. (Input) ; ; TIMESTAMP: Set this keyword if you wish a time stamp to be appended to the provided ; filename. Otherwise, the filename is used as defined. Default filenames ; always have a timestamp appended to the file name. (Input) ; ; METHODS: ; ; AddError: Adds an error text string or array to the error log file. By default, ; it will add the HELP, LAST_MESSAGE=1, /TRACEBACE traceback ; information to the file. (Procedure) ; ; AddText: Adds a text string or array to the error log file. (Procedure) ; ; ClearLog: Erases all the text currently in the error log file. (Procedure) ; ; CloseFile: Closes the currently open error log file. (Procedure) ; ; Flush: Forces a write of any current information to the disk (Procedure) ; ; GetProperty: Gets properties of the object. (Procedure) ; ; LastMessage: Returns the last message text written into the error log file. (Function) ; ; OpenFile: Opens the error log file for writing. (Function) ; ; PrintLastMessage: Writes the last message text written into the error log file to ; standard output. (Procedure) ; ; Status: Returns the current status of the error logger. (0 - waiting for input, ; 1 - normal operation, 2 - error operation.) (Function) ; ; SetProperty: Sets properties of the object. (Procedure) ; ; SetStatus: Sets the current status of the error logger. Normally not used by the ; user, but used internally. (Procedure) ; ; MODIFICATION HISTORY: ; ; Written by David W. Fanning, November 2009. ; Modified and expanded the way errors are written into the log file and displayed. ; Also made it possible to automatically delete the log file when the object is ; destroyed, if the error logger is not in an error state at the time. Added ; DELETE_ON_DESTROY and NOTRACEBACK keywords to the INIT and SetProperty ; methods. 28 Jan 2010. DWF. ; Modified default filenames so that I am now guaranteed to get unique file names ; by using cgTimestamp program from the Coyote Library. 8 Feb 2010. DWF. ; Added NOCLUTTER keyword. 15 February 2010. DWF. ; Added PRINT keyword to AddText method to allow users to log statements that should ; also be printed easily to a file. 17 February 2010. DWF. ; Small documentation changes to the program. 22 June 2010. DWF. ; Made a change so that the file is not opened until something needs to be written ; to it. 22 June 2010. DWF. ; Added FLUSH method and keyword IMMEDIATE to the INIT method (defaults to 1) which ; will immediately flush the log information to disk when log information is ; added to the object. This will prevent missing information that is buffered ; when a program crashes. Matt Savoie suggestion. DWF, 10 Sept 2010. ; Now calling cgTimeStamp rather than TimeStamp to avoid problems with IDL code. 6 Feb 2013. DWF. ;- ; ;******************************************************************************************; ; Copyright (c) 2009-2010, by Fanning Software Consulting, Inc. ; ; All rights reserved. ; ; ; ; Redistribution and use in source and binary forms, with or without ; ; modification, are permitted provided that the following conditions are met: ; ; ; ; * Redistributions of source code must retain the above copyright ; ; notice, this list of conditions and the following disclaimer. ; ; * Redistributions in binary form must reproduce the above copyright ; ; notice, this list of conditions and the following disclaimer in the ; ; documentation and/or other materials provided with the distribution. ; ; * Neither the name of Fanning Software Consulting, Inc. nor the names of its ; ; contributors may be used to endorse or promote products derived from this ; ; software without specific prior written permission. ; ; ; ; THIS SOFTWARE IS PROVIDED BY FANNING SOFTWARE CONSULTING, INC. ''AS IS'' AND ANY ; ; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ; ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT ; ; SHALL FANNING SOFTWARE CONSULTING, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, ; ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ; ; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ; ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ; ; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ; ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ; ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ; ;******************************************************************************************; ; ; NAME: ; ErrorLogger::AddError ; ; PURPOSE: ; ; Adds error text to the error log file and sets the error log status to 2 (error ; condition). If the error logger alert flag is set to 1, the method will alert ; the user to the error with a pop-up message dialog as well as writing the output ; to standard output. ; ; CALLING SEQUENCE: ; ; errorLogger -> AddError, theText ; ; ARGUMENTS: ; ; theText : The error message text you wish to add to the file. If not provided, ; the text of the last error message (Help, /LAST_MESSAGE) is used and ; written to the file. ; ; KEYWORDS: ; ; None. ; ;******************************************************************************************; PRO ErrorLogger::AddError, theText ; The text will equal the ERROR_STATE messsage string if not available. IF N_Elements(theText) EQ 0 THEN theText = !Error_State.Msg ; Get the call stack and the calling routine's name. callStack = Scope_Traceback() callingRoutine = (StrSplit(StrCompress(callStack[1])," ", /Extract))[0] ; Are widgets supported? IF !D.Name EQ 'PS' THEN BEGIN widgetsSupported = 1 ENDIF ELSE BEGIN widgetsSupported = ((!D.Flags AND 65536L) NE 0) ENDELSE ; No dialogs, unless alert is set. IF ~Keyword_Set(self.alert) THEN widgetsSupported = 0 ; It is not enough to know if widgets are supported. In CRON jobs, widgets are ; supported, but there is no X connection and pop-up dialogs are not allowed. ; Here is a quick test to see if we can connect to a windowing system. If not, ; then we are going to assume widgets are not supported. Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL widgetsSupported = 0 GOTO, testWidgetSupport ENDIF theWindow = !D.Window IF (!D.Flags AND 256) NE 0 THEN Window, /FREE, XSIZE=5, YSIZE=5, /PIXMAP Catch, /CANCEL testWidgetSupport: ; Come here if you choke on creating a window. IF !D.Window NE theWindow THEN BEGIN WDelete, !D.Window IF theWindow GE 0 THEN WSet, theWindow ENDIF IF widgetsSupported && self.alert THEN BEGIN ; If this is an error produced with the MESSAGE command, it is a trapped ; error and will have the name "IDL_M_USER_ERR". IF !ERROR_STATE.NAME EQ "IDL_M_USER_ERR" THEN BEGIN IF N_Elements(title) EQ 0 THEN title = 'Trapped Error' ; If the message has the name of the calling routine in it, ; it should be stripped out. Can you find a colon in the string? ; Is the calling routine an object method? If so, special processing ; is required. Object methods will have two colons together. doublecolon = StrPos(theText, "::") IF doublecolon NE -1 THEN BEGIN prefix = StrMid(theText, 0, doublecolon+2) submessage = StrMid(theText, doublecolon+2) colon = StrPos(submessage, ":") IF colon NE -1 THEN BEGIN ; Extract the text up to the colon. Is this the same as ; the callingRoutine? If so, strip it. IF StrMid(theText, 0, colon+StrLen(prefix)) EQ callingRoutine THEN $ theText = StrMid(theText, colon+1+StrLen(prefix)) ENDIF ENDIF ELSE BEGIN colon = StrPos(theText, ":") IF colon NE -1 THEN BEGIN ; Extract the text up to the colon. Is this the same as ; the callingRoutine? If so, strip it. IF StrMid(theText, 0, colon) EQ callingRoutine THEN $ theText = StrMid(theText, colon+1) ENDIF ENDELSE ; Add the calling routine's name. void = Dialog_Message(StrUpCase(callingRoutine) + ": " + theText, Title=title) ENDIF ELSE BEGIN ; Otherwise, this is an IDL system error. IF N_Elements(title) EQ 0 THEN title = 'System Error' IF StrUpCase(callingRoutine) EQ "$MAIN$" THEN BEGIN void = Dialog_Message(theText, Title=title) ENDIF ELSE BEGIN void = Dialog_Message(StrUpCase(callingRoutine) + "--> " + theText, Title=title) ENDELSE ENDELSE ENDIF ELSE BEGIN Message, theText, /Continue, /NoPrint, /NoName, /NoPrefix self -> AddText, '%' + callingRoutine + ': ' + theText ENDELSE ; Provide traceback information if requested. Help, /Last_Message, Output=traceback traceback = ['Traceback Report from ' + StrUpCase(callingRoutine) + ':', $ '', " " + traceback] IF self.alert THEN BEGIN IF Keyword_Set(self.traceback) THEN BEGIN FOR j=0,N_Elements(traceback)-1 DO Print, " " + traceback[j] ENDIF ENDIF IF Keyword_Set(self.traceback) THEN self -> AddText, traceback ; Set the status to error condition. self -> SetStatus, 2 END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::AddText ; ; PURPOSE: ; ; Adds text to the error log file and sets the error log status to 1 (normal ; condition). ; ; CALLING SEQUENCE: ; ; errorLogger -> AddText, theText ; ; ARGUMENTS: ; ; theText : The message text you wish to add to the file. ; ; KEYWORDS: ; ; ADD_CALLER: If this keyword is set, the name of the caller routine is ; prepended to the text message. ; ; PRINT: If this keyword is set, the added text is also sent to standard ; output. ; ;******************************************************************************************; PRO ErrorLogger::AddText, theText, PRINT=print, ADD_CALLER=add_caller Compile_Opt idl2 ; Error handling. Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL void = cgErrorMsg() RETURN ENDIF ; Have to have text to do anything. IF N_Elements(theText) EQ 0 THEN RETURN ; Make sure these are strings we are writing. thisType = Size(theText, /TNAME) IF thisType NE 'STRING' THEN Message, 'Only strings can be written into the error log file.' IF Keyword_Set(add_caller) THEN BEGIN ; Get the call stack and the calling routine's name. Help, Calls=callStack callingRoutine = (StrSplit(StrCompress(callStack[1])," ", /Extract))[0] theText = callingRoutine + ': ' + theText ENDIF ; Write the text to the file and to standard output, if requested. IF self.lun EQ 0 THEN BEGIN success = self -> OpenFile(self.filename) IF ~success THEN Message, 'Cannot successfully open the error log file.' ENDIF numLines = N_Elements(theText) FOR j=0L, N_Elements(theText) -1 DO BEGIN PrintF, self.lun, theText[j] IF Keyword_Set( print ) THEN Print, theText[ j ] ENDFOR ; Write to disk immediately? IF self.immediate NE 0 THEN self -> Flush ; Update the error logger status to normal. If this method is called ; from AddError, then when we return to AddError, the status will be ; set to 2, or error status. But setting to 1 here allows us to add ; text to the file whenever we like. self -> SetStatus, 1 ; Save the last message for later recall. *self.lastMessage = theText END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::ClearLog ; ; PURPOSE: ; ; Clears the error log file of text. ; ; CALLING SEQUENCE: ; ; errorLogger -> ClearLog ; ; ARGUMENTS: ; ; None. ; ; KEYWORDS: ; ; None. ; ;******************************************************************************************; PRO ErrorLogger::ClearLog ; Close the current error log file and delete it. self -> CloseFile File_Delete, self.filename, /ALLOW_NONEXISTENT ; Open a new error log file with the same name. self -> OpenFile, self.filename ; Set the error logger status to waiting. self -> SetStatus, 0 END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::Flush ; ; PURPOSE: ; ; Flushes the current error logger information to the file in case of crash. ; ; CALLING SEQUENCE: ; ; errorLogger -> Flush ; ; ARGUMENTS: ; ; None. ; ; KEYWORDS: ; ; None. ; ;******************************************************************************************; PRO ErrorLogger::Flush IF self.lun GE 100 THEN Flush, self.lun END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::CloseFile ; ; PURPOSE: ; ; Closes the currently open error log file. ; ; CALLING SEQUENCE: ; ; errorLogger -> CloseFile ; ; ARGUMENTS: ; ; None. ; ; KEYWORDS: ; ; None. ; ;******************************************************************************************; PRO ErrorLogger::CloseFile IF self.lun GE 100 THEN Free_Lun, self.lun ELSE IF self.lun GT 0 THEN Close, self.lun END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::GetFileName ; ; PURPOSE: ; ; Returns the file name of the error log file. ; ; CALLING SEQUENCE: ; ; filename = errorLogger -> GetFileName() ; ; RETURN VALUE: ; ; filename: The name of the error log file. ; ; ARGUMENTS: ; ; None. ; ; KEYWORDS: ; ; None. ; ;******************************************************************************************; FUNCTION ErrorLogger::GetFileName RETURN, self.filename END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::Status ; ; PURPOSE: ; ; Returns the current status of the error logger. ; ; CALLING SEQUENCE: ; ; status = errorLogger -> Status() ; ; RETURN VALUE: ; ; status: The error log status: ; 0 - waiting for input ; 1 - normal operation ; 2 - error operation ; ; ARGUMENTS: ; ; None. ; ; KEYWORDS: ; ; None. ; ;******************************************************************************************; FUNCTION ErrorLogger::Status RETURN, self.status END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::SetStatus ; ; PURPOSE: ; ; Sets the current status of the error logger. ; ; CALLING SEQUENCE: ; ; errorLogger -> SetStatus, status ; ; ARGUMENTS: ; ; status: The error log status: ; 0 - waiting for input ; 1 - normal operation ; 2 - error operation ; ; KEYWORDS: ; ; None. ; ;******************************************************************************************; PRO ErrorLogger::SetStatus, status IF N_Elements(status) NE 0 THEN BEGIN IF (self.noclutter AND (status EQ 2)) THEN BEGIN self.status = 1 ENDIF ELSE BEGIN self.status = 0 > status < 2 ENDELSE ENDIF END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::OpenFile ; ; PURPOSE: ; ; Opens the error log file. ; ; CALLING SEQUENCE: ; ; errorLogger -> OpenFile, filename ; ; ARGUMENTS: ; ; filename: The name of the error log file. ; ; KEYWORDS: ; ; DELETE_CURRENT_FILE: If this keyword is set, the current error log file is closed ; and deleted before the new file is opened for writing. ; ;******************************************************************************************; FUNCTION ErrorLogger::OpenFile, newLogFilename, DELETE_CURRENT_FILE=delete_current_file Compile_Opt idl2 ; Error handling Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL void = cgErrorMsg() IF N_Elements(lun) NE 0 THEN BEGIN Free_Lun, lun File_Delete, newLogFilename, /ALLOW_NONEXISTENT ENDIF RETURN, 0 ENDIF ; Can we write into the specified directory? basename = cgRootName(newLogFilename, EXTENSION=ext, DIRECTORY=dir) IF File_Test(dir, /DIRECTORY) EQ 0 THEN Message, 'Specified directory (' + dir + ') does not exist.' ; Close the current file (if any) before opening a new one. self -> CloseFile ; Need to delete the current file? IF Keyword_Set(delete_current_file) THEN File_Delete, self.filename, /ALLOW_NONEXISTENT ; Open the file for writing. OpenW, lun, newLogFilename, /GET_LUN self.lun = lun ; Write a header into the file. PrintF, self.lun, 'Error log file created: ' + Systime() PrintF, self.lun, "" ; Store the filename self.filename = newLogFilename RETURN, 1 END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::LastMessage ; ; PURPOSE: ; ; Returns the last text message written to the error logger. ; ; CALLING SEQUENCE: ; ; message = errorLogger -> LastMessage() ; ; RETURN VALUE: ; ; message: The last text written to the error log file. ; ; ARGUMENTS: ; ; None. ; ; KEYWORDS: ; ; None. ; ;******************************************************************************************; FUNCTION ErrorLogger::LastMessage ; Returns the last message added to the file. IF N_Elements(*self.lastMessage) NE 0 THEN RETURN, *self.lastMessage ELSE RETURN, "" END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::PrintLastMessage ; ; PURPOSE: ; ; Prints the last text message written to the error logger to standard output. ; ; CALLING SEQUENCE: ; ; errorLogger -> PrintLastMessage ; ; ARGUMENTS: ; ; None. ; ; KEYWORDS: ; ; None. ; ;******************************************************************************************; PRO ErrorLogger::PrintLastMessage ; Prints the last message in the error logger. lastMessage = self -> LastMessage() FOR j=0, N_Elements(lastMessage)-1 DO Print, lastMessage[j] END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::GetProperty ; ; PURPOSE: ; ; Allows the user to get properties from the object via keywords. ; ; CALLING SEQUENCE: ; ; errorLogger -> GetProperty, ... ; ; ARGUMENTS: ; ; None. ; ; KEYWORDS: ; ; ALERT: The alert flag in the object. (Output) ; ; DELETE_ON_DESTROY: The delete on destroy flag in the object. (Output) ; ; FILENAME: The name of the error log file. (Output) ; ; LAST_MESSAGE: The last message written into the error log file. (Output) ; ; LUN: The logical unit number of the open error log file. (Output) ; ; STATUS: The current error log status. (Output) ; ; NOTRACEBACK: The notraceback flag in the object. (Output) ; ; ;******************************************************************************************; PRO ErrorLogger::GetProperty, $ ALERT=alert, $ DELETE_ON_DESTROY=delete_on_destroy, $ FILENAME=filename, $ LAST_MESSAGE=last_message, $ LUN=lun, $ NOCLUTTER=noclutter, $ NOTRACEBACK=notraceback, $ STATUS=status alert = self.alert delete_on_destroy = self.delete_on_destroy filename = self.filename last_message = self -> LastMessage() lun = self.lun noclutter = self.noclutter notraceback = ~self.traceback status = self.status END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::SetProperty ; ; PURPOSE: ; ; Allows the user to set properties of the object via keywords. ; ; CALLING SEQUENCE: ; ; errorLogger -> SetProperty, ... ; ; ARGUMENTS: ; ; None. ; ; KEYWORDS: ; ; ALERT: The alert flag in the object. (Input) ; ; DELETE_ON_DESTROY: The delete on destroy flag in the object. (Input) ; ; NOCLUTTER: Set the object up for no file cluttering. (Input). ; ; NOTRACEBACK: The notraceback flag in the object. (Input) ; ; STATUS: The current error log status. (Input) ; ;******************************************************************************************; PRO ErrorLogger::SetProperty, $ ALERT=alert, $ DELETE_ON_DESTROY=delete_on_destroy, $ NOCLUTTER=noclutter, $ NOTRACEBACK=notraceback, $ STATUS=status IF N_Elements(alert) NE 0 THEN self.alert = Keyword_Set(alert) IF N_Elements(delete_on_destroy) NE 0 THEN $ self.delete_on_destroy = Keyword_Set(delete_on_destroy) IF N_Elements(notraceback) NE 0 THEN self.tracebace = 1 - Keyword_Set(notraceback) IF N_Elements(status) NE 0 THEN self -> SetStatus, status IF N_Elements(noclutter) NE 0 THEN BEGIN self.noclutter = Keyword_Set(noclutter) IF self.noclutter THEN BEGIN self.alert = 1 self.delete_on_destroy = 1 ENDIF ENDIF END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::CLEANUP ; ; PURPOSE: ; ; Cleans up the object. ; ; CALLING SEQUENCE: ; ; Called automatically when the object is destroyed. ; ; ARGUMENTS: ; ; None. ; ; KEYWORDS: ; ; None. ; ;******************************************************************************************; PRO ErrorLogger::CLEANUP ; Be sure the file is closed. Otherwise, it can't be deleted. self -> CloseFile ; If the file is not in an error state, and the delete_on_destroy flag ; is set, delete the error log file. IF self.delete_on_destroy THEN BEGIN IF self.status NE 2 THEN File_Delete, self.filename, /ALLOW_NONEXISTENT ENDIF ; Free the last message pointer. Ptr_Free, self.lastMessage END ;******************************************************************************************; ; ; NAME: ; ErrorLogger::INIT ; ; PURPOSE: ; ; The initialization method for the object. ; ; CALLING SEQUENCE: ; ; check = Obj_New('ErrorLogger', filename) ; ; ARGUMENTS: ; ; filename: The name of the error log file. If not provided, a default name ; will be created based on the current system time. (Optional) ; ; KEYWORDS: ; ; ALERT: The default behavior of the error logger is simply to write text to a file. ; But if the ALERT keyword is set, the program will alert the user via a ; message dialog that an error has occurred when using the AddError method. ; Default is 0. (Input) ; ; DELETE_ON_DESTROY: If this keyword is set, the error log file will be deleted when the ; ErrorLogger object is destroyed, but only if the ErrorLogger object is not ; in an error state at that time (error status = 2. Default is 0. (Input) ; ; IMMEDIATE: All messages will flush to disk as soon as they are ; logged. Default is 1 (Input) ; ; NOCLUTTER: Believe it or not, some people who use an ErrorLogger prefer that an error log ; file is never left behind. (They prefer that the program act like cgErrorMsg.) ; For those people, the NOCLUTTER keyword provides a way for them to automatically ; set the ALERT and DESTROY_ON_DELETE keywords to 1. It also prevents the error ; logger from ever setting the error status to 2. Thus, when the ErrorLogger is ; destroyed, the file is always deleted. Default is 0. When set, overrides ALERT ; and DELETE_ON_DESTROY settings. (Input) ; ; NOTRACEBACK: Set this keyword to suppress traceback information in the error log output ; and in any alerts issued by the program. Default is 0. (Input) ; ; TIMESTAMP: Set this keyword if you wish a time stamp to be appended to the provided ; filename. Otherwise, the filename is used as defined. Default filenames ; always have a timestamp appended to the file name. (Input) ; ;******************************************************************************************; FUNCTION ErrorLogger::INIT, filename, $ ALERT=alert, $ DELETE_ON_DESTROY=delete_on_destroy, $ IMMEDIATE = immediate, $ NOCLUTTER=noclutter, $ NOTRACEBACK=notraceback, $ TIMESTAMP=timestamp COMPILE_OPT idl2 Catch, theError IF theError NE 0 THEN BEGIN Catch, /CANCEL void = cgErrorMsg() IF N_Elements(lun) NE 0 THEN BEGIN Free_Lun, lun File_Delete, logFilename, /ALLOW_NONEXISTENT ENDIF RETURN, 0 ENDIF ; Flushing should always be turned on unless there is a good reason ; not to do it. SetDefaultValue, immediate, 1 ; Does the filename exist? IF N_Elements(filename) EQ 0 THEN BEGIN CD, CURRENT=currentDir logFilename = FilePath(ROOT_DIR=currentDir, 'logger' + $ cgTimestamp(RANDOM_DIGITS=6, /VALID) + '.log') filename = logFilename timestamp = 0 ENDIF ; Is this a fully qualified filename? baseName = File_BaseName(filename) IF baseName EQ filename THEN BEGIN CD, CURRENT=currentDir logFilename = FilePath(ROOT_DIR=currentDir, filename) ENDIF ELSE logFilename = filename ; Does the name need a time stamp? IF Keyword_Set(timestamp) THEN BEGIN basename = cgRootName(logFilename, EXTENSION=ext, DIRECTORY=dir) time = Systime(1) randomdigits = StrMid(StrTrim(time - Long(time),2), 2) logFilename = Filepath(ROOT_DIR=dir, basename + cgTimestamp(RANDOM_DIGITS=6, /VALID)) IF ext NE "" THEN logFilename = logFilename + '.' + ext END ; Store the filename. self.filename = logFilename ; Initialize the last message pointer. self.lastMessage = Ptr_New(/ALLOCATE_HEAP) ; Need alerts? self.alert = Keyword_Set(alert) ; Need traceback? self.traceback = 1 - Keyword_Set(notraceback) ; Delete file on destroy? self.delete_on_destroy = Keyword_Set(delete_on_destroy) ; No clutter desired? IF Keyword_Set(noclutter) THEN BEGIN self.alert = 1 self.delete_on_destroy = 1 self.noclutter = 1 ENDIF ; Flushing? self.immediate = immediate ; Successful completion. RETURN, 1 END PRO ErrorLogger__Define, class class = { ERRORLOGGER, $ filename: "", $ ; The error log filename. lun: 0L, $ ; The file logical unit number. alert: 0L, $ ; A flag, if set, will give user alerts on errors. traceback: 0L, $ ; If set, will include traceback information into the log file. lastMessage: Ptr_New(), $ ; The last message written into the file. immediate: 0L, $ ; A flag causing messages to flush to disk immediately delete_on_destroy: 0L, $ ; A flag causing log file to be deleted when object is destroyed. noclutter: 0L, $ ; A flag that sets up file deletion on destroy. status: 0L } ; The current status of the error logger. 0-waiting, 1-normal, 2-error. END