NOTE: This documentation was written for version 1.* of ApplicationMetrics. Minor implementation details may have changed in versions 2.0.0 and above, however the basic principles and use cases documented below are still relevant and correct.
Sample application 5 demonstrates the setup and use of the ApplicationMetrics project, which was included with version 1.3.0.0 of MethodInvocationRemoting. The sample application is based around a GUI application that approximates the value of Pi (the same as in sample application 4). All of the main MethodInvocationRemoting classes used are passed metric logger objects on construction, and the metric logger objects output detailed instrumentation information on the activity and performance of MethodInvocationRemoting.
During setup of the application, multiple classes implementing the IMetricLogger interface are instantiated. The extract from the C# side code below shows the setup of 4 metric loggers logging to a file, the console, a Microsoft Access database, and Windows performance counters...
The FileMetricLogger and MicrosoftAccessMetricLogger are constructed using the SizeLimitedBufferProcessor class to handle queue/buffer processing, and their size limit set to 50 metric events (i.e. the contents of the queues will be written to the file and Access database whenever the total metric events logged reaches 50). An instance of the PerformanceCounterMetricLogger class is created using the deprecated constructor, which defaults to use the LoopingWorkerThreadBufferProcessor class for queue/buffer processing. The interval to write to the Windows performance counters is set to 1000 milliseconds. The ConsoleMetricLogger is also instantiated using the deprecated constructor, and is configured to write metrics to the console every 5 seconds.
Additionally, for all metric loggers the 'intervalMetricChecking' parameter is set to true, so an exception will be thrown if the correct order of logging interval metrics is not followed (e.g. if the End() method is called for a metric without a corresponding Begin()). The MicrosoftAccessMetricLogger must reference the sample Microsoft Access database included in the \Resources folder of MethodInvocationRemoting. Either ensure this file exists in the 'C:\Temp\' folder or adjust the path to the correct location.
A class MetricLoggerDistributor is included with the project, which implements the IMetricLogger interface, and as the name suggests, distributes calls to IMetricLogger methods to multiple objects implementing IMetricLogger. When the MethodInvocationRemoting sender, receiver, and serializer objects are constructed, an instance of the MetricLoggerDistributor class is set on them...
...then further on in the code, the 4 metric loggers are added to the distributor, so that each metric event generated by the MethodInvocationRemoting objects is sent to all four metric loggers...
For the 2 metric loggers which implement interface IMetricAggregateLogger (ConsoleMetricLogger and PerformanceCounterMetricLogger), the metric aggregates which they should calculate must be defined. This step is performed by private method DefineMetricAggregates(). The code for the method appears below...
The following table explains each of the metric aggregates defined in both the C# and Java sides...
Name | Numerator | Denominator | Description | Notes |
---|---|---|---|---|
C# | ||||
BytesSentPerRemoteMethodSent | SerializedMethodInvocationSize | RemoteMethodSent | The average number of bytes sent per remote method sent. | Technically this records the number of characters sent, and the actual number of bytes depends on the character encoding used. However for standard ASCII character the number of characters sent and the number of bytes sent should be equivalent. Additionally the number of characters is recorded by the MethodInvocationSerializer class, and hence does not include any header or delimiter bytes added to transport the message (e.g. as is done by the TcpRemoteSender class). |
BytesReceivedPerRemoteMethodSent | ReceivedMessageSize | RemoteMethodSent | The average number of bytes received per remote method sent. | See notes for 'BytesSentPerRemoteMethodSent' aggregate. |
MessageSendTimePer RemoteMethodSent |
MessageSendTime | RemoteMethodSent | The average time taken to send data per remote method sent in milliseconds. | |
MessageReceiveTimePer RemoteMethodSent |
MessageReceiveTime | RemoteMethodSent | The average time taken to receive data per remote method sent in milliseconds. | |
AverageRemoteMethodSendTime | RemoteMethodSendTime | RemoteMethodSent | The average time taken to send a remote method in milliseconds. | |
BytesSentPerSecond | SerializedMethodInvocationSize | TimeUnit.Second | The average number of bytes sent per second. | See notes for 'BytesSentPerRemoteMethodSent' aggregate. |
BytesReceivedPerSecond | ReceivedMessageSize | TimeUnit.Second | The average number of bytes received per second. | See notes for 'BytesSentPerRemoteMethodSent' aggregate. |
RemoteMethodsSentPerMinute | RemoteMethodSent | TimeUnit.Minute | The average number of remote methods sent per minute. | |
TimeSpentDeserializingReturnValue | ReturnValueDeserializeTime | (total runtime of metric logger) | The percentage of total runtime (i.e. since the metric logger Start() method was called) that consumed deserializing method invocation return values. | For remote invocations of method GenerateScenarios() with a large number of scenarios, the return value will contain a large array, and hence the time taken to deserialize this return value could be significant. |
Java | ||||
BytesSentPerRemoteMethodReceived | CompressedStringSize | RemoteMethodReceived | The average number of bytes sent per remote method received. | Technically this records the number of characters sent, and the actual number of bytes depends on the character encoding used. However for standard ASCII character the number of characters sent and the number of bytes sent should be equivalent. Additionally the number of characters is recorded by the RemoteSenderCompressor class, and hence does not include any header or delimiter bytes added to transport the message (e.g. as is done by the TcpRemoteSender class). |
BytesReceivedPer RemoteMethodReceived |
ReceivedMessageSize | RemoteMethodReceived | The average number of bytes received per remote method received. | See notes for 'BytesSentPer RemoteMethodReceived' aggregate. |
MessageSendTimePer RemoteMethodReceived |
MessageSendTime | RemoteMethodReceived | The average time taken to send data per remote method received in milliseconds. | |
MessageReceiveTimePer RemoteMethodReceived |
MessageReceiveTime | RemoteMethodReceived | The average time taken to receive data per remote method received in milliseconds. | |
AverageRemoteMethodReceiveTime | RemoteMethodReceiveTime | RemoteMethodReceived | The average time taken to receive a remote method in milliseconds. | |
BytesSentPerSecond | CompressedStringSize | TimeUnit.SECONDS | The average number of bytes sent per second. | See notes for 'BytesSentPer RemoteMethodReceived' aggregate. |
BytesReceivedPerSecond | ReceivedMessageSize | TimeUnit.SECONDS | The average number of bytes received per second. | See notes for 'BytesSentPer RemoteMethodReceived' aggregate. |
RemoteMethodsReceivedPerMinute | RemoteMethodReceived() | TimeUnit.MINUTES | The average number of remote methods received per minute. | |
TimeSpentCompressingReturnValues | StringCompressTime | (total runtime of metric logger) | The percentage of total runtime (i.e. since the metric logger Start() method was called) that consumed compressing method invocation return values. | For remote invocations of method GenerateScenarios() with a large number of scenarios, the return value will contain a large array, and hence the time taken to compress this return value could be significant. |
CompressionRatio | CompressedStringSize | SerializedReturnValueSize | The total size of all compressed return values divided by the total size of all uncompressed return values. Hence this effectively shows the compression ratio achieved by the RemoteSender Compressor class. |
The FileMetricLogger and ConsoleMetricLogger will record any base metrics which are logged (through IMetricLogger methods) without requiring any pre-definition or registration of the metrics. The MicrosoftAccessMetricLogger also does not require any registration (although the metrics must be defined in the relevant lookup tables in the Access database). Because of the need to create performance counters in Windows in advance however, the PerformanceCounterMetricLogger requires that any logged metrics are first registered using the RegisterMetric() method. This is performed in the following code...
Additionally, for the PerformanceCounterMetricLogger class, the CreatePerformanceCounters() method is called to create the relevant Windows performance counters and performance counter category in the operating system. Note that the Windows account running the sample application requires appropriate administrative privileges to perform this step...
Any class deriving from MetricLoggerBuffer must have its worker thread started and subsequently stopped. In earlier versions of ApplicationMetrics, this was performed by calling the Start() and Stop() on the metric logger class. From ApplicationMetrics version 1.4.0.0, these methods have been moved to the IBufferProcessingStrategy interface. However the Start() method in classes deriving from MetricAggregateLogger performs additional required initialization steps specific to that class. Generally, the following rules should be observed...
In addition, on the MicrosoftAccessMetricLogger object, the Connect() and Disconnect() methods must be called to connect to and disconnect from the database. These steps are performed in the following code extract...
Similar to standard logging through the ApplicationLogging project, the metric logging can be enabled or disabled in MethodInvocationRemoting at compilation. In C# the conditional compilation symbol 'METRICS_ON' should be set in the MethodInvocationRemoting project build options to enable metric logging. In Java, as with ApplicationLogging, the metrics logging can be enabled by building with Ant, and setting the relevant options in the AntBuild.xml config file as shown below...
The Java code can be started with a command similar to the following (ensure the version of methodinvocationremoting in the 'AntBuild' folder with metric logging enabled is referenced)...
The following should be displayed on the console...
The Java side of the application can be stopped at any time by pressing 'Enter' at the console. The C# code can be started by executing the SampleApplication5.exe file, which will display the following GUI...
Using the application is exactly the same as for SampleApplication4. A number of scenarios (up to 2000) should be entered into the relevant field, and the 'Calculate' button clicked. A remote method call is sent to Java where a number of scenarios are generated. The scenarios are returned to C#, where an approximate value is calculated and displayed in the GUI.
The ConsoleMetricLogger objects on both the C# and Java sides write all current metrics and metric aggregates to the console every 5 seconds. The output will be similar to below in C#...
...and this in Java...
At the same time, each individual metric event will be written to files by the FileMetricLogger classes on both sides. The output will be similar to the following...
Similarly each individual metric will be written to the Microsoft Access database. A number of queries are defined in the database which present the metrics in a readable format. The below screen shot shows a sample of the query 'VwAllMetricInstances', which shows a consolidated view of all logged metrics from both C# and Java...
In the Windows Performance Monitor, the counters to display must be selected through the 'Add Counters' window. The counters defined for the sample application appear in the category 'SampleApplication5Metrics'...
In the below example, three counters are added... AverageRemoteMethodSendTime, BytesSentPerRemoteMethodSent, and BytesSentPerSecond...
The 'Line' view in Performance Monitor shows a graph view of the metrics. In the below case the vertical scale of the graph has been adjusted to a value of 400. Note that the standard counter for BytesSentPerRemoteMethodSent shows a continual average (represented by the blue line). The instantaneous counter however shows only peaks when bytes are sent (represented by the yellow line)...
The 'Report' view can also be used to display all counters in a list...
Remember that the Performance Monitor must be started after the sample application is started (i.e. after the CreatePerformanceCounters() method is called on the PerformanceCounterMetricLogger object) or the counters may not be available to add, or may not display correct values. Also if using aggregates with a time unit denominator, the polling interval of the Performance Monitor must be set to greater than the denominator time unit, for the counters to correctly display.