Skip to content

alexey-lapin/micrometer-prpc

Repository files navigation

micrometer-prpc

Latest release Build Status codecov

Pega PRPC + Micrometer = ❤️

Expose your business and technical metrics from Pega to any monitoring system.

This small library aims to simplify usage of Micrometer for collecting metrics in Pega PRPC environment. Developers can use familiar concept of 'rules' to implement metric value sources.

dashboard

PRPC version tested
7.3.0 ✔️
8.2.1 ✔️

Java 8+ required.

Build

Prerequisites

In order to build the project locally, you have to satisfy dependency prerequisites.

This project does not include any dependencies or any proprietary code. It is intended to be used by authorized Pegasystems Inc clients in their Pega PRPC environments.

This library relies on some internal PRPC jars which usually could be found in <pega-distributive>.zip/archives/pegadbinstall-classes.zip/lib:

  • prbootstrap
  • prbootstrap-api
  • prenginext
  • pricu2jdk
  • prprivate
  • prpublic

The following command will help to install the required jars to a local maven repository:

./mvnw install:install-file -Dfile=<path-to-prpc-libs>/<lib>.jar -DgroupId=com.pega.prpc -DartifactId=<lib> -Dversion=<version.prpc> -Dpackaging=jar -Dversion.prpc=<version.prpc>

Package

After the required jars are installed you may use the following command to build project:

./mvnw package -Dversion.prpc=<version.prpc>

Install

Deploy the following jars to the PRPC instance as usual (from UI or service):

  • micrometer-core-<version.micrometer>.jar
  • micrometer-registry-<registry>-<version.micrometer>.jar - one or multiple registry libs and its dependencies
  • micrometer-prpc-<version>.jar

Use

Create sources:

// Sql source
PrpcSource source = SqlSource.builder()
        .queryString("select FirstProperty as \"Tag(first)\", " +
                            "SecondProperty as \"Tag(second)\", " +
                            "ThirdProperty as \"Value(count)\" " +
                            "from {CLASS:Some-Data-Class}")
        .groupPropName("pxPages")
        .expirationDuration(2)
        .expirationTimeUnit(TimeUnit.MINUTES)
        .build();

// Data Page source
PrpcSource source = DataPageSource.builder()
        .ruleName("D_SomeDataPage")
        .accessGroupName("Some:AccessGroup")
        .resultsPropName("pxResults")
        .groupPropName("pxPages")
        .expirationDuration(5)
        .expirationTimeUnit(TimeUnit.MINUTES)
        .build();

// Activity source
PrpcSource source = ActivitySource.builder()
        .ruleName("SomeActivity")
        .ruleClass("Some-Class")
        .accessGroupName("Some:AccessGroup")
        .resultsPropName("pxResults")
        .groupPropName("pxPages")
        .expirationDuration(10)
        .expirationTimeUnit(TimeUnit.MINUTES)
        .build();

A source should construct the following clipboard structure:

TopLevelPage [Page]
    pxResults(1) [Page List]
        Tag(tag_name_1) tagValue1 [Value Group]
        Tag(tag_name_2) tagValue2
        Value(count_1) 10         [Value Group]
        Value(count_2) 15
    pxResults(2)
        Tag(tag_name_1) tagValue3
        Tag(tag_name_2) tagValue4
        Value(count_1) 7
        Value(count_2) 13
    ...

Register metrics:

// Create registry
MeterRegistry registry = ...

// Gauge - register single metric
registry.gauge("metric.gauge.single", source, PrpcCallback.strong(source, "PropertyReference"));

// MultiGauge - register multiple metrics with unique tags
PrpcMultiGauge mg = PrpcMultiGauge.builder("metric.gauge.multi")
                .registry(registry)
                .source(source)
                .valuePropName("PropertyReference")
                .build();

// Counter
registry.more().counter("metric.counter.single", Tags.empty(), source, PrpcCallback.strong(source, "PropertyReference"));

For more information about micrometer features visit micrometer docs page.

  1. Deploy libs:
  1. Implement startup agent:
// Initialize registry and store it
MeterRegistry registry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
Metrics.getInstance().registries().put("prometheus", registry);

// Create source from out-of-the-box data page - D_pzNodeInformation
PrpcSource source = DataPageSource.builder()
        .ruleName("D_pzNodeInformation")
        .expirationDuration(2)
        .expirationTimeUnit(TimeUnit.MINUTES)
        .build();

// Register meters which have constant tags cardinality during app lifetime
registry.gauge("prpc.node.requestors", source, PrpcCallback.strong(source, "pxNumberRequestors"));
registry.gauge("prpc.node.agents", source, PrpcCallback.strong(source, "pxNumberAgents"));
registry.gauge("prpc.node.listeners", source, PrpcCallback.strong(source, "pxNumberListeners"));

registry.more().counter("prpc.node.requestors.initiated", Tags.of("type", "browser"), source, PrpcCallback.strong(source, "pxNumberBrowserInitiatedRequestorStarts"));
registry.more().counter("prpc.node.requestors.initiated", Tags.of("type", "batch"), source, PrpcCallback.strong(source, "pxNumberBatchInitiatedRequestorStarts"));
registry.more().counter("prpc.node.requestors.initiated", Tags.of("type", "service"), source, PrpcCallback.strong(source, "pxNumberServiceInitiatedRequestorStarts"));
registry.more().counter("prpc.node.requestors.initiated", Tags.of("type", "portlet"), source, PrpcCallback.strong(source, "pxNumberPortletInitiatedRequestorStarts"));

// Create custom activity source
PrpcSource source = ActivitySource.builder()
                .ruleName("MetricRequestorPools")
                .ruleClass("Code-Pega-List")
                .accessGroupName("Metrics")
                .resultsPropName("pxResults")
                .groupPropName("pxPages")
                .expirationDuration(2)
                .expirationTimeUnit(TimeUnit.Minutes)
                .build();

// Register meters which have various tags cardinality during app lifetime
PrpcMultiGauge mg = PrpcMultiGauge.builder("prpc.requestor.pools.active")
                .registry(registry)
                .source(source)
                .valuePropName("Value(active)")
                .build();

// Store to cache
Metrics.getInstance().meters().add(mg);

mg.register();
  1. Implement recurring agent (eg. every 10 minutes)
// Get stored multi meters and re-register
Metrics.getInstance().meters().register();
  1. Implement rest service:
// Obtain registry and get textual representation of metrics
PrometheusMeterRegistry registry = (PrometheusMeterRegistry) Metrics.getInstance().registries().get("prometheus");
if (registry != null) {
    response = registry.scrape();
}

The following setup results to a response which looks like:

# HELP prpc_node_listeners  
# TYPE prpc_node_listeners gauge
prpc_node_listeners 0.0
# HELP prpc_node_agents  
# TYPE prpc_node_agents gauge
prpc_node_agents 56.0
# HELP prpc_node_active_threads  
# TYPE prpc_node_active_threads gauge
prpc_node_active_threads 30.0
# HELP prpc_node_requestors_initiated_total  
# TYPE prpc_node_requestors_initiated_total counter
prpc_node_requestors_initiated_total{type="service",} 4.0
prpc_node_requestors_initiated_total{type="browser",} 1.0
prpc_node_requestors_initiated_total{type="portlet",} 0.0
prpc_node_requestors_initiated_total{type="batch",} 576.0
# HELP prpc_node_requestors  
# TYPE prpc_node_requestors gauge
prpc_node_requestors 14.0
# HELP prpc_node_production_level  
# TYPE prpc_node_production_level gauge
prpc_node_production_level 2.0
  1. Configure Prometheus to scrape created rest service URL.
  2. Configure Prometheus data source in Grafana.
  3. Create dashboard in Grafana which could look like image above.