add arcus-plugin

This commit is contained in:
Jaehong Kim
2015-06-16 16:21:55 +09:00
parent b5ee7a7675
commit 31e8ada621
30 changed files with 1765 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
/target/
/.settings/
/.classpath
/.project
/*.iml
+5
View File
@@ -0,0 +1,5 @@
NmMRuoKXgVJaWcFxmQgPsNWFORqaKAmmTFKWebObfCEQOuf
mj2KSKWpbfygHlTk2r9juoUM2L0CwcuusX2To7Fr<SzC<pn
QnPrXSmmnrQRppQRPPmssqmOQNqRQRmQNRxVwsWOXXtsxtV
UxxwXXRooNmnmnmUUnpntuopommmmmUUnpntuopommmmmUU
E8EWZlomloXqflkUUnmmmm
+49
View File
@@ -0,0 +1,49 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pom</artifactId>
<relativePath>../..</relativePath>
<version>1.5.0-SNAPSHOT</version>
</parent>
<artifactId>pinpoint-arcus-plugin</artifactId>
<name>pinpoint-arcus-plugin</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pinpoint-bootstrap</artifactId>
</dependency>
<dependency>
<groupId>com.navercorp.arcus</groupId>
<artifactId>arcus-java-client</artifactId>
<version>1.8.1</version>
<scope>provided</scope>
</dependency>
<!-- Logging depedencies -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<!-- commons-logging-adapter -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,26 @@
package com.navercorp.pinpoint.plugin.arcus;
import static com.navercorp.pinpoint.common.trace.AnnotationKeyMatcher.*;
import static com.navercorp.pinpoint.common.trace.HistogramSchema.*;
import static com.navercorp.pinpoint.common.trace.ServiceTypeProperty.*;
import com.navercorp.pinpoint.common.trace.ServiceType;
public interface ArcusConstants {
public static final ServiceType ARCUS = ServiceType.of(8100, "ARCUS", FAST_SCHEMA, TERMINAL, RECORD_STATISTICS, INCLUDE_DESTINATION_ID);
public static final ServiceType ARCUS_FUTURE_GET = ServiceType.of(8101, "ARCUS_FUTURE_GET", "ARCUS", FAST_SCHEMA, TERMINAL, INCLUDE_DESTINATION_ID);
public static final ServiceType ARCUS_EHCACHE_FUTURE_GET = ServiceType.of(8102, "ARCUS_EHCACHE_FUTURE_GET", "ARCUS-EHCACHE", FAST_SCHEMA, TERMINAL, INCLUDE_DESTINATION_ID);
public static final ServiceType ARCUS_INTERNAL = ServiceType.of(8103, "ARCUS_INTERNAL", "ARCUS", FAST_SCHEMA);
public static final String ARCUS_SCOPE = "ArcusScope";
public static final String ARCUS_FUTURE_SCOPE = "ArcusFutureScope";
public static final String ATTRIBUTE_CONFIG = "arcusPluginConfig";
public static final String METADATA_SERVICE_CODE = "serviceCode";
public static final String MEATDATA_CACHE_NAME = "cacheName";
public static final String METADATA_CACHE_KEY = "cacheKey";
public static final String METADATA_OPERATION = "operation";
public static final String METADATA_ASYNC_TRACE_ID = "asyncTraceId";
}
@@ -0,0 +1,256 @@
package com.navercorp.pinpoint.plugin.arcus;
import static com.navercorp.pinpoint.bootstrap.plugin.transformer.ClassConditions.*;
import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter;
import com.navercorp.pinpoint.bootstrap.instrument.MethodInfo;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPlugin;
import com.navercorp.pinpoint.bootstrap.plugin.ProfilerPluginContext;
import com.navercorp.pinpoint.bootstrap.plugin.transformer.BaseClassFileTransformerBuilder;
import com.navercorp.pinpoint.bootstrap.plugin.transformer.ClassFileTransformerBuilder;
import com.navercorp.pinpoint.bootstrap.plugin.transformer.ConditionalClassFileTransformerBuilder;
import com.navercorp.pinpoint.bootstrap.plugin.transformer.ConditionalClassFileTransformerSetup;
import com.navercorp.pinpoint.bootstrap.plugin.transformer.MethodTransformerBuilder;
import com.navercorp.pinpoint.bootstrap.plugin.transformer.MethodTransformerExceptionHandler;
import com.navercorp.pinpoint.bootstrap.plugin.transformer.MethodTransformerProperty;
import com.navercorp.pinpoint.plugin.arcus.filter.ArcusMethodFilter;
import com.navercorp.pinpoint.plugin.arcus.filter.FrontCacheMemcachedMethodFilter;
import com.navercorp.pinpoint.plugin.arcus.filter.MemcachedMethodFilter;
/**
*
* @author jaehong.kim
*
*/
public class ArcusPlugin implements ProfilerPlugin, ArcusConstants {
private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
@Override
public void setup(ProfilerPluginContext context) {
ArcusPluginConfig config = new ArcusPluginConfig(context.getConfig());
context.setAttribute(ArcusConstants.ATTRIBUTE_CONFIG, config);
boolean arcus = config.isArcus();
boolean memcached = config.isMemcached();
if (arcus) {
addArcusClientEditor(context, config);
addCollectionFutureEditor(context);
addFrontCacheGetFutureEditor(context);
addFrontCacheMemcachedClientEditor(context, config);
addCacheManagerEditor(context);
// add none operation future. over 1.5.4
addBTreeStoreGetFutureEditor(context);
addCollectionGetBulkFutureEditor(context);
addSMGetFutureFutureEditor(context);
}
if (arcus || memcached) {
addMemcachedClientEditor(context, config);
addBaseOperationImplEditor(context);
addGetFutureEditor(context);
addOperationFutureEditor(context);
// add none operation future.
addImmediateFutureEditor(context);
addBulkGetFutureEditor(context);
}
}
private void addArcusClientEditor(ProfilerPluginContext context, final ArcusPluginConfig config) {
final ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.ArcusClient");
builder.conditional(hasMethod("addOp", "net.spy.memcached.ops.Operation", "java.lang.String", "net.spy.memcached.ops.Operation"), new ConditionalClassFileTransformerSetup() {
@Override
public void setup(ConditionalClassFileTransformerBuilder conditional) {
boolean traceKey = config.isArcusKeyTrace();
conditional.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.SetCacheManagerInterceptor");
MethodTransformerBuilder mb = conditional.editMethods(new ArcusMethodFilter());
mb.exceptionHandler(new MethodTransformerExceptionHandler() {
public void handle(String targetClassName, String targetMethodName, String[] targetMethodParameterTypes, Throwable exception) throws Throwable {
if (logger.isWarnEnabled()) {
logger.warn("Unsupported method " + targetClassName + "." + targetMethodName, exception);
}
}
});
mb.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.ApiInterceptor", traceKey);
}
});
context.addClassFileTransformer(builder.build());
}
private void addCacheManagerEditor(ProfilerPluginContext context) {
ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.CacheManager");
builder.injectMetadata(METADATA_SERVICE_CODE);
builder.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.CacheManagerConstructInterceptor");
context.addClassFileTransformer(builder.build());
}
private void addBaseOperationImplEditor(ProfilerPluginContext context) {
ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.protocol.BaseOperationImpl");
builder.injectMetadata(METADATA_SERVICE_CODE);
context.addClassFileTransformer(builder.build());
}
private void addFrontCacheGetFutureEditor(ProfilerPluginContext context) {
ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.plugin.FrontCacheGetFuture");
builder.injectMetadata(MEATDATA_CACHE_NAME);
builder.injectMetadata(METADATA_CACHE_KEY);
builder.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.FrontCacheGetFutureConstructInterceptor");
MethodTransformerBuilder mb2 = builder.editMethod("get", "long", "java.util.concurrent.TimeUnit");
mb2.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.FrontCacheGetFutureGetInterceptor");
MethodTransformerBuilder mb3 = builder.editMethod("get");
mb3.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.FrontCacheGetFutureGetInterceptor");
context.addClassFileTransformer(builder.build());
}
private void addFrontCacheMemcachedClientEditor(ProfilerPluginContext context, final ArcusPluginConfig config) {
ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.plugin.FrontCacheMemcachedClient");
// builder.conditional(hasDeclaredMethod("putFrontCache", "java.lang.String", "java.util.concurrent.Future", "long"),
// new ConditionalClassFileTransformerSetup() {
//
// @Override
// public void setup(ConditionalClassFileTransformerBuilder conditional) {
// boolean traceKey = config.isMemcachedKeyTrace();
// MethodTransformerBuilder mb = conditional.editMethods(new FrontCacheMemcachedMethodFilter());
// mb.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.ApiInterceptor", traceKey);
// }
// }
// );
boolean traceKey = config.isMemcachedKeyTrace();
MethodTransformerBuilder mb = builder.editMethods(new FrontCacheMemcachedMethodFilter());
mb.exceptionHandler(new MethodTransformerExceptionHandler() {
public void handle(String targetClassName, String targetMethodName, String[] targetMethodParameterTypes, Throwable exception) throws Throwable {
if (logger.isWarnEnabled()) {
logger.warn("Unsupported method " + targetClassName + "." + targetMethodName, exception);
}
}
});
mb.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.ApiInterceptor", traceKey);
context.addClassFileTransformer(builder.build());
}
private void addMemcachedClientEditor(ProfilerPluginContext context, final ArcusPluginConfig config) {
ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.MemcachedClient");
builder.conditional(hasDeclaredMethod("addOp", "java.lang.String", "net.spy.memcached.ops.Operation"), new ConditionalClassFileTransformerSetup() {
@Override
public void setup(ConditionalClassFileTransformerBuilder conditional) {
conditional.injectMetadata(METADATA_SERVICE_CODE);
conditional.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.AddOpInterceptor");
}
});
boolean traceKey = config.isMemcachedKeyTrace();
MethodTransformerBuilder mb2 = builder.editMethods(new MemcachedMethodFilter());
mb2.exceptionHandler(new MethodTransformerExceptionHandler() {
public void handle(String targetClassName, String targetMethodName, String[] targetMethodParameterTypes, Throwable exception) throws Throwable {
if (logger.isWarnEnabled()) {
logger.warn("Unsupported method " + targetClassName + "." + targetMethodName, exception);
}
}
});
mb2.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.ApiInterceptor", traceKey);
context.addClassFileTransformer(builder.build());
}
private void injectFutureInterceptor(ProfilerPluginContext context, BaseClassFileTransformerBuilder builder) {
builder.injectMetadata(ArcusConstants.METADATA_OPERATION);
builder.injectMetadata(ArcusConstants.METADATA_ASYNC_TRACE_ID);
// setOperation
final MethodTransformerBuilder setOperationMethodBuilder = builder.editMethod("setOperation", "net.spy.memcached.ops.Operation");
setOperationMethodBuilder.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST);
setOperationMethodBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.FutureSetOperationInterceptor");
// cancel, get, set
final MethodTransformerBuilder methodBuilder = builder.editMethods(new MethodFilter() {
@Override
public boolean filter(MethodInfo method) {
final String name = method.getName();
return !(name.equals("cancel") || name.equals("get") || name.equals("set") || name.equals("signalComplete"));
}
});
methodBuilder.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST);
methodBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.FutureGetInterceptor");
}
private void addCollectionFutureEditor(ProfilerPluginContext context) {
final ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.internal.CollectionFuture");
injectFutureInterceptor(context, builder);
context.addClassFileTransformer(builder.build());
}
private void addGetFutureEditor(ProfilerPluginContext context) {
ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.internal.GetFuture");
injectFutureInterceptor(context, builder);
context.addClassFileTransformer(builder.build());
}
private void addOperationFutureEditor(ProfilerPluginContext context) {
ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.internal.OperationFuture");
injectFutureInterceptor(context, builder);
context.addClassFileTransformer(builder.build());
}
private void addImmediateFutureEditor(ProfilerPluginContext context) {
ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.internal.ImmediateFuture");
injectFutureInternalInterceptor(context, builder);
context.addClassFileTransformer(builder.build());
}
private void addBulkGetFutureEditor(ProfilerPluginContext context) {
ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.internal.BulkGetFuture");
injectFutureInternalInterceptor(context, builder);
context.addClassFileTransformer(builder.build());
}
private void addBTreeStoreGetFutureEditor(ProfilerPluginContext context) {
ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.internal.BTreeStoreAndGetFuture");
injectFutureInternalInterceptor(context, builder);
context.addClassFileTransformer(builder.build());
}
private void addCollectionGetBulkFutureEditor(ProfilerPluginContext context) {
ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.internal.CollectionGetBulkFuture");
injectFutureInternalInterceptor(context, builder);
context.addClassFileTransformer(builder.build());
}
private void addSMGetFutureFutureEditor(ProfilerPluginContext context) {
ClassFileTransformerBuilder builder = context.getClassFileTransformerBuilder("net.spy.memcached.internal.SMGetFuture");
injectFutureInternalInterceptor(context, builder);
context.addClassFileTransformer(builder.build());
}
private void injectFutureInternalInterceptor(ProfilerPluginContext context, BaseClassFileTransformerBuilder builder) {
builder.injectMetadata(ArcusConstants.METADATA_ASYNC_TRACE_ID);
// cancel, get
final MethodTransformerBuilder methodBuilder = builder.editMethods(new MethodFilter() {
@Override
public boolean filter(MethodInfo method) {
final String name = method.getName();
return !(name.equals("cancel") || name.equals("get"));
}
});
methodBuilder.property(MethodTransformerProperty.IGNORE_IF_NOT_EXIST);
methodBuilder.injectInterceptor("com.navercorp.pinpoint.plugin.arcus.interceptor.FutureInternalMethodInterceptor");
}
}
@@ -0,0 +1,48 @@
package com.navercorp.pinpoint.plugin.arcus;
import com.navercorp.pinpoint.bootstrap.config.ProfilerConfig;
public class ArcusPluginConfig {
private final boolean arcus;
private final boolean arcusKeyTrace;
private final boolean memcached;
private final boolean memcachedKeyTrace;
public ArcusPluginConfig(ProfilerConfig src) {
this.arcus = src.readBoolean("profiler.arcus", true);
this.arcusKeyTrace = src.readBoolean("profiler.arcus.keytrace", false);
this.memcached = src.readBoolean("profiler.memcached", true);
this.memcachedKeyTrace = src.readBoolean("profiler.memcached.keytrace", false);
}
public boolean isArcus() {
return arcus;
}
public boolean isArcusKeyTrace() {
return arcusKeyTrace;
}
public boolean isMemcached() {
return memcached;
}
public boolean isMemcachedKeyTrace() {
return memcachedKeyTrace;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ArcusPluginConfig={arcus=").append(arcus);
sb.append(", arcusKeyTrace=").append(arcusKeyTrace);
sb.append(", memcached=").append(memcached);
sb.append(", memcachedKeyTrace=").append(memcachedKeyTrace);
sb.append("}");
return sb.toString();
}
}
@@ -0,0 +1,34 @@
/**
* Copyright 2014 NAVER Corp.
* 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 com.navercorp.pinpoint.plugin.arcus;
import com.navercorp.pinpoint.common.trace.TraceMetadataProvider;
import com.navercorp.pinpoint.common.trace.TraceMetadataSetupContext;
import static com.navercorp.pinpoint.common.trace.AnnotationKeyMatcher.*;
/**
* @author Jongho Moon
*
*/
public class ArcusTypeProvider implements TraceMetadataProvider, ArcusConstants {
@Override
public void setup(TraceMetadataSetupContext context) {
context.addServiceType(ARCUS, ARGS_MATCHER);
context.addServiceType(ARCUS_FUTURE_GET);
context.addServiceType(ARCUS_EHCACHE_FUTURE_GET);
}
}
@@ -0,0 +1,23 @@
package com.navercorp.pinpoint.plugin.arcus;
import com.navercorp.pinpoint.bootstrap.instrument.MethodInfo;
/**
* @author emeroad
*/
public class ParameterUtils {
public static int findFirstString(MethodInfo method, int maxIndex) {
if (method == null) {
return -1;
}
final String[] methodParams = method.getParameterTypes();
final int minIndex = Math.min(methodParams.length, maxIndex);
for(int i =0; i < minIndex; i++) {
if ("java.lang.String".equals(methodParams[i])) {
return i;
}
}
return -1;
}
}
@@ -0,0 +1,82 @@
package com.navercorp.pinpoint.plugin.arcus.filter;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter;
import com.navercorp.pinpoint.bootstrap.instrument.MethodInfo;
/**
* @author emeroad
*/
public class ArcusMethodFilter implements MethodFilter {
private final static Object FIND = new Object();
private final static Map<String, Object> WHITE_LIST_API;
static {
WHITE_LIST_API = createRule();
}
private static Map<String, Object> createRule() {
String[] apiList = {
"asyncBopCreate",
"asyncBopDecr",
"asyncBopDelete",
"asyncBopFindPosition",
"asyncBopFindPositionWithGet",
"asyncBopGet",
"asyncBopGetBulk",
"asyncBopGetByPosition",
"asyncBopGetItemCount",
"asyncBopIncr",
"asyncBopInsert",
"asyncBopInsertAndGetTrimmed",
"asyncBopInsertBulk",
"asyncBopPipedInsertBulk",
"asyncBopPipedUpdateBulk",
"asyncBopSortMergeGet",
"asyncBopUpdate",
"asyncBopUpsert",
"asyncBopUpsertAndGetTrimmed",
"asyncGetAttr",
"asyncLopCreate",
"asyncLopDelete",
"asyncLopGet",
"asyncLopInsert",
"asyncLopInsertBulk",
"asyncLopPipedInsertBulk",
"asyncSetAttr",
"asyncSetBulk",
"asyncSetPipedExist",
"asyncSopCreate",
"asyncSopDelete",
"asyncSopExist",
"asyncSopGet",
"asyncSopInsert",
"asyncSopInsertBulk",
"asyncSopPipedExistBulk",
"asyncSopPipedInsertBulk"
};
Map<String, Object> rule = new HashMap<String, Object>();
for (String api : apiList) {
rule.put(api, FIND);
}
return rule;
}
public ArcusMethodFilter() {
}
@Override
public boolean filter(MethodInfo ctMethod) {
final int modifiers = ctMethod.getModifiers();
if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers) || Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
return true;
}
if (WHITE_LIST_API.get(ctMethod.getName()) == FIND) {
return false;
}
return true;
}
}
@@ -0,0 +1,65 @@
package com.navercorp.pinpoint.plugin.arcus.filter;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter;
import com.navercorp.pinpoint.bootstrap.instrument.MethodInfo;
/**
* @author emeroad
* @author harebox
*/
public class FrontCacheMemcachedMethodFilter implements MethodFilter {
private final static Object FIND = new Object();
private final static Map<String, Object> WHITE_LIST_API;
static {
WHITE_LIST_API = createRule();
}
private static Map<String, Object> createRule() {
String[] apiList = {
"add",
"append",
"asyncCAS",
"asyncDecr",
"asyncGet",
"asyncGetBulk",
"asyncGets",
"asyncIncr",
"cas",
"decr",
"delete",
"get",
"getBulk",
"gets",
"incr",
"prepend",
"replace",
"set",
"putFrontCache"
};
Map<String, Object> rule = new HashMap<String, Object>();
for (String api : apiList) {
rule.put(api, FIND);
}
return rule;
}
public FrontCacheMemcachedMethodFilter() {
}
@Override
public boolean filter(MethodInfo ctMethod) {
final int modifiers = ctMethod.getModifiers();
if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers) || Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
return true;
}
if (WHITE_LIST_API.get(ctMethod.getName()) == FIND) {
return false;
}
return true;
}
}
@@ -0,0 +1,66 @@
package com.navercorp.pinpoint.plugin.arcus.filter;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import com.navercorp.pinpoint.bootstrap.instrument.MethodFilter;
import com.navercorp.pinpoint.bootstrap.instrument.MethodInfo;
/**
* @author emeroad
*/
public class MemcachedMethodFilter implements MethodFilter {
private final static Object FIND = new Object();
private final static Map<String, Object> WHITE_LIST_API;
static {
WHITE_LIST_API = createRule();
}
private static Map<String, Object> createRule() {
String[] apiList = {
"add",
"append",
"asyncCAS",
"asyncDecr",
"asyncGet",
"asyncGetAndTouch",
"asyncGetBulk",
"asyncGets",
"asyncIncr",
"cas",
"decr",
"delete",
"get",
"getAndTouch",
"getBulk",
"gets",
"incr",
"prepend",
"replace",
"set",
"touch"
};
Map<String, Object> rule = new HashMap<String, Object>();
for (String api : apiList) {
rule.put(api, FIND);
}
return rule;
}
public MemcachedMethodFilter() {
}
@Override
public boolean filter(MethodInfo ctMethod) {
final int modifiers = ctMethod.getModifiers();
if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers) || Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
return true;
}
if (WHITE_LIST_API.get(ctMethod.getName()) == FIND) {
return false;
}
return true;
}
}
@@ -0,0 +1,45 @@
package com.navercorp.pinpoint.plugin.arcus.interceptor;
import com.navercorp.pinpoint.bootstrap.MetadataAccessor;
import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.TargetMethod;
import com.navercorp.pinpoint.plugin.arcus.ArcusConstants;
/**
*
* @author netspider
* @author emeroad
*/
@TargetMethod(name="addOp", paramTypes={"java.lang.String", "net.spy.memcached.ops.Operation"})
public class AddOpInterceptor implements SimpleAroundInterceptor {
private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
private final boolean isDebug = logger.isDebugEnabled();
private final MetadataAccessor serviceCodeAccessor;
public AddOpInterceptor(@Name(ArcusConstants.METADATA_SERVICE_CODE) MetadataAccessor serviceCodeAccessor) {
this.serviceCodeAccessor = serviceCodeAccessor;
}
@Override
public void before(Object target, Object[] args) {
if (isDebug) {
logger.beforeInterceptor(target, args);
}
String serviceCode = serviceCodeAccessor.get(target);
serviceCodeAccessor.set(args[1], serviceCode);
}
@Override
public void after(Object target, Object[] args, Object result, Throwable throwable) {
if (isDebug) {
logger.afterInterceptor(target, args, result, throwable);
}
}
}
@@ -0,0 +1,135 @@
package com.navercorp.pinpoint.plugin.arcus.interceptor;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.Future;
import net.spy.memcached.MemcachedNode;
import net.spy.memcached.ops.Operation;
import com.navercorp.pinpoint.bootstrap.MetadataAccessor;
import com.navercorp.pinpoint.bootstrap.context.AsyncTraceId;
import com.navercorp.pinpoint.bootstrap.context.RecordableTrace;
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
import com.navercorp.pinpoint.bootstrap.instrument.MethodInfo;
import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Group;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name;
import com.navercorp.pinpoint.common.trace.ServiceType;
import com.navercorp.pinpoint.plugin.arcus.ArcusConstants;
import com.navercorp.pinpoint.plugin.arcus.ParameterUtils;
/**
* @author emeroad
*/
@Group(ArcusConstants.ARCUS_SCOPE)
public class ApiInterceptor extends SpanEventSimpleAroundInterceptorForPlugin implements ArcusConstants {
private final boolean traceKey;
private final int keyIndex;
private final MetadataAccessor serviceCodeAccessor;
private final MetadataAccessor operationAccessor;
private final MetadataAccessor asyncTraceIdAccessor;
public ApiInterceptor(TraceContext context, MethodInfo targetMethod,
@Name(METADATA_ASYNC_TRACE_ID) MetadataAccessor asyncTraceIdAccessor, @Name(METADATA_SERVICE_CODE) MetadataAccessor serviceCodeAccessor, @Name(METADATA_OPERATION) MetadataAccessor operationAccessor, boolean traceKey) {
super(context, targetMethod.getDescriptor());
if (traceKey) {
int index = ParameterUtils.findFirstString(targetMethod, 3);
if (index != -1) {
this.traceKey = true;
this.keyIndex = index;
} else {
this.traceKey = false;
this.keyIndex = -1;
}
} else {
this.traceKey = false;
this.keyIndex = -1;
}
this.serviceCodeAccessor = serviceCodeAccessor;
this.operationAccessor = operationAccessor;
this.asyncTraceIdAccessor = asyncTraceIdAccessor;
}
@Override
public void doInBeforeTrace(RecordableTrace trace, final Object target, Object[] args) {
trace.markBeforeTime();
}
@Override
public void doInAfterTrace(RecordableTrace trace, Object target, Object[] args, Object result, Throwable throwable) {
if (traceKey) {
final Object recordObject = args[keyIndex];
trace.recordApi(getMethodDescriptor(), recordObject, keyIndex);
} else {
trace.recordApi(getMethodDescriptor());
}
trace.recordException(throwable);
// find the target node
if (result instanceof Future && operationAccessor.isApplicable(result)) {
Operation op = operationAccessor.get(result);
if (op != null) {
MemcachedNode handlingNode = op.getHandlingNode();
SocketAddress socketAddress = handlingNode.getSocketAddress();
if (socketAddress instanceof InetSocketAddress) {
InetSocketAddress address = (InetSocketAddress) socketAddress;
trace.recordEndPoint(address.getHostName() + ":" + address.getPort());
}
} else {
logger.info("operation not found");
}
}
if(serviceCodeAccessor.isApplicable(target)) {
// determine the service type
String serviceCode = serviceCodeAccessor.get(target);
if (serviceCode != null) {
trace.recordDestinationId(serviceCode);
trace.recordServiceType(ARCUS);
} else {
trace.recordDestinationId("MEMCACHED");
trace.recordServiceType(ServiceType.MEMCACHED);
}
} else {
trace.recordDestinationId("MEMCACHED");
trace.recordServiceType(ServiceType.MEMCACHED);
}
try {
if(isAsynchronousInvocation(target, args, result, throwable)) {
// set asynchronous trace
final AsyncTraceId asyncTraceId = trace.getAsyncTraceId();
trace.recordNextAsyncId(asyncTraceId.getAsyncId());
asyncTraceIdAccessor.set(result, asyncTraceId);
if (isDebug) {
logger.debug("Set asyncTraceId metadata {}", asyncTraceId);
}
}
} catch(Throwable t) {
logger.warn("Failed to before process. {}", t.getMessage(), t);
}
trace.markAfterTime();
}
private boolean isAsynchronousInvocation(final Object target, final Object[] args, Object result, Throwable throwable) {
if(throwable != null || result == null) {
return false;
}
if (!asyncTraceIdAccessor.isApplicable(result)) {
logger.debug("Invalid result object. Need metadata accessor({}).", METADATA_ASYNC_TRACE_ID);
return false;
}
return true;
}
}
@@ -0,0 +1,41 @@
package com.navercorp.pinpoint.plugin.arcus.interceptor;
import com.navercorp.pinpoint.bootstrap.MetadataAccessor;
import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.TargetConstructor;
import com.navercorp.pinpoint.plugin.arcus.ArcusConstants;
/**
*
* @author netspider
* @author emeroad
*/
@TargetConstructor({"java.lang.String", "java.lang.String", "net.spy.memcached.ConnectionFactoryBuilder", "java.util.concurrent.CountDownLatch", "int", "int"})
public class CacheManagerConstructInterceptor implements SimpleAroundInterceptor, ArcusConstants {
private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
private final boolean isDebug = logger.isDebugEnabled();
private final MetadataAccessor serviceCodeAccessor;
public CacheManagerConstructInterceptor(@Name(METADATA_SERVICE_CODE) MetadataAccessor serviceCodeAccessor) {
this.serviceCodeAccessor = serviceCodeAccessor;
}
@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);
}
serviceCodeAccessor.set(target, args[1]);
}
}
@@ -0,0 +1,57 @@
package com.navercorp.pinpoint.plugin.arcus.interceptor;
import net.sf.ehcache.Element;
import com.navercorp.pinpoint.bootstrap.MetadataAccessor;
import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.TargetConstructor;
import com.navercorp.pinpoint.plugin.arcus.ArcusConstants;
/**
* @author harebox
*/
@TargetConstructor("net.sf.ehcache.Element")
public class FrontCacheGetFutureConstructInterceptor implements SimpleAroundInterceptor, 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();
private final MetadataAccessor cacheNameAccessor;
private final MetadataAccessor cacheKeyAccessor;
public FrontCacheGetFutureConstructInterceptor(@Name(MEATDATA_CACHE_NAME) MetadataAccessor cacheNameAccessor,
@Name(ArcusConstants.METADATA_CACHE_KEY) MetadataAccessor cacheKeyAccessor) {
this.cacheNameAccessor = cacheNameAccessor;
this.cacheKeyAccessor = cacheKeyAccessor;
}
@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);
}
try {
cacheNameAccessor.set(target, DEFAULT_FRONTCACHE_NAME);
if (args[0] instanceof Element) {
Element element = (Element) args[0];
cacheKeyAccessor.set(target, element.getObjectKey());
}
} catch (Exception e) {
logger.error("failed to add metadata: {}", e);
}
}
}
@@ -0,0 +1,78 @@
package com.navercorp.pinpoint.plugin.arcus.interceptor;
import com.navercorp.pinpoint.bootstrap.MetadataAccessor;
import com.navercorp.pinpoint.bootstrap.context.Trace;
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor;
import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Group;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name;
import com.navercorp.pinpoint.plugin.arcus.ArcusConstants;
/**
* @author harebox
*/
@Group(ArcusConstants.ARCUS_SCOPE)
public class FrontCacheGetFutureGetInterceptor implements SimpleAroundInterceptor, ArcusConstants {
private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
private final boolean isDebug = logger.isDebugEnabled();
private final MethodDescriptor methodDescriptor;
private final TraceContext traceContext;
private final MetadataAccessor cacheNameAccessor;
public FrontCacheGetFutureGetInterceptor(TraceContext traceContext, MethodDescriptor methodDescriptor, @Name(MEATDATA_CACHE_NAME) MetadataAccessor cacheNameAccessor) {
this.methodDescriptor = methodDescriptor;
this.traceContext = traceContext;
this.cacheNameAccessor = cacheNameAccessor;
}
@Override
public void before(Object target, Object[] args) {
if (isDebug) {
logger.beforeInterceptor(target, args);
}
final Trace trace = traceContext.currentTraceObject();
if (trace == null) {
return;
}
trace.traceBlockBegin();
trace.markBeforeTime();
}
@Override
public void after(Object target, Object[] args, Object result, Throwable throwable) {
if (isDebug) {
logger.afterInterceptor(target, args, result, throwable);
}
final Trace trace = traceContext.currentTraceObject();
if (trace == null) {
return;
}
try {
trace.recordApi(methodDescriptor);
// String cacheKey = (String) getCacheKey.invoke(target);
// if (cacheKey != null) {
// // annotate it.
// }
String cacheName = cacheNameAccessor.get(target);
if (cacheName != null) {
trace.recordDestinationId(cacheName);
}
trace.recordServiceType(ARCUS_EHCACHE_FUTURE_GET);
trace.markAfterTime();
} finally {
trace.traceBlockEnd();
}
}
}
@@ -0,0 +1,81 @@
package com.navercorp.pinpoint.plugin.arcus.interceptor;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import net.spy.memcached.MemcachedNode;
import net.spy.memcached.ops.Operation;
import com.navercorp.pinpoint.bootstrap.MetadataAccessor;
import com.navercorp.pinpoint.bootstrap.context.AsyncTraceId;
import com.navercorp.pinpoint.bootstrap.context.Trace;
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor;
import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor;
import com.navercorp.pinpoint.bootstrap.interceptor.SpanAsyncEventSimpleAroundInterceptor;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Group;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name;
import com.navercorp.pinpoint.common.trace.ServiceType;
import com.navercorp.pinpoint.plugin.arcus.ArcusConstants;
/**
* @author emeroad
* @author jaehong.kim
*/
@Group(ArcusConstants.ARCUS_FUTURE_SCOPE)
public class FutureGetInterceptor extends SpanAsyncEventSimpleAroundInterceptor implements ArcusConstants {
private final MetadataAccessor operationAccessor;
private final MetadataAccessor serviceCodeAccessor;
public FutureGetInterceptor(MethodDescriptor methodDescriptor, TraceContext traceContext, @Name(METADATA_ASYNC_TRACE_ID) MetadataAccessor asyncTraceIdAccessor, @Name(METADATA_SERVICE_CODE) MetadataAccessor serviceCodeAccessor,
@Name(METADATA_OPERATION) MetadataAccessor operationAccessor) {
super(traceContext, methodDescriptor, asyncTraceIdAccessor);
this.serviceCodeAccessor = serviceCodeAccessor;
this.operationAccessor = operationAccessor;
}
@Override
protected void doInBeforeTrace(Trace trace, AsyncTraceId asyncTraceId, Object target, Object[] args) {
trace.markBeforeTime();
}
@Override
protected void doInAfterTrace(Trace trace, Object target, Object[] args, Object result, Throwable throwable) {
// find the target node
final Operation op = operationAccessor.get(target);
if (op != null) {
MemcachedNode handlingNode = op.getHandlingNode();
if (handlingNode != null) {
SocketAddress socketAddress = handlingNode.getSocketAddress();
if (socketAddress instanceof InetSocketAddress) {
InetSocketAddress address = (InetSocketAddress) socketAddress;
trace.recordEndPoint(address.getHostName() + ":" + address.getPort());
}
} else {
logger.info("no handling node");
}
} else {
logger.info("operation not found");
}
// determine the service type
String serviceCode = serviceCodeAccessor.get(op);
if (serviceCode != null) {
trace.recordDestinationId(serviceCode);
trace.recordServiceType(ARCUS_FUTURE_GET);
} else {
trace.recordDestinationId("MEMCACHED");
trace.recordServiceType(ServiceType.MEMCACHED_FUTURE_GET);
}
if (op != null) {
trace.recordException(op.getException());
}
trace.recordApi(methodDescriptor);
trace.markAfterTime();
}
}
@@ -0,0 +1,36 @@
package com.navercorp.pinpoint.plugin.arcus.interceptor;
import com.navercorp.pinpoint.bootstrap.MetadataAccessor;
import com.navercorp.pinpoint.bootstrap.context.AsyncTraceId;
import com.navercorp.pinpoint.bootstrap.context.Trace;
import com.navercorp.pinpoint.bootstrap.context.TraceContext;
import com.navercorp.pinpoint.bootstrap.interceptor.MethodDescriptor;
import com.navercorp.pinpoint.bootstrap.interceptor.SpanAsyncEventSimpleAroundInterceptor;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Group;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name;
import com.navercorp.pinpoint.plugin.arcus.ArcusConstants;
/**
* @author emeroad
* @author jaehong.kim
*/
@Group(ArcusConstants.ARCUS_FUTURE_SCOPE)
public class FutureInternalMethodInterceptor extends SpanAsyncEventSimpleAroundInterceptor implements ArcusConstants {
public FutureInternalMethodInterceptor(MethodDescriptor methodDescriptor, TraceContext traceContext, @Name(METADATA_ASYNC_TRACE_ID) MetadataAccessor asyncTraceIdAccessor) {
super(traceContext, methodDescriptor, asyncTraceIdAccessor);
}
@Override
protected void doInBeforeTrace(Trace trace, AsyncTraceId asyncTraceId, Object target, Object[] args) {
trace.markBeforeTime();
}
@Override
protected void doInAfterTrace(Trace trace, Object target, Object[] args, Object result, Throwable throwable) {
trace.recordServiceType(ARCUS_INTERNAL);
trace.recordException(throwable);
trace.recordApi(methodDescriptor);
trace.markAfterTime();
}
}
@@ -0,0 +1,43 @@
package com.navercorp.pinpoint.plugin.arcus.interceptor;
import com.navercorp.pinpoint.bootstrap.MetadataAccessor;
import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.TargetMethod;
import com.navercorp.pinpoint.plugin.arcus.ArcusConstants;
/**
* @author harebox
* @author emeroad
*/
public class FutureSetOperationInterceptor implements SimpleAroundInterceptor, ArcusConstants {
private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
private final boolean isDebug = logger.isDebugEnabled();
private final MetadataAccessor operationAccessor;
public FutureSetOperationInterceptor(@Name(METADATA_OPERATION) MetadataAccessor operationAccessor) {
this.operationAccessor = operationAccessor;
}
@Override
public void before(Object target, Object[] args) {
if (isDebug) {
logger.beforeInterceptor(target, args);
}
operationAccessor.set(target, args[0]);
}
@Override
public void after(Object target, Object[] args, Object result, Throwable throwable) {
if (isDebug) {
logger.afterInterceptor(target, args);
}
}
}
@@ -0,0 +1,41 @@
package com.navercorp.pinpoint.plugin.arcus.interceptor;
import com.navercorp.pinpoint.bootstrap.MetadataAccessor;
import com.navercorp.pinpoint.bootstrap.interceptor.SimpleAroundInterceptor;
import com.navercorp.pinpoint.bootstrap.logging.PLogger;
import com.navercorp.pinpoint.bootstrap.logging.PLoggerFactory;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.Name;
import com.navercorp.pinpoint.bootstrap.plugin.annotation.TargetMethod;
import com.navercorp.pinpoint.plugin.arcus.ArcusConstants;
/**
*
* @author netspider
* @author emeroad
*/
@TargetMethod(name="setCacheManager", paramTypes="net.spy.memcached.CacheManager")
public class SetCacheManagerInterceptor implements SimpleAroundInterceptor, ArcusConstants {
private final PLogger logger = PLoggerFactory.getLogger(this.getClass());
private final boolean isDebug = logger.isDebugEnabled();
private final MetadataAccessor serviceCodeAccessor;
public SetCacheManagerInterceptor(@Name(METADATA_SERVICE_CODE) MetadataAccessor serviceCodeAccessor) {
this.serviceCodeAccessor = serviceCodeAccessor;
}
@Override
public void after(Object target, Object[] args, Object result, Throwable throwable) {
// do nothing
}
@Override
public void before(Object target, Object[] args) {
if (isDebug) {
logger.beforeInterceptor(target, args);
}
String serviceCode = serviceCodeAccessor.get(args[0]);
serviceCodeAccessor.set(target, serviceCode);
}
}
@@ -0,0 +1 @@
com.navercorp.pinpoint.plugin.arcus.ArcusPlugin
@@ -0,0 +1 @@
com.navercorp.pinpoint.plugin.arcus.ArcusTypeProvider
@@ -0,0 +1,48 @@
package com.navercorp.pinpoint.plugin.arcus;
import org.junit.Ignore;
import org.junit.Test;
//@RunWith(ForkRunner.class)
//@PinpointConfig("pinpoint-test.config")
//@PinpointAgent("build/pinpoint-agent")
//@OnChildClassLoader
public class ArcusPluginTest {
// TODO how to test intercpetor?
@Test
@Ignore // until arcus modifier/interceptors are removed from pinpoint-profiler
public void test() throws Exception {
//
// Class<?> arcusClient = Class.forName("net.spy.memcached.ArcusClient");
//
// Class<?> cacheManager = Class.forName("net.spy.memcached.CacheManager");
// assertTrue(ObjectAccessor.class.isAssignableFrom(cacheManager));
//
// Class<?> collectionFuture = Class.forName("net.spy.memcached.internal.CollectionFuture");
// assertTrue(ObjectAccessor.class.isAssignableFrom(collectionFuture));
//
// Class<?> baseOperationImpl = Class.forName("net.spy.memcached.protocol.BaseOperationImpl");
// assertTrue(ObjectAccessor.class.isAssignableFrom(baseOperationImpl));
//
//
// Class<?> getFuture = Class.forName("net.spy.memcached.internal.GetFuture");
// assertTrue(ObjectAccessor.class.isAssignableFrom(getFuture));
//
// Class<?> immediateFuture = Class.forName("net.spy.memcached.internal.ImmediateFuture");
//// assertTrue(OperationAccessor.class.isAssignableFrom(immediateFuture));
//
// Class<?> operationFuture = Class.forName("net.spy.memcached.internal.OperationFuture");
// assertTrue(ObjectAccessor.class.isAssignableFrom(operationFuture));
//
// Class<?> frontCacheGetFuture = Class.forName("net.spy.memcached.plugin.FrontCacheGetFuture");
// assertTrue(ObjectAccessor.class.isAssignableFrom(frontCacheGetFuture));
// assertTrue(ObjectAccessor2.class.isAssignableFrom(frontCacheGetFuture));
//
// Class<?> frontCacheMemcachedClient = Class.forName("net.spy.memcached.plugin.FrontCacheMemcachedClient");
//
// Class<?> memcachedClient = Class.forName("net.spy.memcached.MemcachedClient");
// assertTrue(ObjectAccessor.class.isAssignableFrom(memcachedClient));
}
}
@@ -0,0 +1,50 @@
package com.navercorp.pinpoint.plugin.arcus;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
/**
* @author harebox
*/
public class FrontCacheGetFutureModifierIntegrationTest /*extends BasePinpointTest*/ {
@Before
public void setUp() throws Exception {
// MockitoAnnotations.initMocks(this);
}
@Test
@Ignore
// FIXME 테스트 깨짐
public void frontCacheShouldBeTraced() throws Exception {
// // given: front-cache-enabled ArcusClient
// ConnectionFactoryBuilder cfb = new ConnectionFactoryBuilder();
// cfb.setMaxFrontCacheElements(100);
// cfb.setFrontCacheExpireTime(100);
// ArcusClient client = ArcusClient.createArcusClient("ncloud.arcuscloud.nhncorp.com:17288", "ff31ddb85e9b431c8c0e5e50a4315c27", cfb);
//
// // when
// try {
// client.set("hello", 0, "world");
// client.asyncGet("hello").get();
// client.asyncGet("hello").get();
// } catch (Exception e) {
// e.printStackTrace();
// fail();
// } finally {
// client.shutdown();
// }
//
// // then
// final List<SpanEventBo> spanEvents = getCurrentSpanEvents();
// assertThat(spanEvents.size(), is(5));
//
// final SpanEventBo getFutureSpan = spanEvents.get(2);
// final SpanEventBo frontCacheGetFutureSpan = spanEvents.get(4);
//
// assertNotNull(getFutureSpan.getEndPoint());
// assertNull(frontCacheGetFutureSpan.getEndPoint());
// assertThat(frontCacheGetFutureSpan.getDestinationId(), is("front"));
}
}
@@ -0,0 +1,28 @@
package com.navercorp.pinpoint.plugin.arcus.interceptor;
import org.junit.Test;
public class ApiInterceptorTest {
@Test
public void testAround() {
// String[] parameterTypes = new String[] { "java.lang.String", "int", "java.lang.Object" };
// String[] parameterNames = new String[] { "key", "exptime", "value" };
// Object[] args = new Object[] { "key", 10, "my_value" };
//
// TraceContext traceContext = mock(TraceContext.class);
// MethodDescriptor methodDescriptor = new DefaultMethodDescriptor(Object.class.getName(), "set", parameterTypes, parameterNames);
// MethodInfo methodInfo = mock(MethodInfo.class);
// ObjectAccessor target = mock(ObjectAccessor.class);
//
// when(methodInfo.getDescriptor()).thenReturn(methodDescriptor);
// when(methodInfo.getParameterTypes()).thenReturn(parameterTypes);
// when(target._$PINPOINT$_getObject()).thenReturn("serviceCode");
//
// ApiInterceptor interceptor = new ApiInterceptor(traceContext, methodInfo, true);
//
//
// interceptor.before(target, args);
// interceptor.after(target, args, null, null);
}
}
@@ -0,0 +1,43 @@
package com.navercorp.pinpoint.plugin.arcus.interceptor;
import org.junit.Assert;
import net.spy.memcached.ops.OperationState;
import org.junit.Test;
public class BaseOperationTransitionStateInterceptorTest {
@Test
public void testComplete() throws Exception {
// 타입비교를 Arcus의 경우 TIMEDOUT state가 별도로 추가되어 정적 타입비교를 할수 있는 상황이 아님.
// toString()을 호출하여, 문자열 비교를 해야 함.
String complete = OperationState.COMPLETE.toString();
Assert.assertEquals("COMPLETE", complete);
}
@Test
public void existArcusTimeoutState() throws Exception {
// 클래스가 강제 로딩되서 다른 test에 영향을 줄수 있음.
if (!isArcusExist()) {
// arcus만의 state체크를 위한 것이므로 없으면 패스한다.
return;
}
// Arcus OperationState.timedout에 변경이 있는지 체크한다.
OperationState[] values = OperationState.values();
for (OperationState value : values) {
if (value.toString().equals("TIMEDOUT")) {
return;
}
}
Assert.fail("OperationState.TIMEDOUT state not found");
}
private boolean isArcusExist() {
try {
Class.forName("net.spy.memcached.ArcusClient");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
@@ -0,0 +1,138 @@
package com.navercorp.pinpoint.plugin.arcus.interceptor;
public class FutureGetInterceptorTest /*extends BaseInterceptorTest*/ {
// private final Logger logger = LoggerFactory.getLogger(FutureGetInterceptorTest.class);
//
// FutureGetInterceptor interceptor = new FutureGetInterceptor(null, new MockTraceContextFactory().create());
//
// @Before
// public void beforeEach() {
// setInterceptor(interceptor);
// super.beforeEach();
// }
//
// @Test
// public void testSuccessful() throws IOException {
// Long timeout = 1000L;
// TimeUnit unit = TimeUnit.MILLISECONDS;
//
// MockOperationFuture future = mock(MockOperationFuture.class);
// MockOperation operation = mock(MockOperation.class);
//
// when(operation.getException()).thenReturn(null);
// when(operation.isCancelled()).thenReturn(false);
// when(future.__getOperation()).thenReturn(operation);
//
// MemcachedNode node = getMockMemcachedNode();
// when(operation.getHandlingNode()).thenReturn(node);
//
// interceptor.before(future, new Object[] { timeout, unit });
// interceptor.after(future, new Object[] { timeout, unit }, null, null);
// }
//
// private MemcachedNode getMockMemcachedNode() throws IOException {
// java.nio.channels.SocketChannel socketChannel = java.nio.channels.SocketChannel.open();
// BlockingQueue<Operation> readQueue = new LinkedBlockingQueue<Operation>();
// BlockingQueue<Operation> writeQueue = new LinkedBlockingQueue<Operation> ();
// BlockingQueue<Operation> inputQueue = new LinkedBlockingQueue<Operation> ();
//
// return new AsciiMemcachedNodeImpl(new InetSocketAddress(11211), socketChannel, 128, readQueue, writeQueue, inputQueue, 1000L);
// }
//
// @Test
// public void testTimeoutException() {
// Long timeout = 1000L;
// TimeUnit unit = TimeUnit.MILLISECONDS;
//
// MockOperationFuture future = mock(MockOperationFuture.class);
// MockOperation operation = mock(MockOperation.class);
//
// try {
// OperationException exception = new OperationException(OperationErrorType.GENERAL, "timed out");
// when(operation.getException()).thenReturn(exception);
// when(operation.isCancelled()).thenReturn(true);
// when(future.__getOperation()).thenReturn(operation);
//
// MemcachedNode node = getMockMemcachedNode();
// when(operation.getHandlingNode()).thenReturn(node);
//
// interceptor.before(future, new Object[] { timeout, unit });
// interceptor.after(future, new Object[] { timeout, unit }, null, null);
// } catch (Exception e) {
// fail(e.getMessage());
// }
// }
//
// class MockOperationFuture extends OperationFuture {
// public MockOperationFuture(CountDownLatch l, AtomicReference oref,
// long opTimeout) {
// super(l, oref, opTimeout);
// }
//
// public String __getServiceCode() {
// return "MEMCACHED";
// }
//
// public Operation __getOperation() {
// return null;
// }
// }
//
// class MockOperation implements Operation {
//
// public String __getServiceCode() {
// return "MEMCACHED";
// }
//
// public void cancel() {
// }
//
// public ByteBuffer getBuffer() {
// return null;
// }
//
// public OperationCallback getCallback() {
// return null;
// }
//
// public OperationException getException() {
// return null;
// }
//
// public MemcachedNode getHandlingNode() {
// return null;
// }
//
// public OperationState getState() {
// return null;
// }
//
// public void handleRead(ByteBuffer arg0) {
//
// }
//
// public boolean hasErrored() {
// return false;
// }
//
// public void initialize() {
// }
//
// public boolean isCancelled() {
// return false;
// }
//
// public void readFromBuffer(ByteBuffer arg0) throws IOException {
// }
//
// public void setHandlingNode(MemcachedNode arg0) {
// }
//
// public void writeComplete() {
// }
//
// }
}
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.EnhancedPatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%-5p](%-35c{1.}:%-3L) %m%n" />
<!-- %L(line number) option is extremely slow. -->
<!--<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%-5p](%-30c{1}) %m%n" />-->
</layout>
</appender>
<appender name="dailyRollingFile" class="org.apache.log4j.DailyRollingFileAppender">
<param name="file" value="${pinpoint.log}/${pinpoint.agentId}-pinpoint.log" />
<param name="Append" value="true" />
<param name="DatePattern" value="'.'yyyy-MM-dd"/>
<layout class="org.apache.log4j.EnhancedPatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%-5p](%-35c{1.}:%-3L) %m%n" />
<!-- %L(line number) option is extremely slow. -->
<!--<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%-5p](%-30c{1}) %m%n" />-->
</layout>
</appender>
<logger name="com.navercorp.pinpoint" additivity="false">
<level value="DEBUG" />
<!-- for development mode -->
<appender-ref ref="console" />
<!-- for release mode -->
<appender-ref ref="dailyRollingFile" />
</logger>
<root>
<level value="DEBUG" />
<!-- for development mode -->
<appender-ref ref="console" />
<!-- for release mode -->
<appender-ref ref="dailyRollingFile" />
</root>
</log4j:configuration>
@@ -0,0 +1,190 @@
#
# Pinpoint agent configuration
# (Phase : local)
#
###########################################################
# Collector server #
###########################################################
# 로컬
profiler.collector.ip=127.0.0.1
# 개발
#profiler.collector.ip=10.64.84.188
# 운영
#profiler.collector.ip=10.25.149.249
profiler.collector.udpspan.port=9996
profiler.collector.udp.port=9995
profiler.collector.tcp.port=9994
###########################################################
# Profiler Global Configuration #
###########################################################
profiler.enable=true
profiler.jvm.collect.interval=1000
profiler.sampling.enable=true
# 아래 지정한 값중 한 개의 트랜잭션을 수집합니다. (예를들어 1로 지정하면 100%수집, 2로 지정하면 50%수집 셈)
profiler.sampling.rate=1
# span을 Io에 flush할 경우 buffering 여부
profiler.io.buffering.enable=true
# buffering 시 몇개 까지 저장할지 여부
profiler.io.buffering.buffersize=20
profiler.spandatasender.write.queue.size=5120
#profiler.spandatasender.socket.sendbuffersize=1048576
#profiler.spandatasender.socket.timeout=3000
profiler.statdatasender.write.queue.size=5120
#profiler.statdatasender.socket.sendbuffersize=1048576
#profiler.statdatasender.socket.timeout=3000
profiler.heartbeat.interval=300000
# Tcp Data Command 허용 여부
profiler.tcpdatasender.command.accept.enable=true
###########################################################
# application type #
###########################################################
#profiler.applicationservertype=TOMCAT
#profiler.applicationservertype=BLOC
###########################################################
# application type detect order #
###########################################################
profiler.type.detect.order=
###########################################################
# user defined classes #
###########################################################
profiler.include=com.navercorp.pinpoint.testweb.controller.*,com.navercorp.pinpoint.testweb.MyClass
###########################################################
# JDBC #
###########################################################
profiler.jdbc=true
profiler.jdbc.sqlcachesize=1024
profiler.jdbc.maxsqlbindvaluesize=1024
#
# MYSQL
#
profiler.jdbc.mysql=true
profiler.jdbc.mysql.setautocommit=true
profiler.jdbc.mysql.commit=true
profiler.jdbc.mysql.rollback=true
#
# MSSQL
#
profiler.jdbc.mssql=false
#
# Oracle
#
profiler.jdbc.oracle=true
profiler.jdbc.oracle.setautocommit=true
profiler.jdbc.oracle.commit=true
profiler.jdbc.oracle.rollback=true
#
# CUBRID
#
profiler.jdbc.cubrid=true
profiler.jdbc.cubrid.setautocommit=true
profiler.jdbc.cubrid.commit=true
profiler.jdbc.cubrid.rollback=true
#
# DBCP
#
profiler.jdbc.dbcp=true
profiler.jdbc.dbcp.connectionclose=true
###########################################################
# Apache HTTP Client 4.x #
###########################################################
profiler.apache.httpclient4=true
profiler.apache.httpclient4.cookie=true
# cookie를 언제 덤프할지 결정. ALWAYS or EXCEPTION 2가지
profiler.apache.httpclient4.cookie.dumptype=ALWAYS
profiler.apache.httpclient4.cookie.sampling.rate=1
# post, put의 entity를 덤프한다. 단 HttpEtity.isRepeatable()=true 인 Entity에 한정된다.
profiler.apache.httpclient4.entity=true
# entity를 언제 덤프할지 결정. ALWAYS or EXCEPTION 2가지
profiler.apache.httpclient4.entity.dumptype=ALWAYS
profiler.apache.httpclient4.entity.sampling.rate=1
profiler.apache.nio.httpclient4=true
###########################################################
# Ning Async HTTP Client #
###########################################################
profiler.ning.asynchttpclient=true
profiler.ning.asynchttpclient.cookie=true
profiler.ning.asynchttpclient.cookie.dumptype=ALWAYS
profiler.ning.asynchttpclient.cookie.dumpsize=1024
profiler.ning.asynchttpclient.cookie.sampling.rate=1
profiler.ning.asynchttpclient.entity=true
profiler.ning.asynchttpclient.entity.dumptype=ALWAYS
profiler.ning.asynchttpclient.entity.dumpsize=1024
profiler.ning.asynchttpclient.entity.sampling.rate=1
profiler.ning.asynchttpclient.param=true
profiler.ning.asynchttpclient.param.dumptype=ALWAYS
profiler.ning.asynchttpclient.param.dumpsize=1024
profiler.ning.asynchttpclient.param.sampling.rate=1
###########################################################
# LINE+ baseframework #
###########################################################
profiler.line.game.netty.param.dumpsize=512
profiler.line.game.netty.entity.dumpsize=512
###########################################################
# Arcus #
###########################################################
profiler.arcus=true
profiler.arcus.keytrace=true
###########################################################
# Memcached #
###########################################################
profiler.memcached=true
profiler.memcached.keytrace=true
###########################################################
# ibatis #
###########################################################
profiler.orm.ibatis=true
###########################################################
# mybatis #
###########################################################
profiler.orm.mybatis=true
###########################################################
# spring-beans
###########################################################
profiler.spring.beans=true
profiler.spring.beans.name.pattern=ma.*, outer
profiler.spring.beans.class.pattern=.*Morae
profiler.spring.beans.annotation=org.springframework.stereotype.Component
+6
View File
@@ -24,6 +24,7 @@
<module>tomcat</module>
<module>thrift</module>
<module>user</module>
<module>arcus</module>
</modules>
<dependencies>
@@ -87,6 +88,11 @@
<artifactId>pinpoint-user-plugin</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.navercorp.pinpoint</groupId>
<artifactId>pinpoint-arcus-plugin</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>