filein "RsUniversalLogViewer.ms" global memUsage = 0 global gLogMemUsage = false fn lastMemStep = ( r=sysinfo.getMAXMemoryInfo() for i=2 to 7 do r[i] /= (1024*1024.) local lastMemUsage = memUsage memUsage = r[3] --(r[2]-r[3]) local msg = stringstream "" format " - used physical memory:\t% MB increase by:\t% MB" memUsage (memusage - lastMemUsage) to:msg --::gRsUlog.LogMessage msg logMem:false quiet:false msg ) --ReUniLogSize = [600, 600] --buttonSize = [70, 30] --checkboxOffset = [160, 27] --local oldData = grsUlog.uniLogFileObj struct sRsULog ( b_goAhead = false, quietMode = false, universalLogObj = undefined, logFactory = undefined, validatedLogFiles = #(), private fn InitLogFactory = ( if (logFactory == undefined) then ( logFactory = dotNetClass "RSG.Base.Logging.LogFactory" logFactory.Initialize "" true ) ), public fn ShowDialog modal:true newErrors:false= ( if true == GetQuietMode() then ( return true ) -- Need to init this because when just choosing Universal Log from the RS Export menu the factory will not have been setup. InitLogFactory() local logDirectory = logFactory.ParentProcessLogDirectory format "Showing log files from: %\n" logDirectory return (::openULogViewer modal:modal allowContinue:((RsAutomatedExport) or (not newErrors)) logDirectory:logDirectory) ), fn GetProcessLogDirectory = ( InitLogFactory() return logFactory.ParentProcessLogDirectory ), fn Shutdown = ( InitLogFactory() print "Shutting down log factory and closing log files..." shutdownMode = dotNetClass "RSG.Base.Logging.LogFactory+ShutdownMode" logFactory.ApplicationShutdown shutdownMode.NoLogDisplay ), fn ClearProcessLogDirectory = ( InitLogFactory() logFactory.ClearLogDirectory true validatedLogFiles = #() ), fn CloseUniversalLogFile = ( if (universalLogObj != undefined) then ( universalLogObj.CloseLog() ) universalLogObj = undefined ), fn ClearLogDirectory = ( InitLogFactory() CloseUniversalLogFile() -- Reset the log directory. This will clear out the log directory but rebuild the main process log file again so we start clean. logFactory.ResetLogDirectory true validatedLogFiles = #() ), fn CreateUniversalLogFile = ( universalLogObj = RsULogObject() universalLogObj.Init "unilog" ), fn ValidateGlobalLog = ( if (universalLogObj == undefined) then CreateUniversalLogFile() ), fn Init context appendToFile:true forceLogFile:undefined skipValidation:false = ( InitLogFactory() ValidateGlobalLog() universalLogObj.ClearErrorsAndWarnings() if not appendToFile then ClearProcessLogDirectory() ), fn Flush = ( InitLogFactory() ValidateGlobalLog() universalLogObj.Flush() logFactory.FlushApplicationLog() ), fn Filename = ( InitLogFactory() -- Returns the filename of the main application filename. -- This is to keep backwards compatibility but in the future will be nice to use per-process log files for this scenario. -- Biggest culprit is RexExport calls. It takes a filename and writes directly to the log file, doesn't use any of the logobjects, etc. logFactory.ApplicationLogFilename ), -- Returns list of message-types/objects stored by log: fn getObjLists = ( local msgList = uniLogFileObj.getmessages 0 -1 local msgTypes = #() local outArray = #() for msg in msgList do ( local msgObjString = msg.objectContext local msgObj if (msgObjString != "") do ( msgObj = getNodeByName msgObjString ) if (msgObj != undefined) do ( local msgType = msg.MsgType local msgNum = findItem msgTypes msgType if (msgNum == 0) do ( append msgTypes msgType append outArray (dataPair type:msgType objs:#()) msgNum = msgTypes.count ) append outArray[msgNum].objs msgObj ) ) fn sortByType v1 v2 = striCmp v1.type v2.type qsort outArray sortByType return outArray ), -- Creates selection-sets for log's message-objects: fn createSelSets = ( local selSetPrefix = "R* Log: " local objArrays = getObjLists() local selSetNames = for item in objArrays collect ( -- Capitalise the message-type: item.type[1] = toUpper item.type[1] selSetPrefix + item.type ) -- Create/update selection sets: for n = 1 to objArrays.count do ( selectionsets[selSetNames[n]] = objArrays[n].objs ) -- Remove unused "R* Log" selection sets: for n = selectionSets.count to 1 by -1 where ( local setName = getNamedSelSetName n ((findString setName selSetPrefix) == 1) and ((findItem selSetNames setName) == 0) ) do ( deleteItem selectionSets n ) OK ), fn GetLogFileEntry logName = ( for i = 1 to validatedLogFiles.count do ( if validatedLogFiles[i].v1 == logName then return validatedLogFiles[i] ) return undefined ), fn CheckNewErrorsWarnings &newErrors &newWarnings justErrors:false = ( InitLogFactory() Flush() local logDirectory = logFactory.ParentProcessLogDirectory local logFiles = getFiles (logDirectory + "\\*.ulog") universalLogFileClass = dotNetClass "RSG.Base.Logging.Universal.UniversalLogFile" currentValidatedLogFiles = #() newErrors = false newWarnings = false -- Check all the current logs in the log directory for any errors or warnings. for logFile in logFiles do ( previousLogEntry = GetLogFileEntry logFile previousLogErrorsWarnings = undefined if (previousLogEntry != undefined) then previousLogErrorsWarnings = previousLogEntry.v2 numErrors = universalLogFileClass.GetNumErrors logFile numWarnings = universalLogFileClass.GetNumWarnings logFile errorWarningEntry = DataPair numErrors numWarnings logFileEntry = DataPair logFile errorWarningEntry if (previousLogErrorsWarnings != undefined) then ( previousLogNumErrors = previousLogErrorsWarnings.v1 previousLogNumWarnings = previousLogErrorsWarnings.v2 --format "Log File % - Current Errors: % -> Previous Errors: %\n" logFile numErrors previousLogNumErrors --format "Log File % - Current Warnings: % -> Previous Warnings: %\n" logFile numWarnings previousLogNumWarnings -- Compare the new and old values to see if we have legitimate errors or warnings if (numErrors > previousLogNumErrors) then newErrors = true if (numWarnings > previousLogNumWarnings) then newWarnings = true ) else ( -- If we don't have a previous entry for the file but we have errors or warnings if (numErrors > 0) then newErrors = true if (numWarnings > 0) then newWarnings = true ) append currentValidatedLogFiles logFileEntry ) validatedLogFiles = currentValidatedLogFiles if justErrors then return newErrors else return newWarnings or newErrors ), fn ValidateLogDirectory noProgressControls:false createSelSets:true justErrors:false = ( hasErrors = false hasWarnings = false CheckNewErrorsWarnings &hasErrors &hasWarnings justErrors:justErrors if (quietMode == true) then ( return true ) else ( if noProgressControls or hasErrors or (hasWarnings and not justErrors) then ( return (gRsULog.ShowDialog modal:(not RsAutomatedExport and not noProgressControls) newErrors:hasErrors) ) else ( return true ) ) ), fn LogDirectoryHasErrors = ( InitLogFactory() local logDirectory = logFactory.ParentProcessLogDirectory local logFiles = getFiles (logDirectory + "\\*.ulog") universalLogFileClass = dotNetClass "RSG.Base.Logging.Universal.UniversalLogFile" local hasErrors = false for logFile in logFiles do ( hasErrors = universalLogFileClass.ContainsErrors logFile if hasErrors then break ) return hasErrors ), fn LogDirectoryHasWarnings = ( InitLogFactory() local logDirectory = logFactory.ParentProcessLogDirectory local logFiles = getFiles (logDirectory + "\\*.ulog") universalLogFileClass = dotNetClass "RSG.Base.Logging.Universal.UniversalLogFile" local hasWarnings = false for logFile in logFiles do ( hasWarnings = universalLogFileClass.ContainsWarnings logFile if hasWarnings then break ) return hasWarnings ), fn Validate noProgressControls:false createSelSets:true = ( -- For now we need to validate all the files in the directory. -- In the future it will be nice to validate just a given log file. --ValidateGlobalLog() --universalLogObj.Validate noProgressControls:noProgressControls createSelSets:createSelSets return ValidateLogDirectory noProgressControls:noProgressControls createSelSets:createSelSets justErrors:false ), fn ValidateJustErrors noProgressControls:false createSelSets:true = ( -- For now we need to validate all the files in the directory. -- In the future it will be nice to validate just a given log file. --ValidateGlobalLog() --universalLogObj.ValidateJustErrors noProgressControls:noProgressControls createSelSets:createSelSets return ValidateLogDirectory noProgressControls:noProgressControls createSelSets:createSelSets justErrors:true ), fn ValidateLogFileErrors filename = ( universalLogFileClass = dotNetClass "RSG.Base.Logging.Universal.UniversalLogFile" local hasErrors = false if not RsFileExists filename then print "COULD NOT FIND LOG FILE: " + filename if universalLogFileClass != undefined then hasErrors = universalLogFileClass.ContainsErrors filename if hasErrors then ( local result = (gRsULog.ShowDialog modal:(not RsAutomatedExport) newErrors:hasErrors) return result ) return true ), fn ValidateProfileContext = ( ValidateGlobalLog() return universalLogObj.ValidateProfileContext() ), fn ProfileContext = ( ValidateGlobalLog() return universalLogObj.ProfileContext() ), fn HasErrors refresh:false = ( -- Would eventually like to do this on a per-log basis --ValidateGlobalLog() --return universalLogObj.HasErrors() return LogDirectoryHasErrors() ), fn HasWarnings refresh:false = ( -- Would eventually like to do this on a per-log basis --ValidateGlobalLog() --return universalLogObj.HasWarnings() return LogDirectoryHasWarnings() ), fn HasNewErrorsWarnings = ( HasNewErrors HasNewWarnings this.CheckNewErrorsWarnings &HasNewErrors &HasNewWarnings if( HasNewErrors or HasNewWarnings ) then ( return true ) else ( return false ) ), fn LogError msg context:"" files: quiet:false = ( ValidateGlobalLog() universalLogObj.LogError msg context:context files:files quiet:quiet ), fn LogToolError msg context:"" files: quiet:true = ( ValidateGlobalLog() universalLogObj.LogToolError msg context:context files:files quiet:quiet ), fn LogWarning msg context:"" files: quiet:true = ( ValidateGlobalLog() universalLogObj.LogWarning msg context:context files:files quiet:quiet ), fn LogMessage msg context:"" files: quiet:true = ( ValidateGlobalLog() universalLogObj.LogMessage msg context:context files:files quiet:quiet ), fn LogDebug msg context:"" files: quiet:true = ( ValidateGlobalLog() universalLogObj.LogDebug msg context:context files:files quiet:quiet ), fn ProfileStart context quiet:true = ( ValidateGlobalLog() universalLogObj.ProfileStart context quiet:quiet ), fn ProfileEnd context: quiet:true = ( ValidateGlobalLog() universalLogObj.ProfileEnd context:context quiet:quiet ), fn ShowULogFile = ( print "This is a message in ShowULogFile" return (::openULogViewer modal:false allowContinue:true) ) ) savePreviousValidationInfo = false previousValidationInfo = #() -- Close our global log file if it's already defined and save the previous validation info if (gRsULog != undefined) then ( gRsULog.CloseUniversalLogFile() savePreviousValidationInfo = true previousValidationInfo = gRsULog.validatedLogFiles ) global gRsULog = sRsULog() global gRsMiscULog = sRsULog() -- This saves the state of the previous validation info so "NewWarnings" and "NewErrors" functionality doesn't get blown away -- when this file gets "filein'd" in other scripts if (savePreviousValidationInfo) then gRsULog.validatedLogFiles = previousValidationInfo struct RsULogObject ( logName = "", currContext = "DirtyDucks", currProfileContext = #(), quietMode = false, logFile = undefined, logObj = undefined, logFactory = undefined, msgPrefix = (if RsUserIsSuperUser() then "SU: " else ""), currentErrors = #(), currentWarnings = #(), private fn InitLogFactory = ( if (logFactory == undefined) then ( logFactory = dotNetClass "RSG.Base.Logging.LogFactory" logFactory.Initialize "" true ) ), fn HasNewErrorsWarnings = ( if undefined == logObj then ( return false ) if quietMode == true then ( return false ) local requestStop = (currentErrors.count > 0 or currentWarnings.count > 0) if (RsDontStopForErrors and requestStop) then ::gRsUlog.logWarning "\"RsDontStopForErrors\" is set! Validation not stopping althout errors occured!" return (not RsDontStopForErrors) and requestStop ), fn HasNewErrors = ( if undefined == logObj then ( return false ) if quietMode == true then ( return false ) local requestStop = (currentErrors.count > 0) if (RsDontStopForErrors and requestStop) then ::gRsUlog.logWarning "\"RsDontStopForErrors\" is set! Validation not stopping althout errors occured!" return (not RsDontStopForErrors) and requestStop ), fn HasNewWarnings = ( if undefined == logObj then ( return false ) if quietMode == true then ( return false ) local requestStop = (currentWarnings.count > 0) if (RsDontStopForErrors and requestStop) then ::gRsUlog.logWarning "\"RsDontStopForErrors\" is set! Validation not stopping althout errors occured!" return (not RsDontStopForErrors) and requestStop ), public fn Init name = ( InitLogFactory() logName = name if (logObj != undefined or logFile != undefined) then ( format "Log file % already initialized..." logName ) logObj = logFactory.CreateUniversalLog name logFile = logFactory.CreateUniversalLogFile logObj ), fn CloseLog = ( if (logObj != undefined and logFile != undefined) then ( logFactory.CloseUniversalLogFile logFile logFactory.CloseUniversalLog logObj logObj = undefined logFile = undefined ) ), fn Flush = ( if (logFile != undefined) then ( logFile.Flush() ) ), fn Filename = ( if (logFile != undefined) then ( return logFile.Filename ) return undefined ), fn ClearErrorsAndWarnings = ( currentErrors = #() currentWarnings = #() ), fn Validate noProgressControls:false createSelSets:true = ( -- Need to figure out a different way to handle selection sets because they could come from multiple log files and also the GetMessages function is now deprecated. --this.createSelSets() Flush() if (quietMode == true) then ( return true ) else ( local newErrors = HasNewErrors() local newWarnings = HasNewWarnings() if noProgressControls or newErrors or newWarnings then ( local result = (gRsULog.ShowDialog modal:(not RsAutomatedExport and not noProgressControls) newErrors:newErrors) -- Clear the errors because we don't want to keep spamming that there are new errors if newErrors then currentErrors = #() if newWarnings then currentWarnings = #() return result ) else ( return true ) ) ), fn ValidateJustErrors noProgressControls:false createSelSets:true = ( -- Create object selection-sets from log: --this.createSelSets() Flush() if quietMode then ( return true ) else ( local newErrors = HasNewErrors() if noProgressControls or newErrors then ( local result = (gRsULog.ShowDialog modal:(not RsAutomatedExport and not noProgressControls) newErrors:newErrors) -- Clear the errors because we don't want to keep spamming that there are new errors if newErrors then currentErrors = #() return result ) else ( return true ) ) ), fn ValidateProfileContext = ( return (currProfileContext.count > 0) ), fn ProfileContext = ( return currProfileContext ), fn MakeSafeMessage m prefix:true = ( m = m as string if (matchpattern m pattern:"*{*") or (matchpattern m pattern:"*}*") then ( m = substituteString m "{" "{{" m = substituteString m "}" "}}" ) if prefix then m = msgPrefix + m return m ), fn getContextString context = ( local retVal = context case of ( ((isKindOf context array) or (isKindOf context ObjectSet)): ( -- Generate comma-separated string-list for arrays: local stringList = for item in context collect (getContextString item) local formatString = stringStream "" for n = 1 to stringList.count do ( format "%" stringList[n] to:formatString if (n != stringList.count) do ( format "," to:formatString ) ) retVal = formatString as string ) (isProperty context #name):(retVal = context.name) default:(context as string) ) return (MakeSafeMessage retVal prefix:false) ), fn LogError msg context:"" files: quiet:false = ( local ctx = (getContextString context) as String if gLogMemUsage then append msg (lastMemStep()) local m = MakeSafeMessage msg if unsupplied!=files then append m (" attached files:"+files as string) if not quiet do (format "ERROR: %\n" (m as string)) append currentErrors m logObj.ErrorCtx ctx m #() ), fn LogToolError msg context:"" files: quiet:false = ( local ctx = (getContextString context) as String if gLogMemUsage then append msg (lastMemStep()) local m = MakeSafeMessage msg if unsupplied!=files then append m (" attached files:"+files as string) if not quiet do (format "TOOL ERROR: %\n" (m as string)) append currentErrors m logObj.ToolErrorCtx ctx m #() ), fn LogWarning msg context:"" files: quiet:true = ( local ctx = (getContextString context) as String if gLogMemUsage then append msg (lastMemStep()) local m = MakeSafeMessage msg if unsupplied!=files then append m (" attached files:"+files as string) if not quiet do (format "WARINING: %\n" (m as string)) append currentWarnings m logObj.WarningCtx ctx m #() ), fn LogMessage msg context:"" files: quiet:true = ( local ctx = (getContextString context) as String if gLogMemUsage then append msg (lastMemStep()) local m = MakeSafeMessage msg if unsupplied!=files then append m (" attached files:"+files as string) if not quiet do (format "MESSAGE: %\n" (m as string)) logObj.MessageCtx ctx m #() ), fn LogDebug msg context:"" files: quiet:true = ( local ctx = (getContextString context) as String if gLogMemUsage then append msg (lastMemStep()) local m = MakeSafeMessage msg if unsupplied!=files then append m (" attached files:"+files as string) if not quiet do (format "DEBUG: %\n" (m as string)) logObj.DebugCtx ctx m #() ), fn ProfileStart context quiet:true = ( local safeContext = context -- resuming context functionality if lastProfileContext == safeContext then ( if currProfileContext.count>0 and currProfileContext[currProfileContext.count]==safeContext then ProfileEnd() local formerNumberIndex = findString safeContext "_#" local newCtxt = (safeContext+"_#0") if 0!=formerNumberIndex then ( local formerNumber = substring safeContext formerNumberIndex (safeContext.count) as number newCtxt = (safeContext+"_#"+(formerNumber+1) as string) ) safeContext = newCtxt ) append currProfileContext safeContext if not quiet do (format "PROFILE START: %\n" (safeContext as string)) logObj.Profile safeContext #() lastProfileContext = safeContext Flush() ), fn ProfileEnd context: quiet:true = ( local currProfileContextindex = currProfileContext.count if currProfileContextindex<1 then ( LogWarning ("More Profile end calls than start calls!") ) else ( if unsupplied!=context and currProfileContext[currProfileContextindex]!=context then LogError ("Context \""+currProfileContext[currProfileContextindex]+"\" got not closed before ending \""+context+"\"") if not quiet do (format "PROFILE END %s\n" currProfileContext[currProfileContextindex]) deleteItem currProfileContext currProfileContextindex logObj.ProfileEnd() Flush() ) ), fn HasErrors refresh:false = ( if logObj == undefined then ( return false ) else ( return logObj.HasErrors ) ), fn HasWarnings refresh:false = ( if logObj == undefined then ( return false ) else ( return logObj.HasWarnings ) ) ) rexSetULogFile (gRsUlog.filename()) fn ShowRsUlogDialog = ( return gRsULog.Validate noProgressControls:true ) fn ShowRsUlogDialogFromMenu = ( return gRsULog.ShowULogFile )