All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.metamx.metrics.CpuAcctDeltaMonitor Maven / Gradle / Ivy

There is a newer version: 1.3.8
Show newest version
/*
 * Copyright 2017 Metamarkets Group Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * 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 com.metamx.metrics;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.metamx.common.logger.Logger;
import com.metamx.emitter.service.ServiceEmitter;
import com.metamx.emitter.service.ServiceMetricEvent;
import com.metamx.metrics.cgroups.CgroupDiscoverer;
import com.metamx.metrics.cgroups.CpuAcct;
import com.metamx.metrics.cgroups.ProcSelfCgroupDiscoverer;
import org.joda.time.DateTime;

import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

public class CpuAcctDeltaMonitor extends FeedDefiningMonitor
{
  private static final Logger log = new Logger(CpuAcctDeltaMonitor.class);
  private final AtomicReference priorSnapshot = new AtomicReference<>(null);
  private final Map dimensions;

  private final CgroupDiscoverer cgroupDiscoverer;

  public CpuAcctDeltaMonitor()
  {
    this(ImmutableMap.of());
  }

  public CpuAcctDeltaMonitor(final Map dimensions)
  {
    this(dimensions, DEFAULT_METRICS_FEED);
  }

  public CpuAcctDeltaMonitor(final Map dimensions, final String feed)
  {
    this(feed, dimensions, new ProcSelfCgroupDiscoverer());
  }

  public CpuAcctDeltaMonitor(
      String feed,
      Map dimensions,
      CgroupDiscoverer cgroupDiscoverer
  )
  {
    super(feed);
    Preconditions.checkNotNull(dimensions);
    this.dimensions = ImmutableMap.copyOf(dimensions);
    this.cgroupDiscoverer = Preconditions.checkNotNull(cgroupDiscoverer, "cgroupDiscoverer required");
  }

  @Override
  public boolean doMonitor(ServiceEmitter emitter)
  {
    final CpuAcct cpuAcct = new CpuAcct(cgroupDiscoverer);
    final CpuAcct.CpuAcctMetric snapshot = cpuAcct.snapshot();
    final long nanoTime = System.nanoTime(); // Approx time... may be influenced by an unlucky GC
    final DateTime dateTime = new DateTime();
    final SnapshotHolder priorSnapshotHolder = this.priorSnapshot.get();
    if (!priorSnapshot.compareAndSet(priorSnapshotHolder, new SnapshotHolder(snapshot, nanoTime))) {
      log.debug("Pre-empted by another monitor run");
      return false;
    }
    if (priorSnapshotHolder == null) {
      log.info("Detected first run, storing result for next run");
      return false;
    }
    final long elapsedNs = nanoTime - priorSnapshotHolder.timestamp;
    if (snapshot.cpuCount() != priorSnapshotHolder.metric.cpuCount()) {
      log.warn(
          "Prior CPU count [%d] does not match current cpu count [%d]. Skipping metrics emission",
          priorSnapshotHolder.metric.cpuCount(),
          snapshot.cpuCount()
      );
      return false;
    }
    for (int i = 0; i < snapshot.cpuCount(); ++i) {
      final ServiceMetricEvent.Builder builderUsr = builder()
          .setDimension("cpuName", Integer.toString(i))
          .setDimension("cpuTime", "usr");
      final ServiceMetricEvent.Builder builderSys = builder()
          .setDimension("cpuName", Integer.toString(i))
          .setDimension("cpuTime", "sys");
      MonitorUtils.addDimensionsToBuilder(builderUsr, dimensions);
      MonitorUtils.addDimensionsToBuilder(builderSys, dimensions);
      emitter.emit(builderUsr.build(
          dateTime,
          "cgroup/cpu_time_delta_ns",
          snapshot.usrTime(i) - priorSnapshotHolder.metric.usrTime(i)
      ));
      emitter.emit(builderSys.build(
          dateTime,
          "cgroup/cpu_time_delta_ns",
          snapshot.sysTime(i) - priorSnapshotHolder.metric.sysTime(i)
      ));
    }
    if (snapshot.cpuCount() > 0) {
      // Don't bother emitting metrics if there aren't actually any cpus (usually from error)
      emitter.emit(builder().build(dateTime, "cgroup/cpu_time_delta_ns_elapsed", elapsedNs));
    }
    return true;
  }

  static class SnapshotHolder
  {
    private final CpuAcct.CpuAcctMetric metric;
    private final long timestamp;

    SnapshotHolder(CpuAcct.CpuAcctMetric metric, long timestamp)
    {
      this.metric = metric;
      this.timestamp = timestamp;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy