Role of Performance Logging Component is data collecting. It is achieved through logging of calls. Call can be method/function call, http request, api call, database call, etc. It can be grouped into hierarchical, parent-child structure (call graph or call tree) where parent contains all invoked subcalls. Component can be used to track both outer application calls as well as inner ones.
Properties of Call
|Application||Name of the application where event occured|
|CallId||call identifier (globaly unique)|
|CallName||method name, request, function, stored procedure, etc|
|CallType||http request, external api call, api invocation, database call, etc.|
|Duration||duration of the call|
|StartTime||date and time when the call started|
|RequestId||Id of the top-level call, initiated by end user (usually a http request)|
|CallerId||CallId which invoked current this call|
|SessionId||End user’s SessionId (if exists)|
|Identity||Current call identity|
|IP||IP address or host name of invoker|
|Host||Hostname of the machine which executes current application|
For logging of inner calls Atomia.Provisioning.Diagnostic library is used. It provides simple and efficient classes for logging method execution time. Drawback is that existing code must be altered in order to log those calls.
Outer application calls can be logged without altering existing code. This is possible due to the fact that majority of Atomia applications uses .NET and IIS server as a platform. More sprecificaly, WCF is used as a service layer, and ASP.NET as a web application container. For data layer NHibernate OR/M is usually used. ASP.NET allows pluging a custom Http Module into http request pipeline by implementing IHttpModule interface and adding implementation class to pipeline through configuration file. WCF on the other hand also has interfaces for intercepting communication messages, both on a client and a server side. NHibernate also provides events which can be utilized to track database calls. Complete list of interfaces which must be implemented is shown in table below.
||Used for intercepting http request/response in web applications|
||Intercepts external API calls from WCF client (proxy class)|
||Used for instantiating IClientMessageInspectorimplementation class|
||Intercepts incoming WCF calls|
||Used for instantiating IDispatchMessageInspectorimplementation class|
||Intercepts calls in ASP.NET .asmx style web services|
||Intercepts database calls made by NHibernate layer|
Logging of calls
It is important that each outer call in a pipeline has some common identifier which can identify initial call and group all subcalls. Further more, except for initial call (e.g. http request), all other outer calls must have some CallerID (in order to identify order of calls). This is done by passing identifiers through application and between applications. Inside of an application it can be achieved by using some implementation of Execution Context and outside it is implemented by storing identifer in a headers which are passed between applications. This way, it is possible to reconstruct calls throughout multiple application tiers.
Most of the interfaces used for call interception has defined at least two methods: one is intercepting call start, the other call end. Each method logs one performance event, and duration of call is calculated by subracting starting timestamp from the ending one.
Logging of calls must have minimal drawback on overall application performance. For logging of calls memory buffer should be used, and its size would have to be configurable. Memory buffer should write to some IPerformanceLogWriter interface so that log destination could be easisly changed (that way concrete implementations that write to local filesystem, database, service, etc. can be easily implemented). Also, to reduce performance effect on application, actual writing should be performed asynchronously.
Configuration options for call filtering must also be implemented. User of Performance Logging component should have possibility to choose which calls are logged, and which are not. That way, some unneccessary call logs can be avoided (e.g. *.jpg, *.png, *.css etc) or only specific calls can be logged (e.g. some specific API method).
- logging only some percentage of all calls
- logging request of specific users
- logging request in specific time periods
- logging of intercepted messages or at least message sizes