8

I would like to know is there a way to get the CPU Usage metrics with Spring Boot Actuator? Im able to see other metrics with /metrics and /health endpoints but not getting the CPU Usage. I want to avoid writing an extra class just to see the CPU Usage. Any idea? Thanks

user2340345
  • 793
  • 4
  • 16
  • 38
  • The /metrics endpoint shows a load average of the machine. Is this what you are looking for ? A idle computer has a load average of 0. Each running process using or waiting for CPU resources adds 1 to the load average. – rjdkolb Dec 20 '16 at 06:39

3 Answers3

10

Just checked and I found this actuator... /actuator/metrics/process.cpu.usage

It outputs the following:

{
    name: "process.cpu.usage",
    description: "The "recent cpu usage" for the Java Virtual Machine process",
    baseUnit: null,
    measurements: [
        {
            statistic: "VALUE",
            value: 0.0001742149747252696
        }
    ],
    availableTags: [ ]
}

Currently using Spring Boot version 2.2.2.RELEASE.

Jose Martinez
  • 11,452
  • 7
  • 53
  • 68
5

Spring Boot 2 actuator solution (building on @diginoise's code to measure CPU load), registering a Gauge with a function to measure the value when requested (no need to start Threads or schedule timers):

@Component
public class CpuMetrics {

    private final static String METRICS_NAME = "process.cpu.load";

    @Autowired
    private MeterRegistry meterRegistry;

    @PostConstruct
    public void init() {
        Gauge.builder(METRICS_NAME, this, CpuMetrics::getProcessCpuLoad)
            .baseUnit("%")
            .description("CPU Load")
            .register(meterRegistry);
    }

    public Double getProcessCpuLoad() {
        try {
            MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
            ObjectName name = ObjectName.getInstance("java.lang:type=OperatingSystem");
            AttributeList list = mbs.getAttributes(name, new String[]{"ProcessCpuLoad"});

            return Optional.ofNullable(list)
                    .map(l -> l.isEmpty() ? null : l)
                    .map(List::iterator)
                    .map(Iterator::next)
                    .map(Attribute.class::cast)
                    .map(Attribute::getValue)
                    .map(Double.class::cast)
                    .orElse(null);

        } catch (Exception ex) {
            return null;
        }
    }
}

The CPU metrics will then be available at /actuator/metrics/process.cpu.load:

{
  "name": "process.cpu.load",
  "description": "CPU Load",
  "baseUnit": "%",
  "measurements": [
    {
      "statistic": "VALUE",
      "value": 0.09767676212004521
    }
  ],
  "availableTags": []
}
Peter Walser
  • 15,208
  • 4
  • 51
  • 78
1

Unfortunately there isn't a CPU metric available via Spring Boot Actuator.
Fortunately you could write your own.

Just create a measuring bean which fulfills the following:

  1. It has access to GaugeService as it will be tracking one value.

    @Autowired
    private GaugeService gaugeService;
    
  2. Creates a thread which calls routine to measure process' CPU load:

    @PostConstruct
    public void startMeasuring() {
        new Thread() {
            @Override
            public void run() {
                gaugeService.submit("process.cpu.load", getProcessCpuLoad());
                Thread.sleep(2000);   //measure every 2sec.
            }
        }.start();
    }
    
  3. Has a routine which gets CPU load for your process using MxBeans:

    public static double getProcessCpuLoad() throws Exception {
        MBeanServer mbs    = ManagementFactory.getPlatformMBeanServer();
        ObjectName name    = ObjectName.getInstance("java.lang:type=OperatingSystem");
        AttributeList list = mbs.getAttributes(name, new String[]{ "ProcessCpuLoad" });
    
        if (list.isEmpty())     return Double.NaN;
    
        Attribute att = (Attribute)list.get(0);
        Double value  = (Double)att.getValue();
    
        // usually takes a couple of seconds before we get real values
        if (value == -1.0)      return Double.NaN;
        // returns a percentage value with 1 decimal point precision
        return ((int)(value * 1000) / 10.0);
    }
    

You could also extract the system wide CPU load using this method.

Hope this helps.

diginoise
  • 7,352
  • 2
  • 31
  • 39
  • how do we get "jvm.memory.used" in similar way ? I used : AttributeList list = mbs.getAttributes(name, new String[]{ "JvmMemoryUsed" }); but it's not working – pujan kc May 23 '23 at 03:46
  • @pujankc There are many answers here how to check memory used via JMX: https://stackoverflow.com/questions/1759831/how-do-i-access-memory-usage-programmatically-via-jmx – diginoise May 23 '23 at 09:29