Skip to content

Commit 8816a55

Browse files
Merge pull request #182 from ExpediaDotCom/MoveSpanUtilsToCommons
Move SpanUtils to trace-commons so that the indexer can use it.
2 parents 1eb201a + 438bcac commit 8816a55

3 files changed

Lines changed: 188 additions & 3 deletions

File tree

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* Copyright 2018 Expedia, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.expedia.www.haystack.trace.commons.utils
18+
19+
import com.expedia.open.tracing.Log
20+
import com.expedia.open.tracing.Span
21+
import com.expedia.open.tracing.Tag
22+
import com.expedia.www.haystack.trace.commons.utils.SpanMarkers._
23+
24+
import scala.collection.JavaConverters._
25+
26+
object SpanUtils {
27+
val URL_TAG_KEY = "url"
28+
29+
def getEventTimestamp(span: Span, event: String): Long = {
30+
span.getLogsList.asScala.find(log => {
31+
log.getFieldsList.asScala.exists(tag => {
32+
tag.getKey.equalsIgnoreCase(LOG_EVENT_TAG_KEY) && tag.getVStr.equalsIgnoreCase(event)
33+
})
34+
}).get.getTimestamp
35+
}
36+
37+
def getEndTime(span: Span): Long = {
38+
span.getStartTime + span.getDuration
39+
}
40+
41+
def isMergedSpan(span: Span): Boolean = {
42+
containsClientLogTag(span) && containsServerLogTag(span)
43+
}
44+
45+
def containsServerLogTag(span: Span): Boolean = {
46+
containsLogTag(span, SERVER_RECV_EVENT) && containsLogTag(span, SERVER_SEND_EVENT)
47+
}
48+
49+
def getEffectiveServiceName(span: Span): String = {
50+
val serviceTag = getServiceTag(span)
51+
if (serviceTag.isDefined) {
52+
val serviceTagValue = serviceTag.get.getVStr
53+
if (serviceTagValue == "") { // Span protobuf-generated code returns empty string for a missing tag key
54+
span.getServiceName
55+
} else {
56+
serviceTagValue
57+
}
58+
} else {
59+
span.getServiceName
60+
}
61+
}
62+
63+
def getServiceTag(span: Span): Option[Tag] = {
64+
span.getTagsList.asScala.find(tag => {
65+
tag.getKey.equalsIgnoreCase(SERVICE_TAG_KEY)
66+
})
67+
}
68+
69+
def containsClientLogTag(span: Span): Boolean = {
70+
containsLogTag(span, CLIENT_RECV_EVENT) && containsLogTag(span, CLIENT_RECV_EVENT)
71+
}
72+
73+
def addServerLogTag(span: Span): Span = {
74+
val receiveEventLog = Log.newBuilder()
75+
.setTimestamp(span.getStartTime)
76+
.addFields(
77+
Tag.newBuilder().setKey(LOG_EVENT_TAG_KEY).setVStr(SERVER_RECV_EVENT))
78+
79+
val sendEventLog = Log.newBuilder()
80+
.setTimestamp(span.getStartTime + span.getDuration)
81+
.addFields(
82+
Tag.newBuilder().setKey(LOG_EVENT_TAG_KEY).setVStr(SERVER_SEND_EVENT) )
83+
84+
span
85+
.toBuilder
86+
.addLogs(receiveEventLog)
87+
.addLogs(sendEventLog)
88+
.build()
89+
}
90+
91+
def addClientLogTag(span: Span): Span = {
92+
val sendEventLog = Log.newBuilder()
93+
.setTimestamp(span.getStartTime)
94+
.addFields(
95+
Tag.newBuilder().setType(Tag.TagType.STRING).setKey(LOG_EVENT_TAG_KEY).setVStr(CLIENT_SEND_EVENT))
96+
97+
val receiveEventLog = Log.newBuilder()
98+
.setTimestamp(span.getStartTime + span.getDuration)
99+
.addFields(
100+
Tag.newBuilder().setType(Tag.TagType.STRING).setKey(LOG_EVENT_TAG_KEY).setVStr(CLIENT_RECV_EVENT))
101+
102+
span
103+
.toBuilder
104+
.addLogs(sendEventLog)
105+
.addLogs(receiveEventLog)
106+
.build()
107+
}
108+
109+
private def containsLogTag(span: Span, event: String) = {
110+
span.getLogsList.asScala.exists(log => {
111+
log.getFieldsList.asScala.exists(tag => {
112+
tag.getKey.equalsIgnoreCase(LOG_EVENT_TAG_KEY) && tag.getVStr.equalsIgnoreCase(event)
113+
})
114+
})
115+
}
116+
117+
def createAutoGeneratedRootSpan(spans: Seq[Span],
118+
reason: String,
119+
rootSpanId: String): Span.Builder = {
120+
val earliestRoot = spans.minBy(_.getStartTime)
121+
val longestDurationSpan = spans.maxBy(span => span.getStartTime + span.getDuration)
122+
123+
val startTime = earliestRoot.getStartTime
124+
val duration = (longestDurationSpan.getStartTime + longestDurationSpan.getDuration) - startTime
125+
126+
val autoGenSpanBuilder = Span.newBuilder()
127+
.setServiceName(earliestRoot.getServiceName)
128+
.setOperationName(AUTOGEN_OPERATION_NAME)
129+
.setTraceId(earliestRoot.getTraceId)
130+
.setSpanId(rootSpanId)
131+
.setParentSpanId("")
132+
.setStartTime(startTime)
133+
.setDuration(duration)
134+
.addTags(Tag.newBuilder().setKey(AUTOGEN_REASON_TAG).setVStr(reason).setType(Tag.TagType.STRING))
135+
.addTags(Tag.newBuilder().setKey(AUTOGEN_SPAN_ID_TAG).setVStr(rootSpanId).setType(Tag.TagType.STRING))
136+
.addTags(Tag.newBuilder().setKey(AUTOGEN_FLAG_TAG).setVBool(true).setType(Tag.TagType.BOOL))
137+
138+
earliestRoot.getTagsList.asScala.find(_.getKey.equalsIgnoreCase(URL_TAG_KEY)) match {
139+
case Some(urlTag) => autoGenSpanBuilder.addTags(urlTag)
140+
case _ => autoGenSpanBuilder
141+
}
142+
}
143+
}
144+
145+
object SpanMarkers {
146+
val AUTOGEN_OPERATION_NAME = "auto-generated"
147+
val AUTOGEN_REASON_TAG = "X-HAYSTACK-AUTOGEN-REASON"
148+
val AUTOGEN_SPAN_ID_TAG = "X-HAYSTACK-AUTOGEN-SPAN-ID"
149+
val AUTOGEN_FLAG_TAG = "X-HAYSTACK-AUTOGEN"
150+
151+
val LOG_EVENT_TAG_KEY = "event"
152+
val SERVER_SEND_EVENT = "ss"
153+
val SERVER_RECV_EVENT = "sr"
154+
val CLIENT_SEND_EVENT = "cs"
155+
val CLIENT_RECV_EVENT = "cr"
156+
157+
val SPAN_KIND_TAG_KEY = "span.kind"
158+
val SERVICE_TAG_KEY = "service"
159+
val SERVER_SPAN_KIND = "server"
160+
val CLIENT_SPAN_KIND = "client"
161+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2018 Expedia, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.expedia.www.haystack.trace.commons.unit
18+
19+
import org.scalatest.easymock.EasyMockSugar
20+
import org.scalatest.FunSpec
21+
import org.scalatest.GivenWhenThen
22+
import org.scalatest.Matchers
23+
24+
trait BaseUnitTestSpec extends FunSpec with GivenWhenThen with Matchers with EasyMockSugar

reader/src/test/scala/com/expedia/www/haystack/trace/reader/readers/utils/SpanUtilsSpec.scala renamed to commons/src/test/scala/com/expedia/www/haystack/trace/commons/unit/SpanUtilsSpec.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package com.expedia.www.haystack.trace.reader.readers.utils
16+
package com.expedia.www.haystack.trace.commons.unit
1717

1818
import java.lang.System.currentTimeMillis
1919

2020
import com.expedia.open.tracing.Span
2121
import com.expedia.open.tracing.Tag
22-
import com.expedia.www.haystack.trace.reader.readers.utils.SpanMarkers.SERVICE_TAG_KEY
23-
import com.expedia.www.haystack.trace.reader.unit.BaseUnitTestSpec
22+
import com.expedia.www.haystack.trace.commons.utils.SpanMarkers.SERVICE_TAG_KEY
23+
import com.expedia.www.haystack.trace.commons.utils.SpanUtils
2424

2525
class SpanUtilsSpec extends BaseUnitTestSpec {
2626
val ServiceNameInAttribute: String = currentTimeMillis + "ServiceNameInAttribute"

0 commit comments

Comments
 (0)