Types described in this section form the substance of the bridge between the internal Experience Manager-Monitor environment and the scripts used to control various aspects of monitor behavior. Each of these types is either created buy a call to a build‑in object, or passed to an event handler defined in script.
A FieldFilter object is used to include or exclude an HVEvent based on the value of one of its fields. All fields in this object are required. In addition, the regex field must contain a valid regular expression as described here:
http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html.
The fieldName value is normally one of standard field names described in metrics.constants Field Names. However, custom field names created with a FieldXform can be used. HVEvents not containing a value in the field specified by fieldName never match the filter.
var appsCollector = metrics.createSummaryCollector(); var testFilter = metrics.createFieldFilter(); testFilter.name = 'testFilter'; testFilter.fieldName = metrics.constants.FN_APPLICATION_NAME; testFilter.regex = 'TEST.*'; if(testFilter.isValid()) { appsCollector.exclusionFilters=[testFilter]; //exclude test events } else { bem.logWarning('Test filter not valid:' + testFilter.toString()); }
Property Name |
Value Type |
Description |
---|---|---|
name |
String |
(Required) Name of the filter. |
fieldName |
String |
(Required) Name of the field the filter operates on. |
Boolean isValid() |
Returns True if all required fields are populated and the expression fields contains a valid regular expressions.If False is returned, the scripting log contains a description of the failure. |
String toString() |
Returns a string representation of this event. |
A FieldXform object is used to normalize data values in an HVEvent object. The name, fieldName, matchExpression, and replaceExpression fields in this object are required. In addition, the matchExpression field must contain a valid regular expressions as described here:
http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html.
The replaceExpression can contain both literal data, as well as references to captured substrings from the matchExpression. Capture references are referenced using a dollar sign ($) followed by the index of the desired capture field, starting with index 1 to indicate the first capture field. A literal dollar sign must be preceded with a backslash to indicate that it is not a capture reference. The fieldName value is normally one of standard field names described in metrics.constants Field Names. However, custom field names created with a previous FieldXform can be used. HVEvents not containing a value in the field specified by fieldName never match.
When an HVEvent is applied to a FieldXForm, the FieldXForm compares the value of the specified field with its matchExpression. If the value does not match the expression, then no changes are made to the HVEvent. The the value does match, then the replaceExpression is used to transform the value, and if specified, the caseRule is used to normalize the case of the transformed value. The resulting value is then save to the destination field, or if not specified, back to the field from which the source value was taken.
The following example for FieldXform is from the DemoMetrics.js script included in the Experience Manager installation. It is designed to identify the same page across multiple hosts, while suppressing any parameters passed to the page.
var ulx= metrics.createXform('URLKey Xform'); ulx.fieldName=metrics.constants.FN_URL; ulx.matchExpression='http[s]?://[^/]+([^#\?]+).*'; ulx.replaceExpression='$1'; ulx.destFieldName='urlKey'; ulx.caseRule=metrics.constants.CASE_TO_LOWER;
It evaluates the URL field in the HVEvent against the match expression:
http[s]?://[^/]+([^#\?]+).*
Table A-1 lists the regular expressions, and describes how the configured matchExpression is interpreted.
Table A-1 matchExpression Interpretations
Match Characters |
Interpretation |
---|---|
http |
Matches only the literal string http. |
[s]? |
Matches 0 or one “s” in this position. |
:// |
Matches only the literal string “://” in this position. |
[^/]+ |
Matches one or more of any character up to but not including the / character. |
([^#\?]+) |
Matches one or more of any character up to but not including # or ? characters. The parentheses mark this section as a capture field that is referenced in replaceExpression. |
.* |
Matches any number of trailing characters of any type. |
Based on this match expression, the xform saves the value of the first capture field ($1), converts it to lower case, then saves it to a custom HVEvent field called urlKey. Table A-2 shows sample URL values and the resulting urlKey values produced by this xform:
Table A-2 Sample URL and resulting urlKey values for the xform of the matchExpression example
URL |
UrlKey |
---|---|
http://www.netiq.com/products/experience-manager/ |
/products/experience-manager/ |
http://localhost:8080/Plugins/invoke.pl?op=threadDump |
/plugins/invoke.pl |
http://us.mc1102.mail.yahoo.com/mc/welcome?.gx=1&.tm=1250689315&.rand=3hsbmdsrkkmg6 |
/mc/welcome |
This approach obviously does not work for all Web sites. You should come up with your own schemes for normalizing data into useful values.
Property Name |
Value Type |
Description |
---|---|---|
name |
String |
(Required) Name of the Xform. |
fieldName |
String |
(Required) Name of the field to be read by the Xform. |
matchExpression |
String |
(Required) Regular expression describing field values that should be transformed. |
replaceExpression |
String |
(Required) A regular expression describing how to transform values that match the matchExpression. |
destFieldName |
String |
Name of the field where transformed data should be written. |
caseRule |
Object |
(Rule for changing the case of matching fields. |
generalProperties |
java.util.Map |
Other properties for the alarm. |
Boolean isValid() |
Returns True if all required fields are populated and the expression fields contains a valid regular expressions.If False is returned, the scripting log contains a description of the failure. |
String toString() |
Returns a string representation of this event. |
An HVEvent object represents a single hit by a user on a single Web page. All properties in this object are read-only. Fields in the event have undergone any transformations implemented in the preprocessor. The get() method can be used to access any custom fields produced by xforms.
Under normal circumstances, the vast majority of events received by a monitor are discarded after processing in order to conserve system resources. However, sampling data collectors capture and report a percentage of these events as HVEvent objects. Summary reports also include a reference to a single HVEvent object, provided for reference purposes.
// Calculate the median response time from sampled events function calculateMedian(events) { var median =0; if(events.length > 1) { var values = new Array(); for(var i=0; i< events.length; i++) { values.push(events[i].responseTime); } values.sort(sortOrder); var mid = Math.floor(values.length/2); if((values.length % 2) == 0) { median = (values[mid-1]+values[mid])/2; } else { median = values[mid]; } } else if(events.length == 1) { median = events[0].responseTime; } return median; } // ensures sorting by numeric order instead of the default alpha sort function sortOrder(a,b) { return a-b; }
Property Name |
Value Type |
Description |
---|---|---|
appName |
String |
The appName parameter from the instrumentation script that generated this event. |
clientIP |
String |
The IP address of the system that delivered this event to the Monitor. |
downloadTime |
integer |
The reported interval between initialization of the current page and final rendering (in milliseconds). |
timestamp |
java.util.Date |
The time when this event was received by the Monitor. |
responseTime |
integer |
The downloadTime+uploadTime, or downloadTime if uploadTime is out of range. This is the value used in SummaryStats calculations. |
title |
String |
The document title of the page that produced this event. |
uploadTime |
String |
The reported interval between unload of previous page and current page initialization. |
URL |
String |
The URL of the page that produced this event. |
userAgent |
String |
The userAgent value reported by the browser that sent this event. |
String get(String fieldName) |
Retrieves the value of a named field. |
String toString() |
Returns a string representation of this event. |
A MetricAlarm object represents an alert to be sent to a remote system. This is a general purpose mechanism and the necessary content of the alarm is based on the needs of the system receiving the alarm. (HVM does not currently support Operations Center alarms.)
metrics.onMemberRefused=handleRefused; function handleRefused(memberData) { var alarm = metrics.createTecAlarm(); alarm.id= memberData.id.hashCode(); alarm.appName='HVM Group Status'; alarm.timestamp = new java.util.Date(); alarm.severity = metrics.constants.SEV_CRITICAL; alarm.description= memberData.id + ' refused control by ' + metrics.getLocalMember().id; metrics.sendAlarm(alarm); }
Property Name |
Value Type |
Description |
---|---|---|
appName |
String |
(Required) Name of the application to which this alert applies. |
collectorName |
String |
Name of the collector this alert is associated with. |
timestamp |
java.util.Date |
(Required) Time when this alert occurred. |
severity |
String |
(Required) Severity of the alarm (see mtrics.constants Severities). |
description |
String |
Description of the alarm. |
id |
String |
(Required) Identifier for this alert. |
generalProperties |
java.util.Map |
Other properties for the alarm. |
Boolean isValid() |
Returns True if object contains all required data and all provided data is valid. If False is returned, the logs include details of the error. |
String toString() |
Returns a string representation of this event. |
A MetricsElement object represents an element on the Operations Center server under the Elements/Experience Manager_adapter/Metrics/ branch. When a MetricsElement object is received by the Experience Manager adapter on the Operations Center server, the MetricsElement data is used to create or update the Operations Center Element. The elementKeys property specifies the relative path from Elements/Experience Manager_adapter/metrics/. So, if you specify elementKeys ['Page Stats', 'Home Page'], then the MetricsElement object creates or updates Elements/Experience Manager_adapter/metrics/Page Stats/Home Page.
It is not necessary to create “Page Stats” prior to creating “Home Page”; if a nonexistent element is referenced in the element hierarchy, it is created automatically. The condition and message properties are used to update the corresponding fields on the Operations Center element.
The seriesData property is used to capture metric data that you wish to record over time. When you select the Performance tab for the Operations Center element you have created, any series data types you have populated should show in the Performance Properties panel of the display.
The properties property is used to populate the metrics properties page (right-click Properties > Metrics) for the element. After a metrics property has been added to an element, it remains there until the element has been removed, or the property is deleted. To delete a property, you can set its value to null (for example, 'elem.properties.put('somePropertyName', null);'). Alternatively, if you set isPropertySetComplete to True, then any properties not included in the MetricsElement object is removed.
var collector = metrics.createSummaryCollector('Page Stats', 60000, processPageStats); collector.groupingFieldNames=[metrics.constants.FN_PAGE_TITLE]; var targetRange = metrics.createResponseTimeRange('target', 0, 1500); var acceptRange = metrics.createResponseTimeRange('accept', 1500, 4000); var problemRange = metrics.createResponseTimeRange('problem', 4000, 60000); collector.ranges=[targetRange,acceptRange,problemRange]; // ... add other collector props and deploy /* * Process reports generated by the Page Stats collector */ function processPageStats(reports) { for(var i=0; i < reports.length;i++) { var report = reports[i]; // create element and automatically map stats into series data. var elem = metrics.createMetricsElement() elem.elementKeys=[report.key.collectorName, report.key.groupValues[0]]; assignConditonAndMessage(elem, report); elem.seriesData = createSeriesEntries(report); elem.properties.put('Reference URL', report.lastEvent.URL); elem.properties.put('Page Title', report.lastEvent.title); elem.properties.put('Hit Count', report.overall.count); // mine other properties .. metrics.sendMetricsElement(elem); } } /* * calculate element condition based on relative hit count */ function assignConditonAndMessage(elem,report) { var targetHits = getRangeHitCount(report,'target'); var acceptHits = getRangeHitCount(report,'accept'); var problemHits = getRangeHitCount(report,'problem'); if(targetHits > acceptHits + problemHits) { elem.condition=metrics.constants.SEV_OK; elem.message = 'Performance target achieved'; } else if (targetHits > problemHits || acceptHits > problemHits) { elem.condition = metrics.constants.SEV_MINOR; elem.message = 'Performance acceptable'; } else if (targetHits + acceptHits > problemHits) { elem.condition = metrics.constants.SEV_MAJOR; elem.message = 'Performance degraded'; } else { elem.condition = metrics.constants.SEV_CRITICAL; elem.message = 'Performance violation'; } elem.message += ': T=' + targetHits + ' A='+ acceptHits + ' P=' + problemHits; } /* * Return hit count if range has data, or 0 if it does not */ function getRangeHitCount(report, rangeName) { var hitCount = 0; var rangeStats = report.rangeStats.get(rangeName); if(rangeStats != null) { hitCount = rangeStats.count; } return hitCount; } /* * Create Series entries for this report */ function createSeriesEntries(report) { var seriesData = new Array(); var avg=metrics.createSeriesData(); avg.name = 'Overall:Avg'; avg.timestamp = report.stopTime; avg.value = report.overall.average; seriesData.push(avg); seriesData.push(metrics.createSeriesData('Overall:Max', report.stopTime,report.overall.high)); seriesData.push(metrics.createSeriesData('Overall:Min', report.stopTime,report.overall.low)); seriesData.push(metrics.createSeriesData('Overall:Count', report.stopTime,report.overall.count)); var iterator = report.rangeStats.entrySet().iterator(); while(iterator.hasNext()) { var mapEntry = iterator.next(); var rangeName = mapEntry.getKey(); var rangeStats = mapEntry.getValue(); seriesData.push(metrics.createSeriesData(rangeName +':Avg', report.stopTime,rangeStats.average)); seriesData.push(metrics.createSeriesData(rangeName +':Max', report.stopTime,rangeStats.high)); seriesData.push(metrics.createSeriesData(rangeName +':Min', report.stopTime,rangeStats.low)); seriesData.push(metrics.createSeriesData(rangeName +':Count', report.stopTime,rangeStats.count)); } return seriesData; }
Property Name |
Value Type |
Description |
---|---|---|
elementKeys |
String |
(Required) The elementKeys array holds the element’s hierarchy relative to Elements/Experience Manager_adapter/metrics/. |
condition |
String |
The condition (OK, MAJOR, CRITICAL, and so on) to assign to this element. If set, the value must one of the constants described in metrics.constants Severities. |
message |
String |
The title bar message for this element that contains a short description. |
seriesData |
SeriesData[] |
Array of time points to record with this element. |
properties |
java.util.Map |
Property name/value pairs to be exposed on the element’s Properties page. |
isPropertySetComplete |
Boolean |
True/false indicator that impacts how properties are applied to a preexisting element. |
Boolean isValid() |
Returns True if object contains all required data and all provided data is valid. If False is returned, the logs include details of the error. |
String toString() |
Returns a string representation of this event. |
A MetricsMember object refers to a Experience Manager monitor that is a member of an HVM group. Instances of this object are returned by the metrics.getLocalMember() and metrics.getAllMembers and are passed as arguments to metrics.onMemberConnect, metrics.onMemberDisconnect and metrics.onMemberRefused event-handlers.
var members = metrics.getAllMembers(); for(var i=0; i < members.length; i++) { var elem = metrics.createMetricsElement(); elem.elementKeys = ['groupStatus', members[i].id]; elem.properties.put('Is Controller', !members[i].isRemote); elem.properties.put('Is Connected' , members[i].isConnected()); elem.condition=metrics.constants.SEV_MINOR; elem.isPropertySetComplete=false; metrics.sendMetricsElement(elem); }
Property Name |
Value Type |
Description |
---|---|---|
id |
String |
(Read-only) MetricsMember.id is a read-only property that uniquely identifies a group member. The format of this identifier matches the format of the member in the HVMetrics.group.members property. |
isRemote |
Boolean |
(Read-only) MetricsMember.isRemote is a read-only property that indicates whether the referenced member is the local system or a remote monitor. |
Boolean isConnected() |
MetricsMember.isConnected() indicates whether connectivity between the local controller and this member is established. |
Preprocessor objects are responsible for normalizing and filtering HVEvent objects before they are processed by data collectors. A deployed preprocessor is the first to handle event data coming in from the browser. First, it populates the response time field by adding the provided upload time and download time values. However, if the provided upload time is greater than the specified uploadTimeLimit, the upload time value is ignored and the response time will equal the download time.
After the deployed preprocessor populates the response time, it performs data transformations as specified by any included xforms. If multiple xforms are specified, they are applied in the sequence that they appear in the array. Following that, filters are applied. Any event matching a preprocessor filter is excluded from further processing.
// filter out local subnet to prevent skew. var subnetFilter= metrics.createFieldFilter( 'ipFilter', metrics.constants.FN_CLIENT_IP, '192.168.1.*'); var ieXform = metrics.createXform( 'IE xform', metrics.constants.FN_USER_AGENT, '(.*)(MSIE[^;]*)(.*)', '$2', 'browserVersion', metrics.constants.CASE_TO_LOWER); var ffXform = metrics.createXform( 'Firefox xform', metrics.constants.FN_USER_AGENT, '(.*)(Firefox\\S*)(.*)', '$2', 'browserVersion', metrics.constants.CASE_TO_LOWER); var preproc = metrics.createPreprocessor(); preproc.uploadTimeLimit=2000; preproc.xforms=[ieXform,ffXform]; preproc.filters=[subnetFilter];
Property Name |
Value Type |
Description |
---|---|---|
uploadTimeLimit |
integer |
(Recommended) Maximum uploadTime value (ms) that is included in response time calculation. |
FieldXform[] |
xforms |
Transformers to be applied to the incoming fields. Transformations are performed in the provided order and are done after response time calculation. |
FieldFilter |
filter |
Filters to describe any events that should be ignored. An event that matches any filter in the preprocessor is ignored. |
String toString() |
Returns a string description of the preprocessor. |
Boolean isValid() |
Returns True if all included xforms and filters are valid. |
A ReportKey object is used to identify a SummaryReport or SamplingReport produced by a data collector. The report key ties the associated report to a particular collector and a particular set of grouping values within that collector. Refer to the associated report type for more information.
Property Name |
Value Type |
Description |
---|---|---|
collectorName |
String |
(Read-only) Name of the data collector that produced the report. |
type |
String |
The type of the data collector (Sampling or Summary). |
groupValues |
String[] |
Values of the grouping fields that provide the scope of this report. |
String toString() |
Returns a string representation of this object. |
ResponseTimeRange objects are used to refine data collectors to track hits where the response time falls within the specified range values. Each defined response time range on a dta collector reports a discreet count, average/high/low response time of hits that fell within the range.
The following example demonstrates how one might derive series data from a report. The implementation shown here mirrors the default series data created when default series data mapping is enabled using the metrics.createMetricsElement() method.
var targetRange = metrics.createResponseTimeRange('target', 0, 1500); var acceptRange = metrics.createResponseTimeRange('accept', 1500, 4000); var problemRange = metrics.createResponseTimeRange('problem', 4000, 60000); var appsCollector = metrics.createSummaryCollector(); appsCollector.ranges=[targetRange,acceptRange,problemRange];
Property Name |
Value Type |
Description |
---|---|---|
name |
String |
(Required) Name of the range. This value tracks through to the report. |
lowTime |
integer |
(Required) Minimum response time to include in this ranges report (inclusive). |
highTime |
integer |
(Required) Maximum response time to include in this ranges report (exclusive). |
String toString() |
Returns a string description of the ResponseTimeRange. |
Boolean isValid() |
Returns True if all values are populated and lowTime <= highTime. |
A SeriesData object is used to capture a data point for historical tracking. These objects must be associated MetricsElement to be sent to Operations Center. The Operations Center server does not process updates to the same name and time stamp value on the same element. If the value should be kept for a longer of shorter period than the default retention period set in the Experience Manager Adapter properties use expiryDays to override.
function createSeriesEntries(report) { var seriesData = new Array(); var avg=metrics.createSeriesData(); avg.name = 'Overall:Avg'; avg.timestamp = report.stopTime; avg.value = report.overall.average; seriesData.push(avg); seriesData.push(metrics.createSeriesData('Overall:Max', report.stopTime,report.overall.high)); seriesData.push(metrics.createSeriesData('Overall:Min', report.stopTime,report.overall.low)); seriesData.push(metrics.createSeriesData('Overall:Count', report.stopTime,report.overall.count)); var iterator = report.rangeStats.entrySet().iterator(); while(iterator.hasNext()) { var mapEntry = iterator.next(); var rangeName = mapEntry.getKey(); var rangeStats = mapEntry.getValue(); seriesData.push(metrics.createSeriesData(rangeName +':Avg', report.stopTime,rangeStats.average)); seriesData.push(metrics.createSeriesData(rangeName +':Max', report.stopTime,rangeStats.high)); seriesData.push(metrics.createSeriesData(rangeName +':Min', report.stopTime,rangeStats.low)); seriesData.push(metrics.createSeriesData(rangeName +':Count', report.stopTime,rangeStats.count)); } return seriesData; }
Property Name |
Value Type |
Description |
---|---|---|
name |
String |
(Required) Name of the data item. |
timestamp |
java.util.Date |
(Required) Time stamp for the data item. |
Number |
value |
(Required) Value of the data item. |
expiryDays |
integer |
Number of days this item should be kept in the active database for reporting. |
String toString() |
Returns a string description of the object. |
Boolean isValid() |
Returns True if all required fields are populated. If False is returned, the scripting log contains a description of the failure. |
SummaryDataCollector objects are used to analyze the HVEvent stream and periodically produce summary reports describing the content of the event stream. These objects are generally created using one of the metrics.createSummaryCollector() methods and deployed in the implementation of an metrics.onload event-handler.
If the collector is deployed, every HVEvent that gets past the preprocessor is analyzed by it. First, the event is checked against inclusionFilters and exclusionFilters. If any inclusionFilters are defined, then an event must match at least one of them, or it is excluded. A match to an exclusionFilter also causes the event to be excluded. If an event passes the filters, the event is included in the next set of interval reports generated by this collector.
Collectors generate reports at the frequency specified by the intervalDuration property and delivered to the function specified by the onreport property. Separate reports are generated for each unique set of grouping field values and include all recorded activity for all HVEvent objects with the same set of grouping field values. After reports are delivered to the handler, the collector forgets that information, so if a given set of grouping field values has no activity in the next interval, no report is generated for it.
In a distributed HVM environment, identical collectors are deployed to all members of the HVM group. At the end of each interval, reports are collected from all HVM members and their content is consolidated into a single set of reports. For example, if a data collector specified page title as the sole grouping field and at the end of the interval HVMGroupMember1 reported the following statistics for the page called 'User Login':
and HVMGroupMember2 reported the following for the same page:
Then the report delivered to the onreport event handler can contain the following:
This consolidation of reports with the same key and interval values is automatic in a distributed HVM configuration. On occasion, a remote monitor can also deliver a report from a previous interval, because some transient condition prevented it from reporting when that interval’s data was processed (see Distributed High-Volume-Metrics Data Collection). In this situation, the stale report data (data from an earlier interval) can be rolled into the current interval’s data, reported to the event handler as a separate report for the old interval, or filtered out entirely. The value of the staleReportOptions property determines the behavior. Appropriate values are described in metrics.constants Stale Report Options.
var appFilter = metrics.createFieldFilter('Banking Filter', metrics.constants.FN_APPLICATION_NAME, 'BANKING'); var devSystemFilter = metrics.createFieldFilter('Dev System Filter', metrics.constants.FN_URL, 'http://DEV.*'); var targetRange = metrics.createResponseTimeRange('target', 0, 1500); var acceptRange = metrics.createResponseTimeRange('accept', 1500, 4000); var problemRange = metrics.createResponseTimeRange('problem', 4000, 60000); var collector = metrics.createSummaryCollector(); collector.name= 'Banking'; collector.intervalDuration=60000; collector.onreport=processBanking; collector.groupingFieldNames=[metrics.constants.FN_PAGE_TITLE]; collector.ranges=[targetRange,acceptRange,problemRange]; collector.inclusionFilters=[appFilter]; collector.exclusionFilters=[devSystemFilter]; collector.staleReportOption=metrics.constants.SRO_PASS; // deploy with preprocessor and other collectors. function processBanking(reports) { // do Banking application processing }
Property Name |
Value Type |
Description |
---|---|---|
name |
String |
(Required) Name of the collector. |
intervalDuration |
interval |
(Required) Frequency with which the collector should produce reports, specified in milliseconds. |
onreport |
Function |
(Required) Is used to specify the event-handler to be called when the collector has reports to be processed. The expected handler signature is void yourHandlerName(SummaryReport[] reports). |
groupingFieldNames |
String[] |
List of HVEvent field names whose unique values will produce a discrete report. |
inclusionFilters |
FieldFilter[] |
List of filters that an HVEvent must match in order to be included in this collector’s reports. |
exclusionFilters |
FieldFilter[] |
List of filters that an HVEvent might not match if it is to be included in this collector’s reports. |
ranges |
ResponseTimeRange[] |
List of ranges for which a discrete set of statistics should be maintained. |
staleReportOption |
String[] |
Instruction indicating how stale reports should be handled in a distributed metrics environment. |
Boolean isValid() |
Returns True if all required values are populated and all populated values are valid. |
String toString() |
Returns a string description of the SummaryDataCollector. |
SummaryReport objects are used to report on activity captured within a reporting interval. Deployed SummaryCollector objects generate a separate report for each unique set of grouping field values and pass them to the collector’s onreport event handler. The key.groupValues property specifies the set of unique values that define the scope of the report. If the collector does not define any grouping fields, it produces a single report per interval in which it saw activity with no specified key.groupingValues.
Each report instance captures the overall statistics, as well as statistics for any defined ranges where at least one hit fell within the range’s constraints. Report data is not generated for grouping values that saw no activity or for ResponseTimeRanges that saw no activity.
The following example defines a SummaryCollector with a one-minute interval for which it reports any activity observed to the processPageStats function. This collector groups information by page title, so for each unique page title appearing in an HVEvent during the interval, the collector generates a report, with the name of the page being reported on specified in report.key.groupValues[0].
As this custom handler receives these reports, it generates metrics elements that appear on a connected Operations Center server. As this script is written, the element name matches the page title, and appears under Elements > Experience Manager_adapter > Metrics > Page Stats > page_title in the element tree. The properties page for this element then has data mined from the Summary Reports. (It can presumably also have Series data showing a history of the page performance, but that logic is omitted here for simplicity.)
This example uses custom logic for driving the condition of the element. The collector defines a set of ranges that presumably have business meaning in the context of the site being monitored. Based on the relative number of hits in each of these ranges, the script assigns an appropriate condition and message (description) for the element.
var collector = metrics.createSummaryCollector('Page Stats', 60000, processPageStats); collector.groupingFieldNames=[metrics.constants.FN_PAGE_TITLE]; var targetRange = metrics.createResponseTimeRange('target', 0, 1500); var acceptRange = metrics.createResponseTimeRange('accept', 1500, 4000); var problemRange = metrics.createResponseTimeRange('problem', 4000, 60000); collector.ranges=[targetRange,acceptRange,problemRange]; // ... add other collector props and deploy function processPageStats(reports) { for(var i=0; i < reports.length;i++) { var report = reports[i]; // create element and automatically map stats into series data. var elem = metrics.createMetricsElement() elem.elementKeys=[report.key.collectorName, report.key.groupValues[0]]; assignConditonAndMessage(elem, report); elem.properties.put('Reference URL', report.lastEvent.URL); elem.properties.put('Page Title', report.lastEvent.title); elem.properties.put('Hit Count', report.overall.count); // mine other properties .. metrics.sendMetricsElement(elem); } } /* * calculate element condition based on relative hit count */ function assignConditonAndMessage(elem,report) { var targetHits = getRangeHitCount(report,'target'); var acceptHits = getRangeHitCount(report,'accept'); var problemHits = getRangeHitCount(report,'problem'); if(targetHits > acceptHits + problemHits) { elem.condition=metrics.constants.SEV_OK; elem.message = 'Performance target achieved'; } else if (targetHits > problemHits || acceptHits > problemHits) { elem.condition = metrics.constants.SEV_MINOR; elem.message = 'Performance acceptable'; } else if (targetHits + acceptHits > problemHits) { elem.condition = metrics.constants.SEV_MAJOR; elem.message = 'Performance degraded'; } else { elem.condition = metrics.constants.SEV_CRITICAL; elem.message = 'Performance violation'; } elem.message += ': T=' + targetHits + ' A='+ acceptHits + ' P=' + problemHits; } /* * Return hit count if range has data, or 0 if it does not */ function getRangeHitCount(report, rangeName) { var hitCount = 0; var rangeStats = report.rangeStats.get(rangeName); if(rangeStats != null) { hitCount = rangeStats.count; } return hitCount; }
Property Name |
Value Type |
Description |
---|---|---|
key |
ReportKey |
Identifier describing the scope covered by this report. |
endTime |
java.util.Date |
End of the period covered by this report. |
collector |
SummaryCollector |
Collector that generated this report. |
lastEvent |
String[] |
A copy of the last event captured during the interval of this report. |
overall |
FieldFilter[] |
Overall statistics for this report. |
rangeStats |
java.util.Map<String,summary_stats> |
Map of SummaryStat for each range that had activity. Map key is the name of the configured ResponseTimeRange. |
reportingMonitors |
String[] |
List of monitors that contributed to this report. |
nonreportingMonitors |
String[] |
List of monitors in the group that could not be contacted when this report was assembled. |
String toString() |
Returns a string representation of this object. |
SummaryStats objects are a collection of statistics that appear in a number of contexts inside a SummaryReport or a SamplingReport. Refer to the containing report type for more information.
Property Name |
Value Type |
Description |
---|---|---|
count |
Number |
(Read-only) Number of hits in the reported scope. |
high |
Number |
(Read-only) Highest response time (in milliseconds) in the scope. |
low |
Number |
(Read-only) Lowest response time in the scope. |
average |
Number |
(Read-only) Arithmetic average of the response times in the scope |
String toString() |
Returns a string representation of this object. |
A SyntheticAlarm object represents an alarm generated by the Experience Manager Monitor test engine. All properties are read-only. SyntheticAlarm objects are reported to the testEngine.onScenarioComplete and testEngine.onTestComplete event handlers to support Synthetic Test Management functionality.
For an example, see Section A.2.18, SyntheticTestResults.
Property Name |
Value Type |
Description |
---|---|---|
testName |
String |
(Read-only) Name of the test that produced this alarm. |
scenarioName |
String |
(Read-only) Name of the test scenario that produced this alarm. |
scenarioSeqNum |
Number |
(Read-only) Sequence number of the originating test scenario within its enclosing test. |
responseTime |
Number |
(Read-only) Execution time reported by the scenario. A negative number indicates an execution failure. |
severity |
Object |
(Read-only) Severity of the alarm. Value corresponds to one of the values in testEngine.constants severities. |
description |
String |
(Read-only) Text description of the alarm. |
userNum |
Number |
((Read-only) Simulated user number. The value is always 1, unless SyntheticTest.userCount is greater than 1. |
timestamp |
java.util.Date |
Time when the alarm was generated. |
String toString() |
Returns a string representation of this object. |
Boolean isFailed() |
Returns a string representation of this object. |
A SyntheticDeployment object provides access to the collection of SyntheticTest objects currently deployed to the monitor. This deployment is created and managed in the Experience Manager adapter using the Operations Center console. A read-only view is exposed in the Monitor’s scripting layer to facilitate Web Operations and Synthetic Test Management functionality.
The following example shows a simple WebOps that displays the content of a requested SyntheticDeployment.
function showDeploymentOp(parmMap) { var html = '<table border="2">'; var tests = testEngine.getDeployment().getTests(); for(var i=0;i< tests.length; i++) { html += addItem('Test -' + tests[i].name,testToHTML(tests[i])) } html+='</table>'; return html; } function testToHTML(test) { var html = '<table border="1">'; html += addItem('name', test.name); html += addItem('userCount', test.userCount); html += addItem('interval', test.interval); html += addItem('enabled', test.enabled); html += addItem('includeRollup', test.includeRollup); var scenarios = test.getScenarios(); for(var i=0;i< scenarios.length; i++) { html+= addItem('scenario-' + scenarios[i].seqNum,scenarioToHTML(scenarios[i])); } html += '</table>'; return html; } function scenarioToHTML(scenario) { var html = '<table>'; html += addItem('name', scenario.name); html += addItem('type', scenario.type); html += addItem('enabled', scenario.enabled); html += addItem('testName', scenario.testName); html += addItem('seqNum', scenario.seqNum); html += addItem('delay', scenario.delay); html += addItem('timeout', scenario.timeout); html += addItem('retries', scenario.retries); html += addItem('continueOnFailure', scenario.continueOnFailure); html += addItem('includeRollup', scenario.includeRollup); html += '</table>'; return html; } function addItem(typeName, value) { return '<tr><td>' + typeName + '</td><td>' + value + '</td></tr>'; }
There are no properties associated with the SyntheticDeployment object.
SyntheticTest[] getTests() |
Returns an array of all SyntheticTest objects currently deployed to this monitor. |
SyntheticTest getTest(String name) |
Returns the test in this deployment where the SyntheticTest.name is equal to the provided name. If no test has the provided name, null is returned. |
String toString() |
Returns a string representation of this object. |
A SyntheticScenario object represents a scenario in a SyntheticTest. These scenarios are created and managed in the Experience Manager adapter using the Operations Center console. A read-only view is exposed in the Monitor’s scripting layer to facilitate Web Operations and Synthetic Test Management functionality.
The following example shows a simple WebOps that displays the content of a requested SyntheticScenario.
function showScenarioOp(parmMap) { var testName=parmMap.get("testName"); var index =parmMap.get("index"); var deployment = testEngine.getDeployment(); var test = deployment.getTest(testName); if(test == null) { return 'Test ' +testName + ' not found'; } var scenario = test.getScenarioBySeqNum(index); if(scenario == null) { return 'Scenario ' + index + ' not found in test ' + testName; } return scenarioToHTML(scenario); } function scenarioToHTML(scenario) { var html = '<table>'; html += addItem('name', scenario.name); html += addItem('type', scenario.type); html += addItem('enabled', scenario.enabled); html += addItem('testName', scenario.testName); html += addItem('seqNum', scenario.seqNum); html += addItem('delay', scenario.delay); html += addItem('timeout', scenario.timeout); html += addItem('retries', scenario.retries); html += addItem('continueOnFailure', scenario.continueOnFailure); html += addItem('includeRollup', scenario.includeRollup); html += '</table>'; return html; } function addItem(typeName, value) { return '<tr><td>' + typeName + '</td><td>' + value + '</td></tr>'; }
Property Name |
Value Type |
Description |
---|---|---|
name |
String |
(Read-only) Name of the scenario. |
type |
Object |
(Read-only) Type of scenario corresponding to one of the testEngine.constants values. |
enabled |
Boolean |
(Read-only) Sequence number of the originating test scenario within its enclosing test. |
testName |
String |
(Read-only) Name of the test containing the scenario. |
seqNum |
Number |
(Read-only) Sequence number of the scenario within the enclosing test. |
delay |
Number |
((Read-only) Artificial delay (in milliseconds) inserted before the scenario executes. |
timeout |
Number |
(Read-only) Amount of time (in milliseconds) before the scenario is marked as failed because it took too long. |
retries |
Number |
(Read-only) Number of times to retry the scenario in the event of a failure. |
continueOnFailure |
Boolean |
Whether the test should continue to the next scenario if this scenario fails. |
includeRollup |
Boolean |
Whether a roll‑up alarm should be generated with this scenario with the cumulative response time since the previous roll‑up. |
String toString() |
Returns a string representation of this object. |
A SyntheticTest object represents a test in a SyntheticDeployment. These tests are created and managed in the Experience Manager adapter using the Operations Center console. A read-only view is exposed in the Monitor’s scripting layer to facilitate Web Operations and Synthetic Test Management functionality.
The following example shows a simple WebOps that displays the content of a requested SyntheticTest.
function showTestOp(parmMap) { var testName=parmMap.get("testName"); var deployment = testEngine.getDeployment(); var test = deployment.getTest(testName); if(test == null) { return 'Test ' +testName + ' not found'; } return testToHTML(test); } function testToHTML(test) { var html = '<table border="1">'; html += addItem('name', test.name); html += addItem('userCount', test.userCount); html += addItem('interval', test.interval); html += addItem('enabled', test.enabled); html += addItem('includeRollup', test.includeRollup); var scenarios = test.getScenarios(); for(var i=0;i< scenarios.length; i++) { html+= addItem('scenario-' + scenarios[i].seqNum,scenarioToHTML(scenarios[i])); } html += '</table>'; return html; } function scenarioToHTML(scenario) { var html = '<table>'; html += addItem('name', scenario.name); html += addItem('type', scenario.type); html += addItem('enabled', scenario.enabled); html += addItem('testName', scenario.testName); html += addItem('seqNum', scenario.seqNum); html += addItem('delay', scenario.delay); html += addItem('timeout', scenario.timeout); html += addItem('retries', scenario.retries); html += addItem('continueOnFailure', scenario.continueOnFailure); html += addItem('includeRollup', scenario.includeRollup); html += '</table>'; return html; } function addItem(typeName, value) { return '<tr><td>' + typeName + '</td><td>' + value + '</td></tr>'; }
Property Name |
Value Type |
Description |
---|---|---|
name |
String |
(Read-only) Name of the test. |
userCount |
Number |
(Read-only) Number of concurrent simulated users to run for this test. |
interval |
Number |
(Read-only) Time (in milliseconds) between executions of this test. |
enabled |
Boolean |
(Read-only) True if the test is activated. |
includeRollup |
Boolean |
Whether a roll‑up alarm should be generated with this test with the cumulative response time of all scenarios in the test. |
String toString() |
Returns a string representation of this object. |
SyntheticScenario[] getScenarios() |
Returns an ordered array of all scenarios in this test as SyntheticScenario objects. |
SyntheticScenario getScenarioByName(String name) |
Returns the scenario in this test where the SyntheticScenario.name is equal to the provided name. If no scenario has the provided name, null is returned. |
SyntheticScenario getScenarioBySeqNum(Number seqNum) |
Returns the scenario in this test where the SyntheticScenario.seqNum is equal to the provided value. If no scenario has the provided sequence number, null is returned. |
A SyntheticTestResults object reports the results of a completed user test execution by the Experience Manager Monitor test engine. All properties are read-only. SyntheticTestResults objects are reported to the testEngine.onTestComplete event handler to support Synthetic Test Management functionality.
The following example shows how to use the SyntheticTestResults object and related objects and services to implement conditional execution of a test. The example is purposely simplified to show the core functionality without getting bogged down in details of configuration management.
/* * Conditional execution: execute test identified in 'conditionalTestName' once if * a triggerScenario in 'mainTestName' produces a Critical alarm */ var mainTestName='test1'; var triggerScenarios='[1][5]'; var conditionalTestName='test2'; testEngine.onTestComplete=handleTestComplete; testEngine.onScenarioComplete=handleScenarioComplete; function handleTestComplete(testResults) { if(testResults.test.name == conditionalTestName) { // stop conditional test once it runs once testEngine.deactivateTest(conditionalTestName); } } function handleScenarioComplete(alarm) { // if this is the alarm is from the right test and its critical if(alarm.testName == mainTestName && alarm.severity == testEngine.constants.SEV_CRITICAL) { // and its one of the trigger scenarios if(triggerScenarios.indexOf('['+alarm.scenarioSeqNum + ']') >=0) { // and we did not already start the conditional test if(!testEngine.getDeployment().getTest(conditionalTestName).enabled) { // then start the conditional test testEngine.activateTest(conditionalTestName); } } } }
Property Name |
Value Type |
Description |
---|---|---|
test |
SyntheticTest |
(Read-only) The test reporting these results. |
String toString() |
Returns a string representation of this object. |
SyntheticAlarm[] getAlarms() |
Returns an ordered array of all alarms generated during the latest test execution. |
Number getFailCount() |
Returns the number of alarms where SyntheticAlarm.isFailed() is True. |
SyntheticAlarm[] getAlarmsBySeverity(Object severity |
Returns an array containing any alarms with the specified severity. Valid severity values are listed in testEngine.constants severities. |