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.
PRPC version | tested |
---|---|
7.3.0 | ✔️ |
8.2.1 | ✔️ |
Java 8+ required.
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>
After the required jars are installed you may use the following command to build project:
./mvnw package -Dversion.prpc=<version.prpc>
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
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.
Prometheus + Grafana example
- Deploy libs:
- micrometer-prpc.jar
- micrometer-core.jar
- micrometer-registry-prometheus.jar
- simpleclient_common.jar
- simpleclient.jar
- 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();
- Implement recurring agent (eg. every 10 minutes)
// Get stored multi meters and re-register
Metrics.getInstance().meters().register();
- 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
- Configure Prometheus to scrape created rest service URL.
- Configure Prometheus data source in Grafana.
- Create dashboard in Grafana which could look like image above.