You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2018/03/15 11:08:49 UTC
[incubator-servicecomb-java-chassis] 02/03: SCB-369 extract
informations from spectator measurement,
just like sql: select * from meters group by ......,
but output is a tree not a table
This is an automated email from the ASF dual-hosted git repository.
liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git
commit b081e2902528d89c7f14bb1e09a6aed7c0bd54b6
Author: wujimin <wu...@huawei.com>
AuthorDate: Wed Mar 7 16:57:05 2018 +0800
SCB-369 extract informations from spectator measurement, just like sql: select * from meters group by ......, but output is a tree not a table
---
.../publish/spectator/MeasurementGroupConfig.java | 48 ++++++++++++
.../metrics/publish/spectator/MeasurementNode.java | 85 ++++++++++++++++++++++
.../metrics/publish/spectator/MeasurementTree.java | 67 +++++++++++++++++
.../spectator/TestMeasurementGroupConfig.java | 72 ++++++++++++++++++
.../publish/spectator/TestMeasurementNode.java | 82 +++++++++++++++++++++
.../publish/spectator/TestMeasurementTree.java | 84 +++++++++++++++++++++
6 files changed, 438 insertions(+)
diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementGroupConfig.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementGroupConfig.java
new file mode 100644
index 0000000..48075fc
--- /dev/null
+++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementGroupConfig.java
@@ -0,0 +1,48 @@
+/*
+ * 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 org.apache.servicecomb.foundation.metrics.publish.spectator;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class MeasurementGroupConfig {
+ // key is measurement id name
+ private Map<String, List<TagFinder>> groups = new HashMap<>();
+
+ public MeasurementGroupConfig() {
+ }
+
+ public MeasurementGroupConfig(String idName, Object... tagNameOrFinders) {
+ addGroup(idName, tagNameOrFinders);
+ }
+
+ public void addGroup(String idName, Object... tagNameOrFinders) {
+ groups.put(idName,
+ Arrays
+ .asList(tagNameOrFinders)
+ .stream()
+ .map(r -> TagFinder.build(r))
+ .collect(Collectors.toList()));
+ }
+
+ public List<TagFinder> findTagFinders(String idName) {
+ return groups.get(idName);
+ }
+}
diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementNode.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementNode.java
new file mode 100644
index 0000000..2d82113
--- /dev/null
+++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementNode.java
@@ -0,0 +1,85 @@
+/*
+ * 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 org.apache.servicecomb.foundation.metrics.publish.spectator;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.netflix.spectator.api.Measurement;
+
+public class MeasurementNode {
+ private String name;
+
+ private List<Measurement> measurements = new ArrayList<>();
+
+ private Map<String, MeasurementNode> children;
+
+ public MeasurementNode(String name, Map<String, MeasurementNode> children) {
+ this.name = name;
+ this.children = children;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Map<String, MeasurementNode> getChildren() {
+ return children;
+ }
+
+ public MeasurementNode findChild(String childName) {
+ if (children == null) {
+ return null;
+ }
+ return children.get(childName);
+ }
+
+ public MeasurementNode findChild(String... childNames) {
+ MeasurementNode node = this;
+ for (String childName : childNames) {
+ if (node == null) {
+ return null;
+ }
+
+ node = node.findChild(childName);
+ }
+ return node;
+ }
+
+ public MeasurementNode addChild(String childName, Measurement measurement) {
+ if (children == null) {
+ children = new HashMap<>();
+ }
+
+ MeasurementNode node = children.computeIfAbsent(childName, name -> {
+ return new MeasurementNode(name, null);
+ });
+ node.addMeasurement(measurement);
+
+ return node;
+ }
+
+ public List<Measurement> getMeasurements() {
+ return measurements;
+ }
+
+ public void addMeasurement(Measurement measurement) {
+ measurements.add(measurement);
+ }
+}
diff --git a/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementTree.java b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementTree.java
new file mode 100644
index 0000000..056bba6
--- /dev/null
+++ b/foundations/foundation-metrics/src/main/java/org/apache/servicecomb/foundation/metrics/publish/spectator/MeasurementTree.java
@@ -0,0 +1,67 @@
+/*
+ * 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 org.apache.servicecomb.foundation.metrics.publish.spectator;
+
+import java.util.Iterator;
+import java.util.List;
+
+import com.netflix.spectator.api.Id;
+import com.netflix.spectator.api.Measurement;
+import com.netflix.spectator.api.Meter;
+import com.netflix.spectator.api.Tag;
+
+// like select * from meters group by ......
+// but output a tree not a table
+public class MeasurementTree extends MeasurementNode {
+ public MeasurementTree() {
+ super(null, null);
+ }
+
+ // groupConfig:
+ // key: id name
+ // value: id tag keys
+ // only id name exists in groupConfig will accept, others will be ignored
+ public void from(Iterator<Meter> meters, MeasurementGroupConfig groupConfig) {
+ meters.forEachRemaining(meter -> {
+ Iterable<Measurement> measurements = meter.measure();
+ from(measurements, groupConfig);
+ });
+ }
+
+ public void from(Iterable<Measurement> measurements, MeasurementGroupConfig groupConfig) {
+ for (Measurement measurement : measurements) {
+ Id id = measurement.id();
+ List<TagFinder> tagFinders = groupConfig.findTagFinders(id.name());
+ if (tagFinders == null) {
+ continue;
+ }
+
+ MeasurementNode node = addChild(id.name(), measurement);
+ for (TagFinder tagFinder : tagFinders) {
+ Tag tag = tagFinder.find(id.tags());
+ if (tag == null) {
+ throw new IllegalStateException(
+ String.format("tag key \"%s\" not exist in %s",
+ tagFinder.getTagKey(),
+ measurement));
+ }
+
+ node = node.addChild(tag.value(), measurement);
+ }
+ }
+ }
+}
diff --git a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementGroupConfig.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementGroupConfig.java
new file mode 100644
index 0000000..51b6a56
--- /dev/null
+++ b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementGroupConfig.java
@@ -0,0 +1,72 @@
+/*
+ * 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 org.apache.servicecomb.foundation.metrics.publish.spectator;
+
+import java.util.List;
+import java.util.Map;
+
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Test;
+
+import mockit.Deencapsulation;
+
+public class TestMeasurementGroupConfig {
+ MeasurementGroupConfig config = new MeasurementGroupConfig();
+
+ Map<String, List<TagFinder>> groups = Deencapsulation.getField(config, "groups");
+
+ @Test
+ public void defaultConstruct() {
+ Assert.assertTrue(groups.isEmpty());
+ }
+
+ @Test
+ public void constructAddGroup() {
+ config = new MeasurementGroupConfig("id", "tag1");
+ groups = Deencapsulation.getField(config, "groups");
+
+ Assert.assertThat(groups.keySet(), Matchers.contains("id"));
+ Assert.assertThat(groups.get("id").stream().map(e -> {
+ return e.getTagKey();
+ }).toArray(), Matchers.arrayContaining("tag1"));
+ }
+
+ @Test
+ public void addGroup() {
+ config.addGroup("id1", "tag1.1", "tag1.2");
+ config.addGroup("id2", "tag2.1", "tag2.2");
+
+ Assert.assertThat(groups.keySet(), Matchers.contains("id2", "id1"));
+ Assert.assertThat(groups.get("id1").stream().map(e -> {
+ return e.getTagKey();
+ }).toArray(), Matchers.arrayContaining("tag1.1", "tag1.2"));
+ Assert.assertThat(groups.get("id2").stream().map(e -> {
+ return e.getTagKey();
+ }).toArray(), Matchers.arrayContaining("tag2.1", "tag2.2"));
+ }
+
+ @Test
+ public void findTagReaders() {
+ config.addGroup("id1", "tag1.1", "tag1.2");
+ config.addGroup("id2", "tag2.1", "tag2.2");
+
+ Assert.assertThat(config.findTagFinders("id2").stream().map(e -> {
+ return e.getTagKey();
+ }).toArray(), Matchers.arrayContaining("tag2.1", "tag2.2"));
+ }
+}
diff --git a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementNode.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementNode.java
new file mode 100644
index 0000000..cf55e56
--- /dev/null
+++ b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementNode.java
@@ -0,0 +1,82 @@
+/*
+ * 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 org.apache.servicecomb.foundation.metrics.publish.spectator;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.netflix.spectator.api.Measurement;
+
+import mockit.Mocked;
+
+public class TestMeasurementNode {
+ MeasurementNode node = new MeasurementNode("name", null);
+
+ @Test
+ public void getName() {
+ Assert.assertEquals("name", node.getName());
+ }
+
+ @Test
+ public void getChildren() {
+ Map<String, MeasurementNode> children = new HashMap<>();
+ node = new MeasurementNode("name", children);
+
+ Assert.assertSame(children, node.getChildren());
+ }
+
+ @Test
+ public void findChild_noChildren() {
+ Assert.assertNull(node.findChild("child"));
+ }
+
+ @Test
+ public void findChild_multiLevel_noMiddleChildren(@Mocked Measurement measurement) {
+ MeasurementNode c1 = node.addChild("c1", measurement);
+ c1.addChild("c2", measurement);
+
+ Assert.assertNull(node.findChild("c1_notExist", "c2"));
+ }
+
+ @Test
+ public void findChild_multiLevel_ok(@Mocked Measurement measurement) {
+ MeasurementNode c1 = node.addChild("c1", measurement);
+ MeasurementNode c2 = c1.addChild("c2", measurement);
+
+ Assert.assertSame(c2, node.findChild("c1", "c2"));
+ }
+
+ @Test
+ public void addChild(@Mocked Measurement measurement) {
+ MeasurementNode c1 = node.addChild("c1", measurement);
+ MeasurementNode c2 = node.addChild("c2", measurement);
+
+ Assert.assertSame(c1, node.findChild("c1"));
+ Assert.assertSame(c2, node.findChild("c2"));
+ }
+
+ @Test
+ public void getMeasurements(@Mocked Measurement measurement) {
+ node.addMeasurement(measurement);
+
+ Assert.assertThat(node.getMeasurements(), Matchers.contains(measurement));
+ }
+}
diff --git a/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementTree.java b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementTree.java
new file mode 100644
index 0000000..a3eb50d
--- /dev/null
+++ b/foundations/foundation-metrics/src/test/java/org/apache/servicecomb/foundation/metrics/publish/spectator/TestMeasurementTree.java
@@ -0,0 +1,84 @@
+/*
+ * 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 org.apache.servicecomb.foundation.metrics.publish.spectator;
+
+import java.util.concurrent.TimeUnit;
+
+import org.hamcrest.Matchers;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.netflix.spectator.api.DefaultRegistry;
+import com.netflix.spectator.api.ManualClock;
+import com.netflix.spectator.api.Registry;
+import com.netflix.spectator.api.Statistic;
+import com.netflix.spectator.api.Timer;
+
+public class TestMeasurementTree {
+ MeasurementTree tree = new MeasurementTree();
+
+ ManualClock clock = new ManualClock();
+
+ Registry registry = new DefaultRegistry(clock);
+
+ Timer timer;
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Before
+ public void setup() {
+ timer = registry.timer("id",
+ "g1",
+ "g1v",
+ "g2",
+ "g2v",
+ "t3",
+ "t3v",
+ "t4",
+ "t4v");
+ registry.counter("id_notCare");
+ }
+
+ @Test
+ public void from() {
+ timer.record(10, TimeUnit.NANOSECONDS);
+ timer.record(2, TimeUnit.NANOSECONDS);
+
+ MeasurementGroupConfig config = new MeasurementGroupConfig("id", "g1", "g2", Statistic.count.key());
+ tree.from(registry.iterator(), config);
+
+ Assert.assertEquals(1, tree.getChildren().size());
+
+ MeasurementNode node = tree.findChild("id", "g1v", "g2v");
+ Assert.assertEquals(2d, node.findChild(Statistic.count.value()).getMeasurements().get(0).value(), 0);
+ Assert.assertEquals(12d, node.findChild(Statistic.totalTime.value()).getMeasurements().get(0).value(), 0);
+ }
+
+ @Test
+ public void from_failed() {
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage(Matchers
+ .is("tag key \"notExist\" not exist in Measurement(id:g1=g1v:g2=g2v:statistic=count:t3=t3v:t4=t4v,0,0.0)"));
+
+ MeasurementGroupConfig config = new MeasurementGroupConfig("id", "notExist");
+ tree.from(registry.iterator(), config);
+ }
+}
--
To stop receiving notification emails like this one, please contact
liubao@apache.org.