Skip to content

Commit

Permalink
Move Trace to zipkin-common (part 1)
Browse files Browse the repository at this point in the history
Moved TraceTimeline and TimelineAnnotation to zipkin-common, pulled out
some thrift dependencies

Author: @franklinhu
Fixes #66
URL: #66
  • Loading branch information
Franklin Hu committed Jul 6, 2012
1 parent 54692f4 commit 3a32463
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 47 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2012 Twitter Inc.
*
* Licensed 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 com.twitter.zipkin.adapter

import com.twitter.zipkin.query.{TraceTimeline, TimelineAnnotation}

trait QueryAdapter {
type timelineAnnotationType /* corresponds to com.twitter.zipkin.query.TimelineAnnotation */
type traceTimelineType /* corresponds to com.twitter.zipkin.query.TraceTimeline */

def apply(t: timelineAnnotationType): TimelineAnnotation
def apply(t: TimelineAnnotation): timelineAnnotationType

def apply(t: traceTimelineType): TraceTimeline
def apply(t: TraceTimeline): traceTimelineType
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2012 Twitter Inc.
*
* Licensed 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 com.twitter.zipkin.query

import com.twitter.zipkin.common.Endpoint

/**
* Extension of `Annotation` that also includes span/service information useful for query side
* responses
*/
case class TimelineAnnotation(timestamp: Long, value: String, host: Endpoint, spanId: Long, parentId: Option[Long],
serviceName: String, spanName: String)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2012 Twitter Inc.
*
* Licensed 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 com.twitter.zipkin.query

import com.twitter.zipkin.common.BinaryAnnotation

/**
* Query side struct that contains
* - trace ID
* - root span (or span closest to the root
* - sorted list of `TimelineAnnotation`s
* - binary annotations
* for a particular trace
*/
case class TraceTimeline(traceId: Long, rootSpanId: Long, annotations: Seq[TimelineAnnotation],
binaryAnnotations: Seq[BinaryAnnotation])
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2012 Twitter Inc.
*
* Licensed 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 com.twitter.zipkin.adapter

import com.twitter.zipkin.gen
import com.twitter.zipkin.query.{TraceTimeline, TimelineAnnotation}

object ThriftQueryAdapter extends QueryAdapter {
type timelineAnnotationType = gen.TimelineAnnotation
type traceTimelineType = gen.TraceTimeline

/* TimelineAnnotation from Thrift */
def apply(t: timelineAnnotationType): TimelineAnnotation = {
TimelineAnnotation(
t.`timestamp`,
t.`value`,
ThriftAdapter(t.`host`),
t.`spanId`,
t.`parentId`,
t.`serviceName`,
t.`spanName`)
}

/* TimelineAnnotation to Thrift */
def apply(t: TimelineAnnotation): timelineAnnotationType = {
gen.TimelineAnnotation(
t.timestamp,
t.value,
ThriftAdapter(t.host),
t.spanId,
t.parentId,
t.serviceName,
t.spanName)
}

/* TraceTimeline from Thrift */
def apply(t: traceTimelineType): TraceTimeline = {
TraceTimeline(
t.`traceId`,
t.`rootMostSpanId`,
t.`annotations`.map { ThriftQueryAdapter(_) },
t.`binaryAnnotations`.map { ThriftAdapter(_) })
}

/* TraceTimeline to Thrift */
def apply(t: TraceTimeline): traceTimelineType = {
gen.TraceTimeline(
t.traceId,
t.rootSpanId,
t.annotations.map { ThriftQueryAdapter(_) },
t.binaryAnnotations.map { ThriftAdapter(_) })
}
}
19 changes: 8 additions & 11 deletions zipkin-server/src/main/scala/com/twitter/zipkin/common/Trace.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ package com.twitter.zipkin.common
import com.twitter.zipkin.gen
import collection.mutable
import mutable.HashMap
import com.twitter.zipkin.query.conversions.TraceToTimeline
import com.twitter.logging.Logger
import java.nio.ByteBuffer
import com.twitter.zipkin.adapter.ThriftAdapter
import com.twitter.finagle.tracing.{Trace => FTrace}
import com.twitter.zipkin.query.conversions.TraceToTimeline
import com.twitter.zipkin.adapter.{ThriftQueryAdapter, ThriftAdapter}
import com.twitter.zipkin.query.TraceTimeline

/**
* Represents a trace, a bundle of spans.
Expand All @@ -49,8 +50,6 @@ case class Trace(spans: Seq[Span]) {

val log = Logger.get(getClass.getName)

private[this] val traceToTimeline = new TraceToTimeline

/**
* Find the trace id for this trace.
* Returns none if we have no spans to look up id by
Expand Down Expand Up @@ -150,13 +149,13 @@ case class Trace(spans: Seq[Span]) {
serviceCounts, endpoints.toList)
}

def toTimeline: Option[gen.TraceTimeline] = {
def toTimeline: Option[TraceTimeline] = {
FTrace.record("toTimeline")
traceToTimeline.toTraceTimeline(this)
TraceToTimeline(this)
}

def toTraceCombo: gen.TraceCombo = {
gen.TraceCombo(toThrift, toTraceSummary.map(ThriftAdapter(_)), toTimeline, toSpanDepths)
gen.TraceCombo(toThrift, toTraceSummary.map(ThriftAdapter(_)), toTimeline.map(ThriftQueryAdapter(_)), toSpanDepths)
}

/**
Expand Down Expand Up @@ -187,11 +186,9 @@ case class Trace(spans: Seq[Span]) {
/**
* Get all the binary annotations in this trace.
*/
def getBinaryAnnotations: Seq[gen.BinaryAnnotation] = {
def getBinaryAnnotations: Seq[BinaryAnnotation] = {
spans.map {
_.binaryAnnotations.map {
ThriftAdapter(_)
}
_.binaryAnnotations
}.flatten
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import com.twitter.zipkin.storage.{Aggregates, TraceIdDuration, Index, Storage}
import java.nio.ByteBuffer
import org.apache.thrift.TException
import scala.collection.Set
import com.twitter.zipkin.adapter.ThriftAdapter
import com.twitter.zipkin.adapter.{ThriftQueryAdapter, ThriftAdapter}

/**
* Able to respond to users queries regarding the traces. Usually does so
Expand Down Expand Up @@ -202,7 +202,7 @@ class QueryService(storage: Storage, index: Index, aggregates: Aggregates, adjus

Stats.timeFutureMillis("query.getTraceTimelinesByIds") {
storage.getTracesByIds(traceIds).map { id =>
id.flatMap(adjusters.foldLeft(_)((trace, adjuster) => adjuster.adjust(trace)).toTimeline)
id.flatMap(adjusters.foldLeft(_)((trace, adjuster) => adjuster.adjust(trace)).toTimeline.map(ThriftQueryAdapter(_)))
} rescue {
case e: Exception =>
log.error(e, "getTraceTimelinesByIds query failed")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@
*/
package com.twitter.zipkin.query.conversions

import com.twitter.zipkin.gen
import com.twitter.zipkin.common.{IncompleteTraceDataException, Endpoint, Trace}
import com.twitter.zipkin.adapter.ThriftAdapter
import com.twitter.zipkin.common._
import com.twitter.zipkin.query.{TraceTimeline, TimelineAnnotation}

class TraceToTimeline {
object TraceToTimeline {

def toTraceTimeline(trace: Trace): Option[gen.TraceTimeline] = {
def apply(trace: Trace): Option[TraceTimeline] = {

if (trace.spans.isEmpty) {
return None
Expand All @@ -30,16 +29,18 @@ class TraceToTimeline {
// convert span and annotation to timeline annotation
val annotations = trace.spans.flatMap(s =>
s.annotations.map{ a =>
gen.TimelineAnnotation(a.timestamp, a.value,
TimelineAnnotation(
a.timestamp,
a.value,
a.host match {
case Some(s) => ThriftAdapter(s)
case None => ThriftAdapter(Endpoint.Unknown)
case Some(s) => s
case None => Endpoint.Unknown
},
s.id,
s.parentId,
a.host match {
case Some(s) => s.serviceName
case None => "Unknown"
case None => "Unknown"
},
s.name)
}
Expand All @@ -53,7 +54,7 @@ class TraceToTimeline {
val rootSpanId = trace.getRootMostSpan.getOrElse(return None).id
val id = trace.id.getOrElse(return None)

Some(gen.TraceTimeline(id, rootSpanId, annotations, trace.getBinaryAnnotations))
Some(TraceTimeline(id, rootSpanId, annotations, trace.getBinaryAnnotations))
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,10 @@ class TraceSpec extends Specification {
}

"getBinaryAnnotations" in {
val ba1 = gen.BinaryAnnotation("key1", ByteBuffer.wrap("value1".getBytes), gen.AnnotationType.String)
val span1 = Span(1L, "", 1L, None, List(), List(ThriftAdapter(ba1)))
val ba2 = gen.BinaryAnnotation("key2", ByteBuffer.wrap("value2".getBytes), gen.AnnotationType.String)
val span2 = Span(1L, "", 2L, None, List(), List(ThriftAdapter(ba2)))
val ba1 = BinaryAnnotation("key1", ByteBuffer.wrap("value1".getBytes), ThriftAdapter(gen.AnnotationType.String), None)
val span1 = Span(1L, "", 1L, None, List(), List(ba1))
val ba2 = BinaryAnnotation("key2", ByteBuffer.wrap("value2".getBytes), ThriftAdapter(gen.AnnotationType.String), None)
val span2 = Span(1L, "", 2L, None, List(), List(ba2))

val trace = Trace(List[Span](span1, span2))
Seq(ba1, ba2) mustEqual trace.getBinaryAnnotations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ import com.twitter.zipkin.common._
import java.nio.ByteBuffer
import com.twitter.util.Future
import com.twitter.scrooge.BinaryThriftStructSerializer
import com.twitter.zipkin.adapter.ThriftAdapter
import com.twitter.zipkin.storage.{Aggregates, TraceIdDuration, Storage, Index}
import com.twitter.zipkin.adapter.{ThriftQueryAdapter, ThriftAdapter}

class QueryServiceSpec extends Specification with JMocker with ClassMocker {
val ep1 = Endpoint(123, 123, "service1")
Expand Down Expand Up @@ -181,7 +181,7 @@ class QueryServiceSpec extends Specification with JMocker with ClassMocker {
}
val trace = trace1.toThrift
val summary = ThriftAdapter(TraceSummary(1, 100, 150, 50, Map("service1" -> 1), List(ep1)))
val timeline = trace1.toTimeline
val timeline = trace1.toTimeline.map(ThriftQueryAdapter(_))
val combo = gen.TraceCombo(trace, Some(summary), timeline, Some(Map(666L -> 1)))
Seq(combo) mustEqual qs.getTraceCombosByIds(List(traceId), List())()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ package com.twitter.zipkin.query.conversions
import org.specs.Specification
import org.specs.mock.{ClassMocker, JMocker}
import com.twitter.zipkin.gen
import com.twitter.zipkin.common.{Trace, Span, Annotation, Endpoint}

import scala.collection.JavaConversions._
import java.nio.ByteBuffer
import com.twitter.zipkin.adapter.ThriftAdapter
import com.twitter.zipkin.query.{TimelineAnnotation, TraceTimeline}
import com.twitter.zipkin.common._

class TraceToTimelineSpec extends Specification with JMocker with ClassMocker {

Expand Down Expand Up @@ -60,9 +61,9 @@ class TraceToTimelineSpec extends Specification with JMocker with ClassMocker {
val endpoint2 = Some(Endpoint(2, 2, cassieName)) //54147
val endpoint3 = Some(Endpoint(3, 3, koalabirdName)) //36516

val et1 = ThriftAdapter(endpoint1.get)
val et2 = ThriftAdapter(endpoint2.get)
val et3 = ThriftAdapter(endpoint3.get)
val et1 = endpoint1.get
val et2 = endpoint2.get
val et3 = endpoint3.get

// This is from a real trace, at least what the data would look like
// after being run through the TimeSkewAdjuster
Expand All @@ -73,10 +74,10 @@ class TraceToTimelineSpec extends Specification with JMocker with ClassMocker {
val ann5 = Annotation(85, gen.Constants.CLIENT_RECV, endpoint2)
val ann6 = Annotation(87, gen.Constants.CLIENT_RECV, endpoint3)

val ba1 = gen.BinaryAnnotation("key1", ByteBuffer.wrap("value1".getBytes), gen.AnnotationType.String)
val ba1 = BinaryAnnotation("key1", ByteBuffer.wrap("value1".getBytes), ThriftAdapter(gen.AnnotationType.String), None)

val span1 = Span(1, "ValuesFromSource", 2209720933601260005L, None,
List(ann3, ann6), List(ThriftAdapter(ba1)))
List(ann3, ann6), List(ba1))
val span2 = Span(1, "ValuesFromSource", 2209720933601260005L, None,
List(ann4, ann1), Nil)
// the above two spans are part of the same actual span
Expand All @@ -86,32 +87,30 @@ class TraceToTimelineSpec extends Specification with JMocker with ClassMocker {
val trace = new Trace(List(span1, span2, span3))

// annotation numbers match those above, order in list should not though
val tAnn1 = gen.TimelineAnnotation(1, gen.Constants.SERVER_RECV, et1,
val tAnn1 = TimelineAnnotation(1, gen.Constants.SERVER_RECV, et1,
2209720933601260005L, None, cuckooName, "ValuesFromSource")
val tAnn2 = gen.TimelineAnnotation(1, gen.Constants.CLIENT_SEND, et2,
val tAnn2 = TimelineAnnotation(1, gen.Constants.CLIENT_SEND, et2,
-855543208864892776L, Some(2209720933601260005L), cassieName, "multiget_slice")
val tAnn3 = gen.TimelineAnnotation(1, gen.Constants.CLIENT_SEND, et3,
val tAnn3 = TimelineAnnotation(1, gen.Constants.CLIENT_SEND, et3,
2209720933601260005L, None, koalabirdName, "ValuesFromSource")
val tAnn4 = gen.TimelineAnnotation(86, gen.Constants.SERVER_SEND, et1,
val tAnn4 = TimelineAnnotation(86, gen.Constants.SERVER_SEND, et1,
2209720933601260005L, None, cuckooName, "ValuesFromSource")
val tAnn5 = gen.TimelineAnnotation(85, gen.Constants.CLIENT_RECV, et2,
val tAnn5 = TimelineAnnotation(85, gen.Constants.CLIENT_RECV, et2,
-855543208864892776L, Some(2209720933601260005L), cassieName, "multiget_slice")
val tAnn6 = gen.TimelineAnnotation(87, gen.Constants.CLIENT_RECV, et3,
val tAnn6 = TimelineAnnotation(87, gen.Constants.CLIENT_RECV, et3,
2209720933601260005L, None, koalabirdName, "ValuesFromSource")

val expectedTimeline = gen.TraceTimeline(1, 2209720933601260005L, List(tAnn3, tAnn1, tAnn2,
val expectedTimeline = TraceTimeline(1, 2209720933601260005L, List(tAnn3, tAnn1, tAnn2,
tAnn5, tAnn4, tAnn6), List(ba1))

val traceToTimeline = new TraceToTimeline

"TraceToTimelineSpec" should {
"convert to timeline with correct annotations ordering" in {
val actualTimeline = traceToTimeline.toTraceTimeline(trace)
val actualTimeline = TraceToTimeline(trace)
Some(expectedTimeline) mustEqual actualTimeline
}

"return none if empty trace" in {
val actualTimeline = traceToTimeline.toTraceTimeline(new Trace(List()))
val actualTimeline = TraceToTimeline(new Trace(List()))
None mustEqual actualTimeline
}
}
Expand Down

0 comments on commit 3a32463

Please sign in to comment.