48/68

# 36 How to Create a Custom Report

The Coherence reporting feature provides a capable query definition that allows for any information residing in the Coherence JMX data source to be logged to a text file. After a custom report has been created, it can be included in a report batch and executed on a specified time interval by the `ReportControl` MBean. For a complete description of the report configuration XML file see the `report-config.dtd` which is packaged in the `coherence.jar` file.

## Configuring a Report File

To correctly generate the report file, several elements must be configured. These elements are described in Table 36-1.

Table 36-1 Elements to Configure an Output File

Element | Optional/Requited | Description
--- | --- | ---
<file-name> | Required | The file name to create or update when the report is executed. For more information, see "file-name Element".
<delim> | Optional | The column delimiter for the report. Valid values are `{tab}`, `{space}` or a printable character. The default value is `{tab}`. If a string longer than one character is entered, the first character in the string is used.
<hide-headers> | Optional | A boolean element to determine if the headers are to be included in the report. If `true`, the column headers and the report description are not included in the file. The default value is `false`.

### file-name Element

The value of this element will have the output path from the `<report-path>` element pre-pended to it and the report will be generated in this location. If the Coherence node cannot access this path, then the file will not be created.

#### file-name Macros

There are pre-defined macros that you can use with the file-name element. These macros can add a node name, a batch number, or a date to the generated file name.

Table 36-2 Macros that can be Used with the file-name Element

Macro | Description
--- | ---
batch | Will include a batch Identifier into the filename of the report. If the information is kept for a short amount of time or is frequently uploaded into and RDBMS.
date | Will include the date (with the format `YYYYMMDD`), into the file name of the report. This is used mostly when the data will only be kept for a certain period and then will be discarded.
node | Will include the node ID into the file name string. This configuration setting is helpful when many nodes are executing the same report and the output files will be integrated for the analysis.

#### file-name Macro Examples

The following example will create a file `20090101_network_status.txt` on January 1, 2009. The filename will change with the system time on the node executing the report.

    <file-name>{{date}}_network_status.txt</file-name>

The following example will create a file `00012_network_status.txt` when the report is executed on node 12. Note that due to the volatile nature of the Node Id, long term storage in this manner is not recommended.

    <file-name>{node}_network_status.txt</file-name>

The following example will create a file `0000000021_network_status.txt` on the 21st execution of the report. Note that due to the volatile nature of the batch, long term storage in this manner is not recommended.

    <file-name>{batch}_network_status.txt</file-name>

## Specifying Data Columns

Data columns can be sourced from JMX Attributes, `ObjectName` key part, JMX composite attributes, JMX joined attributes, Report macros, and Report Constants.

### How to Include an Attribute

To include data from MBeans returned from the query-pattern, the report must have a column with an attribute source. This is the most common item that will be included in the report.

Example 36-1 illustrates how to include the `RoleName` attribute from the query pattern `Coherence:type=Node,*`.

Example 36-1 Including an Attribute Obtained from a Query Pattern

    <column id = "RoleName">
      <type>attribute</type>
      <name>RoleName</name>
      <header>Role Name</header>
    </column>

### How to Include Part of the Key

A value that is present in an `ObjectName` key can be obtained from the `ObjectNames` returned from the query-pattern. This value can subsequently be included in the report.

Example 36-2 illustrates how to include the `nodeId` key part from the query pattern `Coherence:type=Node,*`.

Example 36-2 Including Part of an ObjectName Key in a Report

    <column id ="NodeId">
      <type>key</type>
      <name>nodeId</name>
      <header>Node Id</header>
    </column>

### How to Include Information from Composite Attributes

JMX composite values can be used to include part of a composite data attribute in a report.

Example 36-9 illustrates how to include the `startTime` of the `LastGCInfo` attribute from the query pattern `java.lang:type=GarbageCollector,*`.

Example 36-3 Including Information from a Composite Attribute in a Report

    <column id="LastGCStart">
       <type>attribute</type>
       <name>LastGcInfo/startTime</name>
       <header>Last GC Start Time</header>
    </column>

### How to Include Information from Multiple MBeans

A JMX join attribute is required when a report requires information from multiple MBeans. The major considerations when creating a join is to determine both the primary query, the join query and the foreign key. The primary query should be the query that returns the appropriate number of rows for the report. The join query pattern must reference a single MBean and can not contain a wild card (`*`). The foreign key is determined by what attributes from the primary query that are required to complete the join query string.

The reporter feature that enables joins between MBeans is a column substitution macro. The column substitution allows for the resulting value from a column to be included as part of a string. A column substitution macro is a column ID attribute surrounded by curly braces "`{}`". The reporter does not check for cyclical references and will fail during execution if a cycle is configured.

### Including Multiple MBean Information Example

You can draw information from more than one MBean and include it in a report. This requires a `join` between the MBeans.

Note:

The major limitation of `join` attributes is that the result of the join must have only one value.

For example, if a report requires the `TotalGets` from the `Cache` MBean (`Coherence:type=cache,*`) and `RoleName` from the `Node` MBean (`Coherence:type=Node,*`), then a `join` attribute must be used.

Since a greater number of MBeans will come from the `Cache` MBean, `Coherence:type=Cache,*` would be the primary query and the `RoleName` would be the `join` attribute. The foreign key for this join is the `nodeId` key part from the `Cache` MBean and it must be included in the report. The configuration for this scenario is illustrated in Example 36-4.

Example 36-4 Including Information from Multiple MBeans in a Report

    <column id="RoleName">
       <type>attribute</type>
       <name>RoleName</name>
       <header>Role Name</header>
        <query>
           <pattern>Coherence:type=Node,nodeId={NodeFK}</pattern>
        </query>
    </column>

    <column id ="NodeFK">
      <type>key</type>
      <name>nodeId</name>
      <header>Node Id</header>
    </column>

### How to Use Report Macros

There are three report macros that can be included in a report:

- Report Time (`report-time`)—is the time and date that the report was executed. This information is useful for time series analysis.

- Report Batch/Count (`report-count`)—is a long identifier that can be used to correlate information from different reports executed at the same time.

- Reporting Node (`report-node`)—is used when integrating information from the same report executed on different nodes or excluding the executing node information from the report.

To include the execution time into the report:

Example 36-5 Including Execution Time in a Report

    <column id ="ReportTime">
       <type>global</type>
       <name>{report-time}</name>
       <header>Report Time</header>
    </column>

To include the Report Batch/Count:

Example 36-6 Including the Report Batch/Count in a Report

    <column id="ReportBatch">
      <type>global</type>
      <name>{report-count}</name>
      <header>batch</header>
    </column>

To include the execution node:

Example 36-7 Including the Execution Node

    <column id="ReportNode">
      <type>global</type>
      <name>{report-node}</name>
      <header>ExecNode</header>
      <hidden>true</hidden>
    </column>

### How to Include Constant Values

Report constants can be used to either static values or report parameters. These constants can be either double or string values. Often, these are used in filters to limit the results to a particular data set or in calculations.

Example 36-8 illustrates how to include a constant double of 1.0 in a report:

Example 36-8 Including a Constant Numeric Value in a Report

    <column id ="One">
      <type>constant</type>
      <header>Constant1</header>
      <data-type>double</data-type>
      <value>1.0</value>
      <hidden>true</hidden>
    </column>

Example 36-9 illustrates how to include the constant string `dist-Employee` in a report:

Example 36-9 Including a Constant String in a Report

    <column id ="EmployeeCacheName">
      <type>constant</type>
      <header>Employee Cache Name</header>
      <data-type>string</data-type>
      <value>dist-Employee</value>
      <hidden>true</hidden>
    </column>

## Including Queries in a Report

The query is the foundation of the information included in a report. Each query includes a query pattern, column references, and an optional filter reference. The query pattern is a string that is a JMX `ObjectName` query string. This string can return one or more MBeans. The column references must be defined in the `<columns>` section of the report definition file. The filter reference must be defined in the `<filters>` section of the report section.

Example 36-10 illustrates how to include the list all the Node IDs and `RoleNames` in the cluster where the `RoleName` equals `CoherenceServer`.

Example 36-10 Including a List of the Cluster's NodeIDs and RoleNames in a Report

    <filters>
       <filter id="equalsRef">
         <type>equals</type>
         <params>
            <column-ref>RoleRef</column-ref>
            <column-ref>StringRef</column-ref>
         </params>
       </filter>
    </filters>

    <query>
       <pattern>Coherence:type=Node,*</pattern>
       <filter-ref>equalsRef</filter-ref>
    </query>

    <row>
      <column id ="NodeRef">
        <type>key</type>
        <name>nodeId</name>
        <header>Node Id</header>
      </column>

      <column id ="RoleRef">
        <name>RoleName</name>
        <header>Role</header>
      </column>

      <column id = "StringRef">
        <type>constant</type>
        <name>ConstString</name>
        <data-type>string</data-type>
        <value>CoherenceServer</value>
        <hidden>true</hidden>
      </column>

    </row>

## Using Filters to Construct Reports

Filters limit the data returned in the Report. Filters are either comparison filters or composite filters. Comparison Filters evaluate the results of two columns while composite filters evaluate the boolean results from one or two filters. Comparison filters are `equals`, `greater`, and `less`.

Composite Filter types are `and`, `or`, and `not`. Each composite filter evaluates the filter parameters first to last and apply standard boolean logic. Composite filter evaluation uses standard short circuit logic. Cyclic references checks are not performed during execution. If a cyclic reference occurs, it will create a runtime error.

Example 36-11 illustrates how to define an `equals` filter where `RoleRef` and `StringRef` are defined columns.

Example 36-11 Using an Equals Filter for a Report

    <filters>
       <filter id="equals">
         <type>equals</type>
         <params>
            <column-ref>RoleRef</column-ref>
            <column-ref>StringRef</column-ref>
         </params>
       </filter>
    </filters>

Example 36-12 illustrates how to define a filter where the number of `PacketsResent` are greater than `PacketsSent` (assuming `PacketsResent` and `PacketsSent` are valid column references).

Example 36-12 Defining a "Greater Than" Filter for a Report

    <filters>
       <filter id="greaterRef">
         <type>greater</type>
         <params>
            <column-ref>PacketsResent</column-ref>
            <column-ref>PacketsSent</column-ref>
         </params>
       </filter>
    </filters>

Example 36-13 illustrates how to define an filter where the number of `PacketsResent` are less than `PacketsSent` (assuming `PacketsResent` and `PacketsSent` are valid column references).

Example 36-13 Defining a "Less Than" Filter for a Report

    <filters>
       <filter id="greaterRef">
         <type>less</type>
         <params>
            <column-ref>PacketsResent</column-ref>
            <column-ref>PacketsSent</column-ref>
         </params>
       </filter>
    </filters>

Example 36-14 illustrates how to define an `and` filter (assuming all `column-ref` values are valid).

Example 36-14 Defining an "And" Filter for a Report

    <filters>
       <filter id="equalsRef">
         <type>equals</type>
         <params>
            <column-ref>RoleRef</column-ref>
            <column-ref>StringRef</column-ref>
         </params>
       </filter>

       <filter id="greaterRef">
         <type>greater</type>
         <params>
            <column-ref>PacketsResent</column-ref>
            <column-ref>PacketsSent</column-ref>
         </params>
       </filter>

       <filter>
         <type>and</type>
         <params>
            <filter-ref>greaterRef</filter-ref>
            <filter-ref>equalsRef</filter-ref>
         <params>
       </filter>
    </filters>

Example 36-15 illustrates how to define an `or` filter (assuming all `column-ref` values are valid).

Example 36-15 Defining an "Or" Filter for a Report

    <filters>
       <filter id="equalsRef">
         <type>equals</type>
         <params>
            <column-ref>RoleRef</column-ref>
            <column-ref>StringRef</column-ref>
         </params>
       </filter>

       <filter id="greaterRef">
         <type>greater</type>
         <params>
            <column-ref>PacketsResent</column-ref>
            <column-ref>PacketsSent</column-ref>
         </params>
       </filter>

       <filter>
         <type>or</type>
         <params>
            <filter-ref>greaterRef</filter-ref>
            <filter-ref>equalsRef</filter-ref>
         <params>
       </filter>
    </filters>

Example 36-16 illustrates how to define a `not` `equals` filter, where `RoleRef` and `StringRef` are defined columns.

Example 36-16 Defining a "Not Equals" Filter for a Report

    <filters>
       <filter id="equals">
         <type>equals</type>
         <params>
            <column-ref>RoleRef</column-ref>
            <column-ref>StringRef</column-ref>
         </params>
       </filter>

       <filter id = "Not">
         <type>not</type>
         <params>
            <filter-ref>equals</filter-ref>
         </params>
       </filter>
    </filters>

## Using Functions to Construct a Report

Reporter functions allow mathematical calculations to be performed on data elements within the same row of the report. The supported functions are `Add`, `Subtract`, `Multiply`, and `Divide`. Function columns can then be included as parameters into other function columns.

### Function Examples

Example 36-17 illustrates how to add columns (`Attribute1` and `Attribute2`) and place the results into a third column (`Addition`).

Example 36-17 Adding Column Values and Including Results in a Different Column

    <column id="AttributeID1">
      <name>Attribute1</name>
    </column>

    <column id="AttributeID2">
      <name>Attribute2</name>
    </column>

    <column id="Addition">
      <type>function</type>
      <name>Add2Columns</name>
      <header>Adding Columns</header>
      <function-name>add</function-name>
      <params>
        <column-ref>AttributeID1</column-ref>
        <column-ref>AttributeID2</column-ref>
      </params>
    </column>

Example 36-18 illustrates how to subtract one column value (`Attribute2`) from another (`Attribute1`) and place the results into a third column (`Subtraction`).

Example 36-18 Subtracting Column Values and Including Results in a Different Column

    <column id="AttributeID1">
      <name>Attribute1</name>
    </column>

    <column id="AttributeID2">
      <name>Attribute2</name>
    </column>

    <column id="Subtraction">
      <type>function</type>
      <name>Subtract2Columns</name>
      <header>Difference</header>
      <function-name>subtract</function-name>
      <params>

        <column-ref>AttributeID1</column-ref>
        <column-ref>AttributeID2</column-ref>
      </params>
    </column>

Example 36-19 illustrates how to multiply column values (`Attribute1` and `Attribute2`) place the results into a third column (`Multiplication`).

Example 36-19 Multiplying Column Values and Including Results in a Different Column

    <column id="AttributeID1">
      <name>Attribute1</name>
    </column>

    <column id="AttributeID2">
      <name>Attribute2</name>
    </column>

    <column id="Multiplication">
      <type>function</type>
      <name>Multiply2Columns</name>
      <header>Multiply Columns</header>
      <function-name>multiply</function-name>
      <params>
        <column-ref>AttributeID1</column-ref>
        <column-ref>AttributeID2</column-ref>
      </params>
    </column>

Example 36-20 illustrates how to divide one column (`Attribute1`) by another (`Attribute2`) into a third column (`Division`). The result of all division is a Double data type.

Example 36-20 Dividing Column Values and Including Results in a Different Column

    <column id="AttributeID1">
      <name>Attribute1</name>
    </column>

    <column id="AttributeID2">
      <name>Attribute2</name>
    </column>

    <column id="Division">
      <type>function</type>
      <name>Dividing2Columns</name>
      <header>Division</header>
      <function-name>Divide</function-name>
      <params>
        <column-ref>AttributeID1</column-ref>
        <column-ref>AttributeID2</column-ref>
      </params>
    </column>

## Using Aggregates to Construct a Report

Reporter aggregates allow for multiple rows to be aggregated into a single value or row. Table 36-3 describes the available aggregate types.

Table 36-3 Reporter Aggregate Types

Type | Description
--- | ---
avg | Calculate the mean value for all values in the column.
max | Return the maximum value for all values in the column.
min | Return the minimum value for all values in the column.
sum | Add all the values from a column.

### Aggregate Examples

Sum the values in the `size` column

Example 36-21 Adding the Values in a Column

    <column id ="SumRef">
       <type>function</type>
       <function-name>sum</function-name>
       <column-ref>size</column-ref>>
       <header>Sum</header>
    </column>

Average the values in the `size` column

Example 36-22 Calculating the Average of Values in a Column

    <column id ="AverageRef">
       <type>function</type>
       <header>Average</header>
       <function-name>avg</function-name>
       <column-ref>size</column-ref>>
    </column>

Find the maximum the value in the `size` column

Example 36-23 Finding the Maximum Value in a Column

    <column id ="MaximumRef">
       <type>function</type>
       <header>Maximum</header>
       <function-name>max</function-name>
       <column-ref>size</column-ref>>
    </column>

Find the minimum the value in the `size` column

Example 36-24 Finding the Minimum Value in a Column

    <column id ="MinimumRef">
       <type>function</type>
       <header>Minimum</header>
       <function-name>min</function-name>
       <column-ref>size</column-ref>>
    </column>

## Constructing Delta Functions

Many numeric attributes in the Coherence report are cumulative. These values are reset only when the `resetStatistics` operation is executed on the MBean. To determine the state of the system without resetting the statistics, the Reporter uses a delta function. The delta function subtracts the prior value of a column from the current value of a column and returns the difference.

The prior values for a report are stored in a map on the Reporter client. This map is keyed by the "delta key". By default, the delta key is the MBean name for the attribute. However, when one-to-one relationship does not exist between the MBean and the rows in the report, or the MBean name is subject to change between executions of the report, the delta key will be calculated using the columns provided in the `<params>` section.

Note:

Accuracy of Delta Functions: delta functions are only correct when the report is running as part of a report batch.

### Delta Function Examples

Example 36-25 illustrates how to include a delta calculation of an attribute. (Assume `PacketsSent` is a defined column)

Example 36-25 Delta Calculation for an Attribute

    <column id="DeltaPacketsSent">
      <type>function</type>
      <name>PacketsSent</name>
      <header>Delta Sent</header>
      <function-name>delta</function-name>
      <column-ref>PacketsSent</column-ref>
    </column>

Example 36-26 illustrates how to include a delta calculation of an attribute with an alternate `delta` key. (Assume `PacketsSent`, `NodeID` and `TimeStamp` are defined columns)

Example 36-26 Delta Calculation for an Attribute with an Alternate Delta Key

    <column id="DeltaPacketsSent">
      <type>function</type>
      <name>PacketsSent</name>
      <header>Delta Sent</header>
      <function-name>delta</function-name>
      <column-ref>PacketsSent</column-ref>
      <params>
         <column-ref>NodeID</column-ref>
         <column-ref>TimeStamp</column-ref>
      </params>
    </column>