blob: 19f0090f504f155678c3c4644f01e5ac5795c13b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.geronimo.microprofile.opentracing.impl;
import static java.util.Optional.ofNullable;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.ws.rs.core.MultivaluedMap;
import io.opentracing.Scope;
import io.opentracing.ScopeManager;
import io.opentracing.Span;
import io.opentracing.SpanContext;
import io.opentracing.Tracer;
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap;
@ApplicationScoped
public class GeronimoTracer implements Tracer {
@Inject
private ScopeManager scopeManager;
@Inject
private IdGenerator idGenerator;
@Inject
private Event<FinishedSpan> finishedSpanEvent;
@Override
public ScopeManager scopeManager() {
return scopeManager;
}
@Override
public Span activeSpan() {
return ofNullable(scopeManager.active()).map(Scope::span).orElse(null);
}
@Override
public SpanBuilder buildSpan(final String operationName) {
return new SpanBuilderImpl(this, span -> finishedSpanEvent.fire(new FinishedSpan(span)), operationName, idGenerator);
}
@Override
public <C> void inject(final SpanContext spanContext, final Format<C> format, final C carrier) {
if (!TextMap.class.isInstance(carrier)) {
throw new IllegalArgumentException("Only TextMap are supported");
}
final TextMap textMap = TextMap.class.cast(carrier);
final SpanContextImpl context = SpanContextImpl.class.cast(spanContext);
textMap.put("traceid", String.valueOf(context.getTraceId()));
textMap.put("spanid", String.valueOf(context.getSpanId()));
context.getBaggageItems().forEach((k, v) -> textMap.put("baggage-" + k, v));
}
@Override
public <C> SpanContext extract(final Format<C> format, final C carrier) {
if (HeaderTextMap.class.isInstance(carrier)) {
final MultivaluedMap<String, ?> map = HeaderTextMap.class.cast(carrier).getMap();
final String traceid = (String) map.getFirst("traceid");
final String spanid = (String) map.getFirst("spanid");
if (traceid != null && spanid != null) {
return new SpanContextImpl(traceid, spanid, map.keySet().stream().filter(it -> it.startsWith("baggage-"))
.collect(toMap(identity(), k -> String.valueOf(map.getFirst(k)))));
}
return null;
}
if (!TextMap.class.isInstance(carrier)) {
throw new IllegalArgumentException("Only TextMap are supported");
}
final Iterator<Map.Entry<String, String>> textMap = TextMap.class.cast(carrier).iterator();
String traceId = null;
String spanId = null;
final Map<String, String> baggages = new HashMap<>();
while (textMap.hasNext()) {
final Map.Entry<String, String> next = textMap.next();
if (next.getKey().startsWith("baggage-")) {
baggages.put(next.getKey(), next.getValue());
} else if ("spanid".equals(next.getKey())) {
spanId = next.getValue();
} else if ("traceid".equals(next.getKey())) {
traceId = next.getValue();
}
}
if (traceId != null && spanId != null) {
return new SpanContextImpl(traceId, spanId, baggages);
}
return null;
}
}