package com.yirendai.infra.cicada.capture; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.yirendai.infra.cicada.constants.AnnotationType; import com.yirendai.infra.cicada.entity.trace.Annotation; import com.yirendai.infra.cicada.entity.trace.BinaryAnnotation; import com.yirendai.infra.cicada.entity.trace.Endpoint; import com.yirendai.infra.cicada.entity.trace.Span; import com.yirendai.infra.cicada.transfer.Transfer; import org.apache.commons.lang3.StringUtils; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public final class Tracer { // private static final Logger logger = // LoggerFactory.getLogger(Tracer.class); private static Tracer instance = new Tracer(); private final Sampler sampler = new CustomSampler(); private Transfer transfer; // 传递parentSpan private final ThreadLocal<Span> spanThreadLocal = new ThreadLocal<Span>(); private final ThreadLocal<Span> ctxTheadLocal = new ThreadLocal<Span>(); private Tracer() {} public static Tracer getInstance() { return instance; } void removeParentSpan() { spanThreadLocal.remove(); } Span getParentSpan() { return spanThreadLocal.get(); } void setParentSpan(final Span span) { spanThreadLocal.set(span); } // 构件Span,参数通过上游接口传递过来 @SuppressWarnings("PMD.UseObjectForClearerAPI") Span genSpan(final String appName, final String serviceName, final String methodName, final String traceId, final String pid, final String id, final boolean sample) { final Span span = new Span(); span.setAppName(appName); span.setServiceName(serviceName); span.setMethodName(methodName); span.setId(id); span.setParentId(pid); span.setTraceId(traceId); span.setSample(sample); return span; } // 构件rootSpan,是否采样 Span newSpan(final String appName, final String serviceName, final String methodName) { final Span span = new Span(); span.setAppName(appName); span.setServiceName(serviceName); span.setMethodName(methodName); if (this.isSample()) { span.setSample(true); span.setTraceId(genTracerId()); span.setId("1"); } else { span.setSample(false); span.setTraceId(null); span.setId(null); } return span; } // 构件rootSpan,是否采样 Span newSpan(final String appName, final String serviceName, final String methodName, final Span parentSpan) { final Span span = new Span(); span.setAppName(appName); span.setServiceName(serviceName); span.setMethodName(methodName); if (parentSpan.isSample()) { final int subSpanNum = parentSpan.getSubSpanNum() + 1; parentSpan.setSubSpanNum(subSpanNum); span.setSample(true); span.setTraceId(parentSpan.getTraceId()); span.setParentId(parentSpan.getId()); span.setId(parentSpan.getId() + "." + subSpanNum); } else { span.setSample(false); span.setTraceId(null); span.setParentId(null); span.setId(null); } return span; } public void setSampleRate(final int rate) { sampler.setSampleRate(rate); } boolean isSample() { return sampler.isSample(); } void addBinaryAnntation(final BinaryAnnotation bin) { final Span span = spanThreadLocal.get(); if (span != null) { span.addBinaryAnnotation(bin); } } // 构件cs annotation void clientSendRecord(final Span span, final Endpoint endpoint, final long start) { final Annotation annotation = new Annotation(); annotation.setType(AnnotationType.CLIENT_SEND); annotation.setTimestamp(start); annotation.setEndpoint(endpoint); span.addAnnotation(annotation); } // 构件cr annotation void clientReceiveRecord(final Span span, final Endpoint endpoint, final long end) { if (span.isSample() && transfer != null) { final Annotation annotation = new Annotation(); annotation.setType(AnnotationType.CLIENT_RECEIVE); annotation.setEndpoint(endpoint); annotation.setTimestamp(end); span.addAnnotation(annotation); transfer.asyncSend(span); } } // 构件sr annotation void serverReceiveRecord(final Span span, final Endpoint endpoint, final long start) { if (span.isSample()) { final Annotation annotation = new Annotation(); annotation.setType(AnnotationType.SERVER_RECEIVE); annotation.setEndpoint(endpoint); annotation.setTimestamp(start); span.addAnnotation(annotation); } this.setParentSpan(span); } // 构件 ss annotation void serverSendRecord(final Span span, final Endpoint endpoint, final long end) { if (span.isSample() && transfer != null) { final Annotation annotation = new Annotation(); annotation.setTimestamp(end); annotation.setEndpoint(endpoint); annotation.setType(AnnotationType.SERVER_SEND); span.addAnnotation(annotation); transfer.asyncSend(span); } this.removeParentSpan(); } String genTracerId() { return UUID.randomUUID().toString().replace("-", ""); } public void setTransfer(final Transfer transfer) { this.transfer = transfer; } // =======================以下为提供给对外开放的方法================================= public void addBinaryAnnotation(final String className, final String methodName, final int duration) { final Span span = spanThreadLocal.get(); if (span != null && StringUtils.isNotBlank(className) && StringUtils.isNotBlank(methodName) && duration >= 0) { final BinaryAnnotation binaryAnnotation = new BinaryAnnotation(); binaryAnnotation.setKey(className); binaryAnnotation.setValue(methodName); binaryAnnotation.setDuration(duration); binaryAnnotation.setTimestamp(System.currentTimeMillis()); binaryAnnotation.setEndpoint(span.getEndpoint()); span.addBinaryAnnotation(binaryAnnotation); } } public void addBinaryAnnotation(final String key, final String value) { addBinaryAnnotation(key, value, 0); } public void addBinaryAnnotation(final String className, final String methodName, final Throwable ex) { final Span span = spanThreadLocal.get(); if (span != null && ex != null) { final Endpoint endpoint = span.getEndpoint(); if (endpoint != null) { final BinaryAnnotation exAnnotation = new BinaryAnnotation(); exAnnotation.setThrowable(className, methodName, ex); exAnnotation.setEndpoint(endpoint); addBinaryAnntation(exAnnotation); } } } public String getTraceCtx() { String retStr = ""; final Span span = spanThreadLocal.get(); if (span != null) { final String traceId = span.getTraceId(); final String parenSpantId = span.getParentId(); final String spanId = span.getId(); if (StringUtils.isNotBlank(traceId) && StringUtils.isNotBlank(spanId)) { final Map<String, String> retMap = new ConcurrentHashMap<String, String>(); retMap.put(TracerUtils.TRACE_ID, traceId); retMap.put(TracerUtils.PARENT_SPAN_ID, parenSpantId); retMap.put(TracerUtils.SPAN_ID, spanId); retStr = JSON.toJSONString(retMap); } } return retStr; } public void setTraceCtx(final String ctx) { if (StringUtils.isNotBlank(ctx)) { final JSONObject jsonObject = JSON.parseObject(ctx); final String traceId = jsonObject.getString(TracerUtils.TRACE_ID); final String parenSpantId = jsonObject.getString(TracerUtils.PARENT_SPAN_ID); final String spanId = jsonObject.getString(TracerUtils.SPAN_ID); if (StringUtils.isNotBlank(traceId) && StringUtils.isNotBlank(spanId)) { final Span span = new Span(); span.setTraceId(traceId); span.setParentId(parenSpantId); span.setId(spanId); ctxTheadLocal.set(span); } } } Span getAndRemoveTraceCtx() { final Span retSpan = ctxTheadLocal.get(); ctxTheadLocal.remove(); return retSpan; } }