Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
scouter.agent.trace.TraceApiCall Maven / Gradle / Ivy
/*
* Copyright 2015 the original author or authors.
* @https://github.com/scouter-project/scouter
*
* Licensed 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 scouter.agent.trace;
import scouter.agent.Configure;
import scouter.agent.Logger;
import scouter.agent.counter.meter.MeterAPI;
import scouter.agent.counter.meter.MeterInteraction;
import scouter.agent.counter.meter.MeterInteractionManager;
import scouter.agent.netio.data.DataProxy;
import scouter.agent.plugin.PluginHttpCallTrace;
import scouter.agent.plugin.PluginHttpServiceTrace;
import scouter.agent.proxy.IHttpClient;
import scouter.agent.proxy.SpringRestTemplateHttpRequestFactory;
import scouter.agent.summary.ServiceSummary;
import scouter.agent.trace.api.ApiCallTraceHelper;
import scouter.lang.constants.B3Constant;
import scouter.lang.step.ApiCallStep;
import scouter.lang.step.ApiCallStep2;
import scouter.lang.step.MessageStep;
import scouter.lang.step.SocketStep;
import scouter.util.*;
import java.io.File;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.*;
public class TraceApiCall {
private static Configure conf = Configure.getInstance();
private static Object lock = new Object();
private static IntKeyLinkedMap restTemplateHttpRequests = new IntKeyLinkedMap().setMax(5);
private static IntKeyLinkedMap map = new IntKeyLinkedMap().setMax(2001);
static {
try {
PluginHttpServiceTrace.class.getClass();
} catch (Throwable t) {
}
}
public static class Stat {
public TraceContext ctx;
public Object req;
public Object res;
public Stat(TraceContext ctx, Object req, Object res) {
this.ctx = ctx;
this.req = req;
this.res = res;
}
public Stat(TraceContext ctx) {
this.ctx = ctx;
}
}
public static void apiInfo(String className, String methodName, String methodDesc, Object _this, Object[] arg) {
TraceContext ctx = TraceContextManager.getContext();
if (ctx != null && arg.length >= 2) {
ctx.apicall_target = arg[0] + ":" + arg[1];
}
}
public static Object startApicall(String className, String methodName, String methodDesc, Object _this, Object[] arg) {
try {
TraceContext ctx = TraceContextManager.getContext();
if (ctx == null) {
return null;
}
if (ctx.apicall_name != null) {
return null;
}
HookArgs hookPoint = new HookArgs(className, methodName, methodDesc, _this, arg);
ApiCallStep step = ApiCallTraceHelper.start(ctx, hookPoint);
if (step == null)
return null;
step.start_time = (int) (System.currentTimeMillis() - ctx.startTime);
if (ctx.profile_thread_cputime) {
step.start_cpu = (int) (SysJMX.getCurrentThreadCPU() - ctx.startCpu);
}
ctx.profile.push(step);
return new LocalContext(ctx, step, hookPoint);
} catch (Throwable sss) {
sss.printStackTrace();
}
return null;
}
public static Object startApicall(String name, long apiTxid) {
TraceContext ctx = TraceContextManager.getContext();
if (ctx == null)
return null;
if (ctx.apicall_name != null) {
return null;
}
ApiCallStep step = new ApiCallStep();
step.txid = apiTxid;
step.start_time = (int) (System.currentTimeMillis() - ctx.startTime);
if (ctx.profile_thread_cputime) {
step.start_cpu = (int) (SysJMX.getCurrentThreadCPU() - ctx.startCpu);
}
ctx.profile.push(step);
ctx.apicall_name = name;
return new LocalContext(ctx, step);
}
public static void endApicall(Object stat, Object returnValue, Throwable thr) {
if (stat == null)
return;
try {
LocalContext lctx = (LocalContext) stat;
TraceContext tctx = lctx.context;
ApiCallStep step = (ApiCallStep) lctx.stepSingle;
if (step.address == null) {
step.address = tctx.apicall_target;
}
step.hash = DataProxy.sendApicall(tctx.apicall_name);
tctx.apicall_name = null;
tctx.apicall_target = null;
tctx.lastApiCallStep = null;
step.elapsed = (int) (System.currentTimeMillis() - tctx.startTime) - step.start_time;
if (tctx.profile_thread_cputime) {
step.cputime = (int) (SysJMX.getCurrentThreadCPU() - tctx.startCpu) - step.start_cpu;
}
tctx.apicall_count++;
tctx.apicall_time += step.elapsed;
if (thr != null) {
String msg = thr.getMessage();
if(msg == null){
msg = thr.toString();
}
Configure conf = Configure.getInstance();
if (conf.profile_fullstack_apicall_error_enabled) {
StringBuffer sb = new StringBuffer();
sb.append(msg).append("\n");
ThreadUtil.getStackTrace(sb, thr, conf.profile_fullstack_max_lines);
Throwable cause = thr.getCause();
while (cause != null) {
sb.append("\nCause...\n");
ThreadUtil.getStackTrace(sb, cause, conf.profile_fullstack_max_lines);
cause = cause.getCause();
}
msg = sb.toString();
}
step.error = DataProxy.sendError(msg);
if (tctx.error == 0 && conf.xlog_error_on_apicall_exception_enabled) {
tctx.error = step.error;
}
tctx.offerErrorEntity(ErrorEntity.of(thr, step.error, 0, step.hash));
}
Object hookArgs = lctx.option;
if (hookArgs instanceof HookArgs) {
ApiCallTraceHelper.end(tctx, step, returnValue, (HookArgs) hookArgs);
}
if(step instanceof ApiCallStep2 && ((ApiCallStep2) step).async == 1) {
//skip api metering
} else {
MeterAPI.getInstance().add(step.elapsed, step.error != 0);
if (conf.counter_interaction_enabled) {
int toHash = tctx.lastCalleeObjHash;
tctx.lastCalleeObjHash = 0;
if (toHash == 0) {
if (StringUtil.isEmpty(step.address)) {
step.address = "unknown";
}
toHash = DataProxy.sendObjName(step.address);
MeterInteraction meterInteraction = MeterInteractionManager.getInstance()
.getNormalOutgoingMeter(conf.getObjHash(), toHash);
if (meterInteraction != null) {
meterInteraction.add(step.elapsed, step.error != 0);
}
} else {
MeterInteraction meterInteraction = MeterInteractionManager.getInstance()
.getApiOutgoingMeter(conf.getObjHash(), toHash);
if (meterInteraction != null) {
meterInteraction.add(step.elapsed, step.error != 0);
}
}
}
}
ServiceSummary.getInstance().process(step);
tctx.profile.pop(step);
} catch (Throwable t) {
t.printStackTrace();
}
}
public static Object startSocket(Object socketOrSocketChannel, SocketAddress addr) {
if (!(addr instanceof InetSocketAddress))
return null;
TraceContext ctx = TraceContextManager.getContext();
if (ctx == null) {
if (Configure.getInstance().trace_background_socket_enabled) {
InetSocketAddress inet = (InetSocketAddress) addr;
InetAddress host = inet.getAddress();
int port = inet.getPort();
byte[] ipaddr = host == null ? null : host.getAddress();
SocketTable.add(ipaddr, port, 0, 0);
}
return null;
}
try {
SocketStep step = new SocketStep();
step.start_time = (int) (System.currentTimeMillis() - ctx.startTime);
if (ctx.profile_thread_cputime) {
step.start_cpu = (int) (SysJMX.getCurrentThreadCPU() - ctx.startCpu);
}
InetSocketAddress inet = (InetSocketAddress) addr;
InetAddress host = inet.getAddress();
int port = inet.getPort();
step.ipaddr = host == null ? null : host.getAddress();
step.port = port;
return new LocalContext(ctx, step, socketOrSocketChannel);
} catch (Throwable t) {
Logger.println("A141", "socket trace error", t);
return null;
}
}
public static void endSocket(Object stat, Throwable thr) {
if (stat == null) {
return;
}
try {
LocalContext lctx = (LocalContext) stat;
TraceContext tctx = lctx.context;
SocketStep step = (SocketStep) lctx.stepSingle;
step.elapsed = (int) (System.currentTimeMillis() - tctx.startTime) - step.start_time;
if (thr != null) {
String msg = thr.toString();
step.error = DataProxy.sendError(msg);
if (tctx.error == 0) {
tctx.error = step.error;
}
tctx.offerErrorEntity(ErrorEntity.of(thr, step.error, 0, 0));
}
tctx.profile.add(step);
SocketTable.add(step.ipaddr, step.port, tctx.serviceHash, tctx.txid);
Configure conf = Configure.getInstance();
if (conf.profile_socket_open_fullstack_enabled) {
if (conf.profile_socket_open_fullstack_port == 0 || conf.profile_socket_open_fullstack_port == step.port) {
tctx.profile.add(new MessageStep(step.start_time, ThreadUtil.getThreadStack()));
}
}
} catch (Throwable t) {
Logger.println("A142", "socket trace close error", t);
}
}
public static void open(File file) {
TraceContext ctx = TraceContextManager.getContext();
if (ctx != null) {
MessageStep m = new MessageStep();
m.start_time = (int) (System.currentTimeMillis() - ctx.startTime);
m.message = "FILE " + file.getName();
ctx.profile.add(m);
}
}
public static final IHttpClient dummyHttpClient = new IHttpClient() {
public String getURI(Object o) {
return null;
}
public String getHost(Object o) {
return null;
}
public String getHeader(Object o, String key) {
return null;
}
public String getResponseHeader(Object o, String key) {
return null;
}
public void addHeader(Object o, String key, String value) {
}
};
public static void endCreateSpringRestTemplateRequest(Object _this, Object oRtn) {
if (!conf.trace_interservice_enabled) {
return;
}
TraceContext ctx = TraceContextManager.getContext();
if(ctx == null) return;
if(ctx.lastApiCallStep == null) return;
Configure conf = Configure.getInstance();
int key = System.identityHashCode(_this.getClass());
IHttpClient httpclient = restTemplateHttpRequests.get(key);
if (httpclient == null) {
synchronized (lock) {
if (httpclient == null) {
if (_this.getClass().getClassLoader() == null) {
httpclient = dummyHttpClient;
} else {
Set allSuperSet = getAllExtendedOrImplementedTypesRecursively(oRtn.getClass());
if (allSuperSet.contains("org.springframework.http.HttpRequest")) { //Spring 3.0 doesn't have the interface. HttpRequest is since 3.1
httpclient = SpringRestTemplateHttpRequestFactory.create(_this.getClass().getClassLoader());
} else {
httpclient = dummyHttpClient;
}
}
restTemplateHttpRequests.put(key, httpclient);
}
}
}
try {
if (ctx.gxid == 0) {
ctx.gxid = ctx.txid;
}
ctx.lastApiCallStep.txid = KeyGen.next();
httpclient.addHeader(oRtn, conf._trace_interservice_gxid_header_key, Hexa32.toString32(ctx.gxid));
httpclient.addHeader(oRtn, conf._trace_interservice_caller_header_key, Hexa32.toString32(ctx.txid));
httpclient.addHeader(oRtn, conf._trace_interservice_callee_header_key, Hexa32.toString32(ctx.lastApiCallStep.txid));
httpclient.addHeader(oRtn, conf._trace_interservice_caller_obj_header_key, String.valueOf(conf.getObjHash()));
httpclient.addHeader(oRtn, B3Constant.B3_HEADER_TRACEID, Hexa32.toUnsignedLongHex(ctx.gxid));
httpclient.addHeader(oRtn, B3Constant.B3_HEADER_PARENTSPANID, Hexa32.toUnsignedLongHex(ctx.txid));
httpclient.addHeader(oRtn, B3Constant.B3_HEADER_SPANID, Hexa32.toUnsignedLongHex(ctx.lastApiCallStep.txid));
//httpclient.addHeader(oRtn, B3Constant.B3_HEADER_SAMPLED, "1"); omit means defer
PluginHttpCallTrace.call(ctx, httpclient, oRtn);
} catch (Exception e) {
}
}
public static void setCalleeToCtxInHttpClientResponse(Object _this, Object res) {
if (!conf.trace_interservice_enabled) {
return;
}
TraceContext ctx = TraceContextManager.getContext();
if(ctx == null) return;
try {
ApiCallTraceHelper.setCalleeToCtxInHttpClientResponse(ctx, _this, res);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void setCalleeToCtxInSpringClientHttpResponse(Object _this, Object res) {
if (!conf.trace_interservice_enabled) {
return;
}
TraceContext ctx = TraceContextManager.getContext();
ApiCallStep2 step = null;
if (ctx == null) {
int thisHash = System.identityHashCode(_this);
ApiCallTransferMap.ID transferID = ApiCallTransferMap.get(thisHash);
if (transferID != null) {
ApiCallTransferMap.remove(thisHash);
ctx = transferID.ctx;
step = transferID.step;
} else {
return;
}
}
try {
ApiCallTraceHelper.setCalleeToCtxInSpringClientHttpResponse(ctx, _this, res);
if (step != null && step.async == 1) {
ctx.apicall_time -= step.elapsed;
step.elapsed = (int) (System.currentTimeMillis() - ctx.startTime) - step.start_time;
ctx.apicall_time += step.elapsed;
MeterAPI.getInstance().add(step.elapsed, step.error != 0);
if (conf.counter_interaction_enabled) {
int toHash = ctx.lastCalleeObjHash;
ctx.lastCalleeObjHash = 0;
if (toHash == 0) {
if (StringUtil.isEmpty(step.address)) {
step.address = "unknown";
}
toHash = DataProxy.sendObjName(step.address);
MeterInteraction meterInteraction = MeterInteractionManager.getInstance()
.getNormalOutgoingMeter(conf.getObjHash(), toHash);
if (meterInteraction != null) {
meterInteraction.add(step.elapsed, step.error != 0);
}
} else {
MeterInteraction meterInteraction = MeterInteractionManager.getInstance()
.getApiOutgoingMeter(conf.getObjHash(), toHash);
if (meterInteraction != null) {
meterInteraction.add(step.elapsed, step.error != 0);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void initImmutableJavaHttpRequest(Object requestBuilder) {
if (!conf.trace_interservice_enabled) {
return;
}
TraceContext ctx = TraceContextManager.getContext();
if(ctx == null) return;
try {
ApiCallTraceHelper.setCalleeToCtxJavaHttpRequest(ctx, requestBuilder);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Set getAllExtendedOrImplementedTypesRecursively(Class clazz) {
List res = new ArrayList();
do {
res.add(clazz.getName());
// First, add all the interfaces implemented by this class
Class[] interfaces = clazz.getInterfaces();
if (interfaces.length > 0) {
for(int i=0; i(res);
}
}