/** @author harebox */ @TargetConstructor("net.sf.ehcache.Element") public class FrontCacheGetFutureConstructInterceptor implements AroundInterceptor, ArcusConstants { // TODO This should be extracted from FrontCacheMemcachedClient. private static final String DEFAULT_FRONTCACHE_NAME = "front"; private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); @Override public void before(Object target, Object[] args) { // do nothing } @Override public void after(Object target, Object result, Throwable throwable, Object[] args) { if (isDebug) { logger.afterInterceptor(target, args, result, throwable); } try { ((CacheNameAccessor) target)._$PINPOINT$_setCacheName(DEFAULT_FRONTCACHE_NAME); if (args[0] instanceof Element) { Element element = (Element) args[0]; ((CacheKeyAccessor) target)._$PINPOINT$_setCacheKey(element.getObjectKey()); } } catch (Exception e) { logger.error("failed to add metadata: {}", e); } } }
/** * @author netspider * @author emeroad */ @TargetMethod( name = "addOp", paramTypes = {"java.lang.String", "net.spy.memcached.ops.Operation"}) public class AddOpInterceptor implements AroundInterceptor { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); @Override public void before(Object target, Object[] args) { if (isDebug) { logger.beforeInterceptor(target, args); } String serviceCode = ((ServiceCodeAccessor) target)._$PINPOINT$_getServiceCode(); ((ServiceCodeAccessor) args[1])._$PINPOINT$_setServiceCode(serviceCode); } @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { if (isDebug) { logger.afterInterceptor(target, args, result, throwable); } } }
/** @author emeroad */ public class GroupedInterceptor implements AroundInterceptor { private final PLogger logger = PLoggerFactory.getLogger(getClass()); private final boolean debugEnabled = logger.isDebugEnabled(); private final BeforeInterceptor before; private final AfterInterceptor after; private final InterceptorGroup group; private final ExecutionPolicy policy; public GroupedInterceptor( BeforeInterceptor before, AfterInterceptor after, InterceptorGroup group, ExecutionPolicy policy) { this.before = before; this.after = after; this.group = group; this.policy = policy; } @Override public void before(Object target, Object[] args) { InterceptorGroupInvocation transaction = group.getCurrentInvocation(); if (transaction.tryEnter(policy)) { if (before != null) { before.before(target, args); } } else { if (debugEnabled) { logger.debug( "tryBefore() returns false: interceptorGroupTransaction: {}, executionPoint: {}. Skip interceptor {}", new Object[] {transaction, policy, before == null ? null : before.getClass()}); } } } @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { InterceptorGroupInvocation transaction = group.getCurrentInvocation(); if (transaction.canLeave(policy)) { if (after != null) { after.after(target, args, result, throwable); } transaction.leave(policy); } else { if (debugEnabled) { logger.debug( "tryAfter() returns false: interceptorGroupTransaction: {}, executionPoint: {}. Skip interceptor {}", new Object[] {transaction, policy, after == null ? null : after.getClass()}); } } } }
/** @author Jongho Moon */ public class BeanMethodTransformer implements PinpointClassFileTransformer { private static final int REQUIRED_ACCESS_FLAG = Modifier.PUBLIC; private static final int REJECTED_ACCESS_FLAG = Modifier.ABSTRACT | Modifier.NATIVE | Modifier.STATIC; private static final MethodFilter METHOD_FILTER = MethodFilters.modifier(REQUIRED_ACCESS_FLAG, REJECTED_ACCESS_FLAG); private final PLogger logger = PLoggerFactory.getLogger(getClass()); /* (non-Javadoc) * @see com.navercorp.pinpoint.bootstrap.plugin.transformer.PinpointClassFileTransformer#transform(com.navercorp.pinpoint.bootstrap.plugin.PinpointInstrument, java.lang.ClassLoader, java.lang.String, java.lang.Class, java.security.ProtectionDomain, byte[]) */ @Override public byte[] transform( Instrumentor instrumentContext, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { if (logger.isInfoEnabled()) { logger.info("Modify {}", className); } try { InstrumentClass target = instrumentContext.getInstrumentClass(loader, className, classfileBuffer); if (!target.isInterceptable()) { return null; } List<InstrumentMethod> methodList = target.getDeclaredMethods(METHOD_FILTER); for (InstrumentMethod method : methodList) { if (logger.isTraceEnabled()) { logger.trace( "### c={}, m={}, params={}", new Object[] { className, method.getName(), Arrays.toString(method.getParameterTypes()) }); } method.addInterceptor( BasicMethodInterceptor.class.getName(), va(SpringBeansConstants.SERVICE_TYPE)); } return target.toBytecode(); } catch (Exception e) { logger.warn("modify fail. Cause:{}", e.getMessage(), e); return null; } } }
/** * This interceptor retrieves the method name called by the client and stores it for other * interceptors in the chain to use. * * <p><tt>TBaseAsyncProcessorProcessInterceptor</tt> -> * <b><tt>TProtocolReadMessageBeginInterceptor</tt></b> -> * <tt>TProtocolReadFieldBeginInterceptor</tt> <-> <tt>TProtocolReadTTypeInterceptor</tt> -> * <tt>TProtocolReadMessageEndInterceptor</tt> * * <p>Based on Thrift 0.8.0+ * * @author HyunGil Jeong * @see * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadMessageBeginInterceptor * TProtocolReadMessageBeginInterceptor * @see * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadFieldBeginInterceptor * TProtocolReadFieldBeginInterceptor * @see * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadTTypeInterceptor * TProtocolReadTTypeInterceptor * @see * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadMessageEndInterceptor * TProtocolReadMessageEndInterceptor */ @Scope(value = THRIFT_SERVER_SCOPE, executionPolicy = ExecutionPolicy.INTERNAL) public class TProtocolReadMessageBeginInterceptor implements AroundInterceptor { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private final InterceptorScope scope; public TProtocolReadMessageBeginInterceptor(@Name(THRIFT_SERVER_SCOPE) InterceptorScope scope) { this.scope = scope; } @Override public void before(Object target, Object[] args) { // Do nothing } @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { if (isDebug) { logger.afterInterceptor(target, args, result, throwable); } if (!validate(target)) { return; } final boolean shouldTrace = ((AsyncMarkerFlagFieldAccessor) target)._$PINPOINT$_getAsyncMarkerFlag(); if (shouldTrace) { String methodName = ThriftConstants.UNKNOWN_METHOD_NAME; if (result instanceof TMessage) { TMessage message = (TMessage) result; methodName = message.name; } ThriftClientCallContext clientCallContext = new ThriftClientCallContext(methodName); InterceptorScopeInvocation currentTransaction = this.scope.getCurrentInvocation(); currentTransaction.setAttachment(clientCallContext); } } private boolean validate(Object target) { if (!(target instanceof AsyncMarkerFlagFieldAccessor)) { if (isDebug) { logger.debug( "Invalid target object. Need field accessor({}).", AsyncMarkerFlagFieldAccessor.class.getName()); } return false; } return true; } }
/** * @see * JacksonPlugin#intercept_ObjectMapper(com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginSetupContext) * @author Sungkook Kim */ public class WriteValueAsStringInterceptor implements AroundInterceptor { private final PLogger logger = PLoggerFactory.getLogger(getClass()); private final boolean isDebug = logger.isDebugEnabled(); private final MethodDescriptor descriptor; private final TraceContext traceContext; public WriteValueAsStringInterceptor(TraceContext traceContext, MethodDescriptor descriptor) { this.descriptor = descriptor; this.traceContext = traceContext; } @Override public void before(Object target, Object[] args) { if (isDebug) { logger.beforeInterceptor(target, args); } Trace trace = traceContext.currentTraceObject(); if (trace == null) { return; } SpanEventRecorder recorder = trace.traceBlockBegin(); recorder.recordServiceType(JacksonConstants.SERVICE_TYPE); } @Override public void after(Object target, Object result, Throwable throwable, Object[] args) { if (isDebug) { logger.afterInterceptor(target, args); } Trace trace = traceContext.currentTraceObject(); if (trace == null) { return; } try { SpanEventRecorder recorder = trace.currentSpanEventRecorder(); recorder.recordApi(descriptor); recorder.recordException(throwable); if (result != null) { recorder.recordAttribute( JacksonConstants.ANNOTATION_KEY_LENGTH_VALUE, ((String) result).length()); } } finally { trace.traceBlockEnd(); } } }
/** * @author harebox * @author emeroad */ public class FutureSetOperationInterceptor implements AroundInterceptor, ArcusConstants { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); @Override public void before(Object target, Object[] args) { if (isDebug) { logger.beforeInterceptor(target, args); } ((OperationAccessor) target)._$PINPOINT$_setOperation((Operation) args[0]); } @Override public void after(Object target, Object result, Throwable throwable, Object[] args) { if (isDebug) { logger.afterInterceptor(target, args); } } }
/** @author jaehong.kim */ public class UserIncludeMethodInterceptor implements AroundInterceptor { // scope name, must be unique. private static final String SCOPE_NAME = "##USER_INCLUDE"; private static final UserIncludeMethodDescriptor USER_INCLUDE_METHOD_DESCRIPTOR = new UserIncludeMethodDescriptor(); private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private TraceContext traceContext; private MethodDescriptor descriptor; public UserIncludeMethodInterceptor( TraceContext traceContext, MethodDescriptor methodDescriptor) { this.traceContext = traceContext; this.descriptor = methodDescriptor; traceContext.cacheApi(USER_INCLUDE_METHOD_DESCRIPTOR); } @Override public void before(Object target, Object[] args) { if (isDebug) { logger.beforeInterceptor(target, args); } Trace trace = traceContext.currentRawTraceObject(); if (trace == null) { // create user include trace for standalone entry point. trace = createUserIncludeTrace(); if (trace == null) { return; } } // check user include trace. if (!isUserIncludeTrace(trace)) { return; } // entry scope(default & disable trace). entryUserIncludeTraceScope(trace); // check sampled. if (!trace.canSampled()) { // skip return; } trace.traceBlockBegin(); } @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { if (isDebug) { logger.afterInterceptor(target, args); } final Trace trace = traceContext.currentRawTraceObject(); if (trace == null) { return; } // check user include trace. if (!isUserIncludeTrace(trace)) { return; } // leave scope(default & disable trace). if (!leaveUserIncludeTraceScope(trace)) { logger.warn( "Failed to leave scope of user include trace. trace={}, sampled={}", trace, trace.canSampled()); // delete unstable trace. deleteUserIncludeTrace(trace); return; } // check sampled. if (!trace.canSampled()) { if (isUserIncludeTraceDestination(trace)) { deleteUserIncludeTrace(trace); } return; } try { final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); recorder.recordApi(descriptor); recorder.recordServiceType(ServiceType.INTERNAL_METHOD); recorder.recordException(throwable); } finally { trace.traceBlockEnd(); if (isUserIncludeTraceDestination(trace)) { deleteUserIncludeTrace(trace); } } } private Trace createUserIncludeTrace() { final Trace trace = traceContext.newTraceObject(); if (isDebug) { logger.debug("New user include trace {} and sampled {}", trace, trace.canSampled()); } // add user scope. TraceScope oldScope = trace.addScope(SCOPE_NAME); if (oldScope != null) { // delete corrupted trace. logger.warn("Duplicated user include trace scope={}.", oldScope.getName()); deleteUserIncludeTrace(trace); return null; } if (trace.canSampled()) { // record root span. final SpanRecorder recorder = trace.getSpanRecorder(); recorder.recordServiceType(ServiceType.STAND_ALONE); recorder.recordApi(USER_INCLUDE_METHOD_DESCRIPTOR); } return trace; } private void deleteUserIncludeTrace(final Trace trace) { if (isDebug) { logger.debug("Delete user include trace={}, sampled={}", trace, trace.canSampled()); } traceContext.removeTraceObject(); trace.close(); } private void entryUserIncludeTraceScope(final Trace trace) { final TraceScope scope = trace.getScope(SCOPE_NAME); if (scope != null) { scope.tryEnter(); } } private boolean leaveUserIncludeTraceScope(final Trace trace) { final TraceScope scope = trace.getScope(SCOPE_NAME); if (scope != null) { if (scope.canLeave()) { scope.leave(); } else { return false; } } return true; } private boolean isUserIncludeTrace(final Trace trace) { final TraceScope scope = trace.getScope(SCOPE_NAME); return scope != null; } private boolean isUserIncludeTraceDestination(final Trace trace) { final TraceScope scope = trace.getScope(SCOPE_NAME); return scope != null && !scope.isActive(); } }
/** @author jaehong.kim */ @Group(value = HttpClient4Constants.HTTP_CLIENT4_SCOPE, executionPolicy = ExecutionPolicy.ALWAYS) public class HttpRequestExecutorDoSendRequestAndDoReceiveResponseMethodInterceptor implements AroundInterceptor { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private final TraceContext traceContext; private final MethodDescriptor methodDescriptor; private final InterceptorGroup interceptorGroup; public HttpRequestExecutorDoSendRequestAndDoReceiveResponseMethodInterceptor( TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorGroup interceptorGroup) { this.traceContext = traceContext; this.methodDescriptor = methodDescriptor; this.interceptorGroup = interceptorGroup; } @Override public void before(Object target, Object[] args) { if (isDebug) { logger.beforeInterceptor( target, methodDescriptor.getClassName(), methodDescriptor.getMethodName(), "", args); } final Trace trace = traceContext.currentTraceObject(); if (trace == null) { return; } InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); if (invocation != null && invocation.getAttachment() != null) { HttpCallContext callContext = (HttpCallContext) invocation.getAttachment(); if (methodDescriptor.getMethodName().equals("doSendRequest")) { callContext.setWriteBeginTime(System.currentTimeMillis()); } else { callContext.setReadBeginTime(System.currentTimeMillis()); } logger.debug("Set call context {}", callContext); } } @Override public void after(Object target, Object result, Throwable throwable, Object[] args) { if (isDebug) { logger.afterInterceptor( target, methodDescriptor.getClassName(), methodDescriptor.getMethodName(), "", args, result, throwable); } final Trace trace = traceContext.currentTraceObject(); if (trace == null) { return; } InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); if (invocation != null && invocation.getAttachment() != null) { HttpCallContext callContext = (HttpCallContext) invocation.getAttachment(); if (methodDescriptor.getMethodName().equals("doSendRequest")) { callContext.setWriteEndTime(System.currentTimeMillis()); callContext.setWriteFail(throwable != null); } else { callContext.setReadEndTime(System.currentTimeMillis()); callContext.setReadFail(throwable != null); } logger.debug("Set call context {}", callContext); } } }
/** @author jaehong.kim */ @Group(OkHttpConstants.SEND_REQUEST_SCOPE) public class HttpEngineSendRequestMethodInterceptor implements SimpleAroundInterceptor, OkHttpConstants { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private TraceContext traceContext; private MethodDescriptor methodDescriptor; private InterceptorGroup interceptorGroup; private final boolean cookie; private final DumpType cookieDumpType; private final SimpleSampler cookieSampler; private final boolean statusCode; public HttpEngineSendRequestMethodInterceptor( TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorGroup interceptorGroup, OkHttpPluginConfig config) { this.traceContext = traceContext; this.methodDescriptor = methodDescriptor; this.interceptorGroup = interceptorGroup; this.cookie = config.isCookie(); this.cookieDumpType = config.getCookieDumpType(); if (cookie) { cookieSampler = SimpleSamplerFactory.createSampler(cookie, config.getCookieSamplingRate()); } else { this.cookieSampler = null; } statusCode = config.isStatusCode(); } @Override public void before(Object target, Object[] args) { if (isDebug) { logger.beforeInterceptor(target, args); } final Trace trace = traceContext.currentRawTraceObject(); if (trace == null) { return; } if (!validate(target)) { return; } if (!trace.canSampled()) { return; } SpanEventRecorder recorder = trace.traceBlockBegin(); try { final TraceId nextId = trace.getTraceId().getNextTraceId(); recorder.recordNextSpanId(nextId.getSpanId()); recorder.recordServiceType(OK_HTTP_CLIENT); InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); if (invocation != null) { invocation.getOrCreateAttachment( new AttachmentFactory() { @Override public Object createAttachment() { return nextId; } }); } } catch (Throwable t) { logger.warn("Failed to BEFORE process. {}", t.getMessage(), t); } } private boolean validate(Object target) { if (!(target instanceof UserRequestGetter)) { logger.debug("Invalid target object. Need field accessor({}).", FIELD_USER_REQUEST); return false; } if (!(target instanceof UserResponseGetter)) { logger.debug("Invalid target object. Need field accessor({}).", FIELD_USER_RESPONSE); return false; } if (!(target instanceof ConnectionGetter)) { logger.debug("Invalid target object. Need field accessor({}).", FIELD_CONNECTION); return false; } return true; } @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { if (isDebug) { logger.afterInterceptor(target, args); } final Trace trace = traceContext.currentTraceObject(); if (trace == null) { return; } if (!validate(target)) { return; } try { SpanEventRecorder recorder = trace.currentSpanEventRecorder(); recorder.recordApi(methodDescriptor); recorder.recordException(throwable); Request request = ((UserRequestGetter) target)._$PINPOINT$_getUserRequest(); if (request != null) { recorder.recordAttribute(AnnotationKey.HTTP_URL, request.httpUrl().toString()); recorder.recordDestinationId(request.httpUrl().host() + ":" + request.httpUrl().port()); recordRequest(trace, request, throwable); } // clear attachment. InterceptorGroupInvocation invocation = interceptorGroup.getCurrentInvocation(); if (invocation != null && invocation.getAttachment() != null) { invocation.removeAttachment(); } } finally { trace.traceBlockEnd(); } } private void recordRequest(Trace trace, Request request, Throwable throwable) { final boolean isException = InterceptorUtils.isThrowable(throwable); if (cookie) { if (DumpType.ALWAYS == cookieDumpType) { recordCookie(request, trace); } else if (DumpType.EXCEPTION == cookieDumpType && isException) { recordCookie(request, trace); } } } private void recordCookie(Request request, Trace trace) { for (String cookie : request.headers("Cookie")) { if (cookieSampler.isSampling()) { final SpanEventRecorder recorder = trace.currentSpanEventRecorder(); recorder.recordAttribute(AnnotationKey.HTTP_COOKIE, StringUtils.drop(cookie, 1024)); } return; } } }
/** @author HyunGil Jeong */ @Group(value = THRIFT_CLIENT_SCOPE, executionPoint = ExecutionPolicy.BOUNDARY) public class TAsyncClientManagerCallInterceptor implements SimpleAroundInterceptor, ThriftConstants { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private final TraceContext traceContext; private final MethodDescriptor descriptor; private final InterceptorGroup group; private final MetadataAccessor asyncTraceIdAccessor; private final MetadataAccessor asyncNextSpanIdAccessor; private final MetadataAccessor asyncCallRemoteAddressAccessor; private final MetadataAccessor nonblockingSocketAddressAccessor; public TAsyncClientManagerCallInterceptor( TraceContext traceContext, MethodDescriptor descriptor, @Name(THRIFT_CLIENT_SCOPE) InterceptorGroup group, @Name(METADATA_ASYNC_TRACE_ID) MetadataAccessor asyncTraceIdAccessor, @Name(METADATA_ASYNC_NEXT_SPAN_ID) MetadataAccessor asyncNextSpanIdAccessor, @Name(METADATA_ASYNC_CALL_REMOTE_ADDRESS) MetadataAccessor asyncCallRemoteAddressAccessor, @Name(METADATA_NONBLOCKING_SOCKET_ADDRESS) MetadataAccessor nonblockingSocketAddressAccessor) { this.traceContext = traceContext; this.descriptor = descriptor; this.group = group; this.asyncTraceIdAccessor = asyncTraceIdAccessor; this.asyncNextSpanIdAccessor = asyncNextSpanIdAccessor; this.asyncCallRemoteAddressAccessor = asyncCallRemoteAddressAccessor; this.nonblockingSocketAddressAccessor = nonblockingSocketAddressAccessor; } @Override public void before(Object target, Object[] args) { if (isDebug) { logger.beforeInterceptor(target, args); } if (!validate(target, args)) { return; } final Trace trace = this.traceContext.currentRawTraceObject(); if (trace == null) { return; } try { ThriftRequestProperty parentTraceInfo = new ThriftRequestProperty(); final boolean shouldSample = trace.canSampled(); if (!shouldSample) { if (isDebug) { logger.debug("set Sampling flag=false"); } parentTraceInfo.setShouldSample(shouldSample); } else { SpanEventRecorder recorder = trace.traceBlockBegin(); Object asyncMethodCallObj = args[0]; // inject async trace info to AsyncMethodCall object final AsyncTraceId asyncTraceId = injectAsyncTraceId(asyncMethodCallObj, trace); recorder.recordServiceType(THRIFT_CLIENT_INTERNAL); // retrieve connection information String remoteAddress = getRemoteAddress(asyncMethodCallObj); final TraceId nextId = asyncTraceId.getNextTraceId(); // Inject nextSpanId as the actual sending of data will be handled asynchronously. final long nextSpanId = nextId.getSpanId(); parentTraceInfo.setSpanId(nextSpanId); parentTraceInfo.setTraceId(nextId.getTransactionId()); parentTraceInfo.setParentSpanId(nextId.getParentSpanId()); parentTraceInfo.setFlags(nextId.getFlags()); parentTraceInfo.setParentApplicationName(this.traceContext.getApplicationName()); parentTraceInfo.setParentApplicationType(this.traceContext.getServerTypeCode()); parentTraceInfo.setAcceptorHost(remoteAddress); this.asyncCallRemoteAddressAccessor.set(asyncMethodCallObj, remoteAddress); this.asyncNextSpanIdAccessor.set(asyncMethodCallObj, nextSpanId); } InterceptorGroupInvocation currentTransaction = this.group.getCurrentInvocation(); currentTransaction.setAttachment(parentTraceInfo); } catch (Throwable t) { logger.warn("before error. Caused:{}", t.getMessage(), t); } } @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { if (isDebug) { logger.afterInterceptor(target, args, result, throwable); } final Trace trace = this.traceContext.currentTraceObject(); if (trace == null) { return; } try { SpanEventRecorder recorder = trace.currentSpanEventRecorder(); recorder.recordApi(this.descriptor); recorder.recordException(throwable); } catch (Throwable t) { logger.warn("after error. Caused:{}", t.getMessage(), t); } finally { trace.traceBlockEnd(); } } private boolean validate(final Object target, final Object[] args) { if (args.length != 1) { return false; } Object asyncMethodCallObj = args[0]; if (asyncMethodCallObj == null) { if (isDebug) { logger.debug("Metadata injection target object is null."); } return false; } if (!this.asyncTraceIdAccessor.isApplicable(asyncMethodCallObj)) { if (isDebug) { logger.debug("Invalid target object. Need metadata accessor({})", METADATA_ASYNC_TRACE_ID); } return false; } if (!this.asyncNextSpanIdAccessor.isApplicable(asyncMethodCallObj)) { if (isDebug) { logger.debug( "Invalid target object. Need metadata accessor({})", METADATA_ASYNC_NEXT_SPAN_ID); } return false; } if (!this.asyncCallRemoteAddressAccessor.isApplicable(asyncMethodCallObj)) { if (isDebug) { logger.debug( "Invalid target object. Need metadata accessor({})", METADATA_ASYNC_CALL_REMOTE_ADDRESS); } return false; } return true; } private AsyncTraceId injectAsyncTraceId(final Object asyncMethodCallObj, final Trace trace) { final AsyncTraceId asyncTraceId = trace.getAsyncTraceId(); SpanEventRecorder recorder = trace.currentSpanEventRecorder(); recorder.recordNextAsyncId(asyncTraceId.getAsyncId()); this.asyncTraceIdAccessor.set(asyncMethodCallObj, asyncTraceId); if (isDebug) { logger.debug("Set asyncTraceId metadata {}", asyncTraceId); } return asyncTraceId; } private String getRemoteAddress(Object asyncMethodCallObj) { if (!this.nonblockingSocketAddressAccessor.isApplicable(asyncMethodCallObj)) { if (isDebug) { logger.debug( "Invalid TAsyncMethodCall object. Need metadata accessor({})", METADATA_NONBLOCKING_SOCKET_ADDRESS); } return UNKNOWN_ADDRESS; } Object socketAddress = this.nonblockingSocketAddressAccessor.get(asyncMethodCallObj); if (socketAddress instanceof SocketAddress) { return ThriftUtils.getHostPort((SocketAddress) socketAddress); } return UNKNOWN_ADDRESS; } }
/** @author jaehong.kim */ public class OkHttpPlugin implements ProfilerPlugin { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); @Override public void setup(ProfilerPluginSetupContext context) { final OkHttpPluginConfig config = new OkHttpPluginConfig(context.getConfig()); logger.debug("[OkHttp] Initialized config={}", config); logger.debug("[OkHttp] Add Call class."); addCall(context, config); logger.debug("[OkHttp] Add Dispatcher class."); addDispatcher(context, config); logger.debug("[OkHttp] Add AsyncCall class."); addAsyncCall(context, config); addHttpEngine(context, config); addRequestBuilder(context, config); } private void addCall(ProfilerPluginSetupContext context, final OkHttpPluginConfig config) { context.addClassFileTransformer( "com.squareup.okhttp.Call", new TransformCallback() { @Override public byte[] doInTransform( Instrumentor instrumentContext, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentContext.getInstrumentClass(loader, className, classfileBuffer); for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("execute", "enqueue", "cancel"))) { method.addInterceptor( "com.navercorp.pinpoint.plugin.okhttp.interceptor.CallMethodInterceptor"); } return target.toBytecode(); } }); } private void addDispatcher(ProfilerPluginSetupContext context, final OkHttpPluginConfig config) { context.addClassFileTransformer( "com.squareup.okhttp.Dispatcher", new TransformCallback() { @Override public byte[] doInTransform( Instrumentor instrumentContext, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentContext.getInstrumentClass(loader, className, classfileBuffer); for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name("execute", "cancel"))) { logger.debug("[OkHttp] Add Dispatcher.execute | cancel interceptor."); method.addInterceptor( OkHttpConstants.BASIC_METHOD_INTERCEPTOR, va(OkHttpConstants.OK_HTTP_CLIENT_INTERNAL)); } InstrumentMethod enqueueMethod = target.getDeclaredMethod("enqueue", "com.squareup.okhttp.Call$AsyncCall"); if (enqueueMethod != null) { logger.debug("[OkHttp] Add Dispatcher.enqueue interceptor."); enqueueMethod.addInterceptor( "com.navercorp.pinpoint.plugin.okhttp.interceptor.DispatcherEnqueueMethodInterceptor"); } return target.toBytecode(); } }); } private void addAsyncCall(ProfilerPluginSetupContext context, final OkHttpPluginConfig config) { context.addClassFileTransformer( "com.squareup.okhttp.Call$AsyncCall", new TransformCallback() { @Override public byte[] doInTransform( Instrumentor instrumentContext, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentContext.getInstrumentClass(loader, className, classfileBuffer); target.addField(AsyncTraceIdAccessor.class.getName()); InstrumentMethod executeMethod = target.getDeclaredMethod("execute"); if (executeMethod != null) { logger.debug("[OkHttp] Add AsyncCall.execute interceptor."); executeMethod.addInterceptor( "com.navercorp.pinpoint.plugin.okhttp.interceptor.AsyncCallExecuteMethodInterceptor"); } return target.toBytecode(); } }); } private void addHttpEngine( final ProfilerPluginSetupContext context, final OkHttpPluginConfig config) { context.addClassFileTransformer( "com.squareup.okhttp.internal.http.HttpEngine", new TransformCallback() { @Override public byte[] doInTransform( Instrumentor instrumentContext, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentContext.getInstrumentClass(loader, className, classfileBuffer); target.addGetter(UserRequestGetter.class.getName(), OkHttpConstants.FIELD_USER_REQUEST); target.addGetter( UserResponseGetter.class.getName(), OkHttpConstants.FIELD_USER_RESPONSE); target.addGetter(ConnectionGetter.class.getName(), OkHttpConstants.FIELD_CONNECTION); InstrumentMethod sendRequestMethod = target.getDeclaredMethod("sendRequest"); if (sendRequestMethod != null) { logger.debug("[OkHttp] Add HttpEngine.sendRequest interceptor."); final ObjectRecipe objectRecipe = ObjectRecipe.byConstructor( "com.navercorp.pinpoint.plugin.okhttp.OkHttpPluginConfig", context.getConfig()); sendRequestMethod.addInterceptor( "com.navercorp.pinpoint.plugin.okhttp.interceptor.HttpEngineSendRequestMethodInterceptor", va(objectRecipe)); } InstrumentMethod connectMethod = target.getDeclaredMethod("connect"); if (connectMethod != null) { logger.debug("[OkHttp] Add HttpEngine.connect interceptor."); connectMethod.addInterceptor( "com.navercorp.pinpoint.plugin.okhttp.interceptor.HttpEngineConnectMethodInterceptor"); } InstrumentMethod readResponseMethod = target.getDeclaredMethod("readResponse"); if (readResponseMethod != null) { logger.debug("[OkHttp] Add HttpEngine.connect interceptor."); readResponseMethod.addInterceptor( "com.navercorp.pinpoint.plugin.okhttp.interceptor.HttpEngineReadResponseMethodInterceptor", va(config.isStatusCode())); } return target.toBytecode(); } }); } private void addRequestBuilder( ProfilerPluginSetupContext context, final OkHttpPluginConfig config) { context.addClassFileTransformer( "com.squareup.okhttp.Request$Builder", new TransformCallback() { @Override public byte[] doInTransform( Instrumentor instrumentContext, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentContext.getInstrumentClass(loader, className, classfileBuffer); target.addGetter(HttpUrlGetter.class.getName(), OkHttpConstants.FIELD_HTTP_URL); InstrumentMethod buildMethod = target.getDeclaredMethod("build"); if (buildMethod != null) { logger.debug("[OkHttp] Add Request.Builder.build interceptor."); buildMethod.addInterceptor( "com.navercorp.pinpoint.plugin.okhttp.interceptor.RequestBuilderBuildMethodInterceptor"); } return target.toBytecode(); } }); } }
/** @author jaehong.kim */ @Group(value = HttpClientConstants.EXECUTE_ASYNC_SCOPE, executionPolicy = ExecutionPolicy.ALWAYS) public class HttpRequestExecuteAsyncMethodInterceptor implements AroundInterceptor { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private TraceContext traceContext; private MethodDescriptor methodDescriptor; private InterceptorGroup interceptorGroup; public HttpRequestExecuteAsyncMethodInterceptor( TraceContext traceContext, MethodDescriptor methodDescriptor, InterceptorGroup interceptorGroup) { this.traceContext = traceContext; this.methodDescriptor = methodDescriptor; this.interceptorGroup = interceptorGroup; } @Override public void before(Object target, Object[] args) { if (isDebug) { logger.beforeInterceptor(target, args); } final Trace trace = traceContext.currentTraceObject(); if (trace == null) { return; } SpanEventRecorder recorder = trace.traceBlockBegin(); try { // set asynchronous trace final AsyncTraceId asyncTraceId = trace.getAsyncTraceId(); recorder.recordNextAsyncId(asyncTraceId.getAsyncId()); // set async id. InterceptorGroupInvocation transaction = interceptorGroup.getCurrentInvocation(); if (transaction != null) { transaction.setAttachment(asyncTraceId); if (isDebug) { logger.debug("Set asyncTraceId metadata {}", asyncTraceId); } } } catch (Throwable t) { logger.warn("Failed to before process. {}", t.getMessage(), t); } } @Override public void after(Object target, Object result, Throwable throwable, Object[] args) { if (isDebug) { logger.afterInterceptor(target, args); } final Trace trace = traceContext.currentTraceObject(); if (trace == null) { return; } try { SpanEventRecorder recorder = trace.currentSpanEventRecorder(); recorder.recordApi(methodDescriptor); recorder.recordServiceType(HttpClientConstants.HTTP_CLIENT_INTERNAL); recorder.recordException(throwable); // remove async id. InterceptorGroupInvocation transaction = interceptorGroup.getCurrentInvocation(); if (transaction != null) { // clear transaction.removeAttachment(); } } finally { trace.traceBlockEnd(); } } }
/** * Entry/exit point for tracing asynchronous processors for Thrift services. * * <p>Because trace objects cannot be created until the message is read, this interceptor works in * tandem with other interceptors in the tracing pipeline. The actual processing of input messages * is not off-loaded to <tt>AsyncProcessFunction</tt> (unlike synchronous processors where * <tt>ProcessFunction</tt> does most of the work). * * <ol> * <li> * <p>{@link * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadMessageBeginInterceptor * TProtocolReadMessageBeginInterceptor} retrieves the method name called by the client. * <li> * <p>{@link * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadFieldBeginInterceptor * TProtocolReadFieldBeginInterceptor}, {@link * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadTTypeInterceptor * TProtocolReadTTypeInterceptor} reads the header fields and injects the parent trace object * (if any). * <li> * <p>{@link * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadMessageEndInterceptor * TProtocolReadMessageEndInterceptor} creates the actual root trace object. * </ol> * * <p><b><tt>TBaseAsyncProcessorProcessInterceptor</tt></b> -> * <tt>TProtocolReadMessageBeginInterceptor</tt> -> <tt>TProtocolReadFieldBeginInterceptor</tt> <-> * <tt>TProtocolReadTTypeInterceptor</tt> -> <tt>TProtocolReadMessageEndInterceptor</tt> * * <p>Based on Thrift 0.9.1+ * * @author HyunGil Jeong * @see * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadMessageBeginInterceptor * TProtocolReadMessageBeginInterceptor * @see * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadFieldBeginInterceptor * TProtocolReadFieldBeginInterceptor * @see * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadTTypeInterceptor * TProtocolReadTTypeInterceptor * @see * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadMessageEndInterceptor * TProtocolReadMessageEndInterceptor */ @Scope(value = THRIFT_SERVER_SCOPE, executionPolicy = ExecutionPolicy.BOUNDARY) public class TBaseAsyncProcessorProcessInterceptor implements AroundInterceptor { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private final TraceContext traceContext; private final MethodDescriptor descriptor; private final InterceptorScope scope; public TBaseAsyncProcessorProcessInterceptor( TraceContext traceContext, MethodDescriptor descriptor, @Name(THRIFT_SERVER_SCOPE) InterceptorScope scope) { this.traceContext = traceContext; this.descriptor = descriptor; this.scope = scope; } @Override public void before(Object target, Object[] args) { if (isDebug) { logger.beforeInterceptor(target, args); } // process(final AsyncFrameBuffer fb) if (args.length != 1) { return; } // Set server markers if (args[0] instanceof AsyncFrameBuffer) { AsyncFrameBuffer frameBuffer = (AsyncFrameBuffer) args[0]; attachMarkersToInputProtocol(frameBuffer.getInputProtocol(), true); } } @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { if (isDebug) { logger.afterInterceptor(target, args, result, throwable); } // Unset server markers if (args[0] instanceof AsyncFrameBuffer) { AsyncFrameBuffer frameBuffer = (AsyncFrameBuffer) args[0]; attachMarkersToInputProtocol(frameBuffer.getInputProtocol(), false); } final Trace trace = this.traceContext.currentRawTraceObject(); if (trace == null) { return; } this.traceContext.removeTraceObject(); if (trace.canSampled()) { try { processTraceObject(trace, target, args, throwable); } catch (Throwable t) { logger.warn("Error processing trace object. Cause:{}", t.getMessage(), t); } finally { trace.close(); } } } private boolean validateInputProtocol(Object iprot) { if (iprot instanceof TProtocol) { if (!(iprot instanceof ServerMarkerFlagFieldAccessor)) { if (isDebug) { logger.debug( "Invalid target object. Need field accessor({}).", ServerMarkerFlagFieldAccessor.class.getName()); } return false; } if (!(iprot instanceof AsyncMarkerFlagFieldAccessor)) { if (isDebug) { logger.debug( "Invalid target object. Need field accessor({}).", AsyncMarkerFlagFieldAccessor.class.getName()); } return false; } return true; } return false; } private void attachMarkersToInputProtocol(TProtocol iprot, boolean flag) { if (validateInputProtocol(iprot)) { ((ServerMarkerFlagFieldAccessor) iprot)._$PINPOINT$_setServerMarkerFlag(flag); ((AsyncMarkerFlagFieldAccessor) iprot)._$PINPOINT$_setAsyncMarkerFlag(flag); } } private void processTraceObject( final Trace trace, Object target, Object[] args, Throwable throwable) { // end spanEvent try { // TODO Might need a way to collect and record method arguments // trace.recordAttribute(...); SpanEventRecorder recorder = trace.currentSpanEventRecorder(); recorder.recordException(throwable); recorder.recordApi(this.descriptor); } catch (Throwable t) { logger.warn("Error processing trace object. Cause:{}", t.getMessage(), t); } finally { trace.traceBlockEnd(); } // end root span SpanRecorder recorder = trace.getSpanRecorder(); String methodUri = getMethodUri(target); recorder.recordRpcName(methodUri); } private String getMethodUri(Object target) { String methodUri = ThriftConstants.UNKNOWN_METHOD_URI; InterceptorScopeInvocation currentTransaction = this.scope.getCurrentInvocation(); Object attachment = currentTransaction.getAttachment(); if (attachment instanceof ThriftClientCallContext && target instanceof TBaseAsyncProcessor) { ThriftClientCallContext clientCallContext = (ThriftClientCallContext) attachment; String methodName = clientCallContext.getMethodName(); methodUri = ThriftUtils.getAsyncProcessorNameAsUri((TBaseAsyncProcessor<?>) target); StringBuilder sb = new StringBuilder(methodUri); if (!methodUri.endsWith("/")) { sb.append("/"); } sb.append(methodName); methodUri = sb.toString(); } return methodUri; } }
/** * Entry/exit point for tracing synchronous processors for Thrift services. * * <p>Because trace objects cannot be created until the message is read, this interceptor merely * sends trace objects created by other interceptors in the tracing pipeline: * * <ol> * <li> * <p>{@link * com.navercorp.pinpoint.plugin.thrift.interceptor.server.ProcessFunctionProcessInterceptor * ProcessFunctionProcessInterceptor} marks the start of a trace, and sets up the environment * for trace data to be injected. * <li> * <p>{@link * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadFieldBeginInterceptor * TProtocolReadFieldBeginInterceptor}, {@link * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadTTypeInterceptor * TProtocolReadTTypeInterceptor} reads the header fields and injects the parent trace object * (if any). * <li> * <p>{@link * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadMessageEndInterceptor * TProtocolReadMessageEndInterceptor} creates the actual root trace object. * </ol> * * <p><b><tt>TBaseProcessorProcessInterceptor</tt></b> -> <tt>ProcessFunctionProcessInterceptor</tt> * -> <tt>TProtocolReadFieldBeginInterceptor</tt> <-> <tt>TProtocolReadTTypeInterceptor</tt> -> * <tt>TProtocolReadMessageEndInterceptor</tt> * * <p>Based on Thrift 0.8.0+ * * @author HyunGil Jeong * @see com.navercorp.pinpoint.plugin.thrift.interceptor.server.ProcessFunctionProcessInterceptor * ProcessFunctionProcessInterceptor * @see * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadFieldBeginInterceptor * TProtocolReadFieldBeginInterceptor * @see * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadTTypeInterceptor * TProtocolReadTTypeInterceptor * @see * com.navercorp.pinpoint.plugin.thrift.interceptor.tprotocol.server.TProtocolReadMessageEndInterceptor * TProtocolReadMessageEndInterceptor */ @Group(value = THRIFT_SERVER_SCOPE, executionPoint = ExecutionPolicy.BOUNDARY) public class TBaseProcessorProcessInterceptor implements SimpleAroundInterceptor, ThriftConstants { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); private final boolean isDebug = logger.isDebugEnabled(); private final TraceContext traceContext; private final MethodDescriptor descriptor; private final InterceptorGroup group; private final MetadataAccessor socketAccessor; public TBaseProcessorProcessInterceptor( TraceContext traceContext, MethodDescriptor descriptor, @Name(THRIFT_SERVER_SCOPE) InterceptorGroup group, @Name(METADATA_SOCKET) MetadataAccessor socketAccessor) { this.traceContext = traceContext; this.descriptor = descriptor; this.group = group; this.socketAccessor = socketAccessor; } @Override public void before(Object target, Object[] args) { // Do nothing } @Override public void after(Object target, Object[] args, Object result, Throwable throwable) { final Trace trace = this.traceContext.currentRawTraceObject(); if (trace == null) { return; } // logging here as some Thrift servers depend on TTransportException being thrown for normal // operations. // log only when current transaction is being traced. if (isDebug) { logger.afterInterceptor(target, args, result, throwable); } this.traceContext.removeTraceObject(); if (trace.canSampled()) { try { processTraceObject(trace, target, args, throwable); } catch (Throwable t) { logger.warn("Error processing trace object. Cause:{}", t.getMessage(), t); } finally { trace.close(); } } } private void processTraceObject( final Trace trace, Object target, Object[] args, Throwable throwable) { // end spanEvent try { SpanEventRecorder recorder = trace.currentSpanEventRecorder(); // TODO Might need a way to collect and record method arguments // trace.recordAttribute(...); recorder.recordException(throwable); recorder.recordApi(this.descriptor); } catch (Throwable t) { logger.warn("Error processing trace object. Cause:{}", t.getMessage(), t); } finally { trace.traceBlockEnd(); } // end root span SpanRecorder recorder = trace.getSpanRecorder(); String methodUri = getMethodUri(target); recorder.recordRpcName(methodUri); // retrieve connection information String localIpPort = UNKNOWN_ADDRESS; String remoteAddress = UNKNOWN_ADDRESS; if (args.length == 2 && args[0] instanceof TProtocol) { TProtocol inputProtocol = (TProtocol) args[0]; if (this.socketAccessor.isApplicable(inputProtocol.getTransport())) { Socket socket = this.socketAccessor.get(inputProtocol.getTransport()); if (socket != null) { localIpPort = ThriftUtils.getHostPort(socket.getLocalSocketAddress()); remoteAddress = ThriftUtils.getHost(socket.getRemoteSocketAddress()); } } } if (localIpPort != UNKNOWN_ADDRESS) { recorder.recordEndPoint(localIpPort); } if (remoteAddress != UNKNOWN_ADDRESS) { recorder.recordRemoteAddress(remoteAddress); } } private String getMethodUri(Object target) { String methodUri = UNKNOWN_METHOD_URI; InterceptorGroupInvocation currentTransaction = this.group.getCurrentInvocation(); Object attachment = currentTransaction.getAttachment(); if (attachment instanceof ThriftClientCallContext && target instanceof TBaseProcessor) { ThriftClientCallContext clientCallContext = (ThriftClientCallContext) attachment; String methodName = clientCallContext.getMethodName(); methodUri = ThriftUtils.getProcessorNameAsUri((TBaseProcessor<?>) target); StringBuilder sb = new StringBuilder(methodUri); if (!methodUri.endsWith("/")) { sb.append("/"); } sb.append(methodName); methodUri = sb.toString(); } return methodUri; } }
/** @author jaehong.kim */ public class UserPlugin implements ProfilerPlugin, UserConstants { private final PLogger logger = PLoggerFactory.getLogger(this.getClass()); @Override public void setup(ProfilerPluginSetupContext context) { final UserPluginConfig config = new UserPluginConfig(context.getConfig()); // add user include methods for (String fullQualifiedMethodName : config.getIncludeList()) { try { addUserIncludeClass(context, fullQualifiedMethodName); if (logger.isDebugEnabled()) { logger.debug("Add user include class interceptor {}", fullQualifiedMethodName); } } catch (Exception e) { logger.warn("Failed to add user include class(" + fullQualifiedMethodName + ").", e); } } } private void addUserIncludeClass( ProfilerPluginSetupContext context, final String fullQualifiedMethodName) { final String className = toClassName(fullQualifiedMethodName); final String methodName = toMethodName(fullQualifiedMethodName); context.addClassFileTransformer( className, new PinpointClassFileTransformer() { @Override public byte[] transform( PinpointInstrument instrumentContext, ClassLoader classLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException { InstrumentClass target = instrumentContext.getInstrumentClass(classLoader, className, classfileBuffer); for (InstrumentMethod method : target.getDeclaredMethods(MethodFilters.name(methodName))) { try { method.addInterceptor( "com.navercorp.pinpoint.plugin.user.interceptor.UserIncludeMethodInterceptor"); } catch (Exception e) { if (logger.isWarnEnabled()) { logger.warn("Unsupported method " + method, e); } } } return target.toBytecode(); } }); } String toClassName(String fullQualifiedMethodName) { final int classEndPosition = fullQualifiedMethodName.lastIndexOf("."); if (classEndPosition <= 0) { throw new IllegalArgumentException( "invalid full qualified method name(" + fullQualifiedMethodName + "). not found method"); } return fullQualifiedMethodName.substring(0, classEndPosition); } String toMethodName(String fullQualifiedMethodName) { final int methodBeginPosition = fullQualifiedMethodName.lastIndexOf("."); if (methodBeginPosition <= 0 || methodBeginPosition + 1 >= fullQualifiedMethodName.length()) { throw new IllegalArgumentException( "invalid full qualified method name(" + fullQualifiedMethodName + "). not found method"); } return fullQualifiedMethodName.substring(methodBeginPosition + 1); } }