You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by al...@apache.org on 2015/05/29 19:22:12 UTC

[19/27] incubator-brooklyn git commit: Adds performance counters

Adds performance counters


Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/fbb4ce9c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/fbb4ce9c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/fbb4ce9c

Branch: refs/heads/master
Commit: fbb4ce9ca9f0077c19a88b8dc1410f69d0d56dd5
Parents: 902f97e
Author: Martin Harris <gi...@nakomis.com>
Authored: Wed May 13 08:58:30 2015 +0100
Committer: Richard Downer <ri...@apache.org>
Committed: Thu May 28 17:27:35 2015 +0100

----------------------------------------------------------------------
 .../windows/WindowsPerformanceCounterFeed.java  | 142 ++++++++++++++-----
 .../WindowsPerformanceCounterPollConfig.java    |   1 +
 .../basic/VanillaWindowsProcessWinRmDriver.java |   3 +-
 .../winrm/WindowsPerformanceCounterSensors.java |  74 ++++++++++
 4 files changed, 181 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fbb4ce9c/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterFeed.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterFeed.java b/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterFeed.java
index 468af57..35ffa93 100644
--- a/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterFeed.java
+++ b/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterFeed.java
@@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import java.math.BigInteger;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedMap;
@@ -38,30 +39,35 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
+import brooklyn.entity.Entity;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.entity.effector.EffectorTasks;
 import brooklyn.event.AttributeSensor;
+import brooklyn.event.basic.Sensors;
 import brooklyn.event.feed.AbstractFeed;
 import brooklyn.event.feed.PollHandler;
 import brooklyn.event.feed.Poller;
 import brooklyn.event.feed.ssh.SshPollValue;
 import brooklyn.location.basic.SshMachineLocation;
+import brooklyn.location.basic.WinRmMachineLocation;
 import brooklyn.management.ExecutionContext;
 import brooklyn.util.flags.TypeCoercions;
+import brooklyn.util.guava.Maybe;
 import brooklyn.util.task.ssh.SshTasks;
 import brooklyn.util.task.system.ProcessTaskFactory;
 import brooklyn.util.task.system.ProcessTaskWrapper;
 import brooklyn.util.time.Duration;
+import io.cloudsoft.winrm4j.winrm.WinRmToolResponse;
 
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
-import com.google.common.base.Optional;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.reflect.TypeToken;
@@ -98,10 +104,11 @@ public class WindowsPerformanceCounterFeed extends AbstractFeed {
     // This pattern matches CSV line(s) with the date in the first field, and at least one further field.
     protected static final Pattern lineWithPerfData = Pattern.compile("^\"[\\d:/\\-. ]+\",\".*\"$", Pattern.MULTILINE);
     private static final Joiner JOINER_ON_SPACE = Joiner.on(' ');
+    private static final Joiner JOINER_ON_COMMA = Joiner.on(',');
 
     @SuppressWarnings("serial")
-    public static final ConfigKey<Set<WindowsPerformanceCounterPollConfig<?>>> POLLS = ConfigKeys.newConfigKey(
-            new TypeToken<Set<WindowsPerformanceCounterPollConfig<?>>>() {},
+    public static final ConfigKey<List<WindowsPerformanceCounterPollConfig<?>>> POLLS = ConfigKeys.newConfigKey(
+            new TypeToken<List<WindowsPerformanceCounterPollConfig<?>>>() {},
             "polls");
 
     public static Builder builder() {
@@ -133,7 +140,7 @@ public class WindowsPerformanceCounterFeed extends AbstractFeed {
             return this;
         }
         public Builder period(Duration period) {
-            period = checkNotNull(period, "period");
+            this.period = checkNotNull(period, "period");
             return this;
         }
         public Builder period(long millis) {
@@ -166,7 +173,7 @@ public class WindowsPerformanceCounterFeed extends AbstractFeed {
     }
 
     protected WindowsPerformanceCounterFeed(Builder builder) {
-        Set<WindowsPerformanceCounterPollConfig<?>> polls = Sets.newLinkedHashSet();
+        List<WindowsPerformanceCounterPollConfig<?>> polls = Lists.newArrayList();
         for (WindowsPerformanceCounterPollConfig<?> config : builder.polls) {
             @SuppressWarnings({ "unchecked", "rawtypes" })
             WindowsPerformanceCounterPollConfig<?> configCopy = new WindowsPerformanceCounterPollConfig(config);
@@ -179,50 +186,50 @@ public class WindowsPerformanceCounterFeed extends AbstractFeed {
 
     @Override
     protected void preStart() {
-        Set<WindowsPerformanceCounterPollConfig<?>> polls = getConfig(POLLS);
+        List<WindowsPerformanceCounterPollConfig<?>> polls = getConfig(POLLS);
         
         long minPeriod = Integer.MAX_VALUE;
-        SortedSet<String> performanceCounterNames = Sets.newTreeSet();
+        List<String> performanceCounterNames = Lists.newArrayList();
         for (WindowsPerformanceCounterPollConfig<?> config : polls) {
             minPeriod = Math.min(minPeriod, config.getPeriod());
             performanceCounterNames.add(config.getPerformanceCounterName());
         }
         
-        SshMachineLocation machine = EffectorTasks.getSshMachine(getEntity());
         Iterable<String> allParams = ImmutableList.<String>builder()
-                .add("typeperf")
-                .addAll(Iterables.transform(performanceCounterNames, QuoteStringFunction.INSTANCE))
-                .add("-sc")
-                .add("1")
+                .add("Get-Counter")
+                .add("-Counter")
+                .add(JOINER_ON_COMMA.join(Iterables.transform(performanceCounterNames, QuoteStringFunction.INSTANCE)))
+                .add("-SampleInterval")
+                .add("2") // TODO: This should be a config key
                 .build();
-        String command = JOINER_ON_SPACE.join(allParams);
+        String command = String.format("(%s).CounterSamples.CookedValue", JOINER_ON_SPACE.join(allParams));
         log.debug("Windows performance counter poll command will be: {}", command);
-        
-        final ProcessTaskFactory<Integer> taskFactory = SshTasks.newSshExecTaskFactory(machine, command)
-                .allowingNonZeroExitCode()
-                .runAsCommand();
-
-        final Callable<SshPollValue> queryForCounterValues = new Callable<SshPollValue>() {
-            public SshPollValue call() throws Exception {
-                ProcessTaskWrapper<Integer> taskWrapper = taskFactory.newTask();
-                final ExecutionContext executionContext =
-                        ((EntityInternal) entity).getManagementSupport().getExecutionContext();
-                executionContext.submit(taskWrapper);
-                taskWrapper.block();
-                Optional<Integer> exitCode = Optional.fromNullable(taskWrapper.getExitCode());
-                return new SshPollValue(null, exitCode.or(-1), taskWrapper.getStdout(), taskWrapper.getStderr());
-            }
-        };
 
-        getPoller().scheduleAtFixedRate(
-                new CallInEntityExecutionContext<SshPollValue>(entity, queryForCounterValues),
-                new SendPerfCountersToSensors(entity, polls),
-                minPeriod);
+        getPoller().scheduleAtFixedRate(new GetPerformanceCountersJob<WinRmToolResponse>(getEntity(), command),
+                new SendPerfCountersToSensors(getEntity(), getConfig(POLLS)), 100L);
+    }
+
+    private static class GetPerformanceCountersJob<T> implements Callable<T> {
+
+        private final Entity entity;
+        private final String command;
+
+        GetPerformanceCountersJob(Entity entity, String command) {
+            this.entity = entity;
+            this.command = command;
+        }
+
+        @Override
+        public T call() throws Exception {
+            WinRmMachineLocation machine = EffectorTasks.getWinRmMachine(entity);
+            WinRmToolResponse response = machine.executePsScript(command);
+            return (T)response;
+        }
     }
 
     @SuppressWarnings("unchecked")
-    protected Poller<SshPollValue> getPoller() {
-        return (Poller<SshPollValue>) super.getPoller();
+    protected Poller<WinRmToolResponse> getPoller() {
+        return (Poller<WinRmToolResponse>) super.getPoller();
     }
 
     /**
@@ -251,10 +258,71 @@ public class WindowsPerformanceCounterFeed extends AbstractFeed {
         }
     }
 
+    private static class SendPerfCountersToSensors implements PollHandler<WinRmToolResponse> {
+
+        private final EntityLocal entity;
+        private final List<WindowsPerformanceCounterPollConfig<?>> polls;
+
+        public SendPerfCountersToSensors(EntityLocal entity, List<WindowsPerformanceCounterPollConfig<?>> polls) {
+            this.entity = entity;
+            this.polls = polls;
+        }
+
+        @Override
+        public boolean checkSuccess(WinRmToolResponse val) {
+            if (val.getStatusCode() != 0) return false;
+            String stderr = val.getStdErr();
+            if (stderr == null || stderr.length() != 0) return false;
+            String out = val.getStdOut();
+            if (out == null || out.length() == 0) return false;
+            return true;
+        }
+
+        @Override
+        public void onSuccess(WinRmToolResponse val) {
+            String[] values = val.getStdOut().split("\r\n");
+            for (int i = 0; i < polls.size(); i++) {
+                Class<?> clazz = polls.get(i).getSensor().getType();
+                Maybe<? extends Object> maybeValue = TypeCoercions.tryCoerce(values[i], TypeToken.of(clazz));
+                Object value = maybeValue.isAbsent() ? null : maybeValue.get();
+                AttributeSensor<Object> attribute = (AttributeSensor<Object>) Sensors.newSensor(clazz, polls.get(i).getSensor().getName(), polls.get(i).getDescription());
+                entity.setAttribute(attribute, value);
+            }
+        }
+
+        @Override
+        public void onFailure(WinRmToolResponse val) {
+            log.error("Windows Performance Counter query did not respond as expected. exitcode={} stdout={} stderr={}",
+                    new Object[]{val.getStatusCode(), val.getStdOut(), val.getStdErr()});
+            for (WindowsPerformanceCounterPollConfig<?> config : polls) {
+                entity.setAttribute(Sensors.newSensor(config.getSensor().getClass(), config.getPerformanceCounterName(), config.getDescription()), null);
+            }
+        }
+
+        @Override
+        public void onException(Exception exception) {
+            log.error("Detected exception while retrieving Windows Performance Counters from entity " +
+                    entity.getDisplayName(), exception);
+            for (WindowsPerformanceCounterPollConfig<?> config : polls) {
+                entity.setAttribute(Sensors.newSensor(config.getSensor().getClass(), config.getPerformanceCounterName(), config.getDescription()), null);
+            }
+        }
+
+        @Override
+        public String getDescription() {
+            return "" + polls;
+        }
+
+        @Override
+        public String toString() {
+            return super.toString()+"["+getDescription()+"]";
+        }
+    }
+
     /**
      * A poll handler that takes the result of the <tt>typeperf</tt> invocation and sets the appropriate sensors.
      */
-    private static class SendPerfCountersToSensors implements PollHandler<SshPollValue> {
+    private static class SendPerfCountersToSensors2 implements PollHandler<SshPollValue> {
 
         private static final Set<? extends Class<? extends Number>> INTEGER_TYPES
                 = ImmutableSet.of(Integer.class, Long.class, Byte.class, Short.class, BigInteger.class);
@@ -262,7 +330,7 @@ public class WindowsPerformanceCounterFeed extends AbstractFeed {
         private final EntityLocal entity;
         private final SortedMap<String, AttributeSensor> sensorMap;
 
-        public SendPerfCountersToSensors(EntityLocal entity, Set<WindowsPerformanceCounterPollConfig<?>> polls) {
+        public SendPerfCountersToSensors2(EntityLocal entity, List<WindowsPerformanceCounterPollConfig<?>> polls) {
             this.entity = entity;
             
             sensorMap = Maps.newTreeMap();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fbb4ce9c/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterPollConfig.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterPollConfig.java b/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterPollConfig.java
index a5d2abd..77681ea 100644
--- a/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterPollConfig.java
+++ b/core/src/main/java/brooklyn/event/feed/windows/WindowsPerformanceCounterPollConfig.java
@@ -31,6 +31,7 @@ public class WindowsPerformanceCounterPollConfig<T> extends PollConfig<Object, T
     @SuppressWarnings({ "unchecked", "rawtypes" })
     public WindowsPerformanceCounterPollConfig(AttributeSensor<T> sensor) {
         super(sensor);
+        description(sensor.getDescription());
         onSuccess((Function)Functions.identity());
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fbb4ce9c/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessWinRmDriver.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessWinRmDriver.java b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessWinRmDriver.java
index a5c91db..4e66180 100644
--- a/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessWinRmDriver.java
+++ b/software/base/src/main/java/brooklyn/entity/basic/VanillaWindowsProcessWinRmDriver.java
@@ -19,7 +19,6 @@
 package brooklyn.entity.basic;
 
 import brooklyn.location.basic.WinRmMachineLocation;
-import brooklyn.util.time.Duration;
 
 public class VanillaWindowsProcessWinRmDriver extends AbstractSoftwareProcessWinRmDriver implements VanillaWindowsProcessDriver {
 
@@ -47,7 +46,7 @@ public class VanillaWindowsProcessWinRmDriver extends AbstractSoftwareProcessWin
     @Override
     public boolean isRunning() {
         return executeCommand(VanillaWindowsProcess.CHECK_RUNNING_COMMAND,
-                VanillaWindowsProcess.CHECK_RUNNING_POWERSHELL_COMMAND, false);
+                VanillaWindowsProcess.CHECK_RUNNING_POWERSHELL_COMMAND, false).getStatusCode() == 0;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fbb4ce9c/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java b/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java
new file mode 100644
index 0000000..e36d285
--- /dev/null
+++ b/software/base/src/main/java/brooklyn/entity/software/winrm/WindowsPerformanceCounterSensors.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 brooklyn.entity.software.winrm;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.config.ConfigKey;
+import brooklyn.entity.basic.ConfigKeys;
+import brooklyn.entity.basic.EntityInternal;
+import brooklyn.entity.basic.EntityLocal;
+import brooklyn.entity.proxying.EntityInitializer;
+import brooklyn.event.basic.Sensors;
+import brooklyn.event.feed.windows.WindowsPerformanceCounterFeed;
+import brooklyn.util.config.ConfigBag;
+import brooklyn.util.text.Strings;
+
+import com.google.common.reflect.TypeToken;
+
+public class WindowsPerformanceCounterSensors implements EntityInitializer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(WindowsPerformanceCounterSensors.class);
+
+    public final static ConfigKey<Set<Map<String, String>>> PERFORMANCE_COUNTERS = ConfigKeys.newConfigKey(new TypeToken<Set<Map<String, String>>>(){}, "performance.counters");
+
+    protected final Set<Map<String, String>> sensors;
+
+    public WindowsPerformanceCounterSensors(ConfigBag params) {
+        sensors = params.get(PERFORMANCE_COUNTERS);
+    }
+
+    public WindowsPerformanceCounterSensors(Map<String, String> params) {
+        this(ConfigBag.newInstance(params));
+    }
+
+    @Override
+    public void apply(EntityLocal entity) {
+        WindowsPerformanceCounterFeed.Builder builder = WindowsPerformanceCounterFeed.builder()
+                .entity(entity);
+        for (Map<String, String> sensorConfig : sensors) {
+            String sensorType = sensorConfig.get("sensorType");
+            Class<?> clazz;
+            try {
+                clazz = Strings.isNonEmpty(sensorType) ?
+                ((EntityInternal)entity).getManagementContext().getCatalog().getRootClassLoader().loadClass(sensorType) : String.class;
+            } catch (ClassNotFoundException e) {
+                LOG.warn("Could not load type {} for sensor {}", sensorType, sensorConfig.get("name"));
+                clazz = String.class;
+            }
+            builder.addSensor(sensorConfig.get("counter"), Sensors.newSensor(clazz, sensorConfig.get("name"), sensorConfig.get("description")));
+        }
+        builder.build();
+    }
+
+}