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/servicecomb-java-chassis.git
commit 229b3c2d40ae595a881cd7835fcb1f60b925a226 Author: wujimin <wuji...@huawei.com> AuthorDate: Mon Nov 12 16:52:36 2018 +0800 [SCB-1021] publish vertx client/server meters to log --- demo/perf/src/main/resources/microservice.yaml | 6 +- .../test/scaffolding/log/LogCollector.java | 4 + .../AbstractMeasurementNodeLogPublisher.java | 40 +++++ .../metrics/core/publish/DefaultLogPublisher.java | 26 ++- .../core/publish/EndpointsLogPublisher.java | 78 +++++++++ .../metrics/core/publish/PublishModelFactory.java | 8 + .../metrics/core/TestVertxMetersInitializer.java | 174 +++++++++++++++++++++ 7 files changed, 332 insertions(+), 4 deletions(-) diff --git a/demo/perf/src/main/resources/microservice.yaml b/demo/perf/src/main/resources/microservice.yaml index ffa9c23..d460f19 100644 --- a/demo/perf/src/main/resources/microservice.yaml +++ b/demo/perf/src/main/resources/microservice.yaml @@ -38,10 +38,12 @@ servicecomb: client: thread-count: 8 references: - transport: rest + transport: highway metrics: window_time: 1000 - publisher.defaultLog.enabled: true + publisher.defaultLog: + enabled: true + endpoints.client.detail.enabled: true sync-count: 10 async-count: 20 diff --git a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/log/LogCollector.java b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/log/LogCollector.java index 53359e3..026408a 100644 --- a/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/log/LogCollector.java +++ b/foundations/foundation-test-scaffolding/src/main/java/org/apache/servicecomb/foundation/test/scaffolding/log/LogCollector.java @@ -61,4 +61,8 @@ public class LogCollector { public void teardown() { Logger.getRootLogger().removeAppender(appender); } + + public void clear() { + events = new ArrayList<>(); + } } diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/AbstractMeasurementNodeLogPublisher.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/AbstractMeasurementNodeLogPublisher.java new file mode 100644 index 0000000..960c7b6 --- /dev/null +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/AbstractMeasurementNodeLogPublisher.java @@ -0,0 +1,40 @@ +/* + * 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 org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; + +public abstract class AbstractMeasurementNodeLogPublisher { + protected StringBuilder sb; + + protected MeasurementNode measurementNode; + + private boolean exists; + + public AbstractMeasurementNodeLogPublisher(MeasurementTree tree, StringBuilder sb, String... childNames) { + this.sb = sb; + measurementNode = tree.findChild(childNames); + exists = measurementNode != null && !measurementNode.getMeasurements().isEmpty(); + } + + public boolean isExists() { + return exists; + } + + public abstract void print(boolean printDetail); +} 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 index 8259ff9..75a6642 100644 --- 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 @@ -30,6 +30,7 @@ import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNo import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; import org.apache.servicecomb.foundation.vertx.VertxUtils; +import org.apache.servicecomb.metrics.core.VertxMetersInitializer; import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst; import org.apache.servicecomb.metrics.core.meter.os.NetMeter; import org.apache.servicecomb.metrics.core.meter.os.OsMeter; @@ -54,6 +55,9 @@ public class DefaultLogPublisher implements MetricsInitializer { public static final String ENABLED = "servicecomb.metrics.publisher.defaultLog.enabled"; + // for a client, maybe will connect to too many endpoints, so default not print detail, just print summary + public static final String ENDPOINTS_CLIENT_DETAIL_ENABLED = "servicecomb.metrics.publisher.defaultLog.endpoints.client.detail.enabled"; + //sample private static final String SIMPLE_HEADER = "%s:\n simple:\n" + " status tps latency operation\n"; @@ -107,7 +111,7 @@ public class DefaultLogPublisher implements MetricsInitializer { DefaultPublishModel model = factory.createDefaultPublishModel(); printOsLog(factory.getTree(), sb); - printVertxMetrics(sb); + printVertxMetrics(factory.getTree(), sb); printThreadPoolMetrics(model, sb); printConsumerLog(model, sb); @@ -410,7 +414,7 @@ public class DefaultLogPublisher implements MetricsInitializer { return sb; } - protected void printVertxMetrics(StringBuilder sb) { + protected void printVertxMetrics(MeasurementTree tree, StringBuilder sb) { appendLine(sb, "vertx:"); appendLine(sb, " instances:"); @@ -420,6 +424,24 @@ public class DefaultLogPublisher implements MetricsInitializer { entry.getKey(), entry.getValue().getEventLoopContextCreatedCount()); } + + EndpointsLogPublisher client = new EndpointsLogPublisher(tree, sb, VertxMetersInitializer.ENDPOINTS_CLINET, + "client.endpoints", "remote"); + EndpointsLogPublisher server = new EndpointsLogPublisher(tree, sb, VertxMetersInitializer.ENDPOINTS_SERVER, + "server.endpoints", "listen"); + if (client.isExists() || server.isExists()) { + appendLine(sb, " transport:"); + if (client.isExists()) { + client.print(DynamicPropertyFactory + .getInstance() + .getBooleanProperty(ENDPOINTS_CLIENT_DETAIL_ENABLED, false) + .get()); + } + + if (server.isExists()) { + server.print(true); + } + } } private static String getDetailsFromPerf(PerfInfo perfInfo) { diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/EndpointsLogPublisher.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/EndpointsLogPublisher.java new file mode 100644 index 0000000..5fcf601 --- /dev/null +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/EndpointsLogPublisher.java @@ -0,0 +1,78 @@ +/* + * 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 static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.appendLine; + +import org.apache.servicecomb.foundation.common.net.NetUtils; +import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; +import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; +import org.apache.servicecomb.metrics.core.VertxMetersInitializer; +import org.apache.servicecomb.metrics.core.meter.vertx.EndpointMeter; + +public class EndpointsLogPublisher extends AbstractMeasurementNodeLogPublisher { + private final String title; + + private final String endpointTitle; + + public EndpointsLogPublisher(MeasurementTree tree, StringBuilder sb, String meterName, String title, + String endpointTitle) { + super(tree, sb, VertxMetersInitializer.VERTX_ENDPOINTS, meterName); + this.title = title; + this.endpointTitle = endpointTitle; + } + + @Override + public void print(boolean printDetail) { + appendLine(sb, " %s:", title); + appendLine(sb, " %-21s connectCount disconnectCount connections send receive", + endpointTitle); + + double connect = 0; + double disconnect = 0; + double connections = 0; + double readSize = 0; + double writeSize = 0; + for (MeasurementNode address : measurementNode.getChildren().values()) { + connect += address.findChild(EndpointMeter.CONNECT_COUNT).summary(); + disconnect += address.findChild(EndpointMeter.DISCONNECT_COUNT).summary(); + connections += address.findChild(EndpointMeter.CONNECTIONS).summary(); + readSize += address.findChild(EndpointMeter.BYTES_READ).summary(); + writeSize += address.findChild(EndpointMeter.BYTES_WRITTEN).summary(); + + if (printDetail) { + appendLine(sb, " %-21s %-15.0f %-15.0f %-15.0f %-12s %-12s", + address.getName(), + address.findChild(EndpointMeter.CONNECT_COUNT).summary(), + address.findChild(EndpointMeter.DISCONNECT_COUNT).summary(), + address.findChild(EndpointMeter.CONNECTIONS).summary(), + NetUtils.humanReadableBytes((long) address.findChild(EndpointMeter.BYTES_WRITTEN).summary()), + NetUtils.humanReadableBytes((long) address.findChild(EndpointMeter.BYTES_READ).summary()) + ); + } + } + + appendLine(sb, " %-21s %-15.0f %-15.0f %-15.0f %-12s %-12s", + "(summary)", + connect, + disconnect, + connections, + NetUtils.humanReadableBytes((long) writeSize), + NetUtils.humanReadableBytes((long) readSize) + ); + } +} diff --git a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishModelFactory.java b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishModelFactory.java index d12d0eb..9b94ba3 100644 --- a/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishModelFactory.java +++ b/metrics/metrics-core/src/main/java/org/apache/servicecomb/metrics/core/publish/PublishModelFactory.java @@ -22,9 +22,11 @@ import org.apache.servicecomb.foundation.metrics.publish.spectator.DefaultTagFin import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementGroupConfig; import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementNode; import org.apache.servicecomb.foundation.metrics.publish.spectator.MeasurementTree; +import org.apache.servicecomb.metrics.core.VertxMetersInitializer; import org.apache.servicecomb.metrics.core.meter.invocation.MeterInvocationConst; import org.apache.servicecomb.metrics.core.meter.os.NetMeter; import org.apache.servicecomb.metrics.core.meter.os.OsMeter; +import org.apache.servicecomb.metrics.core.meter.vertx.EndpointMeter; import org.apache.servicecomb.metrics.core.publish.model.DefaultPublishModel; import org.apache.servicecomb.metrics.core.publish.model.invocation.OperationPerfGroups; import org.apache.servicecomb.swagger.invocation.InvocationType; @@ -60,12 +62,18 @@ public class PublishModelFactory { MeterInvocationConst.TAG_STATUS, MeterInvocationConst.TAG_STAGE, MeterInvocationConst.TAG_STATISTIC); + //os config groupConfig.addGroup(OsMeter.OS_NAME, OsMeter.OS_TYPE, new DefaultTagFinder(NetMeter.INTERFACE, true), NetMeter.STATISTIC); + groupConfig.addGroup(VertxMetersInitializer.VERTX_ENDPOINTS, + VertxMetersInitializer.ENDPOINTS_TYPE, + EndpointMeter.ADDRESS, + EndpointMeter.STATISTIC); + return groupConfig; } diff --git a/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestVertxMetersInitializer.java b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestVertxMetersInitializer.java new file mode 100644 index 0000000..16c316c --- /dev/null +++ b/metrics/metrics-core/src/test/java/org/apache/servicecomb/metrics/core/TestVertxMetersInitializer.java @@ -0,0 +1,174 @@ +/* + * 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; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.servicecomb.core.transport.AbstractTransport; +import org.apache.servicecomb.core.transport.TransportVertxFactory; +import org.apache.servicecomb.foundation.metrics.PolledEvent; +import org.apache.servicecomb.foundation.metrics.registry.GlobalRegistry; +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.publish.DefaultLogPublisher; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.google.common.collect.Lists; +import com.google.common.eventbus.EventBus; +import com.netflix.spectator.api.DefaultRegistry; +import com.netflix.spectator.api.ManualClock; +import com.netflix.spectator.api.Measurement; +import com.netflix.spectator.api.Meter; +import com.netflix.spectator.api.Registry; + +import io.vertx.core.AbstractVerticle; +import io.vertx.core.DeploymentOptions; +import io.vertx.core.Future; +import io.vertx.core.http.HttpClient; +import io.vertx.core.http.HttpServer; +import io.vertx.ext.web.Router; +import mockit.Expectations; + +public class TestVertxMetersInitializer { + GlobalRegistry globalRegistry = new GlobalRegistry(new ManualClock()); + + Registry registry = new DefaultRegistry(globalRegistry.getClock()); + + EventBus eventBus = new EventBus(); + + TransportVertxFactory transportVertxFactory; + + VertxMetersInitializer vertxMetersInitializer = new VertxMetersInitializer(); + + DefaultLogPublisher logPublisher = new DefaultLogPublisher(); + + static int port; + + static String body = "body"; + + public static class TestServerVerticle extends AbstractVerticle { + @Override + public void start(Future<Void> startFuture) { + Router mainRouter = Router.router(vertx); + mainRouter.route("/").handler(context -> { + context.response().end(context.getBody()); + }); + + HttpServer server = vertx.createHttpServer(); + server.requestHandler(mainRouter::accept); + server.listen(0, "0.0.0.0", ar -> { + if (ar.succeeded()) { + port = ar.result().actualPort(); + startFuture.complete(); + return; + } + + startFuture.fail(ar.cause()); + }); + } + } + + public static class TestClientVerticle extends AbstractVerticle { + @Override + public void start(Future<Void> startFuture) { + HttpClient client = vertx.createHttpClient(); + client.post(port, "127.0.0.1", "/").handler(resp -> { + startFuture.complete(); + }).end(body); + } + } + + @Before + public void setup() { + VertxUtils.blockCloseVertxByName("transport"); + } + + @After + public void teardown() { + VertxUtils.blockCloseVertxByName("transport"); + } + + @Test + public void init() throws InterruptedException { + transportVertxFactory = new TransportVertxFactory(); + new Expectations(AbstractTransport.class) { + { + AbstractTransport.getTransportVertxFactory(); + result = transportVertxFactory; + } + }; + + globalRegistry.add(registry); + vertxMetersInitializer.init(globalRegistry, eventBus, null); + logPublisher.init(null, eventBus, null); + VertxUtils + .blockDeploy(transportVertxFactory.getTransportVertx(), TestServerVerticle.class, new DeploymentOptions()); + VertxUtils + .blockDeploy(transportVertxFactory.getTransportVertx(), TestClientVerticle.class, new DeploymentOptions()); + + globalRegistry.poll(1); + List<Meter> meters = Lists.newArrayList(registry.iterator()); + List<Measurement> measurements = new ArrayList<>(); + for (Meter meter : meters) { + meter.measure().forEach(measurements::add); + } + + LogCollector logCollector = new LogCollector(); + + testLog(logCollector, meters, measurements, true); + logCollector.clear(); + testLog(logCollector, meters, measurements, false); + + logCollector.teardown(); + } + + private void testLog(LogCollector logCollector, List<Meter> meters, List<Measurement> measurements, + boolean printDetail) { + ArchaiusUtils.setProperty(DefaultLogPublisher.ENDPOINTS_CLIENT_DETAIL_ENABLED, String.valueOf(printDetail)); + logPublisher.onPolledEvent(new PolledEvent(meters, measurements)); + + StringBuilder sb = new StringBuilder(); + logCollector.getEvents().forEach(event -> sb.append(event.getMessage()).append("\n")); + String actual = sb.toString(); + int idx = actual.indexOf("vertx:\n"); + actual = actual.substring(idx); + + String expect = "vertx:\n" + + " instances:\n" + + " name eventLoopContext-created\n" + + " transport 4\n" + + " transport:\n" + + " client.endpoints:\n" + + " remote connectCount disconnectCount connections send receive\n"; + if (printDetail) { + expect += String.format( + " 127.0.0.1:%-5s 1 0 1 4 B 21 B \n", + port); + } + expect += " (summary) 1 0 1 4 B 21 B \n" + + " server.endpoints:\n" + + " listen connectCount disconnectCount connections send receive\n" + + " 0.0.0.0:0 1 0 1 21 B 4 B \n" + + " (summary) 1 0 1 21 B 4 B \n\n"; + Assert.assertEquals(expect, actual); + } +}