1 /* 2 * Copyright 2018, OpenCensus Authors 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 io.opencensus.exporter.trace.jaeger; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static java.util.Collections.singletonList; 21 import static java.util.concurrent.TimeUnit.MILLISECONDS; 22 import static org.mockito.Matchers.eq; 23 import static org.mockito.Mockito.mock; 24 import static org.mockito.Mockito.verify; 25 26 import com.google.common.collect.ImmutableMap; 27 import com.google.common.collect.Lists; 28 import com.uber.jaeger.exceptions.SenderException; 29 import com.uber.jaeger.senders.HttpSender; 30 import com.uber.jaeger.thriftjava.Log; 31 import com.uber.jaeger.thriftjava.Process; 32 import com.uber.jaeger.thriftjava.Span; 33 import com.uber.jaeger.thriftjava.SpanRef; 34 import com.uber.jaeger.thriftjava.SpanRefType; 35 import com.uber.jaeger.thriftjava.Tag; 36 import com.uber.jaeger.thriftjava.TagType; 37 import io.opencensus.common.Timestamp; 38 import io.opencensus.trace.Annotation; 39 import io.opencensus.trace.AttributeValue; 40 import io.opencensus.trace.Link; 41 import io.opencensus.trace.MessageEvent; 42 import io.opencensus.trace.SpanContext; 43 import io.opencensus.trace.SpanId; 44 import io.opencensus.trace.Status; 45 import io.opencensus.trace.TraceId; 46 import io.opencensus.trace.TraceOptions; 47 import io.opencensus.trace.export.SpanData; 48 import java.util.List; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 import org.mockito.ArgumentCaptor; 52 import org.mockito.Captor; 53 import org.mockito.runners.MockitoJUnitRunner; 54 55 @RunWith(MockitoJUnitRunner.class) 56 public class JaegerExporterHandlerTest { 57 private static final byte FF = (byte) 0xFF; 58 59 private final HttpSender mockSender = mock(HttpSender.class); 60 private final Process process = new Process("test"); 61 private final JaegerExporterHandler handler = new JaegerExporterHandler(mockSender, process); 62 63 @Captor private ArgumentCaptor<List<Span>> captor; 64 65 @Test 66 public void exportShouldConvertFromSpanDataToJaegerThriftSpan() throws SenderException { 67 final long startTime = 1519629870001L; 68 final long endTime = 1519630148002L; 69 final SpanData spanData = 70 SpanData.create( 71 sampleSpanContext(), 72 SpanId.fromBytes(new byte[] {(byte) 0x7F, FF, FF, FF, FF, FF, FF, FF}), 73 true, 74 "test", 75 Timestamp.fromMillis(startTime), 76 SpanData.Attributes.create(sampleAttributes(), 0), 77 SpanData.TimedEvents.create(singletonList(sampleAnnotation()), 0), 78 SpanData.TimedEvents.create(singletonList(sampleMessageEvent()), 0), 79 SpanData.Links.create(sampleLinks(), 0), 80 0, 81 Status.OK, 82 Timestamp.fromMillis(endTime)); 83 84 handler.export(singletonList(spanData)); 85 86 verify(mockSender).send(eq(process), captor.capture()); 87 List<Span> spans = captor.getValue(); 88 89 assertThat(spans.size()).isEqualTo(1); 90 Span span = spans.get(0); 91 92 assertThat(span.operationName).isEqualTo("test"); 93 assertThat(span.spanId).isEqualTo(256L); 94 assertThat(span.traceIdHigh).isEqualTo(-72057594037927936L); 95 assertThat(span.traceIdLow).isEqualTo(1L); 96 assertThat(span.parentSpanId).isEqualTo(Long.MAX_VALUE); 97 assertThat(span.flags).isEqualTo(1); 98 assertThat(span.startTime).isEqualTo(MILLISECONDS.toMicros(startTime)); 99 assertThat(span.duration).isEqualTo(MILLISECONDS.toMicros(endTime - startTime)); 100 101 assertThat(span.tags.size()).isEqualTo(3); 102 assertThat(span.tags) 103 .containsExactly( 104 new Tag("BOOL", TagType.BOOL).setVBool(false), 105 new Tag("LONG", TagType.LONG).setVLong(Long.MAX_VALUE), 106 new Tag("STRING", TagType.STRING) 107 .setVStr( 108 "Judge of a man by his questions rather than by his answers. -- Voltaire")); 109 110 assertThat(span.logs.size()).isEqualTo(1); 111 Log log = span.logs.get(0); 112 assertThat(log.timestamp).isEqualTo(1519629872987654L); 113 assertThat(log.fields.size()).isEqualTo(4); 114 assertThat(log.fields) 115 .containsExactly( 116 new Tag("description", TagType.STRING).setVStr("annotation #1"), 117 new Tag("bool", TagType.BOOL).setVBool(true), 118 new Tag("long", TagType.LONG).setVLong(1337L), 119 new Tag("string", TagType.STRING) 120 .setVStr("Kind words do not cost much. Yet they accomplish much. -- Pascal")); 121 122 assertThat(span.references.size()).isEqualTo(1); 123 SpanRef reference = span.references.get(0); 124 assertThat(reference.traceIdHigh).isEqualTo(-1L); 125 assertThat(reference.traceIdLow).isEqualTo(-256L); 126 assertThat(reference.spanId).isEqualTo(512L); 127 assertThat(reference.refType).isEqualTo(SpanRefType.CHILD_OF); 128 } 129 130 private static SpanContext sampleSpanContext() { 131 return SpanContext.create( 132 TraceId.fromBytes(new byte[] {FF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}), 133 SpanId.fromBytes(new byte[] {0, 0, 0, 0, 0, 0, 1, 0}), 134 TraceOptions.builder().setIsSampled(true).build()); 135 } 136 137 private static ImmutableMap<String, AttributeValue> sampleAttributes() { 138 return ImmutableMap.of( 139 "BOOL", AttributeValue.booleanAttributeValue(false), 140 "LONG", AttributeValue.longAttributeValue(Long.MAX_VALUE), 141 "STRING", 142 AttributeValue.stringAttributeValue( 143 "Judge of a man by his questions rather than by his answers. -- Voltaire")); 144 } 145 146 private static SpanData.TimedEvent<Annotation> sampleAnnotation() { 147 return SpanData.TimedEvent.create( 148 Timestamp.create(1519629872L, 987654321), 149 Annotation.fromDescriptionAndAttributes( 150 "annotation #1", 151 ImmutableMap.of( 152 "bool", AttributeValue.booleanAttributeValue(true), 153 "long", AttributeValue.longAttributeValue(1337L), 154 "string", 155 AttributeValue.stringAttributeValue( 156 "Kind words do not cost much. Yet they accomplish much. -- Pascal")))); 157 } 158 159 private static SpanData.TimedEvent<MessageEvent> sampleMessageEvent() { 160 return SpanData.TimedEvent.create( 161 Timestamp.create(1519629871L, 123456789), 162 MessageEvent.builder(MessageEvent.Type.SENT, 42L).build()); 163 } 164 165 private static List<Link> sampleLinks() { 166 return Lists.newArrayList( 167 Link.fromSpanContext( 168 SpanContext.create( 169 TraceId.fromBytes( 170 new byte[] {FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, FF, 0}), 171 SpanId.fromBytes(new byte[] {0, 0, 0, 0, 0, 0, 2, 0}), 172 TraceOptions.builder().setIsSampled(false).build()), 173 Link.Type.CHILD_LINKED_SPAN, 174 ImmutableMap.of( 175 "Bool", AttributeValue.booleanAttributeValue(true), 176 "Long", AttributeValue.longAttributeValue(299792458L), 177 "String", 178 AttributeValue.stringAttributeValue( 179 "Man is condemned to be free; because once thrown into the world, " 180 + "he is responsible for everything he does. -- Sartre")))); 181 } 182 } 183