dubbo鏈路跟蹤

沒有使用框架,自己寫的簡單鏈路跟蹤,主要是下面兩個過濾器TraceRpcFilter、TraceHttpFilter 。

@Activate(group = {Constants.CONSUMER,Constants.PROVIDER})

public class TraceRpcFilter implements Filter {

? ? /**

? ? * 1、保證RpcContext中存在mdcData,為了下一次獲取mdcData后寫入到MDC

? ? * 2、保證MDC中存在mdcData,為了最終的日志打印輸入

? ? * @param invoker

? ? * @param invocation

? ? * @return

? ? * @throws RpcException

? ? */

? ? public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {

? ? ? ? //創(chuàng)建traceId

? ? ? ? TraceUtils.createTrace();

? ? ? ? //創(chuàng)建spanId

? ? ? ? TraceUtils.createSpan();

? ? ? ? //設(shè)置parentId

? ? ? ? TraceUtils.setParent();

? ? ? ? //設(shè)置其它信息

? ? ? ? TraceUtils.setRpcOthersInfo();

? ? ? ? return invoker.invoke(invocation);

? ? }

}


public class TraceHttpFilter extends OncePerRequestFilter implements Ordered {

? ? private static final Logger logger? = LoggerFactory.getLogger(TraceHttpFilter.class);

? ? @Autowired(required = false)

? ? private TraceLogInformation traceLogInformation;

? ? @Override

? ? public int getOrder() {

? ? ? ? return 0;

? ? }

? ? /***

? ? * 生成traceId和spanId,并寫入slf4j的本地線程變量(也就意味著,請求中開啟的線程和定時任務(wù)是得不到traceId和spanId的)

? ? * @Param [request, response, filterChain]

? ? * @return void

? ? **/

? ? @Override

? ? protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

? ? ? ? try {

? ? ? ? ? ? String traceId = request.getHeader("x-http-trace");//nginx可能附加的請求頭

? ? ? ? ? ? if (StringUtils.isEmpty(traceId)) {

? ? ? ? ? ? ? ? MDC.put(TraceConstants.TRACE_ID, TraceUtils.getLogId());

? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? MDC.put(TraceConstants.TRACE_ID, traceId);

? ? ? ? ? ? }

? ? ? ? ? ? //初次調(diào)用,生成spanId

? ? ? ? ? ? MDC.put(TraceConstants.SPAN_ID, TraceUtils.getLogId());

? ? ? ? ? ? if (traceLogInformation != null) {

? ? ? ? ? ? ? ? traceLogInformation.setLocalIp(AccessIpUtils.getLocalIp());//本地IP

? ? ? ? ? ? ? ? traceLogInformation.setRemoteIp(AccessIpUtils.getRemoteIp(request));//訪問IP

? ? ? ? ? ? ? ? TraceUtils.setHttpOthersInfo(traceLogInformation);

? ? ? ? ? ? }

? ? ? ? }catch (Exception ex){

? ? ? ? ? ? logger.error("http請求過濾器處理異常:{}",ex.getMessage());

? ? ? ? }

? ? ? ? filterChain.doFilter(request ,response);

? ? }

}


public class AccessIpUtils {

? ? /***

? ? * X-Forwarded-For:? ? Squid 服務(wù)代理

? ? * Proxy-Client-IP:? ? apache 服務(wù)代理

? ? * WL-Proxy-Client-IP:? weblogic 服務(wù)代理

? ? * X-Real-IP:? ? ? ? ? nginx服務(wù)代理

? ? * HTTP_CLIENT_IP:? ? ? 有些代理服務(wù)器

? ? *對http請求獲取請求IP

? ? * @Param [request]

? ? * @return java.lang.String

? ? **/

? ? public static String getRemoteIp(HttpServletRequest request) {

? ? ? ? String ip = null;

? ? ? ? String ipAddresses = request.getHeader("X-Forwarded-For");

? ? ? ? if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {

? ? ? ? ? ? ipAddresses = request.getHeader("Proxy-Client-IP");

? ? ? ? }

? ? ? ? if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {

? ? ? ? ? ? ipAddresses = request.getHeader("WL-Proxy-Client-IP");

? ? ? ? }

? ? ? ? if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {

? ? ? ? ? ? ipAddresses = request.getHeader("HTTP_CLIENT_IP");

? ? ? ? }

? ? ? ? if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {

? ? ? ? ? ? ipAddresses = request.getHeader("X-Real-IP");

? ? ? ? }

? ? ? ? //有些網(wǎng)絡(luò)通過多層代理,那么獲取到的ip就會有多個,一般都是通過逗號(,)分割開來,并且第一個ip為客戶端的真實IP

? ? ? ? if (ipAddresses != null && ipAddresses.length() != 0) {

? ? ? ? ? ? ip = ipAddresses.split(",")[0];

? ? ? ? }

? ? ? ? if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {

? ? ? ? ? ? ip = request.getRemoteAddr();

? ? ? ? }

? ? ? ? return ip;

? ? }

? ? public static String getLocalIp()throws UnknownHostException{

? ? ? ? return InetAddress.getLocalHost().getHostAddress();

? ? }

}

public class TraceConstants {

? ? public static final String TRACE_TEXT_FORMAT = "[TraceId:%s]";

? ? public static final String TRACE_ID =? "traceId2";

? ? public static final String SPAN_ID? =? "spanId2";

? ? public static final String PARENT_ID =? "parentId2";

? ? public static final String APP_FLAG = UUID.randomUUID().toString();

}

public class TraceUtils {

? ? /***

? ? * 通過UUID,生成traceId、spanId

? ? * @Param []

? ? * @return java.lang.String

? ? **/

? ? public static String getLogId(){

? ? ? ? return UUID.randomUUID().toString().replaceAll("-","");

? ? }

? ? /***

? ? * 生成TraceId,

? ? * 關(guān)鍵點:traceId不應(yīng)該為空,僅從該點出發(fā)判斷邏輯即可,不做任何其它邏輯上的判斷

? ? * @Param []

? ? * @return void

? ? **/

? ? public static? void? createTrace(){

? ? ? ? String? rpcTraceId? =? RpcContext.getContext().getAttachment(TraceConstants.TRACE_ID);

? ? ? ? String? mdcTraceId? =? MDC.get(TraceConstants.TRACE_ID);

? ? ? ? if(StringUtils.isEmpty(mdcTraceId)&&StringUtils.isEmpty(rpcTraceId)){

? ? ? ? ? ? rpcTraceId? =? TraceUtils.getLogId();

? ? ? ? ? ? MDC.put(TraceConstants.TRACE_ID ,rpcTraceId);

? ? ? ? ? ? RpcContext.getContext().setAttachment(TraceConstants.TRACE_ID ,rpcTraceId);

? ? ? ? }else if(StringUtils.isEmpty(mdcTraceId)&&StringUtils.isNotEmpty(rpcTraceId)){

? ? ? ? ? ? MDC.put(TraceConstants.TRACE_ID ,rpcTraceId);

? ? ? ? }else if(StringUtils.isEmpty(rpcTraceId)&&StringUtils.isNotEmpty(mdcTraceId)){

? ? ? ? ? ? RpcContext.getContext().setAttachment(TraceConstants.TRACE_ID ,mdcTraceId);

? ? ? ? }

? ? }

? ? /***

? ? * 生成SpanId,

? ? * 關(guān)鍵點:一次調(diào)用的同一個服務(wù)中,spanId是不變的;不同的服務(wù)中,spanId是不一樣的;另外,spanId不可能為空

? ? * @Param []

? ? * @return void

? ? **/

? ? public static? void? createSpan(){

? ? ? ? String? rpcSpanId? =? RpcContext.getContext().getAttachment(TraceConstants.SPAN_ID);

? ? ? ? String? mdcSpanId? =? MDC.get(TraceConstants.SPAN_ID);

? ? ? ? if(StringUtils.isEmpty(mdcSpanId)&&StringUtils.isEmpty(rpcSpanId)){

? ? ? ? ? ? rpcSpanId? =? TraceUtils.getLogId();

? ? ? ? ? ? MDC.put(TraceConstants.SPAN_ID ,rpcSpanId);

? ? ? ? ? ? RpcContext.getContext().setAttachment(TraceConstants.SPAN_ID ,rpcSpanId);

? ? ? ? } else if(StringUtils.isEmpty(mdcSpanId)&&StringUtils.isNotEmpty(rpcSpanId)){

? ? ? ? ? ? MDC.put(TraceConstants.SPAN_ID ,TraceUtils.getLogId());

? ? ? ? }

? ? }

? ? /***

? ? * 設(shè)置parentId

? ? * 關(guān)鍵點:同一個服務(wù)中的一次調(diào)用,parentId是不變的;其他情況下,parentId為上一次的spanId

? ? * @Param []

? ? * @return void

? ? **/

? ? public static? void setParent(){

? ? ? ? String mdcSpanId? ? =? MDC.get(TraceConstants.SPAN_ID);

? ? ? ? String? rpcSpanId? =? RpcContext.getContext().getAttachment(TraceConstants.PARENT_ID);

? ? ? ? if(StringUtils.isNotEmpty(mdcSpanId)){

? ? ? ? ? ? RpcContext.getContext().setAttachment(TraceConstants.PARENT_ID ,mdcSpanId);

? ? ? ? }

? ? ? ? if(StringUtils.isNotEmpty(rpcSpanId)){

? ? ? ? ? ? MDC.put(TraceConstants.PARENT_ID, rpcSpanId);

? ? ? ? }

? ? }

? ? /**

? ? * 應(yīng)用名稱、Ip等信息

? ? * @Param []

? ? * @return void

? ? **/

? ? public static? void setRpcOthersInfo(){

? ? ? ? String appName = RpcContext.getContext().getUrl().getParameter("application");

? ? ? ? String localIp = RpcContext.getContext().getLocalHost();

? ? ? ? String remoteIp = RpcContext.getContext().getRemoteHost();

? ? ? ? MDC.put("appName" ,appName);

? ? ? ? MDC.put("localIp2" ,localIp);

? ? ? ? MDC.put("remoteIp2",remoteIp);

? ? }

? ? /**

? ? * 應(yīng)用名稱、Ip等信息

? ? * @Param []

? ? * @return void

? ? **/

? ? public static? void setHttpOthersInfo(TraceLogInformation traceLogInformation){

? ? ? ? MDC.put("appName" ,traceLogInformation.getApplicationName());

? ? ? ? MDC.put("localIp" ,traceLogInformation.getLocalIp());

? ? ? ? MDC.put("remoteIp" ,traceLogInformation.getRemoteIp());

? ? }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容