49. 面向对象的LotusScript(十五)之Log4Dom下
Log4Dom是模仿Log4J的思想建立的。Log4J能够向多种记录媒介以统一的格式写入各种级别的日志信息(包括错误、调试和信息等),还可以籍配置文件在运行时方便地修改记入日志的级别。Log4Dom提供了类似的功能。现在我们就来看看它的各部分元素和代码。
1. 记录日志的文档所用的表单
2. 用于配置日志级别的表单
3. 日志文档视图
第一列按创建日期分类,第二列是文档序号,第三列是创建时间,最后一列是日志名称。还有一个操作可以编辑配置文档。
4. 日志类代码
'*version 1.2-18th March 2008 '*added Log4Dom profile, '*simplified the usage and renamed some methods, '*deleted unnecessary log document size check '*added several features e.g. logging generated error message, expanding the log message '*argument to variant '*corrected several bugs '*@author Starrow Pan '/** '* class for the domino implementation of a logger in a similar format '* as log4J (http://jakarta.apache.org/log5j/ '* @author tony.palmer@ing.com.au '* @version 1.0 - 4th November 2003 '*/ Private Const CUSTOM_ERR=10000 Private Const CUSTOM_ERROR="CUSTOM ERROR: " ' debugging levels 0 - 5 system, 6 - 10 custom Const LEVEL_DEBUG = 5 Const LEVEL_DEBUG_STRING = "DEBUG" Const LEVEL_INFO = 4 Const LEVEL_INFO_STRING="INFO" Const LEVEL_WARN = 3 Const LEVEL_WARN_STRING = "WARN" Const LEVEL_ERROR = 2 Const LEVEL_ERROR_STRING = "ERROR" Const LEVEL_FATAL = 1 Const LEVEL_FATAL_STRING = "FATAL" Const LEVEL_NONE = 0 ' destination types Const DEST_TYPE_DB = 0 '/ notes database Const DEST_TYPE_FILE = 1 '/ text file Const DEST_TYPE_STATUS = 2 '/ notes status bar Const DEST_TYPE_PROMPT = 3 '/ message box prompts Class Log4Dom public logLevel As Integer public module As String 'module 'the Log Destination, set as a variant then depending on the log type, 'set as either a LogDB, logNotesFile, logStatus or logPrompt Private logFile As Variant Private m_sess As NotesSession Private m_curdb As NotesDatabase 'current database Private m_profile As NotesDocument 'Log4Dom profile document public logName As String 'log name from the profile Sub New () Set m_sess=New NotesSession logLevel = LEVEL_DEBUG End Sub %REM Add a log destination. As the de facto only used log destination is Notes DB, I didn't handle the case of multiple log destinations of different types. %END REM Public Function AddLogFile(file As Variant) Set logFile = file If TypeName(file)="LOGDB" then 'read parameter from Log4Dom profile by starrow Set m_curdb=m_sess.CurrentDatabase Set m_profile=m_curdb.GetProfileDocument("Log4DomProfile") If Not m_profile Is Nothing Then If m_profile.GetItemValue("LogLevel")(0)><"" then logLevel=m_profile.GetItemValue("LogLevel")(0) End if logName=m_profile.GetItemValue("LogName")(0) End If 'if no parameter provided, try the agent name If logName="" Then If Not m_sess.CurrentAgent Is Nothing Then logName=m_sess.CurrentAgent.Name End If End If logFile.LogName=logName End if End Function 'logging at the different levels, INFO, WARN etc Public Function info(message As variant) As Integer info = WriteLog(LEVEL_INFO, message) End Function Public Function warn(message As variant) As Integer warn = WriteLog(LEVEL_WARN, message) End Function Public Function debug(message As variant) As Integer debug = WriteLog(LEVEL_DEBUG, message) End Function Public Function LogError(message As variant) As Integer 'can't use error as its a reserved word If message="" Then 'LSI_THREAD_CALLMODULE=11, LSI_THREAD_CALLPROC=10 message = GetThreadInfo(11) & ">" & GetThreadInfo(10) & ": " & _ "Error(" & Err() & "): " & Error() & " at line "& Erl() End If LogError = WriteLog(LEVEL_ERROR, message) End Function Public Function fatal(message As variant) As Integer fatal = WriteLog(LEVEL_FATAL, message) End Function 'user level logging, for specific level logging '@param level integer - the level 10 is the most detail, 1 the lowest level Public Function WriteLog(level As Integer, message As variant) As Integer Dim theDate As String Dim theLevel As String Dim theMessage As String theDate = Cstr(Now) theLevel = "["+GetLevelString(level)+"] " theMessage = theDate+" "+theLevel+" "+module+" - "+message ' check that logging is turned on for this level ' otherwise there is no need to log If level <= logLevel Then Call logFile.writelog(theMessage) End If End Function 'closes the log, saves notes doc or closes file Public Function Close logFile.close End Function 'convert from level numbers into string Private Function GetLevelString(level As Integer) As String Select Case level Case LEVEL_INFO : GetLevelString = LEVEL_INFO_STRING Case LEVEL_DEBUG : GetLevelString = LEVEL_DEBUG_STRING Case LEVEL_WARN : GetLevelString = LEVEL_WARN_STRING Case LEVEL_ERROR : GetLevelString = LEVEL_ERROR_STRING Case LEVEL_FATAL : GetLevelString = LEVEL_FATAL_STRING Case Else : GetLevelString = "LEVEL "+Cstr(level) End Select End Function End Class '/** '* Set Log destination as a domino database '*/ Class LogDB Private m_sess As NotesSession Private m_dbLog As NotesDatabase 'nsf if destination is db Private m_docLog As NotesDocument 'document that the log gets appended to Private m_rtitem As NotesRichTextItem 'rtf public logName As String Sub New(db As NotesDatabase) Set m_sess=New NotesSession If db Is Nothing Then Set m_dbLog = m_sess.currentdatabase Else Set m_dbLog = db If m_dbLog.isOpen = False Then Error CUSTOM_ERR, CUSTOM_ERROR & "Could not open the log Database." End If End If End Sub 'get the log document as some calling program may need access it e.g. mail it. Public Property Get LogDocument As NotesDocument Set LogDocument=m_docLog End Property '/** '* method for logging to a notes document '*/ Public Function writeLog(message As String) As Integer If m_docLog Is Nothing Then ' create a new log document Set m_docLog = m_dbLog.createDocument Call m_docLog.ReplaceItemValue("LogName",logName) If m_sess.IsOnServer Then Call m_docLog.ReplaceItemValue("ScriptRunOn","Server") Else Call m_docLog.ReplaceItemValue("ScriptRunOn","Workstation") End If Set m_rtitem = New NotesRichTextItem(m_docLog, "logBody") End If 'currently each log line is in one paragraph, no limits will be violated m_rtitem.appendtext(message) m_rtitem.addnewline(1) writeLog= True End Function '/** '* closes the log, saves notes doc '*/ Public Function Close If Not(m_docLog Is Nothing) Then m_docLog.Form="log" Call m_docLog.Save(True,True) End If End Function End Class 'Get a logger instance that writes to the specified db. Public Function GetLogger(db As NotesDatabase) As log4Dom Dim logger As log4dom Set logger = New log4dom() Dim logFile As New LogDB(db) Call logger.AddLogFile(logFile) Set GetLogger=logger End Function
上述代码的各个方法都有注释。使用的时候像上一篇文章里所示样例一样,只需初始化一个logger实例并添加目标数据库(若为当前数据库,就传入Nothing),之后就可以调用Info()、Debug()、LogError()等各种方法写入日志。传入LogError()方法的如果是空字符串,它就会试图记录最近发生的错误的详细信息,因此可以用作处理错误的语句。最后要调用Close()方法,记录日志的文档才会被保存。
原来版本所具的其他日志目标媒介类,实际上都极少用到。Notes文档和视图的现成功能使其很适宜用来记录和查询日志。文本文件比起来不那么方便,而要写到状态栏或者用对话框显示直接用LotusScript对应的语句即可。