You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ke...@apache.org on 2020/02/02 09:45:16 UTC
[skywalking] branch master updated: Clean up legacy v1 header logic,
use built-in Base64 since JDK8 (#4307)
This is an automated email from the ASF dual-hosted git repository.
kezhenxu94 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git
The following commit(s) were added to refs/heads/master by this push:
new bf38e43 Clean up legacy v1 header logic, use built-in Base64 since JDK8 (#4307)
bf38e43 is described below
commit bf38e43d3aadeec93a0b30f9b92e2226ff9e953c
Author: kezhenxu94 <ke...@apache.org>
AuthorDate: Sun Feb 2 17:45:05 2020 +0800
Clean up legacy v1 header logic, use built-in Base64 since JDK8 (#4307)
### Motivation:
Codes clean up
### Modifications:
- Remove v1 header, follow up #4244
- Use built-in Base64 class (since JDK8)
### Result:
- No more legacy v1 headers
- No unnecessary codes concerns by using built-in ability
---
.../skywalking/apm/agent/core/base64/Base64.java | 160 +--------------------
.../apm/agent/core/context/ContextCarrier.java | 87 ++++-------
.../apm/agent/core/context/ContextManagerTest.java | 11 +-
3 files changed, 39 insertions(+), 219 deletions(-)
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/base64/Base64.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/base64/Base64.java
index 2f17909..11d8d65 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/base64/Base64.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/base64/Base64.java
@@ -17,172 +17,24 @@
*/
package org.apache.skywalking.apm.agent.core.base64;
-import java.io.UnsupportedEncodingException;
-import org.apache.skywalking.apm.agent.core.logging.api.ILog;
-import org.apache.skywalking.apm.agent.core.logging.api.LogManager;
+import java.nio.charset.StandardCharsets;
/**
- * Copied from {@code zipkin.internal.Base64}, adapted from {@code okio.Base64} as JRE 6 doesn't have a base64Url
- * encoder.
- *
- * @author okio cited the original author as Alexander Y. Kleymenov
+ * A wrapper of {@link java.util.Base64} with convenient conversion methods between {@code byte[]} and {@code String}
*/
public final class Base64 {
- private static final ILog logger = LogManager.getLogger(Base64.class);
+ private static final java.util.Base64.Decoder DECODER = java.util.Base64.getDecoder();
+ private static final java.util.Base64.Encoder ENCODER = java.util.Base64.getEncoder();
private Base64() {
}
public static String decode2UTFString(String in) {
- try {
- return new String(decode(in), "utf-8");
- } catch (UnsupportedEncodingException e) {
- logger.error(e, "Can't decode BASE64 text {}", in);
- return "";
- }
- }
-
- public static byte[] decode(String in) {
- // Ignore trailing '=' padding and whitespace from the input.
- int limit = in.length();
- for (; limit > 0; limit--) {
- char c = in.charAt(limit - 1);
- if (c != '=' && c != '\n' && c != '\r' && c != ' ' && c != '\t') {
- break;
- }
- }
-
- // If the input includes whitespace, this output array will be longer than necessary.
- byte[] out = new byte[(int)(limit * 6L / 8L)];
- int outCount = 0;
- int inCount = 0;
-
- int word = 0;
- for (int pos = 0; pos < limit; pos++) {
- char c = in.charAt(pos);
-
- int bits;
- if (c >= 'A' && c <= 'Z') {
- // char ASCII value
- // A 65 0
- // Z 90 25 (ASCII - 65)
- bits = c - 65;
- } else if (c >= 'a' && c <= 'z') {
- // char ASCII value
- // a 97 26
- // z 122 51 (ASCII - 71)
- bits = c - 71;
- } else if (c >= '0' && c <= '9') {
- // char ASCII value
- // 0 48 52
- // 9 57 61 (ASCII + 4)
- bits = c + 4;
- } else if (c == '+' || c == '-') {
- bits = 62;
- } else if (c == '/' || c == '_') {
- bits = 63;
- } else if (c == '\n' || c == '\r' || c == ' ' || c == '\t') {
- continue;
- } else {
- return null;
- }
-
- // Append this char's 6 bits to the word.
- word = (word << 6) | (byte)bits;
-
- // For every 4 chars of input, we accumulate 24 bits of output. Emit 3 bytes.
- inCount++;
- if (inCount % 4 == 0) {
- out[outCount++] = (byte)(word >> 16);
- out[outCount++] = (byte)(word >> 8);
- out[outCount++] = (byte)word;
- }
- }
-
- int lastWordChars = inCount % 4;
- if (lastWordChars == 1) {
- // We read 1 char followed by "===". But 6 bits is a truncated byte! Fail.
- return null;
- } else if (lastWordChars == 2) {
- // We read 2 chars followed by "==". Emit 1 byte with 8 of those 12 bits.
- word = word << 12;
- out[outCount++] = (byte)(word >> 16);
- } else if (lastWordChars == 3) {
- // We read 3 chars, followed by "=". Emit 2 bytes for 16 of those 18 bits.
- word = word << 6;
- out[outCount++] = (byte)(word >> 16);
- out[outCount++] = (byte)(word >> 8);
- }
-
- // If we sized our out array perfectly, we're done.
- if (outCount == out.length)
- return out;
-
- // Copy the decoded bytes to a new, right-sized array.
- byte[] prefix = new byte[outCount];
- System.arraycopy(out, 0, prefix, 0, outCount);
- return prefix;
+ return new String(DECODER.decode(in), StandardCharsets.UTF_8);
}
- private static final byte[] MAP = new byte[] {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
- 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
- '5', '6', '7', '8', '9', '+', '/'
- };
-
- private static final byte[] URL_MAP = new byte[] {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
- 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
- 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
- '5', '6', '7', '8', '9', '-', '_'
- };
-
public static String encode(String text) {
- try {
- return encode(text.getBytes("utf-8"));
- } catch (UnsupportedEncodingException e) {
- logger.error(e, "Can't encode {} in BASE64", text);
- return "";
- }
+ return ENCODER.encodeToString(text.getBytes(StandardCharsets.UTF_8));
}
- public static String encode(byte[] in) {
- return encode(in, MAP);
- }
-
- public static String encodeUrl(byte[] in) {
- return encode(in, URL_MAP);
- }
-
- private static String encode(byte[] in, byte[] map) {
- int length = (in.length + 2) / 3 * 4;
- byte[] out = new byte[length];
- int index = 0, end = in.length - in.length % 3;
- for (int i = 0; i < end; i += 3) {
- out[index++] = map[(in[i] & 0xff) >> 2];
- out[index++] = map[((in[i] & 0x03) << 4) | ((in[i + 1] & 0xff) >> 4)];
- out[index++] = map[((in[i + 1] & 0x0f) << 2) | ((in[i + 2] & 0xff) >> 6)];
- out[index++] = map[in[i + 2] & 0x3f];
- }
- switch (in.length % 3) {
- case 1:
- out[index++] = map[(in[end] & 0xff) >> 2];
- out[index++] = map[(in[end] & 0x03) << 4];
- out[index++] = '=';
- out[index++] = '=';
- break;
- case 2:
- out[index++] = map[(in[end] & 0xff) >> 2];
- out[index++] = map[((in[end] & 0x03) << 4) | ((in[end + 1] & 0xff) >> 4)];
- out[index++] = map[(in[end + 1] & 0x0f) << 2];
- out[index++] = '=';
- break;
- }
- try {
- return new String(out, "US-ASCII");
- } catch (UnsupportedEncodingException e) {
- throw new AssertionError(e);
- }
- }
}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextCarrier.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextCarrier.java
index 33d4aed..03eaf05 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextCarrier.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/context/ContextCarrier.java
@@ -24,7 +24,6 @@ import org.apache.skywalking.apm.agent.core.base64.Base64;
import org.apache.skywalking.apm.agent.core.context.ids.DistributedTraceId;
import org.apache.skywalking.apm.agent.core.context.ids.ID;
import org.apache.skywalking.apm.agent.core.context.ids.PropagatedTraceId;
-import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
import org.apache.skywalking.apm.agent.core.dictionary.DictionaryUtil;
import org.apache.skywalking.apm.util.StringUtil;
@@ -35,9 +34,6 @@ import org.apache.skywalking.apm.util.StringUtil;
* Created by wusheng on 2017/2/17.
*/
public class ContextCarrier implements Serializable {
- /**
- * {@link TraceSegment#traceSegmentId}
- */
private ID traceSegmentId;
/**
@@ -97,9 +93,8 @@ public class ContextCarrier implements Serializable {
Base64.encode(this.getPeerHost()),
Base64.encode(this.getEntryEndpointName()),
Base64.encode(this.getParentEndpointName()));
- } else {
- return "";
}
+ return "";
}
/**
@@ -108,53 +103,36 @@ public class ContextCarrier implements Serializable {
* @param text carries {@link #traceSegmentId} and {@link #spanId}, with '|' split.
*/
ContextCarrier deserialize(String text, HeaderVersion version) {
- if (text != null) {
- // if this carrier is initialized by v1 or v2, don't do deserialize again for performance.
- if (this.isValid(HeaderVersion.v1) || this.isValid(HeaderVersion.v2)) {
- return this;
- }
- if (HeaderVersion.v1.equals(version)) {
- String[] parts = text.split("\\|", 8);
- if (parts.length == 8) {
- try {
- this.traceSegmentId = new ID(parts[0]);
- this.spanId = Integer.parseInt(parts[1]);
- this.parentServiceInstanceId = Integer.parseInt(parts[2]);
- this.entryServiceInstanceId = Integer.parseInt(parts[3]);
- this.peerHost = parts[4];
- this.entryEndpointName = parts[5];
- this.parentEndpointName = parts[6];
- this.primaryDistributedTraceId = new PropagatedTraceId(parts[7]);
- } catch (NumberFormatException e) {
-
- }
- }
- } else if (HeaderVersion.v2.equals(version)) {
- String[] parts = text.split("\\-", 9);
- if (parts.length == 9) {
- try {
- // parts[0] is sample flag, always trace if header exists.
- this.primaryDistributedTraceId = new PropagatedTraceId(Base64.decode2UTFString(parts[1]));
- this.traceSegmentId = new ID(Base64.decode2UTFString(parts[2]));
- this.spanId = Integer.parseInt(parts[3]);
- this.parentServiceInstanceId = Integer.parseInt(parts[4]);
- this.entryServiceInstanceId = Integer.parseInt(parts[5]);
- this.peerHost = Base64.decode2UTFString(parts[6]);
- this.entryEndpointName = Base64.decode2UTFString(parts[7]);
- this.parentEndpointName = Base64.decode2UTFString(parts[8]);
- } catch (NumberFormatException e) {
-
- }
+ if (text == null) {
+ return this;
+ }
+ // if this carrier is initialized by v2, don't do deserialize again for performance.
+ if (this.isValid(HeaderVersion.v2)) {
+ return this;
+ }
+ if (HeaderVersion.v2 == version) {
+ String[] parts = text.split("-", 9);
+ if (parts.length == 9) {
+ try {
+ // parts[0] is sample flag, always trace if header exists.
+ this.primaryDistributedTraceId = new PropagatedTraceId(Base64.decode2UTFString(parts[1]));
+ this.traceSegmentId = new ID(Base64.decode2UTFString(parts[2]));
+ this.spanId = Integer.parseInt(parts[3]);
+ this.parentServiceInstanceId = Integer.parseInt(parts[4]);
+ this.entryServiceInstanceId = Integer.parseInt(parts[5]);
+ this.peerHost = Base64.decode2UTFString(parts[6]);
+ this.entryEndpointName = Base64.decode2UTFString(parts[7]);
+ this.parentEndpointName = Base64.decode2UTFString(parts[8]);
+ } catch (NumberFormatException ignored) {
+
}
- } else {
- throw new IllegalArgumentException("Unimplemented header version." + version);
}
}
return this;
}
public boolean isValid() {
- return isValid(HeaderVersion.v2) || isValid(HeaderVersion.v1);
+ return isValid(HeaderVersion.v2);
}
/**
@@ -163,17 +141,7 @@ public class ContextCarrier implements Serializable {
* @return true for unbroken {@link ContextCarrier} or no-initialized. Otherwise, false;
*/
boolean isValid(HeaderVersion version) {
- if (HeaderVersion.v1.equals(version)) {
- return traceSegmentId != null
- && traceSegmentId.isValid()
- && getSpanId() > -1
- && parentServiceInstanceId != DictionaryUtil.nullValue()
- && entryServiceInstanceId != DictionaryUtil.nullValue()
- && !StringUtil.isEmpty(peerHost)
- && !StringUtil.isEmpty(entryEndpointName)
- && !StringUtil.isEmpty(parentEndpointName)
- && primaryDistributedTraceId != null;
- } else if (HeaderVersion.v2.equals(version)) {
+ if (HeaderVersion.v2 == version) {
return traceSegmentId != null
&& traceSegmentId.isValid()
&& getSpanId() > -1
@@ -181,9 +149,8 @@ public class ContextCarrier implements Serializable {
&& entryServiceInstanceId != DictionaryUtil.nullValue()
&& !StringUtil.isEmpty(peerHost)
&& primaryDistributedTraceId != null;
- } else {
- throw new IllegalArgumentException("Unimplemented header version." + version);
}
+ return false;
}
public String getEntryEndpointName() {
@@ -267,6 +234,6 @@ public class ContextCarrier implements Serializable {
}
public enum HeaderVersion {
- v1, v2
+ v2
}
}
diff --git a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/ContextManagerTest.java b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/ContextManagerTest.java
index 66b435e..6e048d8 100644
--- a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/ContextManagerTest.java
+++ b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/ContextManagerTest.java
@@ -22,6 +22,7 @@ package org.apache.skywalking.apm.agent.core.context;
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.List;
+import java.util.Objects;
import org.apache.skywalking.apm.agent.core.conf.RemoteDownstreamConfig;
import org.apache.skywalking.apm.agent.core.context.tag.Tags;
import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
@@ -80,7 +81,7 @@ public class ContextManagerTest {
@Test
public void createSpanWithInvalidateContextCarrier() {
- ContextCarrier contextCarrier = new ContextCarrier().deserialize("#AQA=#AQA=4WcWe0tQNQA=|1|#127.0.0.1:8080|#/testEntrySpan|#/testEntrySpan|#AQA=#AQA=Et0We0tQNQA=", ContextCarrier.HeaderVersion.v1);
+ ContextCarrier contextCarrier = new ContextCarrier();
AbstractSpan firstEntrySpan = ContextManager.createEntrySpan("/testEntrySpan", contextCarrier);
firstEntrySpan.setComponent(ComponentsDefine.TOMCAT);
@@ -94,7 +95,7 @@ public class ContextManagerTest {
assertNull(actualSegment.getRefs());
List<AbstractTracingSpan> spanList = SegmentHelper.getSpan(actualSegment);
- assertThat(spanList.size(), is(1));
+ assertThat(Objects.requireNonNull(spanList).size(), is(1));
AbstractTracingSpan actualEntrySpan = spanList.get(0);
assertThat(actualEntrySpan.getOperationName(), is("/testEntrySpan"));
@@ -104,7 +105,7 @@ public class ContextManagerTest {
@Test
public void createMultipleEntrySpan() {
- ContextCarrier contextCarrier = new ContextCarrier().deserialize("1.2343.234234234|1|1|1|#127.0.0.1:8080|#/portal/|#/testEntrySpan|1.2343.234234234", ContextCarrier.HeaderVersion.v1);
+ ContextCarrier contextCarrier = new ContextCarrier().deserialize("1-MS4yMzQzLjIzNDIzNDIzNA==-MS4yMzQzLjIzNDIzNDIzNA==-1-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWwv-Iy90ZXN0RW50cnlTcGFu", ContextCarrier.HeaderVersion.v2);
assertTrue(contextCarrier.isValid());
AbstractSpan firstEntrySpan = ContextManager.createEntrySpan("/testFirstEntry", contextCarrier);
@@ -195,7 +196,7 @@ public class ContextManagerTest {
assertNull(actualSegment.getRefs());
List<AbstractTracingSpan> spanList = SegmentHelper.getSpan(actualSegment);
- assertThat(spanList.size(), is(2));
+ assertThat(Objects.requireNonNull(spanList).size(), is(2));
AbstractTracingSpan actualFirstExitSpan = spanList.get(0);
assertThat(actualFirstExitSpan.getOperationName(), is("/testFirstExit"));
@@ -227,7 +228,7 @@ public class ContextManagerTest {
@Test
public void testTransform() throws InvalidProtocolBufferException {
- ContextCarrier contextCarrier = new ContextCarrier().deserialize("1.234.1983829|3|1|1|#127.0.0.1:8080|#/portal/|#/testEntrySpan|1.2343.234234234", ContextCarrier.HeaderVersion.v1);
+ ContextCarrier contextCarrier = new ContextCarrier().deserialize("1-MS4yMzQzLjIzNDIzNDIzNA==-MS4yMzQuMTk4MzgyOQ==-3-1-1-IzEyNy4wLjAuMTo4MDgw-Iy9wb3J0YWwv-Iy90ZXN0RW50cnlTcGFu", ContextCarrier.HeaderVersion.v2);
assertTrue(contextCarrier.isValid());
AbstractSpan firstEntrySpan = ContextManager.createEntrySpan("/testFirstEntry", contextCarrier);