diff --git a/Jenkinsfile b/Jenkinsfile index 102ec4f8c2cfbd114f60a8dd073ff781dfd170f6..86d4fa286cb6daa87f3ebf79c95c9badddf9f65c 100755 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -27,6 +27,10 @@ pipeline { skipStagesAfterUnstable() } + environment { + MAVEN_OPTS = '-Dmaven.repo.local=.m2/repository -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:-UseGCOverheadLimit -Xmx3g' + } + stages { stage('Install & Test') { parallel { diff --git a/Jenkinsfile-E2E b/Jenkinsfile-E2E index c2ec97b94b4ae3e4ff3778720143a66cac053026..9546fd93fd9d7b8c6aa5b1dfaad75082ec7a0858 100755 --- a/Jenkinsfile-E2E +++ b/Jenkinsfile-E2E @@ -26,7 +26,7 @@ pipeline { } environment { - MAVEN_OPTS = '-XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:-UseGCOverheadLimit -Xmx3g' + MAVEN_OPTS = '-Dmaven.repo.local=.m2/repository -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -XX:-UseGCOverheadLimit -Xmx3g' } stages { @@ -55,7 +55,7 @@ pipeline { stage('Compile Test Codes') { steps { - sh './mvnw -f test/e2e/pom.xml clean' + sh './mvnw -f test/e2e/pom.xml -pl e2e-base clean install' } } diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/logging/core/PatternLoggerTest.java b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/logging/core/PatternLoggerTest.java index f940b091265cc59f66d04937f6ea8f3b9ff4dfc0..842de0588c0f561f7f38684232a8f616c3c7b5b6 100644 --- a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/logging/core/PatternLoggerTest.java +++ b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/logging/core/PatternLoggerTest.java @@ -23,13 +23,11 @@ import com.google.common.collect.Lists; import org.apache.skywalking.apm.agent.core.conf.Config; import org.apache.skywalking.apm.agent.core.conf.Constants; import org.hamcrest.core.StringContains; -import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.mockito.Mockito; -import java.io.PrintStream; import java.util.List; import static org.mockito.Matchers.anyString; @@ -42,28 +40,20 @@ public class PatternLoggerTest { public static final String PATTERN = "%timestamp+0800 %level [%agent_name,,,] [%thread] %class:-1 %msg %throwable"; - private static PrintStream OUT_REF; - private static PrintStream ERR_REF; - @BeforeClass public static void initAndHoldOut() { - OUT_REF = System.out; - ERR_REF = System.err; Config.Agent.SERVICE_NAME = "testAppFromConfig"; } @Test public void testLog() { - PrintStream output = Mockito.mock(PrintStream.class); - System.setOut(output); - PrintStream err = Mockito.mock(PrintStream.class); - System.setErr(err); + final IWriter output = Mockito.mock(IWriter.class); PatternLogger logger = new PatternLogger(PatternLoggerTest.class, PATTERN) { @Override protected void logger(LogLevel level, String message, Throwable e) { String r = format(level, message, e); - SystemOutWriter.INSTANCE.write(r); + output.write(r); } }; @@ -84,19 +74,16 @@ public class PatternLoggerTest { logger.error(new NullPointerException(), "hello {}", "world"); Mockito.verify(output, times(9)) - .println(anyString()); + .write(anyString()); } @Test public void testLogWithSpecialChar() { - PrintStream output = Mockito.mock(PrintStream.class); - System.setOut(output); - PrintStream err = Mockito.mock(PrintStream.class); - System.setErr(err); + final IWriter output = Mockito.mock(IWriter.class); PatternLogger logger = new PatternLogger(PatternLoggerTest.class, PATTERN) { @Override protected void logger(LogLevel level, String message, Throwable e) { - SystemOutWriter.INSTANCE.write(format(level, message, e)); + output.write(format(level, message, e)); } }; @@ -117,7 +104,7 @@ public class PatternLoggerTest { logger.error(new NullPointerException(), "hello {}", "&&&**%%"); Mockito.verify(output, times(9)) - .println(anyString()); + .write(anyString()); } @Test @@ -156,10 +143,4 @@ public class PatternLoggerTest { } - @AfterClass - public static void reset() { - System.setOut(OUT_REF); - System.setErr(ERR_REF); - } - } diff --git a/docs/en/setup/backend/backend-setup.md b/docs/en/setup/backend/backend-setup.md index 335d5c45edea63038aa187821140fb91254e684c..9555fd1f01b9fae04408d2b5deb048e21f94f06d 100755 --- a/docs/en/setup/backend/backend-setup.md +++ b/docs/en/setup/backend/backend-setup.md @@ -83,6 +83,8 @@ system. set the expired time for each dimension. 1. [Dynamic Configuration](dynamic-config.md). Make configuration of OAP changed dynamic, from remote service or 3rd party configuration management system. +1. [Uninstrumented Gateways](uninstrumented-gateways.md). Configure gateways/proxies that are not supported by SkyWalking agent plugins, +to reflect the delegation in topology graph. ## Telemetry for backend OAP backend cluster itself underlying is a distributed streaming process system. For helping the Ops team, @@ -112,4 +114,4 @@ For example, metrics time will be formatted like YYYYMMDDHHmm in minute dimensio which format process is timezone related. In default, SkyWalking OAP backend choose the OS default timezone. -If you want to override it, please follow Java and OS documents to do so. \ No newline at end of file +If you want to override it, please follow Java and OS documents to do so. diff --git a/docs/en/setup/backend/dynamic-config.md b/docs/en/setup/backend/dynamic-config.md old mode 100644 new mode 100755 index 9aadb7cb8a62d1d8967476f9fd32c3cc0c71b407..fc9372b305ce389c98d5086daa1e7d377561ccd9 --- a/docs/en/setup/backend/dynamic-config.md +++ b/docs/en/setup/backend/dynamic-config.md @@ -7,6 +7,7 @@ Right now, SkyWalking supports following dynamic configurations. | Config Key | Value Description | Value Format Example | |:----:|:----:|:----:| |receiver-trace.default.slowDBAccessThreshold| Thresholds of slow Database statement, override `receiver-trace/default/slowDBAccessThreshold` of `applciation.yml`. | default:200,mongodb:50| +|receiver-trace.default.uninstrumentedGateways| The uninstrumented gateways, override `gateways.yml`. | not set | This feature depends on upstream service, so it is **OFF** as default. diff --git a/docs/en/setup/backend/uninstrumented-gateways.md b/docs/en/setup/backend/uninstrumented-gateways.md new file mode 100755 index 0000000000000000000000000000000000000000..b1be04cbc087809d0085490d79fa556391b83781 --- /dev/null +++ b/docs/en/setup/backend/uninstrumented-gateways.md @@ -0,0 +1,22 @@ +# Uninstrumented Gateways/Proxies + +The uninstrumented gateways are not instrumented by SkyWalking agent plugin when they are started, +but they can be configured in `gateways.yml` file or via [Dynamic Configuration](dynamic-config.md). The reason why they can't register +to backend automatically is that there're no suitable agent plugins, for example, there is no agent plugins for Nginx, haproxy, etc. +So in order to visualize the real topology, we provide a way to configure the gateways/proxies manually. + +## Configuration Format + +The configuration content includes the gateways' names and their instances: + +```yml +gateways: + - name: proxy0 # the name is not used for now + instances: + - host: 127.0.0.1 # the host/ip of this gateway instance + port: 9099 # the port of this gateway instance, defaults to 80 +``` + +**Note** that the `host` of the instance must be the one that is actually used in client side, for example, +if the instance `proxyA` has 2 IPs, say `192.168.1.110` and `192.168.1.111`, both of which delegates the target service, +and the client connects to `192.168.1.110`, then configuring `192.168.1.111` as the `host` won't work properly. diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/register/ServiceInventory.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/register/ServiceInventory.java index 5441cc137a90a73ab0c4a8fe6d0f49485ea68616..af910a3dad573a1c0eb143505f2e6afddb6b98d2 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/register/ServiceInventory.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/register/ServiceInventory.java @@ -58,6 +58,8 @@ public class ServiceInventory extends RegisterSource { @Getter(AccessLevel.PRIVATE) @Column(columnName = PROPERTIES) private String prop = Const.EMPTY_JSON_OBJECT_STRING; @Getter private JsonObject properties; + @Getter @Setter private boolean resetServiceMapping = false; + public NodeType getServiceNodeType() { return NodeType.get(this.nodeType); } @@ -119,6 +121,7 @@ public class ServiceInventory extends RegisterSource { inventory.setAddressId(addressId); inventory.setLastUpdateTime(getLastUpdateTime()); inventory.setMappingServiceId(mappingServiceId); + inventory.setResetServiceMapping(resetServiceMapping); inventory.setProp(prop); return inventory; @@ -150,6 +153,7 @@ public class ServiceInventory extends RegisterSource { remoteBuilder.addDataIntegers(addressId); remoteBuilder.addDataIntegers(mappingServiceId); remoteBuilder.addDataIntegers(nodeType); + remoteBuilder.addDataIntegers(resetServiceMapping ? 1 : 0); remoteBuilder.addDataLongs(getRegisterTime()); remoteBuilder.addDataLongs(getHeartbeatTime()); @@ -166,6 +170,7 @@ public class ServiceInventory extends RegisterSource { setAddressId(remoteData.getDataIntegers(2)); setMappingServiceId(remoteData.getDataIntegers(3)); setNodeType(remoteData.getDataIntegers(4)); + setResetServiceMapping(remoteData.getDataIntegers(5) == 1); setRegisterTime(remoteData.getDataLongs(0)); setHeartbeatTime(remoteData.getDataLongs(1)); @@ -186,8 +191,11 @@ public class ServiceInventory extends RegisterSource { if (serviceInventory.getLastUpdateTime() >= this.getLastUpdateTime()) { this.nodeType = serviceInventory.getNodeType(); + this.resetServiceMapping = serviceInventory.isResetServiceMapping(); setProp(serviceInventory.getProp()); - if (Const.NONE != serviceInventory.getMappingServiceId()) { + if (serviceInventory.isResetServiceMapping()) { + this.mappingServiceId = Const.NONE; + } else if (Const.NONE != serviceInventory.getMappingServiceId()) { this.mappingServiceId = serviceInventory.getMappingServiceId(); } isChanged = true; diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/register/service/IServiceInventoryRegister.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/register/service/IServiceInventoryRegister.java old mode 100644 new mode 100755 index 93fdc25debc4b3d0c111ee38ca15b955312d9159..3aba70732ca24da741b2be0553d23db2a0a8a831 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/register/service/IServiceInventoryRegister.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/register/service/IServiceInventoryRegister.java @@ -36,4 +36,16 @@ public interface IServiceInventoryRegister extends Service { void heartbeat(int serviceId, long heartBeatTime); void updateMapping(int serviceId, int mappingServiceId); + + /** + * Reset the {@link org.apache.skywalking.oap.server.core.register.ServiceInventory#mappingServiceId} + * of a given service id. + * + * There are cases when the mapping service id needs to be reset to {@code 0}, for example, when an + * uninstrumented gateway joins, the mapping service id of the services that are delegated by this gateway + * should be reset to {@code 0}, allowing the gateway to appear in the topology, see #3308 for more detail. + * + * @param serviceId id of the service whose mapping service id is to be reset + */ + void resetMapping(int serviceId); } diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/register/service/ServiceInventoryRegister.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/register/service/ServiceInventoryRegister.java index b5640b37d9eee2c2ac2a6a97c64dce224a862b75..8b276b23ba14759fead4340f58263994b5329399 100644 --- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/register/service/ServiceInventoryRegister.java +++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/register/service/ServiceInventoryRegister.java @@ -19,14 +19,18 @@ package org.apache.skywalking.oap.server.core.register.service; import com.google.gson.JsonObject; -import java.util.Objects; -import org.apache.skywalking.oap.server.core.*; +import org.apache.skywalking.oap.server.core.Const; +import org.apache.skywalking.oap.server.core.CoreModule; import org.apache.skywalking.oap.server.core.cache.ServiceInventoryCache; -import org.apache.skywalking.oap.server.core.register.*; +import org.apache.skywalking.oap.server.core.register.NodeType; +import org.apache.skywalking.oap.server.core.register.ServiceInventory; import org.apache.skywalking.oap.server.core.register.worker.InventoryStreamProcessor; import org.apache.skywalking.oap.server.library.module.ModuleDefineHolder; import org.apache.skywalking.oap.server.library.util.BooleanUtils; -import org.slf4j.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; import static java.util.Objects.isNull; @@ -132,6 +136,19 @@ public class ServiceInventoryRegister implements IServiceInventoryRegister { } } + @Override public void resetMapping(int serviceId) { + ServiceInventory serviceInventory = getServiceInventoryCache().get(serviceId); + if (Objects.nonNull(serviceInventory)) { + serviceInventory = serviceInventory.getClone(); + serviceInventory.setLastUpdateTime(System.currentTimeMillis()); + serviceInventory.setResetServiceMapping(true); + + InventoryStreamProcessor.getInstance().in(serviceInventory); + } else { + logger.warn("Service {} mapping update, but not found in storage.", serviceId); + } + } + private boolean compare(ServiceInventory newServiceInventory, NodeType nodeType) { if (Objects.nonNull(newServiceInventory)) { return nodeType.equals(newServiceInventory.getServiceNodeType()); diff --git a/oap-server/server-library/library-client/pom.xml b/oap-server/server-library/library-client/pom.xml old mode 100644 new mode 100755 index 28f019c9b83edf892c7a920439fafe8ddc7ceb16..faf65d09c7162c32648acaa279f9d51a728992ab --- a/oap-server/server-library/library-client/pom.xml +++ b/oap-server/server-library/library-client/pom.xml @@ -87,7 +87,7 @@ started - + single-node diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceModuleProvider.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceModuleProvider.java old mode 100644 new mode 100755 index a1502e3d9f99e4b9f883ad55def4ac5f6ac361d5..3890f9e00e246508e5b2707dc1a4ff9c1e94c5bd --- a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceModuleProvider.java +++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceModuleProvider.java @@ -18,23 +18,34 @@ package org.apache.skywalking.oap.server.receiver.trace.provider; -import java.io.IOException; -import org.apache.skywalking.oap.server.configuration.api.*; +import org.apache.skywalking.oap.server.configuration.api.ConfigurationModule; +import org.apache.skywalking.oap.server.configuration.api.DynamicConfigurationService; import org.apache.skywalking.oap.server.core.CoreModule; -import org.apache.skywalking.oap.server.core.server.*; -import org.apache.skywalking.oap.server.library.module.*; +import org.apache.skywalking.oap.server.core.server.GRPCHandlerRegister; +import org.apache.skywalking.oap.server.core.server.JettyHandlerRegister; +import org.apache.skywalking.oap.server.library.module.ModuleConfig; +import org.apache.skywalking.oap.server.library.module.ModuleDefine; +import org.apache.skywalking.oap.server.library.module.ModuleProvider; +import org.apache.skywalking.oap.server.library.module.ModuleStartException; +import org.apache.skywalking.oap.server.library.module.ServiceNotProvidedException; import org.apache.skywalking.oap.server.receiver.sharing.server.SharingServerModule; import org.apache.skywalking.oap.server.receiver.trace.module.TraceModule; import org.apache.skywalking.oap.server.receiver.trace.provider.handler.v5.grpc.TraceSegmentServiceHandler; import org.apache.skywalking.oap.server.receiver.trace.provider.handler.v5.rest.TraceSegmentServletHandler; import org.apache.skywalking.oap.server.receiver.trace.provider.handler.v6.grpc.TraceSegmentReportServiceHandler; -import org.apache.skywalking.oap.server.receiver.trace.provider.parser.*; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.ISegmentParserService; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SegmentParse; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SegmentParseV2; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SegmentParserListenerManager; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SegmentParserServiceImpl; import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.endpoint.MultiScopesSpanListener; import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.segment.SegmentSpanListener; import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.service.ServiceMappingSpanListener; import org.apache.skywalking.oap.server.receiver.trace.provider.parser.standardization.SegmentStandardizationWorker; import org.apache.skywalking.oap.server.telemetry.TelemetryModule; +import java.io.IOException; + /** * @author peng-yongsheng */ @@ -44,6 +55,7 @@ public class TraceModuleProvider extends ModuleProvider { private SegmentParse.Producer segmentProducer; private SegmentParseV2.Producer segmentProducerV2; private DBLatencyThresholdsAndWatcher thresholds; + private UninstrumentedGatewaysConfig uninstrumentedGatewaysConfig; public TraceModuleProvider() { this.moduleConfig = new TraceServiceModuleConfig(); @@ -64,7 +76,10 @@ public class TraceModuleProvider extends ModuleProvider { @Override public void prepare() throws ServiceNotProvidedException { thresholds = new DBLatencyThresholdsAndWatcher(moduleConfig.getSlowDBAccessThreshold(), this); + uninstrumentedGatewaysConfig = new UninstrumentedGatewaysConfig(this); + moduleConfig.setDbLatencyThresholdsAndWatcher(thresholds); + moduleConfig.setUninstrumentedGatewaysConfig(uninstrumentedGatewaysConfig); segmentProducer = new SegmentParse.Producer(getManager(), listenerManager(), moduleConfig); segmentProducerV2 = new SegmentParseV2.Producer(getManager(), listenerManager(), moduleConfig); @@ -89,6 +104,7 @@ public class TraceModuleProvider extends ModuleProvider { JettyHandlerRegister jettyHandlerRegister = getManager().find(SharingServerModule.NAME).provider().getService(JettyHandlerRegister.class); try { dynamicConfigurationService.registerConfigChangeWatcher(thresholds); + dynamicConfigurationService.registerConfigChangeWatcher(uninstrumentedGatewaysConfig); grpcHandlerRegister.addHandler(new TraceSegmentServiceHandler(segmentProducer)); grpcHandlerRegister.addHandler(new TraceSegmentReportServiceHandler(segmentProducerV2, getManager())); diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceServiceModuleConfig.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceServiceModuleConfig.java old mode 100644 new mode 100755 index b0ffbd6dcaa2231dd58b63221ca93a79e6ae228c..49d3c1bb1860a88a997ab51fd0ea78e9d1468557 --- a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceServiceModuleConfig.java +++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/TraceServiceModuleConfig.java @@ -39,6 +39,7 @@ public class TraceServiceModuleConfig extends ModuleConfig { */ @Setter @Getter private String slowDBAccessThreshold = "default:200"; @Setter @Getter private DBLatencyThresholdsAndWatcher dbLatencyThresholdsAndWatcher; + @Setter @Getter private UninstrumentedGatewaysConfig uninstrumentedGatewaysConfig; /** * Analysis trace status. * diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/UninstrumentedGatewaysConfig.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/UninstrumentedGatewaysConfig.java new file mode 100755 index 0000000000000000000000000000000000000000..5ed2b56b1746f3f369efbf3d2233232f613804f4 --- /dev/null +++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/UninstrumentedGatewaysConfig.java @@ -0,0 +1,159 @@ +/* + * 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.skywalking.oap.server.receiver.trace.provider; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; +import org.apache.skywalking.oap.server.configuration.api.ConfigChangeWatcher; +import org.apache.skywalking.oap.server.core.Const; +import org.apache.skywalking.oap.server.library.util.ResourceUtils; +import org.apache.skywalking.oap.server.receiver.trace.module.TraceModule; +import org.yaml.snakeyaml.Yaml; + +import java.io.FileNotFoundException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static java.util.Objects.isNull; + +/** + * @author kezhenxu94 + */ +@Slf4j +public class UninstrumentedGatewaysConfig extends ConfigChangeWatcher { + private final AtomicReference settingsString; + private volatile Map gatewayInstanceKeyedByAddress = Collections.emptyMap(); + + UninstrumentedGatewaysConfig(TraceModuleProvider provider) { + super(TraceModule.NAME, provider, "uninstrumentedGateways"); + this.settingsString = new AtomicReference<>(Const.EMPTY_STRING); + final GatewayInfos defaultGateways = parseGatewaysFromFile("gateways.yml"); + log.info("Default configured gateways: {}", defaultGateways); + onGatewaysUpdated(defaultGateways); + } + + private void activeSetting(String config) { + if (log.isDebugEnabled()) { + log.debug("Updating using new static config: {}", config); + } + this.settingsString.set(config); + onGatewaysUpdated(parseGatewaysFromYml(config)); + } + + @Override + public void notify(ConfigChangeEvent value) { + if (EventType.DELETE.equals(value.getEventType())) { + activeSetting(""); + } else { + activeSetting(value.getNewValue()); + } + } + + @Override + public String value() { + return settingsString.get(); + } + + private void onGatewaysUpdated(final GatewayInfos gateways) { + log.info("Updating uninstrumented gateways with: {}", gateways); + if (isNull(gateways)) { + gatewayInstanceKeyedByAddress = Collections.emptyMap(); + } else { + gatewayInstanceKeyedByAddress = + StreamSupport.stream(gateways.spliterator(), false) + .flatMap(instance -> instance.getInstances().stream()) + .collect(Collectors.toMap(GatewayInstanceInfo::getAddress, Function.identity())); + } + } + + public boolean isAddressConfiguredAsGateway(final String address) { + final boolean isConfiguredAsGateway = gatewayInstanceKeyedByAddress.get(address) != null; + if (log.isDebugEnabled()) { + log.debug("Address [{}] is configured as gateway: {}", address, isConfiguredAsGateway); + } + return isConfiguredAsGateway; + } + + private GatewayInfos parseGatewaysFromFile(final String file) { + try { + final Reader reader = ResourceUtils.read(file); + return new Yaml().loadAs(reader, GatewayInfos.class); + } catch (FileNotFoundException e) { + log.error("Cannot load gateways from: {}", file, e); + } + return GatewayInfos.EMPTY; + } + + private GatewayInfos parseGatewaysFromYml(final String ymlContent) { + try { + return new Yaml().loadAs(ymlContent, GatewayInfos.class); + } catch (Exception e) { + log.error("Failed to parse yml content as gateways: \n{}", ymlContent, e); + } + return GatewayInfos.EMPTY; + } + + @Getter + @Setter + @ToString + public static class GatewayInfo { + private String name; + private List instances; + } + + @ToString + public static class GatewayInfos implements Iterable { + static final GatewayInfos EMPTY = new GatewayInfos(); + + @Getter + @Setter + private Collection gateways; + + GatewayInfos() { + gateways = new ArrayList<>(); + } + + @Override + public Iterator iterator() { + return gateways.iterator(); + } + } + + @Getter + @Setter + @ToString + public static class GatewayInstanceInfo { + private String host; + private Integer port; + + String getAddress() { + return getHost() + ":" + (isNull(getPort()) || getPort() <= 0 ? "80" : getPort()); + } + } +} diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/endpoint/MultiScopesSpanListener.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/endpoint/MultiScopesSpanListener.java old mode 100644 new mode 100755 index be6077d3b044d38346d3a39f2274a1c7e0882732..5fd0af120b7884729d1b11465004bd3350e0736a --- a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/endpoint/MultiScopesSpanListener.java +++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/endpoint/MultiScopesSpanListener.java @@ -18,20 +18,31 @@ package org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.endpoint; -import java.util.*; import org.apache.skywalking.apm.network.common.KeyStringValuePair; import org.apache.skywalking.apm.network.language.agent.*; import org.apache.skywalking.apm.util.StringUtil; import org.apache.skywalking.oap.server.core.*; +import org.apache.skywalking.oap.server.core.analysis.TimeBucket; import org.apache.skywalking.oap.server.core.cache.*; import org.apache.skywalking.oap.server.core.source.*; import org.apache.skywalking.oap.server.library.module.ModuleManager; -import org.apache.skywalking.oap.server.core.analysis.TimeBucket; -import org.apache.skywalking.oap.server.receiver.trace.provider.*; +import org.apache.skywalking.oap.server.receiver.trace.provider.DBLatencyThresholdsAndWatcher; +import org.apache.skywalking.oap.server.receiver.trace.provider.TraceServiceModuleConfig; import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SpanTags; -import org.apache.skywalking.oap.server.receiver.trace.provider.parser.decorator.*; -import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.*; -import org.slf4j.*; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.decorator.ReferenceDecorator; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.decorator.SegmentCoreInfo; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.decorator.SpanDecorator; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.EntrySpanListener; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.ExitSpanListener; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.GlobalTraceIdsListener; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.SpanListener; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.SpanListenerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; import static java.util.Objects.nonNull; @@ -57,6 +68,7 @@ public class MultiScopesSpanListener implements EntrySpanListener, ExitSpanListe private final List exitSourceBuilders; private final List slowDatabaseAccesses; private final TraceServiceModuleConfig config; + private final NetworkAddressInventoryCache networkAddressInventoryCache; private SpanDecorator entrySpanDecorator; private long minuteTimeBucket; private String traceId; @@ -69,6 +81,7 @@ public class MultiScopesSpanListener implements EntrySpanListener, ExitSpanListe this.instanceInventoryCache = moduleManager.find(CoreModule.NAME).provider().getService(ServiceInstanceInventoryCache.class); this.serviceInventoryCache = moduleManager.find(CoreModule.NAME).provider().getService(ServiceInventoryCache.class); this.endpointInventoryCache = moduleManager.find(CoreModule.NAME).provider().getService(EndpointInventoryCache.class); + this.networkAddressInventoryCache = moduleManager.find(CoreModule.NAME).provider().getService(NetworkAddressInventoryCache.class); this.config = config; this.traceId = null; } @@ -87,9 +100,12 @@ public class MultiScopesSpanListener implements EntrySpanListener, ExitSpanListe SourceBuilder sourceBuilder = new SourceBuilder(); sourceBuilder.setSourceEndpointId(reference.getParentEndpointId()); - if (spanDecorator.getSpanLayer().equals(SpanLayer.MQ)) { - int serviceIdByPeerId = serviceInventoryCache.getServiceId(reference.getNetworkAddressId()); - int instanceIdByPeerId = instanceInventoryCache.getServiceInstanceId(serviceIdByPeerId, reference.getNetworkAddressId()); + final int networkAddressId = reference.getNetworkAddressId(); + final int serviceIdByPeerId = serviceInventoryCache.getServiceId(networkAddressId); + final String address = networkAddressInventoryCache.get(networkAddressId).getName(); + + if (spanDecorator.getSpanLayer().equals(SpanLayer.MQ) || config.getUninstrumentedGatewaysConfig().isAddressConfiguredAsGateway(address)) { + int instanceIdByPeerId = instanceInventoryCache.getServiceInstanceId(serviceIdByPeerId, networkAddressId); sourceBuilder.setSourceServiceInstanceId(instanceIdByPeerId); sourceBuilder.setSourceServiceId(serviceIdByPeerId); } else { diff --git a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/service/ServiceMappingSpanListener.java b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/service/ServiceMappingSpanListener.java old mode 100644 new mode 100755 index 338a1cd82af68c059c8eaba15e558afa7ed71051..7010b8815a813417cd4661476d041c6e83f82c7d --- a/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/service/ServiceMappingSpanListener.java +++ b/oap-server/server-receiver-plugin/skywalking-trace-receiver-plugin/src/main/java/org/apache/skywalking/oap/server/receiver/trace/provider/parser/listener/service/ServiceMappingSpanListener.java @@ -18,17 +18,25 @@ package org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.service; -import java.util.*; -import lombok.*; +import lombok.Getter; +import lombok.Setter; import org.apache.skywalking.apm.network.language.agent.SpanLayer; import org.apache.skywalking.oap.server.core.CoreModule; +import org.apache.skywalking.oap.server.core.cache.NetworkAddressInventoryCache; import org.apache.skywalking.oap.server.core.cache.ServiceInventoryCache; import org.apache.skywalking.oap.server.core.register.service.IServiceInventoryRegister; import org.apache.skywalking.oap.server.library.module.ModuleManager; import org.apache.skywalking.oap.server.receiver.trace.provider.TraceServiceModuleConfig; -import org.apache.skywalking.oap.server.receiver.trace.provider.parser.decorator.*; -import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.*; -import org.slf4j.*; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.decorator.SegmentCoreInfo; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.decorator.SpanDecorator; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.EntrySpanListener; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.SpanListener; +import org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener.SpanListenerFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.LinkedList; +import java.util.List; /** * @author peng-yongsheng @@ -38,12 +46,17 @@ public class ServiceMappingSpanListener implements EntrySpanListener { private static final Logger logger = LoggerFactory.getLogger(ServiceMappingSpanListener.class); private final IServiceInventoryRegister serviceInventoryRegister; + private final TraceServiceModuleConfig config; private final ServiceInventoryCache serviceInventoryCache; - private List serviceMappings = new LinkedList<>(); + private final NetworkAddressInventoryCache networkAddressInventoryCache; + private final List serviceMappings = new LinkedList<>(); + private final List servicesToResetMapping = new LinkedList<>(); - private ServiceMappingSpanListener(ModuleManager moduleManager) { + private ServiceMappingSpanListener(ModuleManager moduleManager, TraceServiceModuleConfig config) { this.serviceInventoryCache = moduleManager.find(CoreModule.NAME).provider().getService(ServiceInventoryCache.class); + this.networkAddressInventoryCache = moduleManager.find(CoreModule.NAME).provider().getService(NetworkAddressInventoryCache.class); this.serviceInventoryRegister = moduleManager.find(CoreModule.NAME).provider().getService(IServiceInventoryRegister.class); + this.config = config; } @Override public boolean containsPoint(Point point) { @@ -58,9 +71,16 @@ public class ServiceMappingSpanListener implements EntrySpanListener { if (!spanDecorator.getSpanLayer().equals(SpanLayer.MQ)) { if (spanDecorator.getRefsCount() > 0) { for (int i = 0; i < spanDecorator.getRefsCount(); i++) { - int serviceId = serviceInventoryCache.getServiceId(spanDecorator.getRefs(i).getNetworkAddressId()); - int mappingServiceId = serviceInventoryCache.get(serviceId).getMappingServiceId(); - if (mappingServiceId != segmentCoreInfo.getServiceId()) { + int networkAddressId = spanDecorator.getRefs(i).getNetworkAddressId(); + String address = networkAddressInventoryCache.get(networkAddressId).getName(); + int serviceId = serviceInventoryCache.getServiceId(networkAddressId); + + if (config.getUninstrumentedGatewaysConfig().isAddressConfiguredAsGateway(address)) { + if (logger.isDebugEnabled()) { + logger.debug("{} is configured as gateway, will reset its mapping service id", serviceId); + } + servicesToResetMapping.add(serviceId); + } else { ServiceMapping serviceMapping = new ServiceMapping(); serviceMapping.setServiceId(serviceId); serviceMapping.setMappingServiceId(segmentCoreInfo.getServiceId()); @@ -78,18 +98,24 @@ public class ServiceMappingSpanListener implements EntrySpanListener { } serviceInventoryRegister.updateMapping(serviceMapping.getServiceId(), serviceMapping.getMappingServiceId()); }); + servicesToResetMapping.forEach(serviceId -> { + if (logger.isDebugEnabled()) { + logger.debug("service mapping listener build, reset mapping of service id: {}", serviceId); + } + serviceInventoryRegister.resetMapping(serviceId); + }); } public static class Factory implements SpanListenerFactory { @Override public SpanListener create(ModuleManager moduleManager, TraceServiceModuleConfig config) { - return new ServiceMappingSpanListener(moduleManager); + return new ServiceMappingSpanListener(moduleManager, config); } } @Setter @Getter - private class ServiceMapping { + private static class ServiceMapping { private int serviceId; private int mappingServiceId; } diff --git a/oap-server/server-receiver-plugin/zipkin-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/zipkin/analysis/transform/SpringSleuthSegmentBuilderTest.java b/oap-server/server-receiver-plugin/zipkin-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/zipkin/analysis/transform/SpringSleuthSegmentBuilderTest.java index 96e51ca9737d6a9d00959e5b9bbdd88db949f00b..b4ecf2ee0ea6a4495cdba720f3e9d92d45da1bad 100644 --- a/oap-server/server-receiver-plugin/zipkin-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/zipkin/analysis/transform/SpringSleuthSegmentBuilderTest.java +++ b/oap-server/server-receiver-plugin/zipkin-receiver-plugin/src/test/java/org/apache/skywalking/oap/server/receiver/zipkin/analysis/transform/SpringSleuthSegmentBuilderTest.java @@ -78,6 +78,9 @@ public class SpringSleuthSegmentBuilderTest implements SegmentListener { } + @Override public void resetMapping(final int serviceId) { + + } }; IServiceInstanceInventoryRegister instanceIDService = new IServiceInstanceInventoryRegister() { @@ -193,4 +196,4 @@ public class SpringSleuthSegmentBuilderTest implements SegmentListener { Assert.assertEquals(-1, spanObject.getParentSpanId()); Assert.assertEquals(SpanType.Entry, spanObject.getSpanType()); } -} \ No newline at end of file +} diff --git a/oap-server/server-starter/src/main/assembly/assembly.xml b/oap-server/server-starter/src/main/assembly/assembly.xml old mode 100644 new mode 100755 diff --git a/oap-server/server-starter/src/main/assembly/gateways.yml b/oap-server/server-starter/src/main/assembly/gateways.yml new file mode 100755 index 0000000000000000000000000000000000000000..9b501a7d6bd3a2e1f30a273948cd325dc5d5d132 --- /dev/null +++ b/oap-server/server-starter/src/main/assembly/gateways.yml @@ -0,0 +1,20 @@ +# 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. + +#gateways: +# - name: proxy0 +# instances: +# - host: 127.0.0.1 # the host/ip of this gateway instance +# port: 9099 # the port of this gateway instance, defaults to 80 diff --git a/pom.xml b/pom.xml index e7df6278aea7c7ae51e1ac011cb4e73ff0a2c005..6aaf68414dfc088af6948b1095019618bf6860cc 100755 --- a/pom.xml +++ b/pom.xml @@ -424,6 +424,8 @@ .mvn/wrapper/maven-wrapper.properties tools/dependencies/known-oap-backend-dependencies.txt apm-checkstyle/CHECKSTYLE_HEAD + + .m2/** diff --git a/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/TestController.java b/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/TestController.java index c59f3d315f693e6d2cb9dd674be51f33944b3989..a50088b4138750b1c5a3b63d59704db94f8e9426 100644 --- a/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/TestController.java +++ b/test/e2e/e2e-cluster/consumer/src/main/java/org/apache/skywalking/e2e/cluster/TestController.java @@ -43,7 +43,7 @@ public class TestController { public User createAuthor(@RequestBody final User user) throws InterruptedException { Thread.sleep(1000L); final ResponseEntity response = restTemplate.postForEntity( - "http://localhost:9090/e2e/users", user, User.class + "http://127.0.0.1:9099/e2e/users", user, User.class ); return response.getBody(); } diff --git a/test/e2e/e2e-cluster/gateway/pom.xml b/test/e2e/e2e-cluster/gateway/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..afc8ff353a5478851bb8bd454df3630aec748599 --- /dev/null +++ b/test/e2e/e2e-cluster/gateway/pom.xml @@ -0,0 +1,65 @@ + + + + + + e2e-cluster + org.apache.skywalking + 1.0.0 + + 4.0.0 + + gateway + + + + org.springframework.boot + spring-boot-starter-web + ${spring.boot.version} + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + ${spring.cloud.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.version} + + true + true + true + + + + + repackage + + + + + + + diff --git a/test/e2e/e2e-cluster/gateway/src/main/java/org/apache/skywalking/e2e/GatewayApplication.java b/test/e2e/e2e-cluster/gateway/src/main/java/org/apache/skywalking/e2e/GatewayApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..a4e4311f2c550c8bbdc0e93d31e7240e65946a63 --- /dev/null +++ b/test/e2e/e2e-cluster/gateway/src/main/java/org/apache/skywalking/e2e/GatewayApplication.java @@ -0,0 +1,33 @@ +/* + * 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.skywalking.e2e; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; + +/** + * @author kezhenxu94 + */ +@EnableZuulProxy +@SpringBootApplication +public class GatewayApplication { + public static void main(String[] args) { + SpringApplication.run(GatewayApplication.class, args); + } +} diff --git a/test/e2e/e2e-cluster/gateway/src/main/resources/application.yml b/test/e2e/e2e-cluster/gateway/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..32131fc57e5af1dd5ade61254ecf4b5d0550249f --- /dev/null +++ b/test/e2e/e2e-cluster/gateway/src/main/resources/application.yml @@ -0,0 +1,28 @@ +# 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. + +server: + port: 9099 + +spring: + application: + name: SkyWalking + +zuul: + ignoredServices: '*' + routes: + api: + path: /e2e/users + url: http://127.0.0.1:9090 diff --git a/test/e2e/e2e-cluster/pom.xml b/test/e2e/e2e-cluster/pom.xml index 757863d453c34f8c3117eda541de8a2577daa106..f9c4895549f29d4bec93616a658476d8c85547e1 100644 --- a/test/e2e/e2e-cluster/pom.xml +++ b/test/e2e/e2e-cluster/pom.xml @@ -33,6 +33,7 @@ provider consumer + gateway test-runner diff --git a/test/e2e/e2e-cluster/test-runner/pom.xml b/test/e2e/e2e-cluster/test-runner/pom.xml index af90ce315fed2b8da6d0d7143c296a10518fdf1c..38c7d36b1585729fb18d1a3e9f17f54a0bbe10e0 100755 --- a/test/e2e/e2e-cluster/test-runner/pom.xml +++ b/test/e2e/e2e-cluster/test-runner/pom.xml @@ -38,6 +38,12 @@ ${project.version} + + org.apache.skywalking + gateway + ${project.version} + + org.apache.skywalking provider @@ -53,8 +59,9 @@ - provider - consumer + provider + consumer + gateway 1.1 skywalking-e2e-container-${build.id}-cluster @@ -99,7 +106,7 @@ binding to port - + @@ -117,22 +124,22 @@ - ${service0.name}-${project.version}.jar + ${provider.name}-${project.version}.jar -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 - -DSW_AGENT_NAME=${service0.name} + -DSW_AGENT_NAME=${provider.name} --server.port=9090 - ${service1.name}-${project.version}.jar + ${consumer.name}-${project.version}.jar -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11801 - -DSW_AGENT_NAME=${service1.name} + -DSW_AGENT_NAME=${consumer.name} --server.port=9091 @@ -156,10 +163,13 @@ ../../../../dist-for-cluster/apache-skywalking-apm-bin:/sw - ../${service0.name}/target/${service0.name}-${project.version}.jar:/home/${service0.name}-${project.version}.jar + ../${gateway.name}/target/${gateway.name}-${project.version}.jar:/home/${gateway.name}-${project.version}.jar + + + ../${provider.name}/target/${provider.name}-${project.version}.jar:/home/${provider.name}-${project.version}.jar - ../${service1.name}/target/${service1.name}-${project.version}.jar:/home/${service1.name}-${project.version}.jar + ../${consumer.name}/target/${consumer.name}-${project.version}.jar:/home/${consumer.name}-${project.version}.jar ${project.basedir}/src/docker/rc.d:/rc.d:ro @@ -171,7 +181,7 @@ SkyWalking e2e container is ready for tests - + diff --git a/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc0-prepare.sh b/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc0-prepare.sh index 5baf02b512a68c6e89de100556e7f228e909b523..45331e2ed79beb156f7a39cec46b24ec13030b78 100755 --- a/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc0-prepare.sh +++ b/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc0-prepare.sh @@ -22,7 +22,17 @@ if test "${MODE}" = "cluster"; then # substitute application.yml to be capable of cluster mode cd ${SW_HOME}/config \ && awk -f /clusterize.awk application.yml > clusterized_app.yml \ - && mv clusterized_app.yml application.yml + && mv clusterized_app.yml application.yml \ + && echo ' +gateways: + - name: proxy0 + instances: + - host: 127.0.0.1 # the host/ip of this gateway instance + port: 9099 # the port of this gateway instance, defaults to 80 +' > gateways.yml \ + && sed '//a\ + \n' log4j2.xml > log4j2debuggable.xml \ + && mv log4j2debuggable.xml log4j2.xml cd ${SW_HOME}/webapp \ && awk '/^\s+listOfServers:/ {gsub("listOfServers:.*", "listOfServers: 127.0.0.1:12800,127.0.0.1:12801", $0)} {print}' webapp.yml > clusterized_webapp.yml \ diff --git a/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc1-startup.sh b/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc1-startup.sh index 06576f29694564f3b6109ea68f68faea63324d60..ee78788d24b1f1e1b9dcdffe5620c5dd5e5d2a60 100755 --- a/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc1-startup.sh +++ b/test/e2e/e2e-cluster/test-runner/src/docker/rc.d/rc1-startup.sh @@ -16,12 +16,27 @@ #!/usr/bin/env bash +echo 'starting gateway service...' \ + && java -jar /home/gateway-1.0.0.jar 2>&1 > /tmp/gateway.log & + +check_tcp 127.0.0.1 \ + 9099 \ + 60 \ + 10 \ + 'waiting for the gateway service to be ready' + +if [[ $? -ne 0 ]]; then + echo "gateway service failed to start in 60 * 10 seconds: " + cat /tmp/gateway.log + exit 1 +fi + echo 'starting OAP server...' \ && SW_STORAGE_ES_BULK_ACTIONS=1 \ - && SW_STORAGE_ES_FLUSH_INTERVAL=1 \ - && SW_RECEIVER_BUFFER_PATH=/tmp/oap/trace_buffer1 \ - && SW_SERVICE_MESH_BUFFER_PATH=/tmp/oap/mesh_buffer1 \ - && start_oap 'init' + SW_STORAGE_ES_FLUSH_INTERVAL=1 \ + SW_RECEIVER_BUFFER_PATH=/tmp/oap/trace_buffer1 \ + SW_SERVICE_MESH_BUFFER_PATH=/tmp/oap/mesh_buffer1 \ + start_oap 'init' echo 'starting Web app...' \ && start_webapp '0.0.0.0' 8081 @@ -30,12 +45,12 @@ if test "${MODE}" = "cluster"; then # start another OAP server in a different port echo 'starting OAP server...' \ && SW_CORE_GRPC_PORT=11801 \ - && SW_CORE_REST_PORT=12801 \ - && SW_STORAGE_ES_BULK_ACTIONS=1 \ - && SW_STORAGE_ES_FLUSH_INTERVAL=1 \ - && SW_RECEIVER_BUFFER_PATH=/tmp/oap/trace_buffer2 \ - && SW_SERVICE_MESH_BUFFER_PATH=/tmp/oap/mesh_buffer2 \ - && start_oap 'no-init' + SW_CORE_REST_PORT=12801 \ + SW_STORAGE_ES_BULK_ACTIONS=1 \ + SW_STORAGE_ES_FLUSH_INTERVAL=1 \ + SW_RECEIVER_BUFFER_PATH=/tmp/oap/trace_buffer2 \ + SW_SERVICE_MESH_BUFFER_PATH=/tmp/oap/mesh_buffer2 \ + start_oap 'no-init' fi echo 'starting instrumented services...' && start_instrumented_services diff --git a/test/e2e/e2e-cluster/test-runner/src/test/java/org/apache/skywalking/e2e/ClusterVerificationITCase.java b/test/e2e/e2e-cluster/test-runner/src/test/java/org/apache/skywalking/e2e/ClusterVerificationITCase.java old mode 100644 new mode 100755 index f4e84ae7d4b54152132c09d3b3635a1374abb478..668f3048d3260b477561592252db6badf058df8a --- a/test/e2e/e2e-cluster/test-runner/src/test/java/org/apache/skywalking/e2e/ClusterVerificationITCase.java +++ b/test/e2e/e2e-cluster/test-runner/src/test/java/org/apache/skywalking/e2e/ClusterVerificationITCase.java @@ -45,7 +45,6 @@ import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -61,10 +60,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_ENDPOINT_METRICS; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_INSTANCE_METRICS; -import static org.apache.skywalking.e2e.metrics.MetricsQuery.ALL_SERVICE_METRICS; -import static org.assertj.core.api.Assertions.assertThat; +import static org.apache.skywalking.e2e.metrics.MetricsQuery.*; /** * @author kezhenxu94 @@ -118,18 +114,29 @@ public class ClusterVerificationITCase { } private void verifyTopo(LocalDateTime minutesAgo) throws Exception { - final TopoData topoData = queryClient.topo( - new TopoQuery() - .stepByMinute() - .start(minutesAgo) - .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) - ); - - InputStream expectedInputStream = - new ClassPathResource("expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.topo.yml").getInputStream(); - - final TopoMatcher topoMatcher = yaml.loadAs(expectedInputStream, TopoMatcher.class); - topoMatcher.verify(topoData); + boolean valid = false; + while (!valid) { + try { + final TopoData topoData = queryClient.topo( + new TopoQuery() + .stepByMinute() + .start(minutesAgo) + .end(LocalDateTime.now(ZoneOffset.UTC).plusMinutes(1)) + ); + LOGGER.info("Actual topology: {}", topoData); + + InputStream expectedInputStream = + new ClassPathResource("expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.topo.yml").getInputStream(); + + final TopoMatcher topoMatcher = yaml.loadAs(expectedInputStream, TopoMatcher.class); + topoMatcher.verify(topoData); + valid = true; + } catch (Throwable t) { + LOGGER.warn(t.getMessage(), t); + generateTraffic(); + Thread.sleep(retryInterval); + } + } } private void verifyServices(LocalDateTime minutesAgo) throws Exception { @@ -333,14 +340,17 @@ public class ClusterVerificationITCase { } private void generateTraffic() { - final Map user = new HashMap<>(); - user.put("name", "SkyWalking"); - final ResponseEntity responseEntity = restTemplate.postForEntity( - instrumentedServiceUrl + "/e2e/users", - user, - String.class - ); - LOGGER.info("responseEntity: {}, {}", responseEntity.getStatusCode(), responseEntity.getBody()); - assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); + try { + final Map user = new HashMap<>(); + user.put("name", "SkyWalking"); + final ResponseEntity responseEntity = restTemplate.postForEntity( + instrumentedServiceUrl + "/e2e/users", + user, + String.class + ); + LOGGER.info("responseEntity: {}, {}", responseEntity.getStatusCode(), responseEntity.getBody()); + } catch (Throwable t) { + LOGGER.warn(t.getMessage(), t); + } } } diff --git a/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.topo.yml b/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.topo.yml index 9f74cfce6a420901a0890eae24bb82ca2f4d3f78..8f58605cf42613853ffaf15fd83eff6a7268a4b6 100644 --- a/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.topo.yml +++ b/test/e2e/e2e-cluster/test-runner/src/test/resources/expected-data/org.apache.skywalking.e2e.ClusterVerificationITCase.topo.yml @@ -27,6 +27,9 @@ nodes: - id: not null name: "localhost:-1" type: H2 + - id: not null + name: "127.0.0.1:9099" + type: Unknown calls: - id: not null source: not null @@ -37,3 +40,6 @@ calls: - id: not null source: not null target: not null + - id: not null + source: not null + target: not null diff --git a/test/e2e/pom.xml b/test/e2e/pom.xml index 7017c88aa009df436737d3beaa993ba7bde223f3..21a3ffe029b2f7a0053f3c52992f15fc6f367f5f 100644 --- a/test/e2e/pom.xml +++ b/test/e2e/pom.xml @@ -46,6 +46,7 @@ UTF-8 2.1.5.RELEASE + 2.1.2.RELEASE 2.9.7 4.12 2.9.7