From RPM Wiki
| Table of contents |
Summary
A system that records everything done between the RPM application and RPM database. The system is designed to be used by RPM Software staff for diagnosis and troubleshooting and is not currently accessible through the RPM interface.
The system is designed with the following initial purposes in mind:
- Audit of customer usage for bug tracking.
- Performance tuning (identifying redundant calls and long running calls).
AKA "Kenny Logger"
Functionality described
Every stored procedure call initiated by the RPM application is recorded to a logging database.
Data logged
The data that is logged includes:
- A time stamp indicating when the proc call was run (when it finished)
- The user's ID
- The user's Login ID
- The user's Full name
- The user's IP Address
- The RPM "Box ID" for the subscriber
- The subscriber name
- The database call including parameters and values
- The length of time it took for the call to finish
- The exception message returned by the database server
- The user's Role ID
- The user's Role name
- The user's Type ID
- The user's Type specific ID
- A counter indicating the log entry number (mostly useful for identifying problems with the logger)
The DBLogger class
Design considerations
In light of our current goals for the logger, there is really only one major design consideration over and above simple functionality:
The logger must not interfere with the operation of RPM
This means that if the logger experiences an exception, it must not propagate up and effect software functionality. The logger must also not create an undue performance burden on the system. It would not be acceptable, for example to have RPM stored procedure calls blocking because the logger was waiting on a call to the log database. The logger must also be able to function in a thread-safe way since user generated postbacks (among other things) create threads in an ASP.NET application.
A couple of design alternatives were looked at, but it seemed clear enough that using a simple insert procedure call with a short timeout was the way to go. Another alternative is to cause each logging call to be done on its own thread, but in the event that the server is unresponsive, we could wind up with thousands of threads bogging down the OS.
The only thing about this simple logger that is not thread-safe is the counter it maintains for populating the "Counter" column. Use of the Interlocked.Increment() statement ensures the counter field is not compromised.
Class use
Logging functionality is performed with the DBLogger class. The class is a singleton which is instantiated at application startup. At that time, the SetConnectionString() member is called to pass in a connection string to the logging database.
Typically, the class is used inside the RpmDBHelper classes "execute" methods. There is also a separate method for logging stored procedure calls where the user is not yet logged in. This includes calling the login procedure, a procedure to get contact information displayed on the login page, a procedure that determines the maximum number of login attempts and one that clears out the Progress Lists at application startup. Developers should not often have a need to add logging code since almost all calls are done through an RpmDBHelper instance.
To use the DBLogger class, first get an instance by calling the GetDBLogger() method. Then create a DateTime variable set to the current time. After the call to execute the database command (Typically either an SqlCommand.ExecuteNonQuery() or SqlDataAdapter.Fill() operation) call the DBLogger's CreateLogEntry() method. You can subtract your DateTime variable from "DateTime.Now" to give the logger the timespan spent executing the procedure. Typically, it is best to wrap database calls with a try/catch block. In the catch block, you could put another call to CreateLogEntry() filling in the errorMessage parameter with the text from the caught exception (otherwise set errorMessage to null).
As noted above the CreateLogEntrySpecial() method can be used for situations where the RpmUser instance does not exist (ie. there is no user logged into the system).
A note about DataAdapters
The RPMGrid class requires its user to set a SqlDataAdapter member. Since RPMGrid calls the FillDataSetWithDataAdapter() of RpmDBHelper itself, the call gets logged. If you ever create some other kind of control which requires a DataAdapter, make sure to see that the call is ultimately logged. (It may make sense to attempt to refactor the SqlDataAdapter out of the RPMGrid class)
Runtime management
The DatabaseLogger.config XML file defines logger options. The logger will periodically read this file at runtime and update the options defined. Currently it is possible to turn logging on and off with the <ShouldLog> tag and to set the number of milliseconds between reads of the XML file with the <ReadInterval> tag.
History
- Jupiter: Added
- This page was last modified 19:37, 19 Mar 2008.
- This page has been accessed 2641 times.
