Modifying OpenLog to Accept Additional LogEvent Info
Category OpenLog Lotus Notes Lotus Domino LotusScript
I'll admit it: I am an OpenLog fanboy. It is the absolute best Notes/Domino Utility ever written, hands down, without a doubt, period!
I have several different OpenLog databases, some have processed over a million log documents (mostly logevents, but hey, who writes perfect code?) I say processed because I have a very complex archiving process on these high volume logs.
I love it so much that I just had to extend its functionality to support more data being passed to the logdoc.
Basically I need to have an abstracted logevent routine to process standardized form CRUD events for a bunch of different forms in different databases and view open/close events from the same databases that all get handled via two intermediary custom class who's derived classes get bound to the form/view's lotusscript events (querysave, queryclose, postopen, etc).
However, I wanted to leave the basic structure of LogEvent the same, but I needed to push a couple of different strings in place of the normal 'message' parameter.
So here is what I did:
First I copied the LogEvent function and renamed the copied code to LogEventEx. This lets me keep the default behavior for my normal events and have the 'cool new' behavior for the document CRUD events.
Next I determined that I needed to pass five string values to the function and I created a custom datatype to store the values in:
Public Type EventMsg
Element As String
Action As String
ID As String
Label As String
Msg As String
End Type
Element lets me describe whether the call is from a form or a view.
Action lets me describe what is happening "opening a view", "closing a document", etc.
ID allows me to pass a saved version of the document's UniversalID to the log document so that I can reference the logdoc from the document when needed (I have a 'history' section that has an embedded single category view that looks at these logdocs)
Label lets me describe the document or view with a human recognizable 'name'. EG for my Person document, I might use the shortname field value here 'Andy Broyles'
Msg is the 'normal' message I want passed to the LogEvent call (what gets assigned to the original field 'message' on the logdoc.)
I need these values passed to the logdoc explicitly because I need to use them in views and I wanted an elegantly coded solution rather than simply parsing the controlled 'message' string.
Of course I needed to modify the LotEventEx code to accept and process this custom data type.
Here are the changes I made:
First, I changed the function's parameter list.
Function LogEventEx (msg As EventMsg, severity As String, doc As NotesDocument) As Integer
Then I updated the function's basic code:
With globalLogItem
Call .ResetFields()
.message = msg
.eventTime = Now
.eventType = TYPE_EVENT
.methodName = Lsi_info(12)
.severity = severity
Set .doc = doc
.stackTrace = StringToArray(Strright(Lsi_info(14), Chr(10)), Chr(10))
.userName = globalUserName
.effName = globalEffName
.commonName = globalCommonName
.accessLevel = globalAccessLevel
.userRoles = globalRoles
.clientVersion = globalClientVersion
End With
To support this I needed to modify the internally used LogItem class:
Class LogItem
...
Public message As EventMsg
it's ResetFields sub
Sub ResetFields ()
formName = logFormName
errNum = 0
errLine = 0
errMsg = ""
methodName = ""
stackTrace = ""
severity = SEVERITY_LOW
eventType = TYPE_ERROR
Set eventTime = Nothing
message.element = ""
message.action = ""
message.id = ""
message.label = ""
message.msg = ""
Set doc = Nothing
End Sub
and the CreateLogDoc function
Function CreateLogDoc (db As NotesDatabase) As NotesDocument
On Error Goto processError
'** exit early if there is no database
If (db Is Nothing) Then
Print "Log database was not defined. CreateLogDoc is exiting."
Exit Function
End If
Dim logDoc As New NotesDocument(db)
On Error Resume Next
logDoc.Form = formName
logDoc.LogErrorNumber = errNum
logDoc.LogErrorLine = errLine
logDoc.LogErrorMessage = errMsg
logDoc.LogStackTrace = stackTrace
logDoc.LogSeverity = severity
logDoc.LogEventTime = eventTime
logDoc.LogEventType = eventType
logDoc.LogElement = message.element
logDoc.LogAction = message.action
logDoc.LogID = message.id
logDoc.LogLabel = message.label
logDoc.LogMsg = message.msg
If message.action = "created" Or message.action = "closed without saving" Then
logDoc.LogMessage = Fulltrim(commonName + " " + message.action + " " + message.msg + " " + message.element)
Else
logDoc.LogMessage = Fulltrim(commonName + " " + message.action + " the " + message.msg + " " + message.element + " '" + message.label + "'")
End If
Finally, I have a Use "OpenLogFunctions" reference in my forms/view's global options, and I call LogEventEx from the lotusscript events I want to log (well not exactly, but I'll save that for a later post.)
Here is an example event's code:
logMsg.msg = "a new " + Lcase(Mid(Source.Document.Form(0),3)) + " document"
logMsg.action = "created"
logMsg.id = ""
logMsg.Label = ""
Call LogEventEx(logMsg, SEVERITY_LOW, Nothing)
I'll admit it: I am an OpenLog fanboy. It is the absolute best Notes/Domino Utility ever written, hands down, without a doubt, period!
I have several different OpenLog databases, some have processed over a million log documents (mostly logevents, but hey, who writes perfect code?) I say processed because I have a very complex archiving process on these high volume logs.
I love it so much that I just had to extend its functionality to support more data being passed to the logdoc.
Basically I need to have an abstracted logevent routine to process standardized form CRUD events for a bunch of different forms in different databases and view open/close events from the same databases that all get handled via two intermediary custom class who's derived classes get bound to the form/view's lotusscript events (querysave, queryclose, postopen, etc).
However, I wanted to leave the basic structure of LogEvent the same, but I needed to push a couple of different strings in place of the normal 'message' parameter.
So here is what I did:
First I copied the LogEvent function and renamed the copied code to LogEventEx. This lets me keep the default behavior for my normal events and have the 'cool new' behavior for the document CRUD events.
Next I determined that I needed to pass five string values to the function and I created a custom datatype to store the values in:
Public Type EventMsg
Element As String
Action As String
ID As String
Label As String
Msg As String
End Type
Element lets me describe whether the call is from a form or a view.
Action lets me describe what is happening "opening a view", "closing a document", etc.
ID allows me to pass a saved version of the document's UniversalID to the log document so that I can reference the logdoc from the document when needed (I have a 'history' section that has an embedded single category view that looks at these logdocs)
Label lets me describe the document or view with a human recognizable 'name'. EG for my Person document, I might use the shortname field value here 'Andy Broyles'
Msg is the 'normal' message I want passed to the LogEvent call (what gets assigned to the original field 'message' on the logdoc.)
I need these values passed to the logdoc explicitly because I need to use them in views and I wanted an elegantly coded solution rather than simply parsing the controlled 'message' string.
Of course I needed to modify the LotEventEx code to accept and process this custom data type.
Here are the changes I made:
First, I changed the function's parameter list.
Function LogEventEx (msg As EventMsg, severity As String, doc As NotesDocument) As Integer
Then I updated the function's basic code:
With globalLogItem
Call .ResetFields()
.message = msg
.eventTime = Now
.eventType = TYPE_EVENT
.methodName = Lsi_info(12)
.severity = severity
Set .doc = doc
.stackTrace = StringToArray(Strright(Lsi_info(14), Chr(10)), Chr(10))
.userName = globalUserName
.effName = globalEffName
.commonName = globalCommonName
.accessLevel = globalAccessLevel
.userRoles = globalRoles
.clientVersion = globalClientVersion
End With
To support this I needed to modify the internally used LogItem class:
Class LogItem
...
Public message As EventMsg
it's ResetFields sub
Sub ResetFields ()
formName = logFormName
errNum = 0
errLine = 0
errMsg = ""
methodName = ""
stackTrace = ""
severity = SEVERITY_LOW
eventType = TYPE_ERROR
Set eventTime = Nothing
message.element = ""
message.action = ""
message.id = ""
message.label = ""
message.msg = ""
Set doc = Nothing
End Sub
and the CreateLogDoc function
Function CreateLogDoc (db As NotesDatabase) As NotesDocument
On Error Goto processError
'** exit early if there is no database
If (db Is Nothing) Then
Print "Log database was not defined. CreateLogDoc is exiting."
Exit Function
End If
Dim logDoc As New NotesDocument(db)
On Error Resume Next
logDoc.Form = formName
logDoc.LogErrorNumber = errNum
logDoc.LogErrorLine = errLine
logDoc.LogErrorMessage = errMsg
logDoc.LogStackTrace = stackTrace
logDoc.LogSeverity = severity
logDoc.LogEventTime = eventTime
logDoc.LogEventType = eventType
logDoc.LogElement = message.element
logDoc.LogAction = message.action
logDoc.LogID = message.id
logDoc.LogLabel = message.label
logDoc.LogMsg = message.msg
If message.action = "created" Or message.action = "closed without saving" Then
logDoc.LogMessage = Fulltrim(commonName + " " + message.action + " " + message.msg + " " + message.element)
Else
logDoc.LogMessage = Fulltrim(commonName + " " + message.action + " the " + message.msg + " " + message.element + " '" + message.label + "'")
End If
Finally, I have a Use "OpenLogFunctions" reference in my forms/view's global options, and I call LogEventEx from the lotusscript events I want to log (well not exactly, but I'll save that for a later post.)
Here is an example event's code:
logMsg.msg = "a new " + Lcase(Mid(Source.Document.Form(0),3)) + " document"
logMsg.action = "created"
logMsg.id = ""
logMsg.Label = ""
Call LogEventEx(logMsg, SEVERITY_LOW, Nothing)






Comments
- Julian
Posted by Julian Robichaux at 07:36:17 AM on 07/06/2007 | - Website - |
Posted by Rob McDonagh at 08:02:41 PM on 07/11/2007 | - Website - |
with minimal "optimizations" you could easily generalize your modifications:
Instead of adding just 4 attributes in a hard-coded class, add a list with the item names as keys.
Then add a method AddItem(itemName as String, value as variant) to your extended logging class.
When creating the log document, the order, in which the extra items are added to the log document, is not important, simply iterate through the list and add every item.
Your example event's code would look like this:
Call logMsg.AddItem("msg", "a new " + Lcase(Mid(Source.Document.Form(0),3)) + " document")
Call logMsg.AddItem("action", "created")
Call logMsg.AddItem("id", "")
Call logMsg.AddItem("Label", "")
Call LogEventEx(logMsg, SEVERITY_LOW, Nothing)
To get a flexible message calculated using the standard and the extra items, you could add a attribute messageFormula, which can be evaluated when creating the log doc.
Just an idea...
Thomas
{ Link }
Posted by Thomas Bahn at 03:59:57 PM on 07/29/2007 | - Website - |