Support `logic-endpoint` series tag(s). (#4985)
* Support `logic-endpoint` series tag(s). * Enhance the plugin dev doc. * Update Java-Plugin-Development-Guide.md fix punctuation Co-authored-by: caoyixiong <32847163+IanCao@users.noreply.github.com>
This commit is contained in:
parent
31f42343f6
commit
a93f1b3c3c
|
|
@ -138,7 +138,7 @@ Create ExitSpan by operation name(e.g. service name, uri) and new **ContextCarri
|
|||
*/
|
||||
AbstractSpan setOperationName(String endpointName);
|
||||
```
|
||||
Besides set operation name, tags and logs, two attributes shoule be set, which are component and layer,
|
||||
Besides setting operation name, tags and logs, two attributes should be set, which are component and layer,
|
||||
especially for EntrySpan and ExitSpan
|
||||
|
||||
SpanLayer is the catalog of span. Here are 5 values:
|
||||
|
|
@ -151,6 +151,36 @@ SpanLayer is the catalog of span. Here are 5 values:
|
|||
Component IDs are defined and reserved by SkyWalking project.
|
||||
For component name/ID extension, please follow [Component library definition and extension](Component-library-settings.md) document.
|
||||
|
||||
### Special Span Tags
|
||||
All tags are available in the trace view, meanwhile,
|
||||
in the OAP backend analysis, some special tag or tag combination could provide other advanced features.
|
||||
|
||||
#### Tag key `status_code`
|
||||
The value should be an integer. The response code of OAL entities is according to this.
|
||||
|
||||
### Tag key `db.statement` and `db.type`.
|
||||
The value of `db.statement` should be a String, representing the Database statement, such as SQL, or `[No statement]/`+span#operationName if value is empty.
|
||||
When exit span has this tag, OAP samples the slow statements based on `receiver-trace/default/maxSlowSQLLength`.
|
||||
The threshold of slow statement is defined by following [`receiver-trace/default/slowDBAccessThreshold`](../setup/backend/slow-db-statement.md)
|
||||
|
||||
### Extension logic endpoint. Tag key `x-le`
|
||||
Logic endpoint is a concept, which doesn't represent a real RPC call, but requires the statistic.
|
||||
The value of `x-le` should be JSON format, with two options.
|
||||
1. Define a separated logic endpoint. Provide its own endpoint name, latency and status. Suitable for entry and local span.
|
||||
```json
|
||||
{
|
||||
"name": "GraphQL-service",
|
||||
"latency": 100,
|
||||
"status": true
|
||||
}
|
||||
```
|
||||
2. Declare the current local span representing a logic endpoint.
|
||||
```json
|
||||
{
|
||||
"logic-span": true
|
||||
}
|
||||
```
|
||||
|
||||
### Advanced APIs
|
||||
#### Async Span APIs
|
||||
There is a set of advanced APIs in Span, which work specific for async scenario. When tags, logs, attributes(including end time) of the span
|
||||
|
|
@ -345,6 +375,13 @@ public class URLInstrumentation extends ClassEnhancePluginDefine {
|
|||
**NOTICE**, doing bootstrap instrumentation should only happen in necessary, but mostly it effect the JRE core(rt.jar),
|
||||
and could make very unexpected result or side effect.
|
||||
|
||||
### Plugin Test Tool
|
||||
[Apache SkyWalking Agent Test Tool Suite](https://github.com/apache/skywalking-agent-test-tool)
|
||||
a tremendously useful test tools suite in a wide variety of languages of Agent. Includes mock collector and validator.
|
||||
The mock collector is a SkyWalking receiver, like OAP server.
|
||||
|
||||
You could learn how to use this tool to test the plugin in [this doc](Plugin-test.md). If you want to contribute plugins
|
||||
to SkyWalking official repo, this is required.
|
||||
|
||||
### Contribute plugins into Apache SkyWalking repository
|
||||
We are welcome everyone to contribute plugins.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,16 @@
|
|||
|
||||
package org.apache.skywalking.oap.server.core.source;
|
||||
|
||||
/**
|
||||
* RPC request type.
|
||||
*/
|
||||
public enum RequestType {
|
||||
DATABASE, HTTP, RPC, gRPC
|
||||
DATABASE,
|
||||
HTTP,
|
||||
RPC,
|
||||
gRPC,
|
||||
/**
|
||||
* Logic request only.
|
||||
*/
|
||||
LOGIC
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,32 @@
|
|||
|
||||
package org.apache.skywalking.oap.server.receiver.trace.provider.parser;
|
||||
|
||||
/**
|
||||
* Reserved keys of the span. The backend analysis the metrics according the existed tags.
|
||||
*/
|
||||
public class SpanTags {
|
||||
public static final String STATUS_CODE = "status_code";
|
||||
|
||||
public static final String DB_STATEMENT = "db.statement";
|
||||
|
||||
public static final String DB_TYPE = "db.type";
|
||||
|
||||
/**
|
||||
* Tag, x-le(extension logic endpoint) series tag. Value is JSON format.
|
||||
* <pre>
|
||||
* {
|
||||
* "name": "GraphQL-service",
|
||||
* "latency": 100,
|
||||
* "status": true
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Also, could use value to indicate this local span is representing a logic endpoint.
|
||||
* <pre>
|
||||
* {
|
||||
* "logic-span": true
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public static final String LOGIC_ENDPOINT = "x-le";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
package org.apache.skywalking.oap.server.receiver.trace.provider.parser.listener;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
|
@ -27,6 +29,7 @@ import org.apache.skywalking.apm.network.language.agent.v3.SegmentObject;
|
|||
import org.apache.skywalking.apm.network.language.agent.v3.SegmentReference;
|
||||
import org.apache.skywalking.apm.network.language.agent.v3.SpanLayer;
|
||||
import org.apache.skywalking.apm.network.language.agent.v3.SpanObject;
|
||||
import org.apache.skywalking.apm.network.language.agent.v3.SpanType;
|
||||
import org.apache.skywalking.apm.util.StringUtil;
|
||||
import org.apache.skywalking.oap.server.core.Const;
|
||||
import org.apache.skywalking.oap.server.core.CoreModule;
|
||||
|
|
@ -47,6 +50,8 @@ import org.apache.skywalking.oap.server.receiver.trace.provider.DBLatencyThresho
|
|||
import org.apache.skywalking.oap.server.receiver.trace.provider.TraceServiceModuleConfig;
|
||||
import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SpanTags;
|
||||
|
||||
import static org.apache.skywalking.oap.server.receiver.trace.provider.parser.SpanTags.LOGIC_ENDPOINT;
|
||||
|
||||
/**
|
||||
* MultiScopesSpanListener includes the most segment to source(s) logic.
|
||||
*
|
||||
|
|
@ -54,10 +59,12 @@ import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SpanTags;
|
|||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class MultiScopesAnalysisListener implements EntryAnalysisListener, ExitAnalysisListener {
|
||||
public class MultiScopesAnalysisListener implements EntryAnalysisListener, ExitAnalysisListener, LocalAnalysisListener {
|
||||
private final List<SourceBuilder> entrySourceBuilders = new ArrayList<>(10);
|
||||
private final List<SourceBuilder> exitSourceBuilders = new ArrayList<>(10);
|
||||
private final List<DatabaseSlowStatement> slowDatabaseAccesses = new ArrayList<>(10);
|
||||
private final List<SourceBuilder> logicEndpointBuilders = new ArrayList<>(10);
|
||||
private final Gson gson = new Gson();
|
||||
private final SourceReceiver sourceReceiver;
|
||||
private final TraceServiceModuleConfig config;
|
||||
private final NetworkAddressAliasCache networkAddressAliasCache;
|
||||
|
|
@ -65,7 +72,7 @@ public class MultiScopesAnalysisListener implements EntryAnalysisListener, ExitA
|
|||
|
||||
@Override
|
||||
public boolean containsPoint(Point point) {
|
||||
return Point.Entry.equals(point) || Point.Exit.equals(point);
|
||||
return Point.Entry.equals(point) || Point.Exit.equals(point) || Point.Local.equals(point);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -132,6 +139,8 @@ public class MultiScopesAnalysisListener implements EntryAnalysisListener, ExitA
|
|||
setPublicAttrs(sourceBuilder, span);
|
||||
entrySourceBuilders.add(sourceBuilder);
|
||||
}
|
||||
|
||||
parseLogicEndpoints(span, segmentObject);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -252,6 +261,11 @@ public class MultiScopesAnalysisListener implements EntryAnalysisListener, ExitA
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parseLocal(final SpanObject span, final SegmentObject segmentObject) {
|
||||
parseLogicEndpoints(span, segmentObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() {
|
||||
entrySourceBuilders.forEach(entrySourceBuilder -> {
|
||||
|
|
@ -292,6 +306,52 @@ public class MultiScopesAnalysisListener implements EntryAnalysisListener, ExitA
|
|||
});
|
||||
|
||||
slowDatabaseAccesses.forEach(sourceReceiver::receive);
|
||||
|
||||
logicEndpointBuilders.forEach(logicEndpointBuilder -> {
|
||||
sourceReceiver.receive(logicEndpointBuilder.toEndpoint());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Logic endpoint could be represent through an entry span or local span. It has special meaning from API
|
||||
* perspective. But it is an actual RPC call.
|
||||
*/
|
||||
private void parseLogicEndpoints(final SpanObject span, final SegmentObject segmentObject) {
|
||||
span.getTagsList().forEach(tag -> {
|
||||
switch (tag.getKey()) {
|
||||
case LOGIC_ENDPOINT:
|
||||
final JsonObject tagValue = gson.fromJson(tag.getValue(), JsonObject.class);
|
||||
final boolean isLocalSpan = SpanType.Local.equals(span.getSpanType());
|
||||
String logicEndpointName;
|
||||
int latency;
|
||||
boolean status;
|
||||
if (isLocalSpan && tagValue.has("logic-span") && tagValue.get("logic-span").getAsBoolean()) {
|
||||
logicEndpointName = span.getOperationName();
|
||||
latency = (int) (span.getEndTime() - span.getStartTime());
|
||||
status = !span.getIsError();
|
||||
} else if (tagValue.has("name") && tagValue.has("latency") && tagValue.has("status")) {
|
||||
logicEndpointName = tagValue.get("name").getAsString();
|
||||
latency = tagValue.get("latency").getAsInt();
|
||||
status = tagValue.get("status").getAsBoolean();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
SourceBuilder sourceBuilder = new SourceBuilder(namingControl);
|
||||
sourceBuilder.setTimeBucket(TimeBucket.getMinuteTimeBucket(span.getStartTime()));
|
||||
sourceBuilder.setDestServiceName(segmentObject.getService());
|
||||
sourceBuilder.setDestServiceInstanceName(segmentObject.getServiceInstance());
|
||||
sourceBuilder.setDestEndpointName(logicEndpointName);
|
||||
sourceBuilder.setDestNodeType(NodeType.Normal);
|
||||
sourceBuilder.setDetectPoint(DetectPoint.SERVER);
|
||||
sourceBuilder.setLatency(latency);
|
||||
sourceBuilder.setStatus(status);
|
||||
sourceBuilder.setType(RequestType.LOGIC);
|
||||
sourceBuilder.setResponseCode(Const.NONE);
|
||||
logicEndpointBuilders.add(sourceBuilder);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static class Factory implements AnalysisListenerFactory {
|
||||
|
|
|
|||
|
|
@ -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.skywalking.oap.server.receiver.trace.provider.parser.listener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.Getter;
|
||||
import org.apache.skywalking.oap.server.core.analysis.DispatcherDetectorListener;
|
||||
import org.apache.skywalking.oap.server.core.source.Source;
|
||||
import org.apache.skywalking.oap.server.core.source.SourceReceiver;
|
||||
|
||||
/**
|
||||
* Mock receiver for testing.
|
||||
*/
|
||||
public class MockReceiver implements SourceReceiver {
|
||||
@Getter
|
||||
private List<Source> receivedSources = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void receive(final Source source) {
|
||||
receivedSources.add(source);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
receivedSources.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DispatcherDetectorListener getDispatcherDetectorListener() {
|
||||
throw new UnsupportedOperationException("No getDispatcherDetectorListener in mock receiver.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,463 @@
|
|||
/*
|
||||
* 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.parser.listener;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import java.util.List;
|
||||
import org.apache.skywalking.apm.network.common.v3.KeyStringValuePair;
|
||||
import org.apache.skywalking.apm.network.language.agent.v3.RefType;
|
||||
import org.apache.skywalking.apm.network.language.agent.v3.SegmentObject;
|
||||
import org.apache.skywalking.apm.network.language.agent.v3.SegmentReference;
|
||||
import org.apache.skywalking.apm.network.language.agent.v3.SpanLayer;
|
||||
import org.apache.skywalking.apm.network.language.agent.v3.SpanObject;
|
||||
import org.apache.skywalking.apm.network.language.agent.v3.SpanType;
|
||||
import org.apache.skywalking.oap.server.core.Const;
|
||||
import org.apache.skywalking.oap.server.core.analysis.IDManager;
|
||||
import org.apache.skywalking.oap.server.core.analysis.NodeType;
|
||||
import org.apache.skywalking.oap.server.core.analysis.manual.networkalias.NetworkAddressAlias;
|
||||
import org.apache.skywalking.oap.server.core.cache.NetworkAddressAliasCache;
|
||||
import org.apache.skywalking.oap.server.core.config.NamingControl;
|
||||
import org.apache.skywalking.oap.server.core.config.group.EndpointNameGrouping;
|
||||
import org.apache.skywalking.oap.server.core.source.All;
|
||||
import org.apache.skywalking.oap.server.core.source.DatabaseAccess;
|
||||
import org.apache.skywalking.oap.server.core.source.Endpoint;
|
||||
import org.apache.skywalking.oap.server.core.source.EndpointRelation;
|
||||
import org.apache.skywalking.oap.server.core.source.Service;
|
||||
import org.apache.skywalking.oap.server.core.source.ServiceInstance;
|
||||
import org.apache.skywalking.oap.server.core.source.ServiceInstanceRelation;
|
||||
import org.apache.skywalking.oap.server.core.source.ServiceMeta;
|
||||
import org.apache.skywalking.oap.server.core.source.ServiceRelation;
|
||||
import org.apache.skywalking.oap.server.core.source.Source;
|
||||
import org.apache.skywalking.oap.server.receiver.trace.provider.TraceServiceModuleConfig;
|
||||
import org.apache.skywalking.oap.server.receiver.trace.provider.UninstrumentedGatewaysConfig;
|
||||
import org.apache.skywalking.oap.server.receiver.trace.provider.parser.SpanTags;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import static org.apache.skywalking.oap.server.receiver.trace.provider.parser.SpanTags.LOGIC_ENDPOINT;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* MultiScopesSpanListener includes the most segment to source(s) logic. This test covers most cases about the segment
|
||||
* to sources translation.
|
||||
*
|
||||
* This test is a good way to study about how OAP analysis trace segment.
|
||||
*/
|
||||
public class MultiScopesAnalysisListenerTest {
|
||||
@Mock
|
||||
private static TraceServiceModuleConfig CONFIG;
|
||||
@Mock
|
||||
private static NetworkAddressAliasCache CACHE;
|
||||
@Mock
|
||||
private static NetworkAddressAliasCache CACHE2;
|
||||
private static NamingControl NAMING_CONTROL = new NamingControl(
|
||||
70,
|
||||
100,
|
||||
100,
|
||||
new EndpointNameGrouping()
|
||||
);
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
when(CACHE.get(any())).thenReturn(null);
|
||||
final NetworkAddressAlias networkAddressAlias = new NetworkAddressAlias();
|
||||
final String serviceId = IDManager.ServiceID.buildId("target-service", true);
|
||||
final String instanceId = IDManager.ServiceInstanceID.buildId(serviceId, "target-instance");
|
||||
networkAddressAlias.setRepresentServiceId(serviceId);
|
||||
networkAddressAlias.setRepresentServiceInstanceId(instanceId);
|
||||
when(CACHE2.get(any())).thenReturn(networkAddressAlias);
|
||||
final UninstrumentedGatewaysConfig uninstrumentedGatewaysConfig = Mockito.mock(
|
||||
UninstrumentedGatewaysConfig.class);
|
||||
when(uninstrumentedGatewaysConfig.isAddressConfiguredAsGateway(any())).thenReturn(false);
|
||||
when(CONFIG.getUninstrumentedGatewaysConfig()).thenReturn(uninstrumentedGatewaysConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainsPoint() {
|
||||
MultiScopesAnalysisListener listener = new MultiScopesAnalysisListener(
|
||||
new MockReceiver(),
|
||||
CONFIG,
|
||||
CACHE,
|
||||
NAMING_CONTROL
|
||||
);
|
||||
Assert.assertTrue(listener.containsPoint(AnalysisListener.Point.Entry));
|
||||
Assert.assertTrue(listener.containsPoint(AnalysisListener.Point.Local));
|
||||
Assert.assertTrue(listener.containsPoint(AnalysisListener.Point.Exit));
|
||||
Assert.assertFalse(listener.containsPoint(AnalysisListener.Point.First));
|
||||
Assert.assertFalse(listener.containsPoint(AnalysisListener.Point.Segment));
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry span without ref, usually the first span of the whole trace.
|
||||
*/
|
||||
@Test
|
||||
public void testEntrySpanWithoutRef() {
|
||||
final MockReceiver mockReceiver = new MockReceiver();
|
||||
MultiScopesAnalysisListener listener = new MultiScopesAnalysisListener(
|
||||
mockReceiver,
|
||||
CONFIG,
|
||||
CACHE,
|
||||
NAMING_CONTROL
|
||||
);
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
SpanObject spanObject = SpanObject.newBuilder()
|
||||
.setOperationName("/springMVC")
|
||||
.setStartTime(startTime)
|
||||
.setEndTime(startTime + 1000L)
|
||||
.setIsError(true)
|
||||
.setSpanType(SpanType.Entry)
|
||||
.addTags(
|
||||
KeyStringValuePair.newBuilder()
|
||||
.setKey(SpanTags.STATUS_CODE)
|
||||
.setValue("500")
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
final SegmentObject segment = SegmentObject.newBuilder()
|
||||
.setService("mock-service")
|
||||
.setServiceInstance("mock-instance")
|
||||
.addSpans(spanObject)
|
||||
.build();
|
||||
listener.parseEntry(spanObject, segment);
|
||||
listener.build();
|
||||
|
||||
final List<Source> receivedSources = mockReceiver.getReceivedSources();
|
||||
Assert.assertEquals(7, receivedSources.size());
|
||||
final All all = (All) receivedSources.get(0);
|
||||
final Service service = (Service) receivedSources.get(1);
|
||||
final ServiceInstance serviceInstance = (ServiceInstance) receivedSources.get(2);
|
||||
final Endpoint endpoint = (Endpoint) receivedSources.get(3);
|
||||
final ServiceRelation serviceRelation = (ServiceRelation) receivedSources.get(4);
|
||||
final ServiceInstanceRelation serviceInstanceRelation = (ServiceInstanceRelation) receivedSources.get(5);
|
||||
final EndpointRelation endpointRelation = (EndpointRelation) receivedSources.get(6);
|
||||
Assert.assertEquals("mock-service", service.getName());
|
||||
Assert.assertEquals(500, service.getResponseCode());
|
||||
Assert.assertFalse(service.isStatus());
|
||||
Assert.assertEquals("mock-instance", serviceInstance.getName());
|
||||
Assert.assertEquals("/springMVC", endpoint.getName());
|
||||
Assert.assertEquals(Const.USER_SERVICE_NAME, serviceRelation.getSourceServiceName());
|
||||
Assert.assertEquals(service.getName(), serviceRelation.getDestServiceName());
|
||||
Assert.assertEquals(Const.USER_INSTANCE_NAME, serviceInstanceRelation.getSourceServiceInstanceName());
|
||||
Assert.assertEquals(serviceInstance.getName(), serviceInstanceRelation.getDestServiceInstanceName());
|
||||
Assert.assertEquals(Const.USER_ENDPOINT_NAME, endpointRelation.getEndpoint());
|
||||
Assert.assertEquals(endpoint.getName(), endpointRelation.getChildEndpoint());
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry span with ref, meaning the downstream has been instrumented.
|
||||
*/
|
||||
@Test
|
||||
public void testEntrySpanRef() {
|
||||
final MockReceiver mockReceiver = new MockReceiver();
|
||||
MultiScopesAnalysisListener listener = new MultiScopesAnalysisListener(
|
||||
mockReceiver,
|
||||
CONFIG,
|
||||
CACHE,
|
||||
NAMING_CONTROL
|
||||
);
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
SpanObject spanObject = SpanObject.newBuilder()
|
||||
.setOperationName("/springMVC")
|
||||
.setStartTime(startTime)
|
||||
.setEndTime(startTime + 1000L)
|
||||
.setIsError(true)
|
||||
.setSpanType(SpanType.Entry)
|
||||
.setSpanLayer(SpanLayer.RPCFramework)
|
||||
.addRefs(
|
||||
SegmentReference.newBuilder()
|
||||
.setRefType(RefType.CrossProcess)
|
||||
.setParentService("downstream-service")
|
||||
.setParentServiceInstance("downstream-instance")
|
||||
.setParentEndpoint("downstream-endpoint")
|
||||
.setNetworkAddressUsedAtPeer("127.0.0.1")
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
final SegmentObject segment = SegmentObject.newBuilder()
|
||||
.setService("mock-service")
|
||||
.setServiceInstance("mock-instance")
|
||||
.addSpans(spanObject)
|
||||
.build();
|
||||
listener.parseEntry(spanObject, segment);
|
||||
listener.build();
|
||||
|
||||
final List<Source> receivedSources = mockReceiver.getReceivedSources();
|
||||
Assert.assertEquals(7, receivedSources.size());
|
||||
final All all = (All) receivedSources.get(0);
|
||||
final Service service = (Service) receivedSources.get(1);
|
||||
final ServiceInstance serviceInstance = (ServiceInstance) receivedSources.get(2);
|
||||
final Endpoint endpoint = (Endpoint) receivedSources.get(3);
|
||||
final ServiceRelation serviceRelation = (ServiceRelation) receivedSources.get(4);
|
||||
final ServiceInstanceRelation serviceInstanceRelation = (ServiceInstanceRelation) receivedSources.get(5);
|
||||
final EndpointRelation endpointRelation = (EndpointRelation) receivedSources.get(6);
|
||||
Assert.assertEquals("mock-service", service.getName());
|
||||
Assert.assertEquals("mock-instance", serviceInstance.getName());
|
||||
Assert.assertEquals("/springMVC", endpoint.getName());
|
||||
Assert.assertEquals("downstream-service", serviceRelation.getSourceServiceName());
|
||||
Assert.assertEquals(service.getName(), serviceRelation.getDestServiceName());
|
||||
Assert.assertEquals("downstream-instance", serviceInstanceRelation.getSourceServiceInstanceName());
|
||||
Assert.assertEquals(serviceInstance.getName(), serviceInstanceRelation.getDestServiceInstanceName());
|
||||
Assert.assertEquals("downstream-endpoint", endpointRelation.getEndpoint());
|
||||
Assert.assertEquals(endpoint.getName(), endpointRelation.getChildEndpoint());
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry span with ref, but as a MQ server, or uninstrumented server.
|
||||
*/
|
||||
@Test
|
||||
public void testEntrySpanMQRef() {
|
||||
final MockReceiver mockReceiver = new MockReceiver();
|
||||
MultiScopesAnalysisListener listener = new MultiScopesAnalysisListener(
|
||||
mockReceiver,
|
||||
CONFIG,
|
||||
CACHE,
|
||||
NAMING_CONTROL
|
||||
);
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
SpanObject spanObject = SpanObject.newBuilder()
|
||||
.setOperationName("/springMVC")
|
||||
.setStartTime(startTime)
|
||||
.setEndTime(startTime + 1000L)
|
||||
.setIsError(true)
|
||||
.setSpanType(SpanType.Entry)
|
||||
.setSpanLayer(SpanLayer.MQ)
|
||||
.addRefs(
|
||||
SegmentReference.newBuilder()
|
||||
.setRefType(RefType.CrossProcess)
|
||||
.setParentService("downstream-service")
|
||||
.setParentServiceInstance("downstream-instance")
|
||||
.setParentEndpoint("downstream-endpoint")
|
||||
.setNetworkAddressUsedAtPeer("127.0.0.1")
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
final SegmentObject segment = SegmentObject.newBuilder()
|
||||
.setService("mock-service")
|
||||
.setServiceInstance("mock-instance")
|
||||
.addSpans(spanObject)
|
||||
.build();
|
||||
listener.parseEntry(spanObject, segment);
|
||||
listener.build();
|
||||
|
||||
final List<Source> receivedSources = mockReceiver.getReceivedSources();
|
||||
Assert.assertEquals(7, receivedSources.size());
|
||||
final All all = (All) receivedSources.get(0);
|
||||
final Service service = (Service) receivedSources.get(1);
|
||||
final ServiceInstance serviceInstance = (ServiceInstance) receivedSources.get(2);
|
||||
final Endpoint endpoint = (Endpoint) receivedSources.get(3);
|
||||
final ServiceRelation serviceRelation = (ServiceRelation) receivedSources.get(4);
|
||||
final ServiceInstanceRelation serviceInstanceRelation = (ServiceInstanceRelation) receivedSources.get(5);
|
||||
final EndpointRelation endpointRelation = (EndpointRelation) receivedSources.get(6);
|
||||
Assert.assertEquals("mock-service", service.getName());
|
||||
Assert.assertEquals("mock-instance", serviceInstance.getName());
|
||||
Assert.assertEquals("/springMVC", endpoint.getName());
|
||||
Assert.assertEquals("127.0.0.1", serviceRelation.getSourceServiceName());
|
||||
Assert.assertEquals(service.getName(), serviceRelation.getDestServiceName());
|
||||
Assert.assertEquals("127.0.0.1", serviceInstanceRelation.getSourceServiceInstanceName());
|
||||
Assert.assertEquals(serviceInstance.getName(), serviceInstanceRelation.getDestServiceInstanceName());
|
||||
Assert.assertEquals("downstream-endpoint", endpointRelation.getEndpoint());
|
||||
Assert.assertEquals(endpoint.getName(), endpointRelation.getChildEndpoint());
|
||||
}
|
||||
|
||||
/**
|
||||
* Local span analysis is triggered with logic span tag.
|
||||
*/
|
||||
@Test
|
||||
public void testParseLocalLogicSpan() {
|
||||
final MockReceiver mockReceiver = new MockReceiver();
|
||||
MultiScopesAnalysisListener listener = new MultiScopesAnalysisListener(
|
||||
mockReceiver,
|
||||
CONFIG,
|
||||
CACHE,
|
||||
NAMING_CONTROL
|
||||
);
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
final JsonObject logicSpanTagValue = new JsonObject();
|
||||
logicSpanTagValue.addProperty("logic-span", true);
|
||||
SpanObject spanObject = SpanObject.newBuilder()
|
||||
.setOperationName("/logic-call")
|
||||
.setStartTime(startTime)
|
||||
.setEndTime(startTime + 1000L)
|
||||
.setIsError(false)
|
||||
.setSpanType(SpanType.Local)
|
||||
.addTags(KeyStringValuePair.newBuilder()
|
||||
.setKey(LOGIC_ENDPOINT)
|
||||
.setValue(logicSpanTagValue.toString())
|
||||
.build())
|
||||
.build();
|
||||
final SegmentObject segment = SegmentObject.newBuilder()
|
||||
.setService("mock-service")
|
||||
.setServiceInstance("mock-instance")
|
||||
.addSpans(spanObject)
|
||||
.build();
|
||||
listener.parseLocal(spanObject, segment);
|
||||
listener.build();
|
||||
|
||||
final List<Source> receivedSources = mockReceiver.getReceivedSources();
|
||||
Assert.assertEquals(1, receivedSources.size());
|
||||
final Endpoint source = (Endpoint) receivedSources.get(0);
|
||||
Assert.assertEquals("/logic-call", source.getName());
|
||||
|
||||
mockReceiver.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Local span analysis is triggered with extension logic service tags.
|
||||
*/
|
||||
@Test
|
||||
public void testParseSpanWithLogicEndpointTag() {
|
||||
final MockReceiver mockReceiver = new MockReceiver();
|
||||
MultiScopesAnalysisListener listener = new MultiScopesAnalysisListener(
|
||||
mockReceiver,
|
||||
CONFIG,
|
||||
CACHE,
|
||||
NAMING_CONTROL
|
||||
);
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
final JsonObject logicSpanTagValue = new JsonObject();
|
||||
logicSpanTagValue.addProperty("name", "/GraphQL-service");
|
||||
logicSpanTagValue.addProperty("latency", 100);
|
||||
logicSpanTagValue.addProperty("status", false);
|
||||
SpanObject spanObject = SpanObject.newBuilder()
|
||||
.setOperationName("/logic-call")
|
||||
.setStartTime(startTime)
|
||||
.setEndTime(startTime + 1000L)
|
||||
.setIsError(false)
|
||||
.setSpanType(SpanType.Local)
|
||||
.addTags(KeyStringValuePair.newBuilder()
|
||||
.setKey(LOGIC_ENDPOINT)
|
||||
.setValue(logicSpanTagValue.toString())
|
||||
.build())
|
||||
.build();
|
||||
final SegmentObject segment = SegmentObject.newBuilder()
|
||||
.setService("mock-service")
|
||||
.setServiceInstance("mock-instance")
|
||||
.addSpans(spanObject)
|
||||
.build();
|
||||
listener.parseLocal(spanObject, segment);
|
||||
listener.build();
|
||||
|
||||
final List<Source> receivedSources = mockReceiver.getReceivedSources();
|
||||
Assert.assertEquals(1, receivedSources.size());
|
||||
final Endpoint source = (Endpoint) receivedSources.get(0);
|
||||
Assert.assertEquals("/GraphQL-service", source.getName());
|
||||
|
||||
mockReceiver.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit span, represent calling a 3rd party system, when the alias has not been setup, including access database.
|
||||
*/
|
||||
@Test
|
||||
public void testExitSpanWithoutAlias() {
|
||||
final MockReceiver mockReceiver = new MockReceiver();
|
||||
MultiScopesAnalysisListener listener = new MultiScopesAnalysisListener(
|
||||
mockReceiver,
|
||||
CONFIG,
|
||||
CACHE,
|
||||
NAMING_CONTROL
|
||||
);
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
SpanObject spanObject = SpanObject.newBuilder()
|
||||
.setOperationName("/springMVC")
|
||||
.setStartTime(startTime)
|
||||
.setEndTime(startTime + 1000L)
|
||||
.setIsError(true)
|
||||
.setSpanType(SpanType.Exit)
|
||||
.setSpanLayer(SpanLayer.Database)
|
||||
.setPeer("127.0.0.1:8080")
|
||||
.build();
|
||||
final SegmentObject segment = SegmentObject.newBuilder()
|
||||
.setService("mock-service")
|
||||
.setServiceInstance("mock-instance")
|
||||
.addSpans(spanObject)
|
||||
.build();
|
||||
listener.parseExit(spanObject, segment);
|
||||
listener.build();
|
||||
|
||||
final List<Source> receivedSources = mockReceiver.getReceivedSources();
|
||||
Assert.assertEquals(4, receivedSources.size());
|
||||
final ServiceRelation serviceRelation = (ServiceRelation) receivedSources.get(0);
|
||||
final ServiceInstanceRelation serviceInstanceRelation = (ServiceInstanceRelation) receivedSources.get(1);
|
||||
final ServiceMeta serviceMeta = (ServiceMeta) receivedSources.get(2);
|
||||
final DatabaseAccess databaseAccess = (DatabaseAccess) receivedSources.get(3);
|
||||
Assert.assertEquals("mock-service", serviceRelation.getSourceServiceName());
|
||||
Assert.assertEquals("127.0.0.1:8080", serviceRelation.getDestServiceName());
|
||||
Assert.assertEquals("mock-instance", serviceInstanceRelation.getSourceServiceInstanceName());
|
||||
Assert.assertEquals("127.0.0.1:8080", serviceInstanceRelation.getDestServiceInstanceName());
|
||||
Assert.assertEquals("127.0.0.1:8080", serviceMeta.getName());
|
||||
Assert.assertEquals(NodeType.Database, serviceMeta.getNodeType());
|
||||
Assert.assertEquals("127.0.0.1:8080", databaseAccess.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Exit span, represent calling a 3rd party system, when the alias has been setup.
|
||||
*/
|
||||
@Test
|
||||
public void testExitSpanWithAlias() {
|
||||
final MockReceiver mockReceiver = new MockReceiver();
|
||||
MultiScopesAnalysisListener listener = new MultiScopesAnalysisListener(
|
||||
mockReceiver,
|
||||
CONFIG,
|
||||
CACHE2,
|
||||
NAMING_CONTROL
|
||||
);
|
||||
|
||||
final long startTime = System.currentTimeMillis();
|
||||
SpanObject spanObject = SpanObject.newBuilder()
|
||||
.setOperationName("/springMVC")
|
||||
.setStartTime(startTime)
|
||||
.setEndTime(startTime + 1000L)
|
||||
.setIsError(true)
|
||||
.setSpanType(SpanType.Exit)
|
||||
.setSpanLayer(SpanLayer.MQ)
|
||||
.setPeer("127.0.0.1:8080")
|
||||
.build();
|
||||
final SegmentObject segment = SegmentObject.newBuilder()
|
||||
.setService("mock-service")
|
||||
.setServiceInstance("mock-instance")
|
||||
.addSpans(spanObject)
|
||||
.build();
|
||||
listener.parseExit(spanObject, segment);
|
||||
listener.build();
|
||||
|
||||
final List<Source> receivedSources = mockReceiver.getReceivedSources();
|
||||
Assert.assertEquals(2, receivedSources.size());
|
||||
final ServiceRelation serviceRelation = (ServiceRelation) receivedSources.get(0);
|
||||
final ServiceInstanceRelation serviceInstanceRelation = (ServiceInstanceRelation) receivedSources.get(1);
|
||||
Assert.assertEquals("mock-service", serviceRelation.getSourceServiceName());
|
||||
Assert.assertEquals("target-service", serviceRelation.getDestServiceName());
|
||||
Assert.assertEquals("mock-instance", serviceInstanceRelation.getSourceServiceInstanceName());
|
||||
Assert.assertEquals("target-instance", serviceInstanceRelation.getDestServiceInstanceName());
|
||||
mockReceiver.clear();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue