Skip to content

Commit

Permalink
[DROOLS-6894] Metrics of rule execution should include rules fired fr…
Browse files Browse the repository at this point in the history
…om bpmn process (#2761) (#2803)
  • Loading branch information
tkobayas authored Jul 25, 2022
1 parent 0fb567a commit 78ac7bd
Show file tree
Hide file tree
Showing 5 changed files with 273 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright 2022 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.kie.server.services.prometheus;

import org.drools.core.event.rule.impl.AfterActivationFiredEventImpl;
import org.drools.core.event.rule.impl.BeforeActivationFiredEventImpl;
import org.kie.api.builder.ReleaseId;
import org.kie.api.event.rule.AfterMatchFiredEvent;
import org.kie.api.event.rule.AgendaEventListener;
import org.kie.api.event.rule.AgendaGroupPoppedEvent;
import org.kie.api.event.rule.AgendaGroupPushedEvent;
import org.kie.api.event.rule.BeforeMatchFiredEvent;
import org.kie.api.event.rule.MatchCancelledEvent;
import org.kie.api.event.rule.MatchCreatedEvent;
import org.kie.api.event.rule.RuleFlowGroupActivatedEvent;
import org.kie.api.event.rule.RuleFlowGroupDeactivatedEvent;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.manager.RuntimeManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PrometheusMetricsRuleTaskListener implements AgendaEventListener {

private static final Logger logger = LoggerFactory.getLogger(PrometheusMetricsRuleTaskListener.class);
private final PrometheusMetrics metrics;
private final RuntimeManager runtimeManager;
private final KieContainer kieContainer;

private static final String KIE_SESSION_ID_DEFAULT = "default"; // default ksession is used in process use cases

public PrometheusMetricsRuleTaskListener(RuntimeManager runtimeManager, KieContainer kieContainer) {
this.metrics = PrometheusKieServerExtension.getMetrics();
this.runtimeManager = runtimeManager;
this.kieContainer = kieContainer;
}

@Override
public void matchCreated(MatchCreatedEvent event) {
// Do nothing
}

@Override
public void matchCancelled(MatchCancelledEvent event) {
// Do nothing
}

@Override
public void beforeMatchFired(BeforeMatchFiredEvent event) {
long nanoTime = System.nanoTime();
BeforeActivationFiredEventImpl impl = getBeforeImpl(event);
impl.setTimestamp(nanoTime);
}

@Override
public void afterMatchFired(AfterMatchFiredEvent event) {
AfterActivationFiredEventImpl afterImpl = getAfterImpl(event);
BeforeActivationFiredEventImpl beforeImpl = getBeforeImpl(afterImpl.getBeforeMatchFiredEvent());
long startTime = beforeImpl.getTimestamp();
long elapsed = System.nanoTime() - startTime;
String ruleName = event.getMatch().getRule().getName();
ReleaseId releaseId = kieContainer.getReleaseId();
String containerId = runtimeManager.getIdentifier();
metrics.getDroolsEvaluationTimeHistogram()
.labels(containerId, KIE_SESSION_ID_DEFAULT, releaseId.getGroupId(), releaseId.getArtifactId(), releaseId.getVersion(), ruleName)
.observe(elapsed);
if (logger.isDebugEnabled()) {
logger.debug("Elapsed time: {}", elapsed);
}
}

@Override
public void agendaGroupPopped(AgendaGroupPoppedEvent event) {
// Do nothing
}

@Override
public void agendaGroupPushed(AgendaGroupPushedEvent event) {
// Do nothing
}

@Override
public void beforeRuleFlowGroupActivated(RuleFlowGroupActivatedEvent event) {
// Do nothing
}

@Override
public void afterRuleFlowGroupActivated(RuleFlowGroupActivatedEvent event) {
// Do nothing
}

@Override
public void beforeRuleFlowGroupDeactivated(RuleFlowGroupDeactivatedEvent event) {
// Do nothing
}

@Override
public void afterRuleFlowGroupDeactivated(RuleFlowGroupDeactivatedEvent event) {
// Do nothing
}

public BeforeActivationFiredEventImpl getBeforeImpl(BeforeMatchFiredEvent e) {
return (BeforeActivationFiredEventImpl)e;
}

public AfterActivationFiredEventImpl getAfterImpl(AfterMatchFiredEvent e) {
return (AfterActivationFiredEventImpl)e;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
<resolver>mvel</resolver>
<identifier>new org.kie.server.services.prometheus.PrometheusCaseEventListener()</identifier>
</event-listener>
<event-listener>
<resolver>mvel</resolver>
<identifier>new org.kie.server.services.prometheus.PrometheusMetricsRuleTaskListener(runtimeManager, kieContainer)</identifier>
</event-listener>
</event-listeners>
<task-event-listeners>
<task-event-listener>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.jbpm;

import org.jbpm.data.Person;

rule "is John"
ruleflow-group "group1"
when
$p : Person(name == "John")
then
System.out.println("Hello, " + $p.getName());
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:bpsim="http://www.bpsim.org/schemas/1.0" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:drools="http://www.jboss.org/drools" xmlns:xsi="xsi" id="_G4JzoZtuEDqs99yHqAh9rw" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd http://www.jboss.org/drools drools.xsd http://www.bpsim.org/schemas/1.0 bpsim.xsd http://www.omg.org/spec/DD/20100524/DC DC.xsd http://www.omg.org/spec/DD/20100524/DI DI.xsd " exporter="jBPM Process Modeler" exporterVersion="2.0" targetNamespace="http://www.omg.org/bpmn20">
<bpmn2:itemDefinition id="_personItem" structureRef="org.jbpm.data.Person"/>
<bpmn2:itemDefinition id="__3BCB2ADB-7158-43EF-8769-989C01A7E54A_namespaceInputXItem" structureRef="java.lang.String"/>
<bpmn2:itemDefinition id="__3BCB2ADB-7158-43EF-8769-989C01A7E54A_modelInputXItem" structureRef="java.lang.String"/>
<bpmn2:itemDefinition id="__3BCB2ADB-7158-43EF-8769-989C01A7E54A_decisionInputXItem" structureRef="java.lang.String"/>
<bpmn2:itemDefinition id="__3BCB2ADB-7158-43EF-8769-989C01A7E54A_personInputXItem" structureRef="org.jbpm.data.Person"/>
<bpmn2:itemDefinition id="__3BCB2ADB-7158-43EF-8769-989C01A7E54A_personOutputXItem" structureRef="org.jbpm.data.Person"/>
<bpmn2:process id="ruletask" drools:packageName="org.jbpm" drools:version="1.0" drools:adHoc="false" name="ruletask" isExecutable="true" processType="Public">
<bpmn2:property id="person" itemSubjectRef="_personItem" name="person"/>
<bpmn2:sequenceFlow id="_DC92975C-AA0F-45A5-90D9-773FD00CEBF0" sourceRef="_3BCB2ADB-7158-43EF-8769-989C01A7E54A" targetRef="_97A1CDE0-F832-48DA-9C3A-4B2B8032BC7A"/>
<bpmn2:sequenceFlow id="_6BF2BC53-4935-48F8-B4D0-81ADD3AB2A94" sourceRef="_2F4301DA-E098-41C4-A75D-3DB1E94144A7" targetRef="_3BCB2ADB-7158-43EF-8769-989C01A7E54A"/>
<bpmn2:endEvent id="_97A1CDE0-F832-48DA-9C3A-4B2B8032BC7A">
<bpmn2:incoming>_DC92975C-AA0F-45A5-90D9-773FD00CEBF0</bpmn2:incoming>
</bpmn2:endEvent>
<bpmn2:businessRuleTask id="_3BCB2ADB-7158-43EF-8769-989C01A7E54A" drools:ruleFlowGroup="group1" name="RuleTask" implementation="http://www.jboss.org/drools/rule">
<bpmn2:extensionElements>
<drools:metaData name="elementname">
<drools:metaValue><![CDATA[RuleTask]]></drools:metaValue>
</drools:metaData>
</bpmn2:extensionElements>
<bpmn2:incoming>_6BF2BC53-4935-48F8-B4D0-81ADD3AB2A94</bpmn2:incoming>
<bpmn2:outgoing>_DC92975C-AA0F-45A5-90D9-773FD00CEBF0</bpmn2:outgoing>
<bpmn2:ioSpecification>
<bpmn2:dataInput id="_3BCB2ADB-7158-43EF-8769-989C01A7E54A_personInputX" drools:dtype="org.jbpm.data.Person" itemSubjectRef="__3BCB2ADB-7158-43EF-8769-989C01A7E54A_personInputXItem" name="person"/>
<bpmn2:dataOutput id="_3BCB2ADB-7158-43EF-8769-989C01A7E54A_personOutputX" drools:dtype="org.jbpm.data.Person" itemSubjectRef="__3BCB2ADB-7158-43EF-8769-989C01A7E54A_personOutputXItem" name="person"/>
<bpmn2:inputSet>
<bpmn2:dataInputRefs>_3BCB2ADB-7158-43EF-8769-989C01A7E54A_personInputX</bpmn2:dataInputRefs>
</bpmn2:inputSet>
<bpmn2:outputSet>
<bpmn2:dataOutputRefs>_3BCB2ADB-7158-43EF-8769-989C01A7E54A_personOutputX</bpmn2:dataOutputRefs>
</bpmn2:outputSet>
</bpmn2:ioSpecification>
<bpmn2:dataInputAssociation>
<bpmn2:sourceRef>person</bpmn2:sourceRef>
<bpmn2:targetRef>_3BCB2ADB-7158-43EF-8769-989C01A7E54A_personInputX</bpmn2:targetRef>
</bpmn2:dataInputAssociation>
<bpmn2:dataOutputAssociation>
<bpmn2:sourceRef>_3BCB2ADB-7158-43EF-8769-989C01A7E54A_personOutputX</bpmn2:sourceRef>
<bpmn2:targetRef>person</bpmn2:targetRef>
</bpmn2:dataOutputAssociation>
</bpmn2:businessRuleTask>
<bpmn2:startEvent id="_2F4301DA-E098-41C4-A75D-3DB1E94144A7">
<bpmn2:outgoing>_6BF2BC53-4935-48F8-B4D0-81ADD3AB2A94</bpmn2:outgoing>
</bpmn2:startEvent>
</bpmn2:process>
<bpmndi:BPMNDiagram>
<bpmndi:BPMNPlane bpmnElement="ruletask">
<bpmndi:BPMNShape id="shape__2F4301DA-E098-41C4-A75D-3DB1E94144A7" bpmnElement="_2F4301DA-E098-41C4-A75D-3DB1E94144A7">
<dc:Bounds height="56" width="56" x="164" y="204"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape__3BCB2ADB-7158-43EF-8769-989C01A7E54A" bpmnElement="_3BCB2ADB-7158-43EF-8769-989C01A7E54A">
<dc:Bounds height="102" width="154" x="300" y="181"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape__97A1CDE0-F832-48DA-9C3A-4B2B8032BC7A" bpmnElement="_97A1CDE0-F832-48DA-9C3A-4B2B8032BC7A">
<dc:Bounds height="56" width="56" x="534" y="204"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge_shape__2F4301DA-E098-41C4-A75D-3DB1E94144A7_to_shape__3BCB2ADB-7158-43EF-8769-989C01A7E54A" bpmnElement="_6BF2BC53-4935-48F8-B4D0-81ADD3AB2A94">
<di:waypoint x="192" y="232"/>
<di:waypoint x="377" y="232"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="edge_shape__3BCB2ADB-7158-43EF-8769-989C01A7E54A_to_shape__97A1CDE0-F832-48DA-9C3A-4B2B8032BC7A" bpmnElement="_DC92975C-AA0F-45A5-90D9-773FD00CEBF0">
<di:waypoint x="377" y="232"/>
<di:waypoint x="562" y="232"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
<bpmn2:relationship type="BPSimData">
<bpmn2:extensionElements>
<bpsim:BPSimData>
<bpsim:Scenario id="default" name="Simulationscenario">
<bpsim:ScenarioParameters/>
<bpsim:ElementParameters elementRef="_2F4301DA-E098-41C4-A75D-3DB1E94144A7">
<bpsim:TimeParameters>
<bpsim:ProcessingTime>
<bpsim:NormalDistribution mean="0" standardDeviation="0"/>
</bpsim:ProcessingTime>
</bpsim:TimeParameters>
</bpsim:ElementParameters>
<bpsim:ElementParameters elementRef="_3BCB2ADB-7158-43EF-8769-989C01A7E54A">
<bpsim:TimeParameters>
<bpsim:ProcessingTime>
<bpsim:NormalDistribution mean="0" standardDeviation="0"/>
</bpsim:ProcessingTime>
</bpsim:TimeParameters>
<bpsim:ResourceParameters>
<bpsim:Availability>
<bpsim:FloatingParameter value="0"/>
</bpsim:Availability>
<bpsim:Quantity>
<bpsim:FloatingParameter value="0"/>
</bpsim:Quantity>
</bpsim:ResourceParameters>
<bpsim:CostParameters>
<bpsim:UnitCost>
<bpsim:FloatingParameter value="0"/>
</bpsim:UnitCost>
</bpsim:CostParameters>
</bpsim:ElementParameters>
</bpsim:Scenario>
</bpsim:BPSimData>
</bpmn2:extensionElements>
<bpmn2:source>_G4JzoZtuEDqs99yHqAh9rw</bpmn2:source>
<bpmn2:target>_G4JzoZtuEDqs99yHqAh9rw</bpmn2:target>
</bpmn2:relationship>
</bpmn2:definitions>
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.task.model.Status;
import org.kie.internal.executor.api.STATUS;
import org.kie.server.api.model.ReleaseId;
Expand All @@ -65,8 +67,10 @@ public class PrometheusIntegrationTest extends JbpmKieServerBaseIntegrationTest

private static final String CONTAINER_ID = "prometheus";
private static final String CONTAINER_ID_CASE = "prometheus-case";
private static final String PROCESS_ID = "per-process-instance-project.usertask";
private static final String USERTASK_PROCESS_ID = "per-process-instance-project.usertask";
private static final String USER_ID = "yoda";
private static final String RULETASK_PROCESS_ID = "ruletask";
private static KieContainer perProcessInstanceProjectkieContainer;

private static final String CASE_DEF_ID = "UserTaskCase";
private static final String CASE_OWNER_ROLE = "owner";
Expand Down Expand Up @@ -94,10 +98,17 @@ public static void buildAndDeployArtifacts() {
KieServerDeployer.buildAndDeployMavenProjectFromResource("/kjars-sources/per-process-instance-project");
KieServerDeployer.buildAndDeployMavenProjectFromResource("/kjars-sources/case-insurance");

perProcessInstanceProjectkieContainer = KieServices.Factory.get().newKieContainer(releaseId);

createContainer(CONTAINER_ID, releaseId);
createContainer(CONTAINER_ID_CASE, caseReleaseId);
}

@Override
protected void addExtraCustomClasses(Map<String, Class<?>> extraClasses) throws Exception {
extraClasses.put(PERSON_CLASS_NAME, Class.forName(PERSON_CLASS_NAME, true, perProcessInstanceProjectkieContainer.getClassLoader()));
}

protected String getMetrics() {
if (httpClient == null) {
httpClient = new ResteasyClientBuilder().readTimeout(10, TimeUnit.SECONDS).build();
Expand Down Expand Up @@ -126,17 +137,17 @@ public void testKieServerStartAndContainersMetrics() {
}

@Test
public void testPrometheusProcessAndTaskMetrics() {
processClient.startProcess(CONTAINER_ID, PROCESS_ID);
Long instanceId = processClient.startProcess(CONTAINER_ID, PROCESS_ID);
public void testPrometheusProcessAndUserTaskMetrics() {
processClient.startProcess(CONTAINER_ID, USERTASK_PROCESS_ID);
Long instanceId = processClient.startProcess(CONTAINER_ID, USERTASK_PROCESS_ID);
processClient.abortProcessInstance(CONTAINER_ID, instanceId);

taskClient.findTasksAssignedAsPotentialOwner(USER_ID, 0, 100).forEach(task -> {
taskClient.startTask(CONTAINER_ID, task.getId(), USER_ID);
taskClient.completeTask(CONTAINER_ID, task.getId(), USER_ID, null);
});

List<ProcessInstance> instances = queryClient.findProcessInstancesByProcessId(PROCESS_ID, Arrays.asList(STATE_COMPLETED, STATE_ABORTED), 0, 100);
List<ProcessInstance> instances = queryClient.findProcessInstancesByProcessId(USERTASK_PROCESS_ID, Arrays.asList(STATE_COMPLETED, STATE_ABORTED), 0, 100);

int totalInstances = instances.size();
long completedInstances = instances.stream().filter(pi -> pi.getState() == STATE_COMPLETED).count();
Expand Down Expand Up @@ -272,6 +283,20 @@ private JobRequestInstance createJobRequestExecutionErrorInstance(Integer number
jobRequestInstance.setCommand(JOB_EXECUTION_ERROR_COMMAND);
jobRequestInstance.setData(data);
return jobRequestInstance;
}

}

@Test
public void testPrometheusProcessAndRuleTaskMetrics() {
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("person", createPersonInstance("John"));
processClient.startProcess(CONTAINER_ID, RULETASK_PROCESS_ID, parameters);

assertThat(getMetrics()).contains("kie_server_process_instance_started_total{container_id=\"prometheus\",process_id=\"ruletask\",}",
"kie_server_process_instance_completed_total{container_id=\"prometheus\",process_id=\"ruletask\",status=\"2\",}",
"kie_server_process_instance_duration_seconds_count{container_id=\"prometheus\",process_id=\"ruletask\",}",
"kie_server_process_instance_duration_seconds_sum{container_id=\"prometheus\",process_id=\"ruletask\",}",
"kie_server_process_instance_running_total{container_id=\"prometheus\",process_id=\"ruletask\",} 0.0",
"drl_match_fired_nanosecond_count{container_id=\"prometheus\",ksessionId=\"default\",group_id=\"org.kie.server.testing\",artifact_id=\"per-process-instance-project\",version=\"1.0.0.Final\",rule_name=\"is John\",}",
"drl_match_fired_nanosecond_sum{container_id=\"prometheus\",ksessionId=\"default\",group_id=\"org.kie.server.testing\",artifact_id=\"per-process-instance-project\",version=\"1.0.0.Final\",rule_name=\"is John\",}");
}
}

0 comments on commit 78ac7bd

Please sign in to comment.