« Two year anniversary | Main| Transformer's meme »

07/05/2007

Modifying OpenLog to Accept Additional LogEvent Info

Category    

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

Gravatar Image1 - Love it! Nice job Andy.

- Julian

Gravatar Image2 - Nice! Any chance you can fill us in on your log archiving setup? You mentioned how complex it is, which is just a *total* tease. Emoticon

Gravatar Image3 - Hi Andy,

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 }

Post A Comment

:-D:-o:-p:-x:-(:-):-\:angry::cool::cry::emb::grin::huh::laugh::lips::rolleyes:;-)

misc links

search my blog

domino blogger search

coComments

tag cloud