diff --git a/haystack-blobs/pom.xml b/haystack-blobs/pom.xml index 7a47f97..fbe85a7 100644 --- a/haystack-blobs/pom.xml +++ b/haystack-blobs/pom.xml @@ -22,9 +22,9 @@ ${project.parent.version} - io.opentracing - opentracing-api - ${opentracing.version} + com.expedia.www + haystack-client-core + 0.2.8 org.apache.commons diff --git a/haystack-blobs/src/main/java/com/expedia/haystack/blobs/SpanBlobContext.java b/haystack-blobs/src/main/java/com/expedia/haystack/blobs/SpanBlobContext.java index 9a90cc0..bdfafb3 100644 --- a/haystack-blobs/src/main/java/com/expedia/haystack/blobs/SpanBlobContext.java +++ b/haystack-blobs/src/main/java/com/expedia/haystack/blobs/SpanBlobContext.java @@ -3,7 +3,7 @@ import com.expedia.blobs.core.BlobContext; import com.expedia.blobs.core.BlobType; import com.expedia.blobs.core.BlobWriter; -import io.opentracing.Span; +import com.expedia.www.haystack.client.Span; import org.apache.commons.lang3.Validate; /** @@ -14,33 +14,30 @@ public class SpanBlobContext implements BlobContext { private final Span span; - private final String serviceName; private final static String PARTIAL_BLOB_KEY = "-blob"; - private final String operationName; /** * constructor * @param span span object - * @param serviceName for a specific service name, can't be null or empty - * @param operationName for a specific operation name */ - public SpanBlobContext(Span span, String serviceName, String operationName) { + public SpanBlobContext(Span span) { Validate.notNull(span, "span cannot be null in context"); - Validate.notEmpty(serviceName, "service name cannot be null in context"); - this.span = span; - this.serviceName = serviceName; - this.operationName = operationName; } @Override public String getOperationName() { - return operationName; + return this.span.getOperationName(); } @Override public String getServiceName() { - return serviceName; + return this.span.getServiceName(); + } + + @Override + public String getOperationId() { + return this.span.context().getSpanId().toString(); } /** diff --git a/haystack-blobs/src/test/scala/com/expedia/haystack/blobs/SpanBlobContextSpec.scala b/haystack-blobs/src/test/scala/com/expedia/haystack/blobs/SpanBlobContextSpec.scala index 4a82237..f6e5201 100644 --- a/haystack-blobs/src/test/scala/com/expedia/haystack/blobs/SpanBlobContextSpec.scala +++ b/haystack-blobs/src/test/scala/com/expedia/haystack/blobs/SpanBlobContextSpec.scala @@ -1,5 +1,10 @@ package com.expedia.haystack.blobs +import java.util + +import com.expedia.blobs.core.BlobType +import com.expedia.www.haystack.client._ +import org.easymock.EasyMock import org.scalatest.easymock.EasyMockSugar import org.scalatest.{FunSpec, Matchers} @@ -9,10 +14,31 @@ class SpanBlobContextSpec extends FunSpec with Matchers with EasyMockSugar { it("should throw an error if span is not present") { val catchExpection = intercept[Exception] { - val _ = new SpanBlobContext(null, "", "") + val _ = new SpanBlobContext(null) } catchExpection.getMessage shouldEqual "span cannot be null in context" } + + it("should add a tag to the Span when onBlobKeyCreate is invoked") { + val spanContext = mock[SpanContext] + val tracer = mock[Tracer] + val tags = new util.HashMap[String, Object] + val span = MockSpanBuilder.mockSpan(tracer, mock[Clock], "span-name", spanContext, + System.currentTimeMillis(), tags, new util.ArrayList[Reference]) + val spanBlobContext = new SpanBlobContext(span) + + expecting { + tracer.getServiceName.andReturn("remote-service").once() + spanContext.getSpanId.andReturn("1234567890").once() + } + EasyMock.replay(tracer, spanContext) + + + spanBlobContext.onBlobKeyCreate(spanBlobContext.makeKey(BlobType.REQUEST), BlobType.REQUEST) + + EasyMock.verify(tracer, spanContext) + tags.get("request-blob") should equal ("remote-service_span-name_1234567890_request") + } } } diff --git a/haystack-blobs/src/test/scala/com/expedia/www/haystack/client/MockSpanBuilder.scala b/haystack-blobs/src/test/scala/com/expedia/www/haystack/client/MockSpanBuilder.scala new file mode 100644 index 0000000..bcb5111 --- /dev/null +++ b/haystack-blobs/src/test/scala/com/expedia/www/haystack/client/MockSpanBuilder.scala @@ -0,0 +1,11 @@ +package com.expedia.www.haystack.client + +import java.util + +object MockSpanBuilder { + def mockSpan(tracer: Tracer, clock: Clock, operationName: String, context: SpanContext, + startTime: Long, tags: util.Map[String, Object], references: util.List[Reference]) : Span = { + new Span(tracer, clock, "span-name", context, + System.currentTimeMillis(), tags, new util.ArrayList[Reference]) + } +} diff --git a/pom.xml b/pom.xml index df5b0f9..44bbbf2 100644 --- a/pom.xml +++ b/pom.xml @@ -14,6 +14,7 @@ stores agent haystack-blobs + zipkin-blobs diff --git a/zipkin-blobs/pom.xml b/zipkin-blobs/pom.xml new file mode 100644 index 0000000..09d2554 --- /dev/null +++ b/zipkin-blobs/pom.xml @@ -0,0 +1,140 @@ + + + + blobs + com.expedia.www + 1.1.0-SNAPSHOT + + 4.0.0 + zipkin-blobs + jar + + + 5.9.0 + + + + + com.expedia.www + blobs-core + ${project.parent.version} + + + io.zipkin.brave + brave + ${zipkin.version} + + + org.apache.commons + commons-lang3 + + + + + org.slf4j + slf4j-log4j12 + + + org.easymock + easymock + + + org.scala-lang + scala-library + + + org.scala-lang + scala-reflect + + + org.scalatest + scalatest_${scala.major.minor.version} + + + org.pegdown + pegdown + + + junit + junit + + + + + + + org.scalatest + scalatest-maven-plugin + + + test + + test + + + com.expedia.test.IntegrationSuite + + + + integration-test + integration-test + + test + + + com.expedia.test.IntegrationSuite + + + + + + + net.alchim31.maven + scala-maven-plugin + + + + org.scalastyle + scalastyle-maven-plugin + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.apache.maven.plugins + maven-source-plugin + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + org.jacoco + jacoco-maven-plugin + + true + + + CLASS + + + LINE + COVEREDRATIO + 0.00 + + + + + + + + + + diff --git a/zipkin-blobs/src/main/java/brave/blobs/SpanBlobContext.java b/zipkin-blobs/src/main/java/brave/blobs/SpanBlobContext.java new file mode 100644 index 0000000..69f2d64 --- /dev/null +++ b/zipkin-blobs/src/main/java/brave/blobs/SpanBlobContext.java @@ -0,0 +1,62 @@ +package brave.blobs; + +import brave.Span; +import com.expedia.blobs.core.BlobContext; +import com.expedia.blobs.core.BlobType; +import com.expedia.blobs.core.BlobWriter; +import org.apache.commons.lang3.Validate; + +/** + * Class representing a {@link BlobContext} associated with {@link BlobWriter} and uses {@link Span} + * to save blob key produced to be used again for reading + */ + +public class SpanBlobContext implements BlobContext { + + private final Span span; + private final String remoteServiceName; + private final static String PARTIAL_BLOB_KEY = "-blob"; + private final String name; + + /** + * constructor + * @param span span object + * @param remoteServiceName for a specific service name, can't be null or empty + * @param name for a specific operation name + */ + public SpanBlobContext(Span span, String remoteServiceName, String name) { + Validate.notNull(span, "span cannot be null in context"); + Validate.notEmpty(remoteServiceName, "remoteServiceName name cannot be null or empty in context"); + Validate.notEmpty(name, "name cannot be null or empty in context"); + + this.span = span; + this.remoteServiceName = remoteServiceName; + this.name = name; + } + + @Override + public String getOperationName() { + return this.name; + } + + @Override + public String getServiceName() { + return this.remoteServiceName; + } + + @Override + public String getOperationId() { + return String.valueOf(this.span.context().spanId()); + } + + /** + * This will be used to add the key produced inside the span + * for it to be used during the time of reading the blob through the span + * @param blobKey created from {@link SpanBlobContext#makeKey(BlobType)} + * @param blobType value of {@link BlobType} + */ + @Override + public void onBlobKeyCreate(String blobKey, BlobType blobType) { + span.tag(String.format("%s%s", blobType.getType(), PARTIAL_BLOB_KEY), blobKey); + } +} diff --git a/zipkin-blobs/src/test/scala/brave/blobs/SpanBlobContextSpec.scala b/zipkin-blobs/src/test/scala/brave/blobs/SpanBlobContextSpec.scala new file mode 100644 index 0000000..1701ac0 --- /dev/null +++ b/zipkin-blobs/src/test/scala/brave/blobs/SpanBlobContextSpec.scala @@ -0,0 +1,55 @@ +package brave.blobs + +import brave.Span +import brave.propagation.TraceContext +import com.expedia.blobs.core.BlobType +import org.easymock.EasyMock.{replay, verify} +import org.scalatest.easymock.EasyMockSugar +import org.scalatest.{FunSpec, Matchers} + +class SpanBlobContextSpec extends FunSpec with Matchers with EasyMockSugar { + + describe("brave.blobs.SpanBlobContext") { + + it("should throw an error if span is not present") { + val catchExpection = intercept[Exception] { + val _ = new SpanBlobContext(null, "", "") + } + + catchExpection.getMessage shouldEqual "span cannot be null in context" + } + + it("should throw an error if serviceName is not present") { + val catchExpection = intercept[Exception] { + val _ = new SpanBlobContext(mock[Span], "", "") + } + + catchExpection.getMessage shouldEqual "remoteServiceName name cannot be null or empty in context" + } + + it("should throw an error if name is not present") { + val catchExpection = intercept[Exception] { + val _ = new SpanBlobContext(mock[Span], "remote-service", "") + } + + catchExpection.getMessage shouldEqual "name cannot be null or empty in context" + } + + it("should add a tag to the Span when onBlobKeyCreate is invoked") { + val span = mock[Span] + val traceContext = TraceContext.newBuilder().traceId(2345678901L).spanId(1234567890L).build() + val spanBlobContext = new SpanBlobContext(span, "remote-service", "span-name") + + expecting { + span.tag("request-blob", "remote-service_span-name_1234567890_request").andReturn(span).once() + span.context().andReturn(traceContext).once() + } + replay(span) + + + spanBlobContext.onBlobKeyCreate(spanBlobContext.makeKey(BlobType.REQUEST), BlobType.REQUEST) + + verify(span) + } + } +}