You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by wu...@apache.org on 2018/03/31 07:17:23 UTC
[incubator-servicecomb-java-chassis] 05/07: SCB-384 provide perf
log publisher
This is an automated email from the ASF dual-hosted git repository.
wujimin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git
commit b0133c1715a149438ccc84855b7f045ffb19302d
Author: wujimin <wu...@huawei.com>
AuthorDate: Fri Mar 23 17:30:58 2018 +0800
SCB-384 provide perf log publisher
---
.../metrics/core/publish/DefaultLogPublisher.java | 170 ++++++++++++++++++
...rvicecomb.foundation.metrics.MetricsInitializer | 1 +
.../core/publish/TestDefaultLogPublisher.java | 191 +++++++++++++++++++++
3 files changed, 362 insertions(+)
diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/DefaultLogPublisher.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/DefaultLogPublisher.java
new file mode 100644
index 0000000..26a3815
--- /dev/null
+++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/DefaultLogPublisher.java
@@ -0,0 +1,170 @@
+/*
+ * 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.metrics.core.publish;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig;
+import org.apache.servicecomb.foundation.metrics.MetricsInitializer;
+import org.apache.servicecomb.foundation.metrics.PolledEvent;
+import org.apache.servicecomb.foundation.vertx.VertxUtils;
+import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst;
+import org.apache.servicecomb.metrics.core.publish.model.DefaultPublishModel;
+import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerf;
+import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroup;
+import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroups;
+import org.apache.servicecomb.metrics.core.publish.model.invocation.PerfInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.eventbus.EventBus;
+import com.google.common.eventbus.Subscribe;
+import com.netflix.config.DynamicPropertyFactory;
+import com.netflix.spectator.api.CompositeRegistry;
+import com.netflix.spectator.api.Meter;
+
+import io.vertx.core.impl.VertxImplEx;
+
+public class DefaultLogPublisher implements MetricsInitializer {
+ private static final Logger LOGGER = LoggerFactory.getLogger(DefaultLogPublisher.class);
+
+ public static final String ENABLED = "servicecomb.metrics.publisher.defaultLog.enabled";
+
+ @Override
+ public void init(CompositeRegistry globalRegistry, EventBus eventBus, MetricsBootstrapConfig config) {
+ if (!DynamicPropertyFactory.getInstance()
+ .getBooleanProperty(ENABLED, true)
+ .get()) {
+ return;
+ }
+
+ eventBus.register(this);
+ }
+
+ @Subscribe
+ public void onPolledEvent(PolledEvent event) {
+ try {
+ printLog(event.getMeters());
+ } catch (Throwable e) {
+ // make development easier
+ LOGGER.error("Failed to print perf log.", e);
+ }
+ }
+
+ protected void printLog(List<Meter> meters) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("\n");
+
+ printVertxMetrics(sb);
+
+ PublishModelFactory factory = new PublishModelFactory(meters);
+ DefaultPublishModel model = factory.createDefaultPublishModel();
+ printConsumerLog(model, sb);
+ printProducerLog(model, sb);
+
+ LOGGER.info(sb.toString());
+ }
+
+ protected void printConsumerLog(DefaultPublishModel model, StringBuilder sb) {
+ OperationPerfGroups consumerPerf = model.getConsumer().getOperationPerfGroups();
+ if (consumerPerf == null) {
+ return;
+ }
+
+ sb.append("consumer:\n");
+ printConsumerPerfLog(consumerPerf, sb);
+ }
+
+ protected void printConsumerPerfLog(OperationPerfGroups consumerPerf, StringBuilder sb) {
+ sb.append(" tps latency(ms) max-latency(ms) operation\n");
+ for (Map<String, OperationPerfGroup> statusMap : consumerPerf.getGroups().values()) {
+ for (OperationPerfGroup perfGroup : statusMap.values()) {
+ sb.append(" ")
+ .append(perfGroup.getTransport())
+ .append(".")
+ .append(perfGroup.getStatus())
+ .append(":\n");
+ for (OperationPerf operationPerf : perfGroup.getOperationPerfs()) {
+ printConsumerOperationPerf(operationPerf, sb);
+ }
+
+ printConsumerOperationPerf(perfGroup.getSummary(), sb);
+ }
+ }
+ }
+
+ protected void printConsumerOperationPerf(OperationPerf operationPerf, StringBuilder sb) {
+ PerfInfo stageTotal = operationPerf.findStage(MeterInvocationConst.STAGE_TOTAL);
+ sb.append(String.format(" %-7d %-11.3f %-15.3f %s\n",
+ stageTotal.getTps(),
+ stageTotal.calcMsLatency(),
+ stageTotal.getMsMaxLatency(),
+ operationPerf.getOperation()));
+ }
+
+ protected void printProducerLog(DefaultPublishModel model, StringBuilder sb) {
+ OperationPerfGroups producerPerf = model.getProducer().getOperationPerfGroups();
+ if (producerPerf == null) {
+ return;
+ }
+
+ sb.append("producer:\n");
+ sb.append(
+ " tps latency(ms) max-latency(ms) queue(ms) max-queue(ms) execute(ms) max-execute(ms) operation\n");
+ for (Map<String, OperationPerfGroup> statusMap : producerPerf.getGroups().values()) {
+ for (OperationPerfGroup perfGroup : statusMap.values()) {
+ sb.append(" ")
+ .append(perfGroup.getTransport())
+ .append(".")
+ .append(perfGroup.getStatus())
+ .append(":\n");
+ for (OperationPerf operationPerf : perfGroup.getOperationPerfs()) {
+ printProducerOperationPerf(operationPerf, sb);
+ }
+
+ printProducerOperationPerf(perfGroup.getSummary(), sb);
+ }
+ }
+ }
+
+ protected void printProducerOperationPerf(OperationPerf operationPerf, StringBuilder sb) {
+ PerfInfo stageTotal = operationPerf.findStage(MeterInvocationConst.STAGE_TOTAL);
+ PerfInfo stageQueue = operationPerf.findStage(MeterInvocationConst.STAGE_EXECUTOR_QUEUE);
+ PerfInfo stageExecution = operationPerf.findStage(MeterInvocationConst.STAGE_EXECUTION);
+ sb.append(String.format(" %-7d %-11.3f %-15.3f %-9.3f %-13.3f %-11.3f %-15.3f %s\n",
+ stageTotal.getTps(),
+ stageTotal.calcMsLatency(),
+ stageTotal.getMsMaxLatency(),
+ stageQueue.calcMsLatency(),
+ stageQueue.getMsMaxLatency(),
+ stageExecution.calcMsLatency(),
+ stageExecution.getMsMaxLatency(),
+ operationPerf.getOperation()));
+ }
+
+ protected void printVertxMetrics(StringBuilder sb) {
+ sb.append("vertx:\n")
+ .append(" name eventLoopContext-created\n");
+ for (Entry<String, VertxImplEx> entry : VertxUtils.getVertxMap().entrySet()) {
+ sb.append(String.format(" %-10s %d\n",
+ entry.getKey(),
+ entry.getValue().getEventLoopContextCreatedCount()));
+ }
+ }
+}
diff --git a/metrics/metrics-core/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer b/metrics/metrics-core/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer
index 2bf2069..2933349 100644
--- a/metrics/metrics-core/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer
+++ b/metrics/metrics-core/src/main/resources/META-INF/services/org.apache.servicecomb.foundation.metrics.MetricsInitializer
@@ -16,3 +16,4 @@
#
org.apache.servicecomb.metrics.core.DefaultMetricsInitializer
+org.apache.servicecomb.metrics.core.publish.DefaultLogPublisher
\ No newline at end of file
diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestDefaultLogPublisher.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestDefaultLogPublisher.java
new file mode 100644
index 0000000..056dd25
--- /dev/null
+++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/publish/TestDefaultLogPublisher.java
@@ -0,0 +1,191 @@
+/*
+ * 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.metrics.core.publish;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import javax.ws.rs.core.Response.Status;
+import javax.xml.ws.Holder;
+
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.servicecomb.core.Const;
+import org.apache.servicecomb.foundation.metrics.MetricsBootstrapConfig;
+import org.apache.servicecomb.foundation.metrics.PolledEvent;
+import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils;
+import org.apache.servicecomb.foundation.test.scaffolding.log.LogCollector;
+import org.apache.servicecomb.foundation.vertx.VertxUtils;
+import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst;
+import org.apache.servicecomb.metrics.core.publish.model.DefaultPublishModel;
+import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerf;
+import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroup;
+import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroups;
+import org.apache.servicecomb.metrics.core.publish.model.invocation.PerfInfo;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.eventbus.EventBus;
+import com.netflix.spectator.api.CompositeRegistry;
+
+import io.vertx.core.impl.VertxImplEx;
+import mockit.Expectations;
+import mockit.Mock;
+import mockit.MockUp;
+import mockit.Mocked;
+
+public class TestDefaultLogPublisher {
+ CompositeRegistry globalRegistry = null;
+
+ EventBus eventBus = new EventBus();
+
+ DefaultLogPublisher publisher = new DefaultLogPublisher();
+
+ LogCollector collector = new LogCollector();
+
+ @Before
+ public void setup() {
+
+ }
+
+ @After
+ public void teardown() {
+ collector.teardown();
+ ArchaiusUtils.resetConfig();
+ }
+
+ @Test
+ public void init_enabled_default() {
+ Holder<Boolean> registered = new Holder<>();
+ new MockUp<EventBus>(eventBus) {
+ @Mock
+ void register(Object object) {
+ registered.value = true;
+ }
+ };
+
+ publisher.init(globalRegistry, eventBus, new MetricsBootstrapConfig());
+ Assert.assertTrue(registered.value);
+ }
+
+ @Test
+ public void init_enabled_true() {
+ Holder<Boolean> registered = new Holder<>();
+ new MockUp<EventBus>(eventBus) {
+ @Mock
+ void register(Object object) {
+ registered.value = true;
+ }
+ };
+
+ ArchaiusUtils.setProperty(DefaultLogPublisher.ENABLED, true);
+
+ publisher.init(globalRegistry, eventBus, new MetricsBootstrapConfig());
+ Assert.assertTrue(registered.value);
+ }
+
+ @Test
+ public void init_enabled_false() {
+ Holder<Boolean> registered = new Holder<>();
+ new MockUp<EventBus>(eventBus) {
+ @Mock
+ void register(Object object) {
+ registered.value = true;
+ }
+ };
+
+ ArchaiusUtils.setProperty(DefaultLogPublisher.ENABLED, false);
+
+ publisher.init(globalRegistry, eventBus, new MetricsBootstrapConfig());
+ Assert.assertNull(registered.value);
+ }
+
+ @Test
+ public void onPolledEvent_failed() {
+ publisher.onPolledEvent(null);
+
+ LoggingEvent event = collector.getEvents().get(0);
+ Assert.assertEquals("Failed to print perf log.", event.getMessage());
+ Assert.assertEquals(NullPointerException.class, event.getThrowableInformation().getThrowable().getClass());
+ }
+
+ @Test
+ public void onPolledEvent(@Mocked VertxImplEx vertxImplEx) {
+ new Expectations(VertxUtils.class) {
+ {
+ VertxUtils.getVertxMap();
+ result = Collections.singletonMap("v", vertxImplEx);
+ vertxImplEx.getEventLoopContextCreatedCount();
+ result = 1;
+ }
+ };
+
+ DefaultPublishModel model = new DefaultPublishModel();
+
+ PerfInfo perfTotal = new PerfInfo();
+ perfTotal.setTps(10);
+ perfTotal.setMsTotalTime(100);
+
+ OperationPerf operationPerf = new OperationPerf();
+ operationPerf.setOperation("op");
+ operationPerf.getStages().put(MeterInvocationConst.STAGE_TOTAL, perfTotal);
+ operationPerf.getStages().put(MeterInvocationConst.STAGE_EXECUTOR_QUEUE, perfTotal);
+ operationPerf.getStages().put(MeterInvocationConst.STAGE_EXECUTION, perfTotal);
+
+ OperationPerfGroup operationPerfGroup = new OperationPerfGroup(Const.RESTFUL, Status.OK.name());
+ operationPerfGroup.addOperationPerf(operationPerf);
+
+ OperationPerfGroups operationPerfGroups = new OperationPerfGroups();
+ operationPerfGroups.getGroups().put(operationPerfGroup.getTransport(),
+ Collections.singletonMap(operationPerfGroup.getStatus(), operationPerfGroup));
+ model.getConsumer().setOperationPerfGroups(operationPerfGroups);
+ model.getProducer().setOperationPerfGroups(operationPerfGroups);
+
+ new MockUp<PublishModelFactory>() {
+ @Mock
+ DefaultPublishModel createDefaultPublishModel() {
+ return model;
+ }
+ };
+
+ publisher.onPolledEvent(new PolledEvent(Collections.emptyList()));
+
+ List<LoggingEvent> events = collector.getEvents().stream().filter(e -> {
+ return DefaultLogPublisher.class.getName().equals(e.getLoggerName());
+ }).collect(Collectors.toList());
+
+ LoggingEvent event = events.get(0);
+ Assert.assertEquals("\n" +
+ "vertx:\n" +
+ " name eventLoopContext-created\n" +
+ " v 1\n" +
+ "consumer:\n" +
+ " tps latency(ms) max-latency(ms) operation\n" +
+ " rest.OK:\n" +
+ " 10 10.000 0.000 op\n" +
+ " 10 10.000 0.000 \n" +
+ "producer:\n" +
+ " tps latency(ms) max-latency(ms) queue(ms) max-queue(ms) execute(ms) max-execute(ms) operation\n" +
+ " rest.OK:\n" +
+ " 10 10.000 0.000 10.000 0.000 10.000 0.000 op\n" +
+ " 10 10.000 0.000 10.000 0.000 10.000 0.000 \n" +
+ "",
+ event.getMessage());
+ }
+}
--
To stop receiving notification emails like this one, please contact
wujimin@apache.org.