4444import java .util .concurrent .ConcurrentHashMap ;
4545import java .util .regex .Matcher ;
4646import java .util .regex .Pattern ;
47+ import java .util .stream .Collectors ;
48+ import java .util .stream .Stream ;
4749
4850import javax .naming .ConfigurationException ;
4951import javax .xml .parsers .DocumentBuilder ;
7678import org .apache .commons .lang .math .NumberUtils ;
7779import org .apache .commons .lang3 .ObjectUtils ;
7880import org .apache .commons .lang3 .StringUtils ;
81+ import org .apache .commons .lang3 .builder .ReflectionToStringBuilder ;
82+ import org .apache .commons .lang3 .builder .ToStringStyle ;
7983import org .apache .logging .log4j .Logger ;
8084import org .apache .logging .log4j .LogManager ;
8185import org .apache .xerces .impl .xpath .regex .Match ;
@@ -446,7 +450,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
446450 protected WatchDogModel watchDogModel = WatchDogModel .I6300ESB ;
447451
448452 private final Map <String , String > pifs = new HashMap <String , String >();
449- private final Map <String , VmStats > vmStats = new ConcurrentHashMap <String , VmStats >();
453+ private final Map <String , LibvirtExtendedVmStatsEntry > vmStats = new ConcurrentHashMap <>();
450454
451455 private final Map <String , DomainBlockStats > vmDiskStats = new ConcurrentHashMap <>();
452456
@@ -2346,7 +2350,7 @@ public PowerState getVmState(final Connect conn, final String vmName) {
23462350 final PowerState s = convertToPowerState (vms .getInfo ().state );
23472351 return s ;
23482352 } catch (final LibvirtException e ) {
2349- LOGGER .warn ( "Can't get vm state " + vmName + e . getMessage () + "retry:" + retry );
2353+ LOGGER .error ( "Could not get state for VM [{}] (retry={}) due to:" , vmName , retry , e );
23502354 } finally {
23512355 try {
23522356 if (vms != null ) {
@@ -4414,127 +4418,189 @@ protected String getDiskPathFromDiskDef(DiskDef disk) {
44144418 return null ;
44154419 }
44164420
4417- private class VmStats {
4418- long usedTime ;
4419- long tx ;
4420- long rx ;
4421- long ioRead ;
4422- long ioWrote ;
4423- long bytesRead ;
4424- long bytesWrote ;
4425- Calendar timestamp ;
4421+ private String vmToString (Domain dm ) throws LibvirtException {
4422+ return String .format ("{\" name\" :\" %s\" ,\" uuid\" :\" %s\" }" , dm .getName (), dm .getUUIDString ());
44264423 }
44274424
4425+ /**
4426+ * Returns metrics for the period since this function was last called for the specified VM.
4427+ * @param conn the Libvirt connection.
4428+ * @param vmName name of the VM.
4429+ * @return metrics for the period since last time this function was called for the VM.
4430+ * @throws LibvirtException
4431+ */
44284432 public VmStatsEntry getVmStat (final Connect conn , final String vmName ) throws LibvirtException {
44294433 Domain dm = null ;
44304434 try {
4435+ LOGGER .debug ("Trying to get VM with name [{}]." , vmName );
44314436 dm = getDomain (conn , vmName );
44324437 if (dm == null ) {
4438+ LOGGER .warn ("Could not get VM with name [{}]." , vmName );
44334439 return null ;
44344440 }
4435- DomainInfo info = dm .getInfo ();
4436- final VmStatsEntry stats = new VmStatsEntry ();
44374441
4438- stats . setNumCPUs ( info . nrVirtCpu );
4439- stats . setEntityType ( "vm" );
4442+ LibvirtExtendedVmStatsEntry newStats = getVmCurrentStats ( dm );
4443+ LibvirtExtendedVmStatsEntry oldStats = vmStats . get ( vmName );
44404444
4441- stats .setMemoryKBs (info .maxMem );
4442- stats .setTargetMemoryKBs (info .memory );
4443- stats .setIntFreeMemoryKBs (getMemoryFreeInKBs (dm ));
4445+ VmStatsEntry metrics = calculateVmMetrics (dm , oldStats , newStats );
4446+ vmStats .put (vmName , newStats );
44444447
4445- /* get cpu utilization */
4446- VmStats oldStats = null ;
4448+ return metrics ;
4449+ } finally {
4450+ if (dm != null ) {
4451+ dm .free ();
4452+ }
4453+ }
4454+ }
44474455
4448- final Calendar now = Calendar .getInstance ();
4456+ /**
4457+ * Returns a VM's current statistics.
4458+ * @param dm domain of the VM.
4459+ * @return current statistics of the VM.
4460+ * @throws LibvirtException
4461+ */
4462+ protected LibvirtExtendedVmStatsEntry getVmCurrentStats (final Domain dm ) throws LibvirtException {
4463+ final LibvirtExtendedVmStatsEntry stats = new LibvirtExtendedVmStatsEntry ();
44494464
4450- oldStats = vmStats .get (vmName );
4465+ getVmCurrentCpuStats (dm , stats );
4466+ getVmCurrentNetworkStats (dm , stats );
4467+ getVmCurrentDiskStats (dm , stats );
44514468
4452- long elapsedTime = 0 ;
4453- if ( oldStats != null ) {
4454- elapsedTime = now . getTimeInMillis () - oldStats . timestamp . getTimeInMillis () ;
4455- double utilization = ( info . cpuTime - oldStats . usedTime ) / (( double ) elapsedTime * 1000000 );
4469+ LOGGER . debug ( "Retrieved statistics for VM [{}]: [{}]." , vmToString ( dm ), stats ) ;
4470+ stats . setTimestamp ( Calendar . getInstance ());
4471+ return stats ;
4472+ }
44564473
4457- utilization = utilization / info .nrVirtCpu ;
4458- if (utilization > 0 ) {
4459- stats .setCPUUtilization (utilization * 100 );
4460- }
4461- }
4474+ /**
4475+ * Passes a VM's current CPU statistics into the provided LibvirtExtendedVmStatsEntry.
4476+ * @param dm domain of the VM.
4477+ * @param stats LibvirtExtendedVmStatsEntry that will receive the current CPU statistics.
4478+ * @throws LibvirtException
4479+ */
4480+ protected void getVmCurrentCpuStats (final Domain dm , final LibvirtExtendedVmStatsEntry stats ) throws LibvirtException {
4481+ LOGGER .trace ("Getting CPU stats for VM [{}]." , vmToString (dm ));
4482+ stats .setCpuTime (dm .getInfo ().cpuTime );
4483+ }
44624484
4463- /* get network stats */
4485+ /**
4486+ * Passes a VM's current network statistics into the provided LibvirtExtendedVmStatsEntry.
4487+ * @param dm domain of the VM.
4488+ * @param stats LibvirtExtendedVmStatsEntry that will receive the current network statistics.
4489+ * @throws LibvirtException
4490+ */
4491+ protected void getVmCurrentNetworkStats (final Domain dm , final LibvirtExtendedVmStatsEntry stats ) throws LibvirtException {
4492+ final String vmAsString = vmToString (dm );
4493+ LOGGER .trace ("Getting network stats for VM [{}]." , vmAsString );
4494+ final List <InterfaceDef > vifs = getInterfaces (dm .getConnect (), dm .getName ());
4495+ LOGGER .debug ("Found [{}] network interface(s) for VM [{}]." , vifs .size (), vmAsString );
4496+ double rx = 0 ;
4497+ double tx = 0 ;
4498+ for (final InterfaceDef vif : vifs ) {
4499+ final DomainInterfaceStats ifStats = dm .interfaceStats (vif .getDevName ());
4500+ rx += ifStats .rx_bytes ;
4501+ tx += ifStats .tx_bytes ;
4502+ }
4503+ stats .setNetworkReadKBs (rx / 1024 );
4504+ stats .setNetworkWriteKBs (tx / 1024 );
4505+ }
44644506
4465- final List <InterfaceDef > vifs = getInterfaces (conn , vmName );
4466- long rx = 0 ;
4467- long tx = 0 ;
4468- for (final InterfaceDef vif : vifs ) {
4469- final DomainInterfaceStats ifStats = dm .interfaceStats (vif .getDevName ());
4470- rx += ifStats .rx_bytes ;
4471- tx += ifStats .tx_bytes ;
4507+ /**
4508+ * Passes a VM's current disk statistics into the provided LibvirtExtendedVmStatsEntry.
4509+ * @param dm domain of the VM.
4510+ * @param stats LibvirtExtendedVmStatsEntry that will receive the current disk statistics.
4511+ * @throws LibvirtException
4512+ */
4513+ protected void getVmCurrentDiskStats (final Domain dm , final LibvirtExtendedVmStatsEntry stats ) throws LibvirtException {
4514+ final String vmAsString = vmToString (dm );
4515+ LOGGER .trace ("Getting disk stats for VM [{}]." , vmAsString );
4516+ final List <DiskDef > disks = getDisks (dm .getConnect (), dm .getName ());
4517+ LOGGER .debug ("Found [{}] disk(s) for VM [{}]." , disks .size (), vmAsString );
4518+ long io_rd = 0 ;
4519+ long io_wr = 0 ;
4520+ double bytes_rd = 0 ;
4521+ double bytes_wr = 0 ;
4522+ for (final DiskDef disk : disks ) {
4523+ if (disk .getDeviceType () == DeviceType .CDROM || disk .getDeviceType () == DeviceType .FLOPPY ) {
4524+ LOGGER .debug ("Ignoring disk [{}] in VM [{}]'s stats since its deviceType is [{}]." , disk .toString ().replace ("\n " , "" ), vmAsString , disk .getDeviceType ());
4525+ continue ;
44724526 }
4527+ final DomainBlockStats blockStats = dm .blockStats (disk .getDiskLabel ());
4528+ io_rd += blockStats .rd_req ;
4529+ io_wr += blockStats .wr_req ;
4530+ bytes_rd += blockStats .rd_bytes ;
4531+ bytes_wr += blockStats .wr_bytes ;
4532+ }
4533+ stats .setDiskReadIOs (io_rd );
4534+ stats .setDiskWriteIOs (io_wr );
4535+ stats .setDiskReadKBs (bytes_rd / 1024 );
4536+ stats .setDiskWriteKBs (bytes_wr / 1024 );
4537+ }
44734538
4474- if (oldStats != null ) {
4475- final double deltarx = rx - oldStats .rx ;
4476- if (deltarx > 0 ) {
4477- stats .setNetworkReadKBs (deltarx / 1024 );
4478- }
4479- final double deltatx = tx - oldStats .tx ;
4480- if (deltatx > 0 ) {
4481- stats .setNetworkWriteKBs (deltatx / 1024 );
4482- }
4539+ /**
4540+ * Calculates a VM's metrics for the period between the two statistics given as parameters.
4541+ * @param dm domain of the VM.
4542+ * @param oldStats old statistics. If null, the CPU, network and disk utilization won't be calculated.
4543+ * @param newStats new statistics.
4544+ * @return metrics for the period between the two statistics.
4545+ * @throws LibvirtException
4546+ */
4547+ protected VmStatsEntry calculateVmMetrics (final Domain dm , final LibvirtExtendedVmStatsEntry oldStats , final LibvirtExtendedVmStatsEntry newStats ) throws LibvirtException {
4548+ final VmStatsEntry metrics = new VmStatsEntry ();
4549+ final DomainInfo info = dm .getInfo ();
4550+ final String vmAsString = vmToString (dm );
4551+
4552+ metrics .setEntityType ("vm" );
4553+ LOGGER .trace ("Writing VM [{}]'s CPU and memory information into the metrics." , vmAsString );
4554+ metrics .setNumCPUs (info .nrVirtCpu );
4555+ metrics .setMemoryKBs (info .maxMem );
4556+ metrics .setTargetMemoryKBs (info .memory );
4557+ LOGGER .trace ("Trying to get free memory for VM [{}]." , vmAsString );
4558+ metrics .setIntFreeMemoryKBs (getMemoryFreeInKBs (dm ));
4559+
4560+ if (oldStats != null ) {
4561+ LOGGER .debug ("Old stats exist for VM [{}]; therefore, the utilization will be calculated." , vmAsString );
4562+
4563+ LOGGER .trace ("Calculating CPU utilization for VM [{}]." , vmAsString );
4564+ final Calendar now = Calendar .getInstance ();
4565+ long elapsedTime = now .getTimeInMillis () - oldStats .getTimestamp ().getTimeInMillis ();
4566+ double utilization = (info .cpuTime - oldStats .getCpuTime ()) / ((double ) elapsedTime * 1000000 * info .nrVirtCpu );
4567+ if (utilization > 0 ) {
4568+ metrics .setCPUUtilization (utilization * 100 );
44834569 }
44844570
4485- /* get disk stats */
4486- final List <DiskDef > disks = getDisks (conn , vmName );
4487- long io_rd = 0 ;
4488- long io_wr = 0 ;
4489- long bytes_rd = 0 ;
4490- long bytes_wr = 0 ;
4491- for (final DiskDef disk : disks ) {
4492- if (disk .getDeviceType () == DeviceType .CDROM || disk .getDeviceType () == DeviceType .FLOPPY ) {
4493- continue ;
4494- }
4495- final DomainBlockStats blockStats = dm .blockStats (disk .getDiskLabel ());
4496- io_rd += blockStats .rd_req ;
4497- io_wr += blockStats .wr_req ;
4498- bytes_rd += blockStats .rd_bytes ;
4499- bytes_wr += blockStats .wr_bytes ;
4571+ LOGGER .trace ("Calculating network utilization for VM [{}]." , vmAsString );
4572+ final double deltarx = newStats .getNetworkReadKBs () - oldStats .getNetworkReadKBs ();
4573+ if (deltarx > 0 ) {
4574+ metrics .setNetworkReadKBs (deltarx );
45004575 }
4501-
4502- if (oldStats != null ) {
4503- final long deltaiord = io_rd - oldStats .ioRead ;
4504- if (deltaiord > 0 ) {
4505- stats .setDiskReadIOs (deltaiord );
4506- }
4507- final long deltaiowr = io_wr - oldStats .ioWrote ;
4508- if (deltaiowr > 0 ) {
4509- stats .setDiskWriteIOs (deltaiowr );
4510- }
4511- final double deltabytesrd = bytes_rd - oldStats .bytesRead ;
4512- if (deltabytesrd > 0 ) {
4513- stats .setDiskReadKBs (deltabytesrd / 1024 );
4514- }
4515- final double deltabyteswr = bytes_wr - oldStats .bytesWrote ;
4516- if (deltabyteswr > 0 ) {
4517- stats .setDiskWriteKBs (deltabyteswr / 1024 );
4518- }
4576+ final double deltatx = newStats .getNetworkWriteKBs () - oldStats .getNetworkWriteKBs ();
4577+ if (deltatx > 0 ) {
4578+ metrics .setNetworkWriteKBs (deltatx );
45194579 }
45204580
4521- /* save to Hashmap */
4522- final VmStats newStat = new VmStats ();
4523- newStat .usedTime = info .cpuTime ;
4524- newStat .rx = rx ;
4525- newStat .tx = tx ;
4526- newStat .ioRead = io_rd ;
4527- newStat .ioWrote = io_wr ;
4528- newStat .bytesRead = bytes_rd ;
4529- newStat .bytesWrote = bytes_wr ;
4530- newStat .timestamp = now ;
4531- vmStats .put (vmName , newStat );
4532- return stats ;
4533- } finally {
4534- if (dm != null ) {
4535- dm .free ();
4581+ LOGGER .trace ("Calculating disk utilization for VM [{}]." , vmAsString );
4582+ final double deltaiord = newStats .getDiskReadIOs () - oldStats .getDiskReadIOs ();
4583+ if (deltaiord > 0 ) {
4584+ metrics .setDiskReadIOs (deltaiord );
4585+ }
4586+ final double deltaiowr = newStats .getDiskWriteIOs () - oldStats .getDiskWriteIOs ();
4587+ if (deltaiowr > 0 ) {
4588+ metrics .setDiskWriteIOs (deltaiowr );
4589+ }
4590+ final double deltabytesrd = newStats .getDiskReadKBs () - oldStats .getDiskReadKBs ();
4591+ if (deltabytesrd > 0 ) {
4592+ metrics .setDiskReadKBs (deltabytesrd );
4593+ }
4594+ final double deltabyteswr = newStats .getDiskWriteKBs () - oldStats .getDiskWriteKBs ();
4595+ if (deltabyteswr > 0 ) {
4596+ metrics .setDiskWriteKBs (deltabyteswr );
45364597 }
45374598 }
4599+
4600+ String metricsAsString = new ReflectionToStringBuilder (metrics , ToStringStyle .JSON_STYLE ).setExcludeFieldNames ("vmId" , "vmUuid" ).toString ();
4601+ LOGGER .debug ("Calculated metrics for VM [{}]: [{}]." , vmAsString , metricsAsString );
4602+
4603+ return metrics ;
45384604 }
45394605
45404606 /**
@@ -4546,10 +4612,8 @@ public VmStatsEntry getVmStat(final Connect conn, final String vmName) throws Li
45464612 */
45474613 protected long getMemoryFreeInKBs (Domain dm ) throws LibvirtException {
45484614 MemoryStatistic [] memoryStats = dm .memoryStats (NUMMEMSTATS );
4549-
4550- if (LOGGER .isTraceEnabled ()){
4551- LOGGER .trace (String .format ("Retrieved memory statistics (information about tags can be found on the libvirt documentation):" , ArrayUtils .toString (memoryStats )));
4552- }
4615+ LOGGER .trace ("Retrieved memory statistics (information about tags can be found on the libvirt documentation): {}." ,
4616+ () -> Stream .of (memoryStats ).map (stat -> stat .toString ().trim ().replace ("\n " , "," )).collect (Collectors .joining ("},{" , "[{" , "}]" )));
45534617
45544618 long freeMemory = NumberUtils .LONG_MINUS_ONE ;
45554619
0 commit comments