Skip to content
This repository was archived by the owner on Nov 4, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.impl.jobexecutor.JobExecutor;
import org.camunda.bpm.spring.boot.starter.actuator.JobExecutorHealthIndicator;
import org.camunda.bpm.spring.boot.starter.actuator.MicrometerMetricsReporter;
import org.camunda.bpm.spring.boot.starter.actuator.ProcessEngineHealthIndicator;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
Expand All @@ -47,4 +49,11 @@ public HealthIndicator jobExecutorHealthIndicator(JobExecutor jobExecutor) {
public HealthIndicator processEngineHealthIndicator(ProcessEngine processEngine) {
return new ProcessEngineHealthIndicator(processEngine);
}

@Bean
@ConditionalOnProperty(prefix = "camunda.bpm.metrics.actuator", name = "interval")
@ConditionalOnExpression("${camunda.bpm.metrics.actuator.interval} > 0")
public MicrometerMetricsReporter micrometerMetricsReporter() {
return new MicrometerMetricsReporter();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. Camunda licenses this file to you under the Apache License,
* Version 2.0; you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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.camunda.bpm.spring.boot.starter.actuator;

import jakarta.annotation.PostConstruct;
import io.micrometer.core.instrument.MeterRegistry;
import java.util.Timer;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.spring.boot.starter.property.CamundaBpmProperties;
import org.springframework.beans.factory.annotation.Autowired;

public class MicrometerMetricsReporter {

@Autowired
MeterRegistry registry;

@Autowired
ProcessEngine processEngine;

@Autowired
CamundaBpmProperties camundaBpmProperties;

private MicrometerMetricsReportingTask micrometerMetricsReportingTask;

@PostConstruct
private void init() {
startReportingCamundaActuatorMetrics();
}

private void startReportingCamundaActuatorMetrics() {
Timer timer = new Timer("Micrometer Camunda Metrics Reporter", true);
long reportingIntervalInMillis = camundaBpmProperties.getMetrics().getActuator().getInterval() * 1000L;
micrometerMetricsReportingTask = new MicrometerMetricsReportingTask(registry, processEngine);
timer.scheduleAtFixedRate(micrometerMetricsReportingTask,
reportingIntervalInMillis,
reportingIntervalInMillis);
}

public void reportNow() {
if(micrometerMetricsReportingTask != null) {
micrometerMetricsReportingTask.run();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. Camunda licenses this file to you under the Apache License,
* Version 2.0; you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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.camunda.bpm.spring.boot.starter.actuator;

import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.management.MetricIntervalValue;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;


public class MicrometerMetricsReportingTask extends TimerTask {

private final MeterRegistry meterRegistry;
private final ProcessEngine processEngine;
Map<String, Long> metricsMap;

public MicrometerMetricsReportingTask(MeterRegistry registry, ProcessEngine processEngine) {
this.meterRegistry = registry;
this.processEngine = processEngine;
metricsMap = new HashMap<>();
}

public void run() {
List<MetricIntervalValue> metricsList = processEngine.getManagementService()
.createMetricsQuery().interval(1);
if(metricsList.isEmpty()){
return;
}
metricsList.forEach(metric ->{
if(!metricsMap.containsKey(metric.getName())) {
Gauge.builder("camunda." + metric.getName(),metricsMap, map -> map.get(metric.getName()))
.register(meterRegistry);
}
metricsMap.put(metric.getName(), metric.getValue());
});
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. Camunda licenses this file to you under the Apache License,
* Version 2.0; you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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.camunda.bpm.spring.boot.starter.property;

import org.camunda.bpm.spring.boot.starter.util.SpringBootStarterException;

public class ActuatorProperty {

private Integer interval = -1; // Default value

public Integer getInterval() {
return interval;
}

public void setInterval(Integer interval) {
if (interval == null || interval < -1 || interval == 0) {
throw new SpringBootStarterException("Invalid value for camunda.bpm.metrics.actuator.interval: " + interval +
". Value must be -1 or greater than 0.");
}
this.interval = interval;
}

@Override
public String toString() {
return "ActuatorProperty[interval=" + interval + "]";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@
*/
package org.camunda.bpm.spring.boot.starter.property;

import org.springframework.boot.context.properties.NestedConfigurationProperty;

import static org.camunda.bpm.spring.boot.starter.property.CamundaBpmProperties.joinOn;

public class MetricsProperty {

private boolean enabled = Defaults.INSTANCE.isMetricsEnabled();
private boolean dbReporterActivate = Defaults.INSTANCE.isDbMetricsReporterActivate();

@NestedConfigurationProperty
private ActuatorProperty actuator = new ActuatorProperty();

public boolean isEnabled() {
return enabled;
}
Expand All @@ -39,11 +44,20 @@ public void setDbReporterActivate(boolean dbReporterActivate) {
this.dbReporterActivate = dbReporterActivate;
}

public ActuatorProperty getActuator() {
return actuator;
}

public void setActuator(ActuatorProperty actuator) {
this.actuator = actuator;
}

@Override
public String toString() {
return joinOn(this.getClass())
.add("enabled=" + enabled)
.add("dbReporterActivate=" + dbReporterActivate)
.add("actuator=" + actuator)
.toString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.camunda.bpm.spring.boot.starter;
package org.camunda.bpm.spring.boot.starter.actuator;

import static org.junit.Assert.assertTrue;

import org.camunda.bpm.spring.boot.starter.AbstractCamundaAutoConfigurationIT;
import org.camunda.bpm.spring.boot.starter.test.nonpa.TestApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. Camunda licenses this file to you under the Apache License,
* Version 2.0; you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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.camunda.bpm.spring.boot.starter.actuator.micrometer.metrics;

import org.camunda.bpm.spring.boot.starter.test.nonpa.TestApplication;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(
classes = {TestApplication.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
public class ActuatorMetricsPropertyAbsentIT {

@Autowired
private ApplicationContext applicationContext;

@Test
public void actuatorMetricsNotCreated() {
//MicrometerMetricsReporter not created when camunda.bpm.metrics.actuator.interval is absent
Assert.assertFalse(applicationContext.containsBean("micrometerMetricsReporter"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. Camunda licenses this file to you under the Apache License,
* Version 2.0; you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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.camunda.bpm.spring.boot.starter.actuator.micrometer.metrics;

import org.camunda.bpm.spring.boot.starter.test.nonpa.TestApplication;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(
classes = {TestApplication.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = { "camunda.bpm.metrics.actuator.interval=-1"}
)
public class ActuatorMetricsPropertyDefaultIT {

@Autowired
private ApplicationContext applicationContext;

@Test
public void actuatorMetricsNotCreated() {
//MicrometerMetricsReporter not created when camunda.bpm.metrics.actuator.interval is -1.
Assert.assertFalse(applicationContext.containsBean("micrometerMetricsReporter"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. Camunda licenses this file to you under the Apache License,
* Version 2.0; you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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.camunda.bpm.spring.boot.starter.actuator.micrometer.metrics;

import org.camunda.bpm.spring.boot.starter.test.nonpa.TestApplication;
import org.camunda.bpm.spring.boot.starter.util.SpringBootStarterException;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import java.util.Map;

public class ActuatorMetricsPropertyInvalidIT {

@Test
public void shouldThrowSpringBootStarterExceptionWhenIntervalLessThanNegative1() {
startApplicationWithInvalidIntervalProperty(-2);
}

@Test
public void shouldThrowSpringBootStarterExceptionWhenIntervalIsZero() {
startApplicationWithInvalidIntervalProperty(0);
}

private void startApplicationWithInvalidIntervalProperty(int interval){
SpringApplication app = new SpringApplication(TestApplication.class);
app.setDefaultProperties(Map.of("camunda.bpm.metrics.actuator.interval", interval));
Exception exception = Assert.assertThrows(Exception.class, app::run);
Throwable rootCause = findRootCause(exception);
Assert.assertTrue(rootCause instanceof SpringBootStarterException);
Assert.assertEquals("Invalid value for camunda.bpm.metrics.actuator.interval: " + interval + ". Value must be -1 or greater than 0.",
rootCause.getMessage());
}
private Throwable findRootCause(Throwable e) {
while (e.getCause() != null) {
e = e.getCause();
}
return e;
}
}
Loading