1111import io .opentelemetry .api .common .AttributeKey ;
1212import io .opentelemetry .api .common .AttributeType ;
1313import io .opentelemetry .api .common .Attributes ;
14+ import io .opentelemetry .api .metrics .MeterProvider ;
1415import io .opentelemetry .api .trace .StatusCode ;
16+ import io .opentelemetry .exporter .internal .ExporterMetrics ;
1517import io .opentelemetry .sdk .common .CompletableResultCode ;
1618import io .opentelemetry .sdk .common .InstrumentationScopeInfo ;
1719import io .opentelemetry .sdk .internal .ThrottlingLogger ;
3537import zipkin2 .Endpoint ;
3638import zipkin2 .Span ;
3739import zipkin2 .codec .BytesEncoder ;
40+ import zipkin2 .codec .Encoding ;
3841import zipkin2 .reporter .Sender ;
3942
4043/**
41- * This class was based on the OpenCensus zipkin exporter code at
42- * https://github.com/census-instrumentation/opencensus-java/tree/c960b19889de5e4a7b25f90919d28b066590d4f0/exporters/trace/zipkin
44+ * This class was based on the <a
45+ * href="https://github.com/census-instrumentation/opencensus-java/tree/c960b19889de5e4a7b25f90919d28b066590d4f0/exporters/trace/zipkin">OpenCensus
46+ * zipkin exporter</a> code.
4347 */
4448public final class ZipkinSpanExporter implements SpanExporter {
45- public static final String DEFAULT_ENDPOINT = "http://localhost:9411/api/v2/spans" ;
49+
4650 public static final Logger baseLogger = Logger .getLogger (ZipkinSpanExporter .class .getName ());
4751
48- private final ThrottlingLogger logger = new ThrottlingLogger ( baseLogger ) ;
52+ public static final String DEFAULT_ENDPOINT = "http://localhost:9411/api/v2/spans" ;
4953
5054 static final String OTEL_DROPPED_ATTRIBUTES_COUNT = "otel.dropped_attributes_count" ;
5155 static final String OTEL_DROPPED_EVENTS_COUNT = "otel.dropped_events_count" ;
@@ -57,13 +61,20 @@ public final class ZipkinSpanExporter implements SpanExporter {
5761 static final String KEY_INSTRUMENTATION_LIBRARY_NAME = "otel.library.name" ;
5862 static final String KEY_INSTRUMENTATION_LIBRARY_VERSION = "otel.library.version" ;
5963
64+ private final ThrottlingLogger logger = new ThrottlingLogger (baseLogger );
65+
6066 private final BytesEncoder <Span > encoder ;
6167 private final Sender sender ;
68+ private final ExporterMetrics exporterMetrics ;
6269 @ Nullable private final InetAddress localAddress ;
6370
64- ZipkinSpanExporter (BytesEncoder <Span > encoder , Sender sender ) {
71+ ZipkinSpanExporter (BytesEncoder <Span > encoder , Sender sender , MeterProvider meterProvider ) {
6572 this .encoder = encoder ;
6673 this .sender = sender ;
74+ this .exporterMetrics =
75+ sender .encoding () == Encoding .JSON
76+ ? ExporterMetrics .createHttpJson ("zipkin" , "span" , meterProvider )
77+ : ExporterMetrics .createHttpProtobuf ("zipkin" , "span" , meterProvider );
6778 localAddress = produceLocalIp ();
6879 }
6980
@@ -83,12 +94,13 @@ static InetAddress produceLocalIp() {
8394 }
8495 }
8596 } catch (Exception e ) {
86- // don't crash the caller if there was a problem reading nics.
97+ // don't crash the caller if there was a problem reading nics
8798 baseLogger .log (Level .FINE , "error reading nics" , e );
8899 }
89100 return null ;
90101 }
91102
103+ // VisibleForTesting
92104 Span generateSpan (SpanData spanData ) {
93105 Endpoint endpoint = getEndpoint (spanData );
94106
@@ -119,26 +131,26 @@ Span generateSpan(SpanData spanData) {
119131
120132 StatusData status = spanData .getStatus ();
121133
122- // include status code & error.
134+ // include status code & error
123135 if (status .getStatusCode () != StatusCode .UNSET ) {
124136 spanBuilder .putTag (OTEL_STATUS_CODE , status .getStatusCode ().toString ());
125137
126- // add the error tag, if it isn't already in the source span.
138+ // add the error tag, if it isn't already in the source span
127139 if (status .getStatusCode () == StatusCode .ERROR && spanAttributes .get (STATUS_ERROR ) == null ) {
128- spanBuilder .putTag (STATUS_ERROR .getKey (), nullToEmpty ( status .getDescription () ));
140+ spanBuilder .putTag (STATUS_ERROR .getKey (), status .getDescription ());
129141 }
130142 }
131143
132144 InstrumentationScopeInfo instrumentationScopeInfo = spanData .getInstrumentationScopeInfo ();
133145
134146 if (!instrumentationScopeInfo .getName ().isEmpty ()) {
135147 spanBuilder .putTag (KEY_INSTRUMENTATION_SCOPE_NAME , instrumentationScopeInfo .getName ());
136- // Include instrumentation library name for backwards compatibility
148+ // include instrumentation library name for backwards compatibility
137149 spanBuilder .putTag (KEY_INSTRUMENTATION_LIBRARY_NAME , instrumentationScopeInfo .getName ());
138150 }
139151 if (instrumentationScopeInfo .getVersion () != null ) {
140152 spanBuilder .putTag (KEY_INSTRUMENTATION_SCOPE_VERSION , instrumentationScopeInfo .getVersion ());
141- // Include instrumentation library name for backwards compatibility
153+ // include instrumentation library name for backwards compatibility
142154 spanBuilder .putTag (
143155 KEY_INSTRUMENTATION_LIBRARY_VERSION , instrumentationScopeInfo .getVersion ());
144156 }
@@ -154,21 +166,17 @@ Span generateSpan(SpanData spanData) {
154166 return spanBuilder .build ();
155167 }
156168
157- private static String nullToEmpty (String value ) {
158- return value != null ? value : "" ;
159- }
160-
161169 private Endpoint getEndpoint (SpanData spanData ) {
162170 Attributes resourceAttributes = spanData .getResource ().getAttributes ();
163171
164172 Endpoint .Builder endpoint = Endpoint .newBuilder ().ip (localAddress );
165173
166- // use the service.name from the Resource, if it's been set.
174+ // use the service.name from the Resource, if it's been set
167175 String serviceNameValue = resourceAttributes .get (ResourceAttributes .SERVICE_NAME );
168176 if (serviceNameValue == null ) {
169177 serviceNameValue = Resource .getDefault ().getAttribute (ResourceAttributes .SERVICE_NAME );
170178 }
171- // In practice should never be null unless the default Resource spec is changed.
179+ // in practice should never be null unless the default Resource spec is changed
172180 if (serviceNameValue != null ) {
173181 endpoint .serviceName (serviceNameValue );
174182 }
@@ -226,7 +234,10 @@ private static String commaSeparated(List<?> values) {
226234
227235 @ Override
228236 public CompletableResultCode export (Collection <SpanData > spanDataList ) {
229- List <byte []> encodedSpans = new ArrayList <>(spanDataList .size ());
237+ int numItems = spanDataList .size ();
238+ exporterMetrics .addSeen (numItems );
239+
240+ List <byte []> encodedSpans = new ArrayList <>(numItems );
230241 for (SpanData spanData : spanDataList ) {
231242 encodedSpans .add (encoder .encode (generateSpan (spanData )));
232243 }
@@ -238,11 +249,13 @@ public CompletableResultCode export(Collection<SpanData> spanDataList) {
238249 new Callback <Void >() {
239250 @ Override
240251 public void onSuccess (Void value ) {
252+ exporterMetrics .addSuccess (numItems );
241253 result .succeed ();
242254 }
243255
244256 @ Override
245257 public void onError (Throwable t ) {
258+ exporterMetrics .addFailed (numItems );
246259 logger .log (Level .WARNING , "Failed to export spans" , t );
247260 result .fail ();
248261 }
0 commit comments