From 74b0af9d85aa66e2666e98719b0a8c255c8cd934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=B4=E6=99=9F=20Wu=20Sheng?= Date: Sun, 8 Mar 2020 18:34:53 +0800 Subject: [PATCH] [Agent Core] Support lazy ContextCarrier injection and lazy peer id setting (#4462) * Support lazy ContextCarrier injection and lazy peer id setting for exit span * Close the set component id for exit and local spans * Follow the review. * Remove `void inject(AbstractSpan exitSpan, ContextCarrier carrier)` from AbstractTracerContext --- .../core/context/AbstractTracerContext.java | 3 +- .../agent/core/context/TracingContext.java | 77 ++++++++++++++----- .../agent/core/context/trace/ExitSpan.java | 31 ++++---- .../{WithPeerInfo.java => ExitTypeSpan.java} | 9 ++- .../agent/core/context/trace/LocalSpan.java | 8 ++ .../core/context/trace/NoopExitSpan.java | 9 ++- 6 files changed, 100 insertions(+), 37 deletions(-) rename apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/{WithPeerInfo.java => ExitTypeSpan.java} (81%) diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java index 7ce1c59d9..4fb0999c6 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/AbstractTracerContext.java @@ -82,7 +82,8 @@ public interface AbstractTracerContext { * Create an exit span * * @param operationName most likely a service name of remote - * @param remotePeer the network id(ip:port, hostname:port or ip1:port1,ip2,port, etc.) + * @param remotePeer the network id(ip:port, hostname:port or ip1:port1,ip2,port, etc.). Remote peer could be set + * later, but must be before injecting. * @return the span represent an exit point of this segment. */ AbstractSpan createExitSpan(String operationName, String remotePeer); diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java index fdf148d84..bbb7b51bc 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/TracingContext.java @@ -29,12 +29,12 @@ import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan; import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan; import org.apache.skywalking.apm.agent.core.context.trace.EntrySpan; import org.apache.skywalking.apm.agent.core.context.trace.ExitSpan; +import org.apache.skywalking.apm.agent.core.context.trace.ExitTypeSpan; import org.apache.skywalking.apm.agent.core.context.trace.LocalSpan; import org.apache.skywalking.apm.agent.core.context.trace.NoopExitSpan; import org.apache.skywalking.apm.agent.core.context.trace.NoopSpan; import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment; import org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentRef; -import org.apache.skywalking.apm.agent.core.context.trace.WithPeerInfo; import org.apache.skywalking.apm.agent.core.dictionary.DictionaryManager; import org.apache.skywalking.apm.agent.core.dictionary.DictionaryUtil; import org.apache.skywalking.apm.agent.core.logging.api.ILog; @@ -129,21 +129,37 @@ public class TracingContext implements AbstractTracerContext { * Inject the context into the given carrier, only when the active span is an exit one. * * @param carrier to carry the context for crossing process. - * @throws IllegalStateException if the active span isn't an exit one. Ref to {@link AbstractTracerContext#inject(ContextCarrier)} + * @throws IllegalStateException if (1) the active span isn't an exit one. (2) doesn't include peer. Ref to {@link + * AbstractTracerContext#inject(ContextCarrier)} */ @Override public void inject(ContextCarrier carrier) { - AbstractSpan span = this.activeSpan(); - if (!span.isExit()) { + this.inject(this.activeSpan(), carrier); + } + + /** + * Inject the context into the given carrier and given span, only when the active span is an exit one. This method + * wouldn't be opened in {@link ContextManager} like {@link #inject(ContextCarrier)}, it is only supported to be + * called inside the {@link ExitTypeSpan#inject(ContextCarrier)} + * + * @param carrier to carry the context for crossing process. + * @param exitSpan to represent the scope of current injection. + * @throws IllegalStateException if (1) the span isn't an exit one. (2) doesn't include peer. + */ + public void inject(AbstractSpan exitSpan, ContextCarrier carrier) { + if (!exitSpan.isExit()) { throw new IllegalStateException("Inject can be done only in Exit Span"); } - WithPeerInfo spanWithPeer = (WithPeerInfo) span; + ExitTypeSpan spanWithPeer = (ExitTypeSpan) exitSpan; String peer = spanWithPeer.getPeer(); int peerId = spanWithPeer.getPeerId(); + if (StringUtil.isEmpty(peer) && DictionaryUtil.isNull(peerId)) { + throw new IllegalStateException("Exit span doesn't include meaningful peer information."); + } carrier.setTraceSegmentId(this.segment.getTraceSegmentId()); - carrier.setSpanId(span.getSpanId()); + carrier.setSpanId(exitSpan.getSpanId()); carrier.setParentServiceInstanceId(segment.getApplicationInstanceId()); @@ -235,7 +251,8 @@ public class TracingContext implements AbstractTracerContext { @Override public ContextSnapshot capture() { List refs = this.segment.getRefs(); - ContextSnapshot snapshot = new ContextSnapshot(segment.getTraceSegmentId(), activeSpan().getSpanId(), segment.getRelatedGlobalTraces()); + ContextSnapshot snapshot = new ContextSnapshot( + segment.getTraceSegmentId(), activeSpan().getSpanId(), segment.getRelatedGlobalTraces()); int entryOperationId; String entryOperationName = ""; int entryApplicationInstanceId; @@ -332,15 +349,23 @@ public class TracingContext implements AbstractTracerContext { if (parentSpan != null && parentSpan.isEntry()) { entrySpan = (AbstractTracingSpan) DictionaryManager.findEndpointSection() .findOnly(segment.getServiceId(), operationName) - .doInCondition(parentSpan::setOperationId, () -> parentSpan - .setOperationName(operationName)); + .doInCondition( + parentSpan::setOperationId, () -> parentSpan + .setOperationName(operationName)); return entrySpan.start(); } else { entrySpan = (AbstractTracingSpan) DictionaryManager.findEndpointSection() .findOnly(segment.getServiceId(), operationName) - .doInCondition(operationId -> new EntrySpan(spanIdGenerator++, parentSpanId, operationId, owner), () -> { - return new EntrySpan(spanIdGenerator++, parentSpanId, operationName, owner); - }); + .doInCondition( + operationId -> new EntrySpan(spanIdGenerator++, + parentSpanId, + operationId, owner + ), () -> { + return new EntrySpan( + spanIdGenerator++, parentSpanId, + operationName, owner + ); + }); entrySpan.start(); return push(entrySpan); } @@ -373,7 +398,8 @@ public class TracingContext implements AbstractTracerContext { * Create an exit span * * @param operationName most likely a service name of remote - * @param remotePeer the network id(ip:port, hostname:port or ip1:port1,ip2,port, etc.) + * @param remotePeer the network id(ip:port, hostname:port or ip1:port1,ip2,port, etc.). Remote peer could be set + * later, but must be before injecting. * @return the span represent an exit point of this segment. * @see ExitSpan */ @@ -391,11 +417,21 @@ public class TracingContext implements AbstractTracerContext { exitSpan = parentSpan; } else { final int parentSpanId = parentSpan == null ? -1 : parentSpan.getSpanId(); - exitSpan = (AbstractSpan) DictionaryManager.findNetworkAddressSection() - .find(remotePeer) - .doInCondition(peerId -> new ExitSpan(spanIdGenerator++, parentSpanId, operationName, peerId, owner), () -> { - return new ExitSpan(spanIdGenerator++, parentSpanId, operationName, remotePeer, owner); - }); + if (StringUtil.isEmpty(remotePeer)) { + exitSpan = new ExitSpan(spanIdGenerator++, parentSpanId, operationName, owner); + } else { + exitSpan = (AbstractSpan) DictionaryManager.findNetworkAddressSection() + .find(remotePeer) + .doInCondition( + peerId -> new ExitSpan(spanIdGenerator++, parentSpanId, + operationName, peerId, owner + ), () -> { + return new ExitSpan( + spanIdGenerator++, parentSpanId, operationName, + remotePeer, owner + ); + }); + } push(exitSpan); } exitSpan.start(); @@ -622,7 +658,10 @@ public class TracingContext implements AbstractTracerContext { if (spanIdGenerator >= Config.Agent.SPAN_LIMIT_PER_SEGMENT) { long currentTimeMillis = System.currentTimeMillis(); if (currentTimeMillis - lastWarningTimestamp > 30 * 1000) { - logger.warn(new RuntimeException("Shadow tracing context. Thread dump"), "More than {} spans required to create", Config.Agent.SPAN_LIMIT_PER_SEGMENT); + logger.warn( + new RuntimeException("Shadow tracing context. Thread dump"), + "More than {} spans required to create", Config.Agent.SPAN_LIMIT_PER_SEGMENT + ); lastWarningTimestamp = currentTimeMillis; } return true; diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/ExitSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/ExitSpan.java index 4d167b2c5..345163fde 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/ExitSpan.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/ExitSpan.java @@ -18,6 +18,7 @@ package org.apache.skywalking.apm.agent.core.context.trace; +import org.apache.skywalking.apm.agent.core.context.ContextCarrier; import org.apache.skywalking.apm.agent.core.context.TracingContext; import org.apache.skywalking.apm.agent.core.context.tag.AbstractTag; import org.apache.skywalking.apm.network.trace.component.Component; @@ -33,24 +34,19 @@ import org.apache.skywalking.apm.network.trace.component.Component; * Such as: Dubbox - Apache Httpcomponent - ...(Remote) The ExitSpan represents the Dubbox span, and ignore * the httpcomponent span's info. */ -public class ExitSpan extends StackBasedTracingSpan implements WithPeerInfo { - +public class ExitSpan extends StackBasedTracingSpan implements ExitTypeSpan { public ExitSpan(int spanId, int parentSpanId, String operationName, String peer, TracingContext owner) { super(spanId, parentSpanId, operationName, peer, owner); } - public ExitSpan(int spanId, int parentSpanId, int operationId, int peerId, TracingContext owner) { - super(spanId, parentSpanId, operationId, peerId, owner); - } - - public ExitSpan(int spanId, int parentSpanId, int operationId, String peer, TracingContext owner) { - super(spanId, parentSpanId, operationId, peer, owner); - } - public ExitSpan(int spanId, int parentSpanId, String operationName, int peerId, TracingContext owner) { super(spanId, parentSpanId, operationName, peerId, owner); } + public ExitSpan(int spanId, int parentSpanId, String operationName, TracingContext owner) { + super(spanId, parentSpanId, operationName, owner); + } + /** * Set the {@link #startTime}, when the first start, which means the first service provided. */ @@ -122,13 +118,12 @@ public class ExitSpan extends StackBasedTracingSpan implements WithPeerInfo { } } + /** + * Illegal operation. Operation name id is the registered endpoint, only work for entry span. + */ @Override public AbstractTracingSpan setOperationId(int operationId) { - if (stackDepth == 1) { - return super.setOperationId(operationId); - } else { - return this; - } + throw new UnsupportedOperationException("Exit span doesn't support operation id"); } @Override @@ -141,6 +136,12 @@ public class ExitSpan extends StackBasedTracingSpan implements WithPeerInfo { return peer; } + @Override + public ExitSpan inject(final ContextCarrier carrier) { + this.owner.inject(this, carrier); + return this; + } + @Override public boolean isEntry() { return false; diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/WithPeerInfo.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/ExitTypeSpan.java similarity index 81% rename from apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/WithPeerInfo.java rename to apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/ExitTypeSpan.java index 249febe92..8f4f580aa 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/WithPeerInfo.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/ExitTypeSpan.java @@ -18,8 +18,15 @@ package org.apache.skywalking.apm.agent.core.context.trace; -public interface WithPeerInfo { +import org.apache.skywalking.apm.agent.core.context.ContextCarrier; + +/** + * The exit span has some additional behaviours + */ +public interface ExitTypeSpan { int getPeerId(); String getPeer(); + + ExitTypeSpan inject(ContextCarrier carrier); } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/LocalSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/LocalSpan.java index 292f53dc6..91bc47f34 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/LocalSpan.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/LocalSpan.java @@ -47,4 +47,12 @@ public class LocalSpan extends AbstractTracingSpan { public AbstractSpan setPeer(String remotePeer) { return this; } + + /** + * Illegal operation. Operation name id is the registered endpoint, only work for entry span. + */ + @Override + public AbstractTracingSpan setOperationId(int operationId) { + throw new UnsupportedOperationException("Exit span doesn't support operation id"); + } } diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/NoopExitSpan.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/NoopExitSpan.java index bb2018b42..6adce3e84 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/NoopExitSpan.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/trace/NoopExitSpan.java @@ -18,7 +18,9 @@ package org.apache.skywalking.apm.agent.core.context.trace; -public class NoopExitSpan extends NoopSpan implements WithPeerInfo { +import org.apache.skywalking.apm.agent.core.context.ContextCarrier; + +public class NoopExitSpan extends NoopSpan implements ExitTypeSpan { private String peer; private int peerId; @@ -41,6 +43,11 @@ public class NoopExitSpan extends NoopSpan implements WithPeerInfo { return peer; } + @Override + public NoopExitSpan inject(final ContextCarrier carrier) { + return this; + } + @Override public boolean isExit() { return true;