diff --git a/scouter.agent.host/src/scouter/agent/counter/task/HostPerf.java b/scouter.agent.host/src/scouter/agent/counter/task/HostPerf.java index a6c534106..eb784491a 100644 --- a/scouter.agent.host/src/scouter/agent/counter/task/HostPerf.java +++ b/scouter.agent.host/src/scouter/agent/counter/task/HostPerf.java @@ -278,7 +278,11 @@ public void disk(CounterBasket pw) { if (conf.disk_ignore_names.hasKey(dir)) continue; - usage = sigar.getFileSystemUsage(dir); + try { + usage = sigar.getFileSystemUsage(dir); + } catch (SigarException e) { + continue; + } float pct = (float) (usage.getUsePercent() * 100); if (pct >= conf.disk_fatal_pct && fatal.length() < 32756) { diff --git a/scouter.agent.java/src/scouter/agent/AgentTransformer.java b/scouter.agent.java/src/scouter/agent/AgentTransformer.java index 21160a0ad..77e7d7eff 100644 --- a/scouter.agent.java/src/scouter/agent/AgentTransformer.java +++ b/scouter.agent.java/src/scouter/agent/AgentTransformer.java @@ -88,15 +88,14 @@ public static void reload() { temp.add(new CallRunnableASM()); temp.add(new SpringReqMapASM()); - temp.add(new SocketASM()); - temp.add(new JspServletASM()); + temp.add(new MapImplASM()); + temp.add(new UserExceptionASM()); + temp.add(new UserExceptionHandlerASM()); temp.add(new AddFieldASM()); - temp.add(new MapImplASM()); - asms = temp; } diff --git a/scouter.agent.java/src/scouter/agent/Configure.java b/scouter.agent.java/src/scouter/agent/Configure.java index 8139935aa..52905eaf4 100644 --- a/scouter.agent.java/src/scouter/agent/Configure.java +++ b/scouter.agent.java/src/scouter/agent/Configure.java @@ -109,6 +109,8 @@ public final static synchronized Configure getInstance() { public boolean profile_http_parameter_enabled; @ConfigDesc("Service URL prefix for Http parameter profile") public String profile_http_parameter_url_prefix = "/"; + @ConfigDesc("spring controller method parameter profile") + public boolean profile_spring_controller_method_parameter_enabled = false; @ConfigDesc("Activating profile summary function") public boolean profile_summary_mode_enabled = false; @ConfigDesc("Calculating CPU time by profile") @@ -137,6 +139,8 @@ public final static synchronized Configure getInstance() { public boolean profile_fullstack_sql_error_enabled = false; @ConfigDesc("Stack profile in occurrence of commit error") public boolean profile_fullstack_sql_commit_enabled = false; + @ConfigDesc("Stack profile in occurrence of sql error") + public boolean profile_fullstack_hooked_exception_enabled = false; @ConfigDesc("Number of stack profile lines in occurrence of error") public int profile_fullstack_max_lines = 0; @ConfigDesc("Activating SQL literal task") @@ -352,6 +356,12 @@ public final static synchronized Configure getInstance() { public String hook_jdbc_rs_classes = ""; @ConfigDesc("Method set for dbconnection wrapping") public String hook_jdbc_wrapping_driver_patterns = ""; + @ConfigDesc("Exception class patterns - These will seem as error on xlog view. (ex) my.app.BizException,my.app.exception.*Exception") + public String hook_exception_class_patterns = ""; + @ConfigDesc("Exception class exlude patterns") + public String hook_exception_exlude_class_patterns = ""; + @ConfigDesc("Exception handler patterns - exceptions passed to these methods are treated as error on xlog view. (ex) my.app.myHandler.handleException") + public String hook_exception_handler_method_patterns = ""; @ConfigDesc("Hook for supporting async servlet") public boolean hook_async_servlet_enabled = true; @@ -556,6 +566,7 @@ private void apply() { this.profile_http_querystring_enabled = getBoolean("profile_http_querystring_enabled", false); this.profile_http_header_enabled = getBoolean("profile_http_header_enabled", false); this.profile_http_parameter_enabled = getBoolean("profile_http_parameter_enabled", false); + this.profile_spring_controller_method_parameter_enabled = getBoolean("profile_spring_controller_method_parameter_enabled", false); this.profile_summary_mode_enabled = getBoolean("profile_summary_mode_enabled", false); this.xlog_lower_bound_time_ms = getInt("xlog_lower_bound_time_ms", 0); this.trace_service_name_header_key = getValue("trace_service_name_header_key", null); @@ -651,6 +662,10 @@ private void apply() { this.hook_jdbc_stmt_classes = getValue("hook_jdbc_stmt_classes", ""); this.hook_jdbc_rs_classes = getValue("hook_jdbc_rs_classes", ""); this.hook_jdbc_wrapping_driver_patterns = getValue("hook_jdbc_wrapping_driver_patterns", ""); + this.hook_exception_class_patterns = getValue("hook_exception_class_patterns", ""); + this.hook_exception_exlude_class_patterns = getValue("hook_exception_exlude_class_patterns", ""); + this.hook_exception_handler_method_patterns = getValue("hook_exception_handler_method_patterns", ""); + this.hook_async_servlet_enabled = getBoolean("_hook_async_servlet_enabled", true); this.hook_async_context_dispatch_patterns = getValue("hook_async_context_dispatch_patterns", ""); @@ -691,6 +706,8 @@ private void apply() { this.profile_fullstack_apicall_error_enabled = getBoolean("profile_fullstack_apicall_error_enabled", false); this.profile_fullstack_sql_error_enabled = getBoolean("profile_fullstack_sql_error_enabled", false); this.profile_fullstack_sql_commit_enabled = getBoolean("profile_fullstack_sql_commit_enabled", false); + this.profile_fullstack_hooked_exception_enabled = getBoolean("profile_fullstack_hooked_exception_enabled", false); + this.profile_fullstack_max_lines = getInt("profile_fullstack_max_lines", 0); this.profile_fullstack_rs_leak_enabled = getBoolean("profile_fullstack_rs_leak_enabled", false); this.profile_fullstack_stmt_leak_enabled = getBoolean("profile_fullstack_stmt_leak_enabled", false); diff --git a/scouter.agent.java/src/scouter/agent/asm/JDBCPreparedStatementASM.java b/scouter.agent.java/src/scouter/agent/asm/JDBCPreparedStatementASM.java index a5445f27d..7db9c1005 100644 --- a/scouter.agent.java/src/scouter/agent/asm/JDBCPreparedStatementASM.java +++ b/scouter.agent.java/src/scouter/agent/asm/JDBCPreparedStatementASM.java @@ -39,6 +39,9 @@ public class JDBCPreparedStatementASM implements IASM, Opcodes { public final HashSet noField = new HashSet(); public JDBCPreparedStatementASM() { + //mariadb 1.5.9 + target.add("org/mariadb/jdbc/AbstractPrepareStatement"); + target.add("org/mariadb/jdbc/AbstractMariaDbPrepareStatement"); target.add("org/mariadb/jdbc/MariaDbClientPreparedStatement"); target.add("org/mariadb/jdbc/MariaDbServerPreparedStatement"); diff --git a/scouter.agent.java/src/scouter/agent/asm/SpringReqMapASM.java b/scouter.agent.java/src/scouter/agent/asm/SpringReqMapASM.java index 9df302bfe..5bb2f8ab3 100644 --- a/scouter.agent.java/src/scouter/agent/asm/SpringReqMapASM.java +++ b/scouter.agent.java/src/scouter/agent/asm/SpringReqMapASM.java @@ -25,6 +25,7 @@ import scouter.org.objectweb.asm.ClassVisitor; import scouter.org.objectweb.asm.MethodVisitor; import scouter.org.objectweb.asm.Opcodes; +import scouter.org.objectweb.asm.Type; import scouter.org.objectweb.asm.commons.LocalVariablesSorter; import scouter.util.StringUtil; @@ -132,12 +133,25 @@ class SpringReqMapMV extends LocalVariablesSorter implements Opcodes { private static final String TRACEMAIN = "scouter/agent/trace/TraceMain"; private final static String SET_METHOD = "setServiceName"; private static final String SET_METHOD_SIGNATURE = "(Ljava/lang/String;)V"; + + private final static String CONTROLLER_START_METHOD = "startSpringControllerMethod"; + private static final String CONTROLLER_START_METHOD_SIGNATURE = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;)V"; + private String methodRequestMappingUrl; private String methodType; private boolean isRequestHandler = false; + private String className; + private int access; + private String methodName; + private String desc; + public SpringReqMapMV(String className, int access, String methodName, String desc, MethodVisitor mv) { super(ASM4, access, desc, mv); + this.className = className; + this.access = access; + this.methodName = methodName; + this.desc = desc; } @Override @@ -166,6 +180,77 @@ public void visitCode() { Logger.println("[Apply Spring F/W REST URL] " + serviceUrl); AsmUtil.PUSH(mv, serviceUrl); mv.visitMethodInsn(Opcodes.INVOKESTATIC, TRACEMAIN, SET_METHOD, SET_METHOD_SIGNATURE, false); + + //=========== call for spring request mapping method capture plugin ============ + Type[] types = Type.getArgumentTypes(desc); + boolean isStatic = (access & ACC_STATIC) != 0; + + int sidx = isStatic ? 0 : 1; + + int arrVarIdx = newLocal(Type.getType("[Ljava/lang/Object;")); + AsmUtil.PUSH(mv, types.length); + mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); + mv.visitVarInsn(Opcodes.ASTORE, arrVarIdx); + + for (int i = 0; i < types.length; i++) { + Type type = types[i]; + mv.visitVarInsn(Opcodes.ALOAD, arrVarIdx); + AsmUtil.PUSH(mv, i); + + switch (type.getSort()) { + case Type.BOOLEAN: + mv.visitVarInsn(Opcodes.ILOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", + false); + break; + case Type.BYTE: + mv.visitVarInsn(Opcodes.ILOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); + break; + case Type.CHAR: + mv.visitVarInsn(Opcodes.ILOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", + false); + break; + case Type.SHORT: + mv.visitVarInsn(Opcodes.ILOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); + break; + case Type.INT: + mv.visitVarInsn(Opcodes.ILOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", + false); + break; + case Type.LONG: + mv.visitVarInsn(Opcodes.LLOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); + break; + case Type.FLOAT: + mv.visitVarInsn(Opcodes.FLOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); + break; + case Type.DOUBLE: + mv.visitVarInsn(Opcodes.DLOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); + break; + default: + mv.visitVarInsn(Opcodes.ALOAD, sidx); + } + mv.visitInsn(Opcodes.AASTORE); + sidx += type.getSize(); + } + AsmUtil.PUSH(mv, className); + AsmUtil.PUSH(mv, methodName); + AsmUtil.PUSH(mv, desc); + if (isStatic) { + AsmUtil.PUSHNULL(mv); + } else { + mv.visitVarInsn(Opcodes.ALOAD, 0); + } + mv.visitVarInsn(Opcodes.ALOAD, arrVarIdx); + + mv.visitMethodInsn(Opcodes.INVOKESTATIC, TRACEMAIN, CONTROLLER_START_METHOD, CONTROLLER_START_METHOD_SIGNATURE, false); + } mv.visitCode(); } diff --git a/scouter.agent.java/src/scouter/agent/asm/UserExceptionASM.java b/scouter.agent.java/src/scouter/agent/asm/UserExceptionASM.java new file mode 100644 index 000000000..8a298a4f8 --- /dev/null +++ b/scouter.agent.java/src/scouter/agent/asm/UserExceptionASM.java @@ -0,0 +1,102 @@ +/* + * Copyright 2015 the original author or authors. + * @https://github.com/scouter-project/scouter + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package scouter.agent.asm; + +import scouter.agent.ClassDesc; +import scouter.agent.Configure; +import scouter.agent.asm.util.AsmUtil; +import scouter.agent.asm.util.HookingSet; +import scouter.agent.trace.TraceMain; +import scouter.org.objectweb.asm.ClassVisitor; +import scouter.org.objectweb.asm.MethodVisitor; +import scouter.org.objectweb.asm.Opcodes; + +import java.util.List; + +public class UserExceptionASM implements IASM, Opcodes { + String exceptionPatterns = HookingSet.classPattrensToMethodPatterns(Configure.getInstance().hook_exception_class_patterns, ""); + String exceptionExcludePatterns = HookingSet.classPattrensToMethodPatterns(Configure.getInstance().hook_exception_exlude_class_patterns, ""); + + private List target = HookingSet.getHookingMethodSet(exceptionPatterns); + private List excludeTarget = HookingSet.getHookingMethodSet(exceptionExcludePatterns); + + public ClassVisitor transform(ClassVisitor cv, String className, ClassDesc classDesc) { + for (int i = 0; i < target.size(); i++) { + HookingSet mset = target.get(i); + if (mset.classMatch.include(className)) { + for (int j = 0; j < excludeTarget.size(); j++) { + HookingSet excludeHookinSet = excludeTarget.get(j); + if (excludeHookinSet.classMatch.include(className)) { + return cv; + } + } + return new UserExceptionCV(cv, mset, className); + } + } + return cv; + } +} + +class UserExceptionCV extends ClassVisitor implements Opcodes { + + private HookingSet mset; + private String className; + + public UserExceptionCV(ClassVisitor cv, HookingSet mset, String className) { + super(ASM4, cv); + this.mset = mset; + this.className = className; + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); + if (mv == null || mset.isA(name, desc) == false) { + return mv; + } + return new UserExceptionConsturtorMV(className, desc, mv); + } +} + +// /////////////////////////////////////////////////////////////////////////// +class UserExceptionConsturtorMV extends MethodVisitor implements Opcodes { + private static final String CLASS = TraceMain.class.getName().replace('.', '/'); + private static final String METHOD = "endExceptionConstructor"; + private static final String SIGNATURE = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;)V"; + + private String className; + private String methodDesc; + + public UserExceptionConsturtorMV(String classname, String methoddesc, MethodVisitor mv) { + super(ASM4, mv); + this.className = classname; + this.methodDesc = methoddesc; + } + + @Override + public void visitInsn(int opcode) { + if ((opcode >= IRETURN && opcode <= RETURN) || opcode == ATHROW) { + AsmUtil.PUSH(mv, className); + AsmUtil.PUSH(mv, methodDesc); + mv.visitVarInsn(Opcodes.ALOAD, 0); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, CLASS, METHOD, SIGNATURE,false); + } + mv.visitInsn(opcode); + } +} + diff --git a/scouter.agent.java/src/scouter/agent/asm/UserExceptionHandlerASM.java b/scouter.agent.java/src/scouter/agent/asm/UserExceptionHandlerASM.java new file mode 100644 index 000000000..9bbb5cff0 --- /dev/null +++ b/scouter.agent.java/src/scouter/agent/asm/UserExceptionHandlerASM.java @@ -0,0 +1,166 @@ +/* + * Copyright 2015 the original author or authors. + * @https://github.com/scouter-project/scouter + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package scouter.agent.asm; + +import scouter.agent.ClassDesc; +import scouter.agent.Configure; +import scouter.agent.asm.util.AsmUtil; +import scouter.agent.asm.util.HookingSet; +import scouter.agent.trace.TraceMain; +import scouter.org.objectweb.asm.ClassVisitor; +import scouter.org.objectweb.asm.MethodVisitor; +import scouter.org.objectweb.asm.Opcodes; +import scouter.org.objectweb.asm.Type; +import scouter.org.objectweb.asm.commons.LocalVariablesSorter; + +import java.util.List; + +public class UserExceptionHandlerASM implements IASM, Opcodes { + private List target = HookingSet.getHookingMethodSet(Configure.getInstance().hook_exception_handler_method_patterns); + + public ClassVisitor transform(ClassVisitor cv, String className, ClassDesc classDesc) { + for (int i = 0; i < target.size(); i++) { + HookingSet mset = target.get(i); + if (mset.classMatch.include(className)) { + return new UserExceptionHandlerCV(cv, mset, className); + } + } + return cv; + } +} + +class UserExceptionHandlerCV extends ClassVisitor implements Opcodes { + + public String className; + private HookingSet mset; + + public UserExceptionHandlerCV(ClassVisitor cv, HookingSet mset, String className) { + super(ASM4, cv); + this.mset = mset; + this.className = className; + } + + @Override + public MethodVisitor visitMethod(int access, String methodName, String desc, String signature, + String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, methodName, desc, signature, exceptions); + if (mv == null || mset.isA(methodName, desc) == false) { + return mv; + } + if (AsmUtil.isSpecial(methodName)) { + return mv; + } + return new UserExceptionHandlerMV(access, desc, mv, Type.getArgumentTypes(desc), (access & ACC_STATIC) != 0, className, + methodName, desc); + } +} + +// /////////////////////////////////////////////////////////////////////////// +class UserExceptionHandlerMV extends LocalVariablesSorter implements Opcodes { + private static final String CLASS = TraceMain.class.getName().replace('.', '/'); + private static final String METHOD = "startExceptionHandler"; + private static final String SIGNATURE = "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Object;[Ljava/lang/Object;)V"; + + private Type[] paramTypes; + private boolean isStatic; + private String className; + private String methodName; + private String methodDesc; + + public UserExceptionHandlerMV(int access, String desc, MethodVisitor mv, Type[] paramTypes, boolean isStatic, String classname, + String methodname, String methoddesc) { + super(ASM4, access, desc, mv); + this.paramTypes = paramTypes; + this.isStatic = isStatic; + this.className = classname; + this.methodName = methodname; + this.methodDesc = methoddesc; + + } + + @Override + public void visitCode() { + + int sidx = isStatic ? 0 : 1; + + int arrVarIdx = newLocal(Type.getType("[Ljava/lang/Object;")); + AsmUtil.PUSH(mv, paramTypes.length); + mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); + mv.visitVarInsn(Opcodes.ASTORE, arrVarIdx); + + for (int i = 0; i < paramTypes.length; i++) { + Type type = paramTypes[i]; + mv.visitVarInsn(Opcodes.ALOAD, arrVarIdx); + AsmUtil.PUSH(mv, i); + + switch (type.getSort()) { + case Type.BOOLEAN: + mv.visitVarInsn(Opcodes.ILOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", + false); + break; + case Type.BYTE: + mv.visitVarInsn(Opcodes.ILOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;", false); + break; + case Type.CHAR: + mv.visitVarInsn(Opcodes.ILOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", + false); + break; + case Type.SHORT: + mv.visitVarInsn(Opcodes.ILOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;", false); + break; + case Type.INT: + mv.visitVarInsn(Opcodes.ILOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", + false); + break; + case Type.LONG: + mv.visitVarInsn(Opcodes.LLOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;", false); + break; + case Type.FLOAT: + mv.visitVarInsn(Opcodes.FLOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false); + break; + case Type.DOUBLE: + mv.visitVarInsn(Opcodes.DLOAD, sidx); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); + break; + default: + mv.visitVarInsn(Opcodes.ALOAD, sidx); + } + mv.visitInsn(Opcodes.AASTORE); + sidx += type.getSize(); + } + AsmUtil.PUSH(mv, className); + AsmUtil.PUSH(mv, methodName); + AsmUtil.PUSH(mv, methodDesc); + if (isStatic) { + AsmUtil.PUSHNULL(mv); + } else { + mv.visitVarInsn(Opcodes.ALOAD, 0); + } + mv.visitVarInsn(Opcodes.ALOAD, arrVarIdx); + + mv.visitMethodInsn(Opcodes.INVOKESTATIC, CLASS, METHOD, SIGNATURE, false); + mv.visitCode(); + } +} diff --git a/scouter.agent.java/src/scouter/agent/asm/util/HookingSet.java b/scouter.agent.java/src/scouter/agent/asm/util/HookingSet.java index 1fd55e285..654b8f6a3 100644 --- a/scouter.agent.java/src/scouter/agent/asm/util/HookingSet.java +++ b/scouter.agent.java/src/scouter/agent/asm/util/HookingSet.java @@ -209,4 +209,16 @@ public static String buildPatterns(String patterns, List patternsList) { } return patterns; } + + public static String classPattrensToMethodPatterns(String classPatterns, String method) { + String[] classes = StringUtil.split(classPatterns, ','); + + List classMethodPatterns = new ArrayList(); + for (int i = 0; i < classes.length; i++) { + String s = classes[i]; + classMethodPatterns.add(s + "." + method); + } + + return buildPatterns("", classMethodPatterns); + } } diff --git a/scouter.agent.java/src/scouter/agent/counter/task/TomcatJMXPerf.java b/scouter.agent.java/src/scouter/agent/counter/task/TomcatJMXPerf.java index d5fdf99e3..6ca1a44eb 100644 --- a/scouter.agent.java/src/scouter/agent/counter/task/TomcatJMXPerf.java +++ b/scouter.agent.java/src/scouter/agent/counter/task/TomcatJMXPerf.java @@ -15,16 +15,6 @@ * limitations under the License. */ package scouter.agent.counter.task; -import java.lang.management.ManagementFactory; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.management.MBeanServer; -import javax.management.ObjectName; - import scouter.agent.Configure; import scouter.agent.Logger; import scouter.agent.ObjTypeDetector; @@ -40,6 +30,11 @@ import scouter.util.CastUtil; import scouter.util.HashUtil; import scouter.util.StringUtil; + +import javax.management.MBeanServer; +import javax.management.ObjectName; +import java.lang.management.ManagementFactory; +import java.util.*; public class TomcatJMXPerf { HashMap meters = new HashMap(); HashMap lastValues = new HashMap(); @@ -146,6 +141,7 @@ private void getMBeanList() { Set mbeans = server.queryNames(null, null); for (final ObjectName mbean : mbeans) { String type = mbean.getKeyProperty("type"); + String connectionpool = mbean.getKeyProperty("connectionpool"); if (type == null) { continue; } @@ -167,7 +163,7 @@ private void getMBeanList() { CounterConstants.REQUESTPROCESS_REQUEST_COUNT); } catch (Exception e) { } - } else if ("DataSource".equals(type)) { // datasource + } else if ("DataSource".equals(type) && connectionpool == null) { // datasource String name = mbean.getKeyProperty("name"); if (StringUtil.isNotEmpty(name)) { try { @@ -187,6 +183,10 @@ private void getMBeanList() { CounterConstants.DATASOURCE_CONN_IDLE); add(objName, mbean, objType, ValueEnum.DECIMAL, "maxActive", CounterConstants.DATASOURCE_CONN_MAX); + // for tomcat 5.5 + + // attribute name is changed from maxActive to maxTotal. (reported from zeroty : https://github.com/zeroty) + add(objName, mbean, objType, ValueEnum.DECIMAL, "maxTotal", + CounterConstants.DATASOURCE_CONN_MAX); } catch (Exception e) { } } diff --git a/scouter.agent.java/src/scouter/agent/plugin/PluginLoader.java b/scouter.agent.java/src/scouter/agent/plugin/PluginLoader.java index 19903eb8e..4dd2521a0 100644 --- a/scouter.agent.java/src/scouter/agent/plugin/PluginLoader.java +++ b/scouter.agent.java/src/scouter/agent/plugin/PluginLoader.java @@ -82,6 +82,14 @@ private void reloadIfModified(File root) { PluginCaptureTrace.plugIn = createICaptureTrace(script); } } + script = new File(root, "springControllerCapture.plug"); + if (script.canRead() == false) { + PluginSpringControllerCaptureTrace.plugIn = null; + } else { + if (PluginSpringControllerCaptureTrace.plugIn == null || PluginSpringControllerCaptureTrace.plugIn.lastModified != script.lastModified()) { + PluginSpringControllerCaptureTrace.plugIn = createICaptureTrace(script); + } + } script = new File(root, "jdbcpool.plug"); if (script.canRead() == false) { PluginJdbcPoolTrace.plugIn = null; @@ -401,7 +409,7 @@ private AbstractCapture createICaptureTrace(File script) { c = impl.toClass(new URLClassLoader(new URL[0], this.getClass().getClassLoader()), null); AbstractCapture plugin = (AbstractCapture) c.newInstance(); plugin.lastModified = script.lastModified(); - Logger.println("PLUG-IN : " + AbstractCapture.class.getName() + " loaded #" + Logger.println("PLUG-IN : " + AbstractCapture.class.getName() + " " + script.getName() + " loaded #" + Hexa32.toString32(plugin.hashCode())); return plugin; } catch (scouter.javassist.CannotCompileException ee) { diff --git a/scouter.agent.java/src/scouter/agent/plugin/PluginSpringControllerCaptureTrace.java b/scouter.agent.java/src/scouter/agent/plugin/PluginSpringControllerCaptureTrace.java new file mode 100644 index 000000000..f14c8d394 --- /dev/null +++ b/scouter.agent.java/src/scouter/agent/plugin/PluginSpringControllerCaptureTrace.java @@ -0,0 +1,57 @@ +/* + * Copyright 2015 the original author or authors. + * @https://github.com/scouter-project/scouter + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package scouter.agent.plugin; + +import scouter.agent.trace.HookArgs; +import scouter.agent.trace.TraceContext; + +public class PluginSpringControllerCaptureTrace { + + static AbstractCapture plugIn; + + static { + PluginLoader.getInstance(); + } + + public static void capArgs(TraceContext ctx, HookArgs hook) { + if (plugIn != null) { + try { + plugIn.capArgs(new WrContext(ctx), hook); + } catch (Throwable t) { + } + } + } + +// public static void capReturn(TraceContext ctx, HookReturn hook) { +// if (plugIn != null) { +// try { +// plugIn.capReturn(new WrContext(ctx), hook); +// } catch (Throwable t) { +// } +// } +// } +// +// public static void capThis(TraceContext ctx, String className, String methodDesc, Object data) { +// if (plugIn != null) { +// try { +// plugIn.capThis(new WrContext(ctx),className, methodDesc, data); +// } catch (Throwable t) { +// } +// } +// } + +} diff --git a/scouter.agent.java/src/scouter/agent/trace/TraceMain.java b/scouter.agent.java/src/scouter/agent/trace/TraceMain.java index f9d094d72..390d01c0b 100644 --- a/scouter.agent.java/src/scouter/agent/trace/TraceMain.java +++ b/scouter.agent.java/src/scouter/agent/trace/TraceMain.java @@ -29,6 +29,7 @@ import scouter.agent.plugin.PluginAppServiceTrace; import scouter.agent.plugin.PluginCaptureTrace; import scouter.agent.plugin.PluginHttpServiceTrace; +import scouter.agent.plugin.PluginSpringControllerCaptureTrace; import scouter.agent.proxy.HttpTraceFactory; import scouter.agent.proxy.IHttpTrace; import scouter.agent.summary.ServiceSummary; @@ -44,7 +45,15 @@ import scouter.lang.step.MethodStep2; import scouter.lang.step.ThreadCallPossibleStep; import scouter.lang.value.MapValue; -import scouter.util.*; +import scouter.util.ArrayUtil; +import scouter.util.HashUtil; +import scouter.util.Hexa32; +import scouter.util.IPUtil; +import scouter.util.KeyGen; +import scouter.util.ObjectUtil; +import scouter.util.StringUtil; +import scouter.util.SysJMX; +import scouter.util.ThreadUtil; import javax.sql.DataSource; import java.lang.reflect.Method; @@ -852,6 +861,27 @@ public static void setServiceName(String name) { } } + public static void startSpringControllerMethod(String className, String methodName, String methodDesc, Object this1, Object[] arg) { + TraceContext ctx = TraceContextManager.getContext(); + if (ctx == null) + return; + if(conf.profile_spring_controller_method_parameter_enabled) { + if (arg == null) { + return; + } + int start_time = (int) (System.currentTimeMillis() - ctx.startTime); + for(int i=0; i