From b740fe1af4a634997ba42c0df337305bad4ab47a Mon Sep 17 00:00:00 2001 From: Lev Khomich Date: Mon, 17 Oct 2016 17:17:18 +0500 Subject: [PATCH] tolerate up to 128-bit span ids by dropping higher bits (#84) --- .../akka/tracing/SpanMetadata.scala | 30 +++++++++------ .../akka/tracing/SpanMetadataSpec.scala | 37 +++++++++++++++++-- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/core/src/main/scala/com/github/levkhomich/akka/tracing/SpanMetadata.scala b/core/src/main/scala/com/github/levkhomich/akka/tracing/SpanMetadata.scala index a8ab322..ee744ca 100644 --- a/core/src/main/scala/com/github/levkhomich/akka/tracing/SpanMetadata.scala +++ b/core/src/main/scala/com/github/levkhomich/akka/tracing/SpanMetadata.scala @@ -71,19 +71,25 @@ object SpanMetadata { } private[tracing] def idFromString(x: String): Long = { - if (x == null || x.length == 0 || x.length > 16) - throw new NumberFormatException("Invalid span id string: " + x) - val s = - if (x.length % 2 == 0) x - else "0" + x - val bytes = new Array[Byte](8) - val start = 7 - (s.length + 1) / 2 - (s.length until 0 by -2).foreach { - i => - val x = Integer.parseInt(s.substring(i - 2, i), 16).toByte - bytes.update(start + i / 2, x) + if (x == null || x.length == 0) { + throw new NumberFormatException("Empty span id") + } else if (x.length > 32) { + throw new NumberFormatException("Span id is too long: " + x) + } else if (x.length > 16) { + idFromString(x.takeRight(16)) + } else { + val s = + if (x.length % 2 == 0) x + else "0" + x + val bytes = new Array[Byte](8) + val start = 7 - (s.length + 1) / 2 + (s.length until 0 by -2).foreach { + i => + val x = Integer.parseInt(s.substring(i - 2, i), 16).toByte + bytes.update(start + i / 2, x) + } + new DataInputStream(new ByteArrayInputStream(bytes)).readLong } - new DataInputStream(new ByteArrayInputStream(bytes)).readLong } /** diff --git a/core/src/test/scala/com/github/levkhomich/akka/tracing/SpanMetadataSpec.scala b/core/src/test/scala/com/github/levkhomich/akka/tracing/SpanMetadataSpec.scala index 6efb8c7..e76126e 100644 --- a/core/src/test/scala/com/github/levkhomich/akka/tracing/SpanMetadataSpec.scala +++ b/core/src/test/scala/com/github/levkhomich/akka/tracing/SpanMetadataSpec.scala @@ -18,7 +18,7 @@ package com.github.levkhomich.akka.tracing import scala.util.Random -import com.github.kristofa.brave.SpanId +import com.github.kristofa.brave.{ IdConversion, SpanId } import org.specs2.mutable.Specification class SpanMetadataSpec extends Specification with TracingTestCommons { @@ -54,7 +54,7 @@ class SpanMetadataSpec extends Specification with TracingTestCommons { failure(s"SpanId deserialization failed for value $x (was $actual instead of $expected)") } - checkValue("FFFFFFFFFFFFFFFF") + checkValue("ffffffffffffffff") checkValue("0") checkValue("00") checkValue("0000000000000000") @@ -75,8 +75,37 @@ class SpanMetadataSpec extends Specification with TracingTestCommons { SpanMetadata.idFromString(null) must throwAn[NumberFormatException] SpanMetadata.idFromString("") must throwAn[NumberFormatException] SpanMetadata.idFromString("not a number") must throwAn[NumberFormatException] - SpanMetadata.idFromString("11111111111111111") must throwAn[NumberFormatException] - SpanMetadata.idFromString("11111111111111111") must throwAn[NumberFormatException] + } + + "tolerate up to 128-bit span ids by dropping higher bits" in { + def checkValue(x: String): Unit = { + val actual = SpanMetadata.idFromString(x) + val expected = IdConversion.convertToLong(x) + if (actual != expected) + failure(s"SpanId deserialization failed for value $x (was $actual instead of $expected)") + } + + checkValue("463ac35c9f6413ad48485a3953bb612412") should throwA[NumberFormatException] + + checkValue("463ac35c9f6413ad48485a3953bb6124") + checkValue("463ac35c9f6413ad48485a3953") + checkValue("463ac35c9f6413ad48485") + checkValue("463ac35c9f6413ad") + checkValue("ffffffffffffffffffffffffffffffff") + checkValue("0") + checkValue("00") + checkValue("00000000000000000000000000000000") + checkValue("1") + checkValue("11") + checkValue("111") + + for (_ <- 1L to IterationsCount) + checkValue { + val str = Random.nextLong().toString.replace("-", "") + str.substring(0, (Random.nextInt(15) + 1) min str.length) + } + + success } "provide metadata [de]serialization support" in {