diff --git a/.gitignore b/.gitignore
index 2bb90a907..57e31d248 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+scouter.agent.batch/bin/*
scouter.agent.java/bin/*
scouter.client/bin/*
scouter.common/bin/*
@@ -98,3 +99,7 @@ dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
+scouter.client.build/.settings/org.eclipse.core.resources.prefs
+scouter.common/.settings/org.eclipse.core.resources.prefs
+scouter.agent.host/.settings/org.eclipse.core.resources.prefs
+scouter.agent.batch/.settings/org.eclipse.core.resources.prefs
diff --git a/README_kr.md b/README_kr.md
index 92af1a915..1c9a1dec5 100644
--- a/README_kr.md
+++ b/README_kr.md
@@ -1,4 +1,4 @@
-
+
[](README.md) 
@@ -53,7 +53,7 @@ APM은 Application performance montoring 또는 application performance manageme
- **Server (Collector)** : Agent가 전송한 데이터를 저장하고 Client 요청시 Client에게 적절한 데이터를 전송
- - **Scala** : Written in Scala. It will provide a variety of features and performance scalability that can not be written in Java.
+ - **Scala** : Scala를 사용하여 개발하였음으로, 자바 코딩으로는 제공하기 어려운 성능 확장성 및 여러가지 기능들을 제공 할수 있음.
- **HASH FILE** : 고속의 자체 개발한 Hash 인덱스 방식의 파일 Repository 사용으로 최상의 속도를 동작하며 추가적인 DB 및 라이브러리의 설치가 불필요하여 압축 해제만으로 쉽게 설치 가능.
- **GZIP** : 압축 옵션을 통해 저장 공간을 절약하도록 개발됨.
diff --git a/scouter.agent.batch/.classpath b/scouter.agent.batch/.classpath
new file mode 100644
index 000000000..66f07b702
--- /dev/null
+++ b/scouter.agent.batch/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/scouter.agent.batch/.project b/scouter.agent.batch/.project
new file mode 100644
index 000000000..6d4b522dc
--- /dev/null
+++ b/scouter.agent.batch/.project
@@ -0,0 +1,17 @@
+
+
+ scouter.agent.batch
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/scouter.agent.batch/.settings/org.eclipse.jdt.core.prefs b/scouter.agent.batch/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..8000cd6ca
--- /dev/null
+++ b/scouter.agent.batch/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/scouter.agent.batch/src/scouter/agent/batch/AgentTransformer.java b/scouter.agent.batch/src/scouter/agent/batch/AgentTransformer.java
new file mode 100644
index 000000000..ce3c619da
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/AgentTransformer.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2016 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.batch;
+
+import scouter.agent.batch.asm.JDBCPreparedStatementASM;
+import scouter.agent.batch.asm.JDBCStatementASM;
+import scouter.agent.batch.asm.JDBCResultSetASM;
+
+import scouter.agent.asm.ScouterClassWriter;
+import scouter.agent.asm.IASM;
+import scouter.agent.ClassDesc;
+import scouter.agent.ObjTypeDetector;
+import scouter.agent.asm.util.AsmUtil;
+import scouter.org.objectweb.asm.*;
+import scouter.util.FileUtil;
+
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.List;
+
+public class AgentTransformer implements ClassFileTransformer {
+ private static List filters = new ArrayList();
+ private static List asms = new ArrayList();
+ // hook 관련 설정이 변경되면 자동으로 변경된다.
+
+ static {
+ asms.add(new JDBCPreparedStatementASM());
+ asms.add(new JDBCStatementASM());
+ asms.add(new JDBCResultSetASM());
+
+ filters.add("Statement");
+ filters.add("ResultSet");
+ }
+
+ private Configure conf = Configure.getInstance();
+ private Logger.FileLog bciOut;
+
+ public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined,
+ ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
+ try {
+ if(!conf.sql_enabled || className == null){
+ return null;
+ }
+
+ if (className.startsWith("scouter/") || !filter(className)) {
+ return null;
+ }
+
+ //classfileBuffer = DirectPatch.patch(className, classfileBuffer);
+ ObjTypeDetector.check(className);
+ final ClassDesc classDesc = new ClassDesc();
+ ClassReader cr = new ClassReader(classfileBuffer);
+ cr.accept(new ClassVisitor(Opcodes.ASM4) {
+ public void visit(int version, int access, String name, String signature, String superName,
+ String[] interfaces) {
+ classDesc.set(version, access, name, signature, superName, interfaces);
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ classDesc.anotation += desc;
+ return super.visitAnnotation(desc, visible);
+ }
+ }, 0);
+ if (AsmUtil.isInterface(classDesc.access)) {
+ return null;
+ }
+ classDesc.classBeingRedefined = classBeingRedefined;
+ ClassWriter cw = getClassWriter(classDesc);
+ ClassVisitor cv = cw;
+ List workAsms = asms;
+ for (int i = 0, max = workAsms.size(); i < max; i++) {
+ cv = workAsms.get(i).transform(cv, className, classDesc);
+ if (cv != cw) {
+ cr = new ClassReader(classfileBuffer);
+ cr.accept(cv, ClassReader.EXPAND_FRAMES);
+ classfileBuffer = cw.toByteArray();
+ cv = cw = getClassWriter(classDesc);
+ if (conf._log_asm_enabled) {
+ if (this.bciOut == null) {
+ this.bciOut = new Logger.FileLog("./scouter.bci");
+ }
+ this.bciOut.println(className + "\t\t[" + loader + "]");
+ dump(className, classfileBuffer);
+ }
+ }
+ }
+ return classfileBuffer;
+ } catch (Throwable t) {
+ Logger.println("A101", "Transformer Error", t);
+ t.printStackTrace();
+ }
+ return null;
+ }
+
+ private ClassWriter getClassWriter(final ClassDesc classDesc) {
+ ClassWriter cw;
+ switch (classDesc.version) {
+ case Opcodes.V1_1:
+ case Opcodes.V1_2:
+ case Opcodes.V1_3:
+ case Opcodes.V1_4:
+ case Opcodes.V1_5:
+ case Opcodes.V1_6:
+ cw = new ScouterClassWriter(ClassWriter.COMPUTE_MAXS);
+ break;
+ default:
+ cw = new ScouterClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+ }
+ return cw;
+ }
+
+ private boolean filter(String className){
+ for(String name: filters){
+ if(className.indexOf(name) >= 0){
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void dump(String className, byte[] bytes) {
+ String fname = "./dump/" + className.replace('/', '_') + ".class";
+ FileUtil.save(fname, bytes);
+ }
+}
diff --git a/scouter.agent.batch/src/scouter/agent/batch/BatchMonitor.java b/scouter.agent.batch/src/scouter/agent/batch/BatchMonitor.java
new file mode 100644
index 000000000..8feeba367
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/BatchMonitor.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2016 Scouter Project.
+ *
+ * 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.batch;
+
+import java.io.File;
+import java.io.FileWriter;
+
+import scouter.agent.batch.dump.ThreadDumpHandler;
+import scouter.agent.batch.trace.TraceContext;
+import scouter.util.ThreadUtil;
+
+public class BatchMonitor extends Thread {
+ private static BatchMonitor instance = null;
+ public Configure config = null;
+
+ static public BatchMonitor getInstance(){
+ if(instance == null){
+ instance = new BatchMonitor();
+ instance.setDaemon(true);
+ instance.setName(ThreadUtil.getName(instance));
+
+ TraceContext.getInstance();
+ Runtime.getRuntime().addShutdownHook(new ResultSender());
+ instance.start();
+ }
+ return instance;
+ }
+
+ public void run() {
+ FileWriter stackWriter = null;
+ FileWriter indexWriter = null;
+ try {
+ File stackFile = null;
+ config = Configure.getInstance();
+ TraceContext traceContext = TraceContext.getInstance();
+ if(config.sfa_dump_enabled){
+ File indexFile = null;
+
+ stackFile = new File(traceContext.getLogFilename() + ".log");
+ if(stackFile.exists()){
+ stackFile = null;
+ }else{
+ traceContext.stackLogFile = stackFile.getAbsolutePath();
+
+ stackWriter = new FileWriter(stackFile);
+ indexWriter = new FileWriter(new File(traceContext.getLogFilename() + ".inx"));
+ }
+ }
+ if(stackWriter != null){
+ while(!config.scouter_stop){
+ ThreadDumpHandler.processDump(stackFile, stackWriter, indexWriter, config.sfa_dump_filter, config.sfa_dump_header_exists);
+ traceContext.checkThread();
+ Thread.sleep(config.sfa_dump_interval_ms);
+ }
+ }
+ }catch(Throwable ex){
+ Logger.println("ERROR: " + ex.getMessage());
+ }finally{
+ if(stackWriter != null){
+ try{ stackWriter.close(); }catch(Exception ex){}
+ }
+ if(indexWriter != null){
+ try{ indexWriter.close(); }catch(Exception ex){}
+ }
+ }
+ }
+}
diff --git a/scouter.agent.batch/src/scouter/agent/batch/Configure.java b/scouter.agent.batch/src/scouter/agent/batch/Configure.java
new file mode 100644
index 000000000..821cad7f1
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/Configure.java
@@ -0,0 +1,393 @@
+/*
+ * Copyright 2016 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.batch;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+
+
+import scouter.agent.util.JarUtil;
+import scouter.lang.conf.ConfigValueUtil;
+import scouter.net.NetConstants;
+import scouter.util.FileUtil;
+import scouter.util.StringSet;
+import scouter.util.StringUtil;
+
+public class Configure {
+ public static final String CONFIG_SCOUTER_ENABLED = "scouter_enabled";
+ public static final String VM_SCOUTER_ENABLED = "scouter.enabled";
+ public static boolean JDBC_REDEFINED = false;
+ private static Configure instance = null;
+
+ public Properties property = new Properties();
+ private File propertyFile;
+ public static String agent_dir_path;
+ static {
+ agent_dir_path = JarUtil.getThisJarFile().getParent();
+ }
+
+ public final static synchronized Configure getInstance() {
+ if (instance == null) {
+ instance = new Configure();
+ }
+ return instance;
+ }
+
+ // Scouter enable/disable
+ public boolean scouter_enabled = true;
+ public boolean scouter_stop = false;
+
+ // Standalone
+ public boolean scouter_standalone = false;
+
+ // Batch basic configuration
+ public String batch_id_type = ""; // Class, Args, Props
+ public String batch_id = "";
+
+ // SQL
+ public boolean sql_enabled = true;
+ public int sql_max_count = 100;
+ public String hook_jdbc_pstmt_classes = "";
+ public String hook_jdbc_stmt_classes = "";
+ public String hook_jdbc_rs_classes = "";
+
+ // SFA(Stack Frequency Analyzer) Thread Dump
+ public boolean sfa_dump_enabled = true;
+ public int sfa_dump_interval_ms = 10000;
+ public String [] sfa_dump_filter = null;
+ public File sfa_dump_dir = new File(agent_dir_path + "/dump");
+ public boolean sfa_dump_header_exists = true;
+
+ // dump send time
+ public long dump_send_elapsed_ms = 0L;
+
+ //Network
+ public String net_collector_ip = "127.0.0.1";
+ public int net_collector_udp_port = NetConstants.SERVER_UDP_PORT;
+ public int net_collector_tcp_port = NetConstants.SERVER_TCP_PORT;
+ public int net_collector_tcp_session_count = 1;
+ public int net_collector_tcp_so_timeout_ms = 60000;
+ public int net_collector_tcp_connection_timeout_ms = 3000;
+ public int net_udp_packet_max_bytes = 60000;
+ public long net_udp_collection_interval_ms = 100;
+
+ //Object
+ public String obj_type = "batch";
+ public String obj_name = "";
+ public String obj_host_type = "";
+ public String obj_host_name = "";
+ public boolean obj_name_auto_pid_enabled = false;
+ public boolean obj_type_inherit_to_child_enabled = false;
+
+ //Dir
+ public File plugin_dir = new File(agent_dir_path + "/plugin");
+ //public File mgr_agent_lib_dir = new File("./_scouter_");
+
+ //Log
+ public boolean _log_asm_enabled;
+
+ public String log_dir ="";
+ public boolean log_rotation_enabled =true;
+ public int log_keep_days =7;
+ public boolean _trace = false;
+ public boolean _trace_use_logger = false;
+
+ //internal variables
+ private int objHash;
+ private String objName;
+ private int objHostHash;
+ private String objHostName;
+
+ private StringSet log_ignore_set = new StringSet();
+
+ /**
+ * sometimes call by sample application, at that time normally set some
+ * properties directly
+ */
+ private Configure() {
+ Properties p = new Properties();
+ Map args = new HashMap();
+ args.putAll(System.getenv());
+ args.putAll(System.getProperties());
+ p.putAll(args);
+ this.property = p;
+ reload();
+ }
+
+ public File getPropertyFile() {
+ if (propertyFile != null) {
+ return propertyFile;
+ }
+ String s = System.getProperty("scouter.config", agent_dir_path + "/conf/scouter.batch.conf");
+ propertyFile = new File(s.trim());
+ return propertyFile;
+ }
+
+ public void reload() {
+ File file = getPropertyFile();
+ Properties temp = new Properties();
+ if (file.canRead()) {
+ FileInputStream in = null;
+ try {
+ in = new FileInputStream(file);
+ temp.load(in);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ FileUtil.close(in);
+ }
+ }
+ property = ConfigValueUtil.replaceSysProp(temp);
+ apply();
+
+ Logger.println(CONFIG_SCOUTER_ENABLED + "=" + this.scouter_enabled);
+ Logger.println("sql_enabled=" + this.sql_enabled);
+ Logger.println("sfa_dump_enabled=" + this.sql_enabled);
+ if(sfa_dump_enabled){
+ Logger.println("sfa_dump_dir=" + this.sfa_dump_dir.getAbsolutePath());
+ }
+ }
+
+ private void apply() {
+ // enable or disable
+ this.scouter_enabled = getBoolean(CONFIG_SCOUTER_ENABLED, true);
+ if(getValue(VM_SCOUTER_ENABLED) != null){
+ this.scouter_enabled = getBoolean(VM_SCOUTER_ENABLED, true);
+ }
+
+ // standalone mode
+ this.scouter_standalone = getBoolean("scouter_standalone", true);
+
+ // start for batch
+ this.batch_id_type = getValue("batch_id_type", "class");
+ if("class".equals(this.batch_id_type)){
+ this.batch_id = getValue("batch_id", "");
+ }else if("args".equals(this.batch_id_type)){
+ this.batch_id = getValue("batch_id", "0");
+ }else if("props".equals(this.batch_id_type)){
+ this.batch_id = getValue("batch_id", "JobId");
+ }
+ this.obj_name = getValue("obj_name", "batch");
+ // end for batch
+
+ // SQL
+ this.sql_max_count = getInt("sql_max_count", 100);
+
+ // Batch Dump
+ this.sfa_dump_interval_ms = getInt("sfa_dump_interval_ms", 10000);
+ if (this.sfa_dump_interval_ms < 5000) {
+ this.sfa_dump_interval_ms = 5000;
+ }
+ String value = getValue("sfa_dump_filter");
+ if(value != null){
+ String [] arrs = StringUtil.split(value, ',');
+ if(arrs != null && arrs.length > 0){
+ ArrayList lists = new ArrayList();
+ for(String line:arrs){
+ line = line.trim();
+ if(line.length() == 0){
+ continue;
+ }
+ lists.add(line);
+ }
+ if(lists.size() > 0){
+ this.sfa_dump_filter = new String[lists.size()];
+ for(int i=0; i < lists.size();i++){
+ this.sfa_dump_filter[i] = lists.get(i);
+ }
+ }
+ }
+ }
+
+ this.sfa_dump_enabled = getBoolean("sfa_dump_enabled", true);
+ if(this.sfa_dump_enabled){
+ value = getValue("sfa_dump_dir", agent_dir_path + "/dump");
+ File dir = new File(value);
+ if(!dir.exists()){
+ try {
+ dir.mkdirs();
+ }catch(Exception ex){}
+ }
+
+ if(dir.isFile()){
+ this.sfa_dump_enabled = false;
+ System.err.println("sfa_dump_dir(" + dir.getAbsolutePath() + ") is file");
+ }
+
+ if(!dir.canWrite()){
+ this.sfa_dump_enabled = false;
+ System.err.println("sfa_dump_dir(" + dir.getAbsolutePath() + ") can't write");
+ }
+
+ this.sfa_dump_dir = dir;
+ this.sfa_dump_header_exists = getBoolean("sfa_dump_header_exists", true);
+ }
+
+ this.dump_send_elapsed_ms = getLong("dump_send_elapsed_ms", 0L);
+
+ this.plugin_dir = new File(getValue("plugin_dir", agent_dir_path + "/plugin"));
+
+ this.net_udp_packet_max_bytes = getInt("net_udp_packet_max_bytes", 60000);
+ this.net_collector_ip = getValue("net_collector_ip", "127.0.0.1");
+ this.net_collector_udp_port = getInt("net_collector_udp_port", NetConstants.SERVER_UDP_PORT);
+ this.net_collector_tcp_port = getInt("net_collector_tcp_port", NetConstants.SERVER_TCP_PORT);
+ this.net_collector_tcp_session_count = getInt("net_collector_tcp_session_count", 1, 1);
+ this.net_collector_tcp_connection_timeout_ms = getInt("net_collector_tcp_connection_timeout_ms", 3000);
+ this.net_collector_tcp_so_timeout_ms = getInt("net_collector_tcp_so_timeout_ms", 60000);
+
+
+ this.sql_enabled = getBoolean("sql_enabled", true);
+ this.hook_jdbc_pstmt_classes = getValue("hook_jdbc_pstmt_classes", "");
+ this.hook_jdbc_stmt_classes = getValue("hook_jdbc_stmt_classes", "");
+ this.hook_jdbc_rs_classes = getValue("hook_jdbc_rs_classes", "");
+ this.net_udp_collection_interval_ms = getInt("net_udp_collection_interval_ms", 100);
+
+ this._log_asm_enabled = getBoolean("_log_asm_enabled", false);
+ this.obj_type_inherit_to_child_enabled = getBoolean("obj_type_inherit_to_child_enabled", false);
+
+ this.log_dir = getValue("log_dir", "");
+ this.log_rotation_enabled = getBoolean("log_rotation_enabled", true);
+ this.log_keep_days = getInt("log_keep_days", 7);
+ this._trace = getBoolean("_trace", false);
+ this._trace_use_logger = getBoolean("_trace_use_logger", false);
+ this.log_ignore_set = getStringSet("mgr_log_ignore_ids", ",");
+
+ }
+
+ public int getObjHash() {
+ return this.objHash;
+ }
+
+ public String getObjName() {
+ return this.objName;
+ }
+
+ public int getObjHostHash(){
+ return this.objHostHash;
+ }
+
+ public String getObjHostName() {
+ return this.objHostName;
+ }
+
+ public boolean isIgnoreLog(String id) {
+ return log_ignore_set.hasKey(id);
+ }
+
+ private StringSet getStringSet(String key, String deli) {
+ StringSet set = new StringSet();
+ String v = getValue(key);
+ if (v != null) {
+ String[] vv = StringUtil.split(v, deli);
+ for (String x : vv) {
+ x = StringUtil.trimToEmpty(x);
+ if (x.length() > 0)
+ set.put(x);
+ }
+ }
+ return set;
+ }
+
+ public String getValue(String key) {
+ return StringUtil.trim(property.getProperty(key));
+ }
+ public String getValue(String key, String def) {
+ return StringUtil.trim(property.getProperty(key, def));
+ }
+ public int getInt(String key, int def) {
+ try {
+ String v = getValue(key);
+ if (v != null)
+ return Integer.parseInt(v);
+ } catch (Exception e) {
+ }
+ return def;
+ }
+ public int getInt(String key, int def, int min) {
+ try {
+ String v = getValue(key);
+ if (v != null) {
+ return Math.max(Integer.parseInt(v), min);
+ }
+ } catch (Exception e) {
+ }
+ return Math.max(def, min);
+ }
+ public long getLong(String key, long def) {
+ try {
+ String v = getValue(key);
+ if (v != null)
+ return Long.parseLong(v);
+ } catch (Exception e) {
+ }
+ return def;
+ }
+ public boolean getBoolean(String key, boolean def) {
+ try {
+ String v = getValue(key);
+ if (v != null)
+ return Boolean.parseBoolean(v);
+ } catch (Exception e) {
+ }
+ return def;
+ }
+ public String loadText() {
+ File file = getPropertyFile();
+ InputStream fin = null;
+ try {
+ fin = new FileInputStream(file);
+ byte[] buff = FileUtil.readAll(fin);
+ return new String(buff);
+ } catch (Exception e) {
+ } finally {
+ FileUtil.close(fin);
+ }
+ return null;
+ }
+ public boolean saveText(String text) {
+ File file = getPropertyFile();
+ OutputStream out = null;
+ try {
+ if (file.getParentFile().exists() == false) {
+ file.getParentFile().mkdirs();
+ }
+ out = new FileOutputStream(file);
+ out.write(text.getBytes());
+ return true;
+ } catch (Exception e) {
+ } finally {
+ FileUtil.close(out);
+ }
+ return false;
+ }
+ public void printConfig() {
+ Logger.info("Configure -Dscouter.config=" + propertyFile);
+ }
+ private static HashSet ignoreSet = new HashSet();
+ static {
+ ignoreSet.add("property");
+ ignoreSet.add("__experimental");
+ }
+}
diff --git a/scouter.agent.batch/src/scouter/agent/batch/JavaAgent.java b/scouter.agent.batch/src/scouter/agent/batch/JavaAgent.java
new file mode 100644
index 000000000..6e3bc4a2a
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/JavaAgent.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016 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.batch;
+
+import java.lang.instrument.Instrumentation;
+
+import scouter.util.logo.Logo;
+import scouter.agent.batch.AgentTransformer;
+
+public class JavaAgent {
+ private static Instrumentation instrumentation;
+
+ public static void premain(String options, Instrumentation instrum) {
+ if (JavaAgent.instrumentation != null) {
+ return;
+ }
+ intro();
+ Configure config = Configure.getInstance();
+
+ JavaAgent.instrumentation = instrum;
+ if(config.scouter_enabled){
+ JavaAgent.instrumentation.addTransformer(new AgentTransformer());
+ BatchMonitor.getInstance();
+ }
+ }
+
+ private static void intro() {
+ try {
+ String confFile = System.getProperty("scouter.config");
+ if( confFile == null){
+ System.setProperty(Configure.VM_SCOUTER_ENABLED, "false");
+ }
+
+ Logo.print(false);
+ String nativeName = JavaAgent.class.getName().replace('.', '/') + ".class";
+ ClassLoader cl = JavaAgent.class.getClassLoader();
+ if (cl == null) {
+ Logger.println("loaded by system classloader ");
+ Logger.println(cut("" + ClassLoader.getSystemClassLoader().getResource(nativeName)));
+ } else {
+ Logger.println("loaded by app classloader ");
+ Logger.println(cut("" + cl.getResource(nativeName)));
+ }
+ Logger.println("scouter.config=" + confFile);
+ } catch (Throwable t) {
+ }
+ }
+
+ private static String cut(String s) {
+ int x = s.indexOf('!');
+ return x > 0 ? s.substring(0, x) : s;
+ }
+
+ public static Instrumentation getInstrumentation() {
+ return instrumentation;
+ }
+}
diff --git a/scouter.agent.batch/src/scouter/agent/batch/Logger.java b/scouter.agent.batch/src/scouter/agent/batch/Logger.java
new file mode 100644
index 000000000..b6e294a08
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/Logger.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2016 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.batch;
+
+import scouter.util.*;
+
+import java.io.*;
+
+public class Logger {
+
+ private static StringLongLinkedMap lastLog = new StringLongLinkedMap().setMax(1000);
+ static Configure conf = Configure.getInstance();
+
+ public static void println(Object message) {
+ println(build("SCOUTER", toString(message)), true);
+ }
+
+ public static void println(String id, Object message) {
+ if (checkOk(id, 0) == false) {
+ return;
+ }
+ println(build(id, toString(message)), true);
+ }
+
+ public static void println(String id, String message, Throwable t) {
+ if (checkOk(id, 10) == false) {
+ return;
+ }
+ println(build(id, message), true);
+ println(ThreadUtil.getStackTrace(t), true);
+ }
+
+ public static void trace(Object message) {
+ if(conf._trace) {
+ if(conf._trace_use_logger) {
+ println(build("SCOUTER-TRC", toString(message)), true);
+ } else {
+ System.out.println(build("SCOUTER-TRC", toString(message)));
+ }
+ }
+ }
+
+ private static String toString(Object message) {
+ return message == null ? "null" : message.toString();
+ }
+
+ private static String build(String id, String message) {
+ return new StringBuffer(20 + id.length() + message.length())
+ .append(DateUtil.datetime(System.currentTimeMillis())).append(" [").append(id).append("] ")
+ .append(message).toString();
+ }
+
+ public static String getCallStack(Throwable t) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ try {
+ t.printStackTrace(pw);
+ return sw.toString();
+ } finally {
+ pw.close();
+ }
+ }
+
+ private static boolean checkOk(String id, int sec) {
+ if (Configure.getInstance().isIgnoreLog(id))
+ return false;
+
+ if (sec > 0) {
+ long last = lastLog.get(id);
+ long now = System.currentTimeMillis();
+ if (now < last + sec * 1000)
+ return false;
+ lastLog.put(id, now);
+ }
+ return true;
+ }
+
+ static PrintWriter pw = null;
+ static File logfile = null;
+
+ private static void println(String msg, boolean sysout) {
+ try {
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
+ return;
+ } else {
+ if (sysout) {
+ System.out.println(msg);
+ }
+ }
+ } catch (Throwable e) {
+ pw = (PrintWriter) FileUtil.close(pw);
+ if (sysout) {
+ System.out.println(msg);
+ }
+ }
+ }
+
+ private static synchronized void openFile(String prefix) throws IOException {
+ if (pw == null && StringUtil.isEmpty(conf.log_dir) == false) {
+ File root = new File(conf.log_dir);
+ if (root.canWrite() == false) {
+ root.mkdirs();
+ }
+ if (root.canWrite() == false) {
+ return;
+ }
+
+ if (conf.log_rotation_enabled) {
+ File file = new File(conf.log_dir, "scouter-" + prefix + "-" + DateUtil.yyyymmdd() + ".log");
+ FileWriter fw = new FileWriter(file, true);
+ pw = new PrintWriter(fw);
+ logfile = file;
+ } else {
+ File file = new File(conf.log_dir, "scouter-" + prefix + ".log");
+ pw = new PrintWriter(new FileWriter(file, true));
+ logfile = file;
+ }
+
+ }
+ }
+
+ static Runnable initializer = new Runnable() {
+ long last = System.currentTimeMillis();
+ long lastDataUnit = DateUtil.getDateUnit();
+ String lastDir = conf.log_dir;
+ boolean lastFileRotation = conf.log_rotation_enabled;
+ String scouter_name = "boot";
+
+ public void run() {
+ try {
+ process();
+ } catch (Throwable t) {
+ }
+ }
+
+ private synchronized void process() {
+ long now = System.currentTimeMillis();
+ if (now > last + DateUtil.MILLIS_PER_HOUR) {
+ last = now;
+ clearOldLog();
+ }
+
+ if (CompareUtil.equals(lastDir, conf.log_dir) == false //
+ || lastFileRotation != conf.log_rotation_enabled //
+ || lastDataUnit != DateUtil.getDateUnit() //
+ || scouter_name.equals(conf.obj_name) == false//
+ || (logfile != null && logfile.exists() == false)) {
+ pw = (PrintWriter) FileUtil.close(pw);
+ logfile = null;
+ lastDir = conf.log_dir;
+ lastFileRotation = conf.log_rotation_enabled;
+ lastDataUnit = DateUtil.getDateUnit();
+ scouter_name = conf.obj_name;
+ }
+
+ try {
+ openFile(scouter_name);
+ } catch (Throwable t) {
+ sysout(t.getMessage());
+ }
+ }
+ };
+
+ protected static void clearOldLog() {
+ if (conf.log_rotation_enabled == false)
+ return;
+ if (conf.log_keep_days <= 0)
+ return;
+ String scouter_prefix = "scouter-" + conf.obj_name;
+ long nowUnit = DateUtil.getDateUnit();
+ File dir = new File(conf.log_dir);
+ File[] files = dir.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ if (files[i].isDirectory())
+ continue;
+ String name = files[i].getName();
+ if (name.startsWith(scouter_prefix + "-") == false)
+ continue;
+ int x = name.lastIndexOf('.');
+ if (x < 0)
+ continue;
+ String date = name.substring(scouter_prefix.length() + 1, x);
+ if (date.length() != 8)
+ continue;
+
+ try {
+ long d = DateUtil.yyyymmdd(date);
+ long fileUnit = DateUtil.getDateUnit(d);
+ if (nowUnit - fileUnit > DateUtil.MILLIS_PER_DAY * conf.log_keep_days) {
+ files[i].delete();
+ }
+ } catch (Exception e) {
+ }
+ }
+
+ }
+
+ public static void main(String[] args) {
+ String name = "scouter-19701123.log";
+ int x = name.lastIndexOf('.');
+ String date = name.substring("scouter-".length(), x);
+ System.out.println(date);
+
+ }
+
+ public static void info(String message) {
+ message = build("SCOUTER", message);
+ sysout(message);
+ println(message, false);
+ }
+
+ private static void sysout(String message) {
+ System.out.println(message);
+ }
+
+ public static class FileLog implements IClose {
+ private PrintWriter out;
+
+ public FileLog(String filename) {
+ try {
+ this.out = new PrintWriter(new FileWriter(filename));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void println(String message) {
+ if (this.out == null)
+ return;
+ this.out.println(DateUtil.datetime(System.currentTimeMillis()) + " " + message);
+ this.out.flush();
+ }
+
+ public void close() {
+ FileUtil.close(this.out);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/scouter.agent.batch/src/scouter/agent/batch/ResultSender.java b/scouter.agent.batch/src/scouter/agent/batch/ResultSender.java
new file mode 100644
index 000000000..17dabc30b
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/ResultSender.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 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.batch;
+
+import java.io.File;
+import java.io.FileWriter;
+
+import scouter.agent.batch.trace.TraceContext;
+
+public class ResultSender extends Thread {
+ public void run(){
+ try {
+ Configure config = Configure.getInstance();
+ config.scouter_stop = true;
+
+ TraceContext traceContext = TraceContext.getInstance();
+ traceContext.endTime = System.currentTimeMillis();
+ traceContext.caculateLast();
+
+ String result = traceContext.toString();
+ if(config.scouter_standalone){
+ saveStandAloneResult(traceContext, result);
+ }
+ Logger.println(result);
+ }catch(Exception ex){
+ ex.printStackTrace();
+ }
+ }
+
+ public void saveStandAloneResult(TraceContext traceContext, String result){
+ File resultFile = new File(traceContext.getLogFilename() + ".sbr");
+ if(resultFile.exists()){
+ return;
+ }
+ FileWriter writer = null;
+ try {
+ writer = new FileWriter(resultFile);
+ writer.write(result);
+ }catch(Exception ex){
+ Logger.println(ex.toString());
+ }finally{
+ if(writer != null){
+ try{ writer.close(); }catch(Exception ex){}
+ }
+ }
+ }
+}
diff --git a/scouter.agent.batch/src/scouter/agent/batch/asm/JDBCPreparedStatementASM.java b/scouter.agent.batch/src/scouter/agent/batch/asm/JDBCPreparedStatementASM.java
new file mode 100644
index 000000000..a4c9b4d2d
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/asm/JDBCPreparedStatementASM.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2016 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.batch.asm;
+
+import scouter.agent.batch.Configure;
+import scouter.agent.batch.Logger;
+import scouter.agent.batch.trace.TraceSQL;
+import scouter.agent.batch.asm.jdbc.PsInitMV;
+import scouter.agent.batch.asm.jdbc.PsExecuteMV;
+import scouter.agent.batch.asm.jdbc.StExecuteMV;
+
+import scouter.agent.asm.IASM;
+import scouter.agent.ClassDesc;
+import scouter.agent.asm.util.HookingSet;
+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 java.util.HashSet;
+
+/**
+ * BCI for a JDBC PreparedStatement
+ * @author @author Paul S.J. Kim(sjkim@whatap.io)
+ * @author Gun Lee (gunlee01@gmail.com)
+ * @author Munsoo Kwon (mskweon82@daum.net)
+ */
+public class JDBCPreparedStatementASM implements IASM, Opcodes {
+ public final HashSet target = HookingSet.getHookingClassSet(Configure.getInstance().hook_jdbc_pstmt_classes);
+ public final HashSet noField = new HashSet();
+
+ public JDBCPreparedStatementASM() {
+ target.add("org/mariadb/jdbc/AbstractMariaDbPrepareStatement");
+ target.add("org/mariadb/jdbc/MariaDbClientPreparedStatement");
+ target.add("org/mariadb/jdbc/MariaDbServerPreparedStatement");
+ target.add("org/mariadb/jdbc/MySQLPreparedStatement");
+ target.add("oracle/jdbc/driver/OraclePreparedStatement");
+ target.add("org/postgresql/jdbc2/AbstractJdbc2Statement");
+ target.add("org/apache/derby/client/am/PreparedStatement");
+ target.add("net/sourceforge/jtds/jdbc/JtdsPreparedStatement");
+ target.add("jdbc/FakePreparedStatement");
+ target.add("jdbc/FakePreparedStatement2");
+ target.add("com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement");
+ target.add("com/tmax/tibero/jdbc/TbPreparedStatement");
+ target.add("org/hsqldb/jdbc/JDBCPreparedStatement");
+ target.add("com/mysql/jdbc/ServerPreparedStatement");
+ target.add("com/mysql/jdbc/PreparedStatement");
+ target.add("cubrid/jdbc/driver/CUBRIDPreparedStatement");
+
+ // @skyworker - MySQL ServerPreparedStatement는 특별히 필드를 추가하지 않음
+ noField.add("com/mysql/jdbc/ServerPreparedStatement");
+ noField.add("jdbc/FakePreparedStatement2");
+ noField.add("org/mariadb/jdbc/MariaDbClientPreparedStatement");
+ noField.add("org/mariadb/jdbc/MariaDbServerPreparedStatement");
+ }
+
+ public ClassVisitor transform(ClassVisitor cv, String className, ClassDesc classDesc) {
+ if (Configure.getInstance().sql_enabled == false) {
+ return cv;
+ }
+ if (target.contains(className) == false) {
+ return cv;
+ }
+ Logger.println("A106", "jdbc pstmt found: " + className);
+ return new PreparedStatementCV(cv, noField);
+ }
+}
+
+class PreparedStatementCV extends ClassVisitor implements Opcodes {
+
+ HashSet noField;
+ private String owner;
+
+ public PreparedStatementCV(ClassVisitor cv, HashSet noField) {
+ super(ASM4, cv);
+ this.noField = noField;
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ this.owner = name;
+ if (noField.contains(name) == false) {
+ // add trace fields
+ super.visitField(ACC_PUBLIC, TraceSQL.CURRENT_TRACESQL_FIELD, Type.getDescriptor(TraceSQL.class), null, null)
+ .visitEnd();
+ }
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+ if ("".equals(name)) {
+ return new PsInitMV(access, desc, mv, owner);
+ } else {
+ if (PsExecuteMV.isTarget(name)) {
+ if (desc.startsWith("()")) {
+ return new PsExecuteMV(access, desc, mv, owner, name);
+ } else if (desc.startsWith("(Ljava/lang/String;)")) {
+ return new StExecuteMV(access, desc, mv, owner, name);
+ }
+ }
+ }
+ return mv;
+ }
+}
diff --git a/scouter.agent.batch/src/scouter/agent/batch/asm/JDBCResultSetASM.java b/scouter.agent.batch/src/scouter/agent/batch/asm/JDBCResultSetASM.java
new file mode 100644
index 000000000..ff8fd2719
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/asm/JDBCResultSetASM.java
@@ -0,0 +1,89 @@
+/*
+ * 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.batch.asm;
+
+import scouter.agent.batch.Configure;
+import scouter.agent.batch.Logger;
+import scouter.agent.batch.asm.jdbc.RsInitMV;
+import scouter.agent.batch.asm.jdbc.RsNextMV;
+import scouter.agent.batch.trace.TraceSQL;
+
+import scouter.agent.ClassDesc;
+import scouter.agent.asm.IASM;
+import scouter.agent.asm.util.HookingSet;
+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 java.util.HashSet;
+public class JDBCResultSetASM implements IASM, Opcodes {
+ public final HashSet target = HookingSet.getHookingClassSet(Configure.getInstance().hook_jdbc_rs_classes);
+ public JDBCResultSetASM() {
+ target.add("org/mariadb/jdbc/MySQLResultSet");
+ target.add("oracle/jdbc/driver/OracleResultSetImpl");
+ target.add("com/mysql/jdbc/ResultSetImpl");
+ target.add("org/postgresql/jdbc2/AbstractJdbc2ResultSet");
+ target.add("org/apache/derby/client/am/ResultSet");
+ target.add("jdbc/FakeResultSet");
+ target.add("net/sourceforge/jtds/jdbc/JtdsResultSet");
+ target.add("com/microsoft/sqlserver/jdbc/SQLServerResultSet");
+ target.add("com/tmax/tibero/jdbc/TbResultSet");
+ target.add("oracle/jdbc/driver/InsensitiveScrollableResultSet");
+ target.add("oracle/jdbc/driver/SensitiveScrollableResultSet");
+ target.add("org/hsqldb/jdbc/JDBCResultSet");
+ target.add("cubrid/jdbc/driver/CUBRIDResultSet");
+ target.add("org/mariadb/jdbc/MariaDbResultSet");
+ }
+
+ public ClassVisitor transform(ClassVisitor cv, String className, ClassDesc classDesc) {
+ if (Configure.getInstance().sql_enabled == false) {
+ return cv;
+ }
+ if (target.contains(className) == false) {
+ return cv;
+ }
+ Logger.println("A107", "jdbc rs found: " + className);
+ return new ResultSetCV(cv);
+ }
+}
+class ResultSetCV extends ClassVisitor implements Opcodes {
+ private String owner;
+ public ResultSetCV(ClassVisitor cv) {
+ super(ASM4, cv);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ super.visitField(ACC_PUBLIC, TraceSQL.CURRENT_TRACESQL_FIELD, Type.getDescriptor(TraceSQL.class), null, null)
+ .visitEnd();
+ this.owner = name;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+
+ if ("".equals(name)) {
+ return new RsInitMV(access, owner, desc, mv);
+ } else if ("next".equals(name) && "()Z".equals(desc)) {
+ return new RsNextMV(owner, mv);
+ }
+ return mv;
+ }
+}
diff --git a/scouter.agent.batch/src/scouter/agent/batch/asm/JDBCStatementASM.java b/scouter.agent.batch/src/scouter/agent/batch/asm/JDBCStatementASM.java
new file mode 100644
index 000000000..ab8e7bf9f
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/asm/JDBCStatementASM.java
@@ -0,0 +1,91 @@
+/*
+ * 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.batch.asm;
+
+import scouter.agent.batch.Configure;
+import scouter.agent.batch.Logger;
+import scouter.agent.batch.asm.jdbc.StExecuteMV;
+import scouter.agent.batch.trace.TraceSQL;
+
+import scouter.agent.ClassDesc;
+import scouter.agent.asm.IASM;
+import scouter.agent.asm.util.HookingSet;
+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 java.util.HashSet;
+
+/**
+ * BCI for a JDBC Statement
+ * @author @author Paul S.J. Kim(sjkim@whatap.io)
+ * @author Gun Lee (gunlee01@gmail.com)
+ * @author Eunsu Kim
+ */
+public class JDBCStatementASM implements IASM, Opcodes {
+ public final HashSet target = HookingSet.getHookingClassSet(Configure.getInstance().hook_jdbc_stmt_classes);
+ public JDBCStatementASM() {
+ target.add("org/mariadb/jdbc/MariaDbStatement");
+ target.add("org/mariadb/jdbc/MySQLStatement");
+ target.add("oracle/jdbc/driver/OracleStatement");
+ target.add("com/mysql/jdbc/StatementImpl");
+ target.add("org/apache/derby/client/am/Statement");
+ target.add("jdbc/FakeStatement");
+ target.add("net/sourceforge/jtds/jdbc/JtdsStatement");
+ target.add("com/microsoft/sqlserver/jdbc/SQLServerStatement");
+ target.add("com/tmax/tibero/jdbc/TbStatement");
+ target.add("org/hsqldb/jdbc/JDBCStatement");
+ target.add("cubrid/jdbc/driver/CUBRIDStatement");
+ }
+
+ public ClassVisitor transform(ClassVisitor cv, String className, ClassDesc classDesc) {
+ if (Configure.getInstance().sql_enabled == false) {
+ return cv;
+ }
+ if (target.contains(className) == false) {
+ return cv;
+ }
+ Logger.println("A108", "jdbc stmt found: " + className);
+ return new StatementCV(cv);
+ }
+}
+class StatementCV extends ClassVisitor implements Opcodes {
+ private String owner;
+ public StatementCV(ClassVisitor cv) {
+ super(ASM4, cv);
+ }
+
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ this.owner = name;
+ super.visitField(ACC_PUBLIC, TraceSQL.CURRENT_TRACESQL_FIELD, Type.getDescriptor(TraceSQL.class), null, null)
+ .visitEnd();
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+ MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
+ if (StExecuteMV.isTarget(name)) {
+ if (desc.startsWith("(Ljava/lang/String;)")) {
+ return new StExecuteMV(access, desc, mv, owner, name);
+ }
+ }
+ return mv;
+ }
+}
diff --git a/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/PsExecuteMV.java b/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/PsExecuteMV.java
new file mode 100644
index 000000000..9470dfd06
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/PsExecuteMV.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2016 Scouter Project.
+ *
+ * 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.batch.asm.jdbc;
+
+import scouter.agent.batch.trace.TraceSQL;
+
+import scouter.org.objectweb.asm.Label;
+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.HashSet;
+import java.util.Set;
+
+
+public class PsExecuteMV extends LocalVariablesSorter implements Opcodes {
+ private static Set target = new HashSet();
+ static {
+ target.add("execute");
+ target.add("executeQuery");
+ target.add("executeUpdate");
+ target.add("executeBatch");
+ }
+
+ public static boolean isTarget(String name) {
+ return target.contains(name);
+ }
+
+ private final static String TRACESQL = TraceSQL.class.getName().replace('.', '/');
+ private final static String START_METHOD = "start";
+ private static final String START_SIGNATURE = "()V";
+ private final static String END_METHOD = "end";
+ private static final String END_SIGNATURE = "()V";
+ private final static String ADD_METHOD = "addRow";
+ private static final String ADD_SIGNATURE = "(I)V";
+ private final static String ADDS_METHOD = "addRows";
+ private static final String ADDS_SIGNATURE = "([I)V";
+
+ public PsExecuteMV(int access, String desc, MethodVisitor mv, String owner,String name) {
+ super(ASM4,access, desc, mv);
+ this.owner = owner;
+ this.returnType = Type.getReturnType(desc);
+ }
+
+ private Label startFinally = new Label();
+ private String owner;
+ private final Type returnType;
+
+ @Override
+ public void visitCode() {
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TRACESQL, START_METHOD, START_SIGNATURE,false);
+ mv.visitLabel(startFinally);
+ mv.visitCode();
+ }
+
+ @Override
+ public void visitInsn(int opcode) {
+ if ((opcode >= IRETURN && opcode <= RETURN)) {
+ int lvPosReturn;
+ switch (returnType.getSort()) {
+ case Type.ARRAY:
+ if(returnType.getElementType().getSort() == Type.INT) {
+ lvPosReturn = newLocal(returnType);
+ mv.visitVarInsn(Opcodes.ASTORE, lvPosReturn);
+ mv.visitVarInsn(Opcodes.ALOAD, lvPosReturn);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ mv.visitVarInsn(Opcodes.ALOAD, lvPosReturn);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TRACESQL, ADDS_METHOD, ADDS_SIGNATURE,false);
+ }
+ break;
+ case Type.INT:
+ lvPosReturn = newLocal(returnType);
+ mv.visitVarInsn(Opcodes.ISTORE, lvPosReturn);
+ mv.visitVarInsn(Opcodes.ILOAD, lvPosReturn);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ mv.visitVarInsn(Opcodes.ILOAD, lvPosReturn);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TRACESQL, ADD_METHOD, ADD_SIGNATURE,false);
+ break;
+ /* case Type.BOOLEAN:
+ lvPosReturn = newLocal(returnType);
+ mv.visitVarInsn(Opcodes.ISTORE, lvPosReturn);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, STATMENT, GETUPDATECOUNT_METHOD, GETUPDATECOUNT_SIGNATURE,false);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TRACESQL, ADD_METHOD, ADD_SIGNATURE,false);
+ mv.visitVarInsn(Opcodes.ILOAD, lvPosReturn);
+ break;*/
+ }
+
+ // Return 결과 셋팅
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TRACESQL, END_METHOD, END_SIGNATURE,false);
+ }
+
+ mv.visitInsn(opcode);
+ }
+
+ @Override
+ public void visitMaxs(int maxStack, int maxLocals) {
+ Label endFinally = new Label();
+ mv.visitTryCatchBlock(startFinally, endFinally, endFinally, null);
+ mv.visitLabel(endFinally);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TRACESQL, END_METHOD, END_SIGNATURE,false);
+
+ int errIdx = newLocal(Type.getType(Throwable.class));
+ mv.visitVarInsn(Opcodes.ASTORE, errIdx);
+ mv.visitInsn(ATHROW);
+
+ mv.visitMaxs(maxStack + 8, maxLocals + 2);
+ }
+
+ public static void main(String[] args) {
+ Type type = Type.getReturnType("(Z)[I");
+ System.out.println("type = " + type.getSort());
+ System.out.println("dim = " + type.getDimensions());
+ System.out.println("element = " + type.getElementType());
+
+ }
+
+}
\ No newline at end of file
diff --git a/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/PsInitMV.java b/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/PsInitMV.java
new file mode 100644
index 000000000..90fda664e
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/PsInitMV.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2015 Scouter Project.
+ *
+ * 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.batch.asm.jdbc;
+
+import scouter.agent.Logger;
+import scouter.agent.asm.util.AsmUtil;
+import scouter.agent.batch.trace.TraceContextManager;
+import scouter.agent.batch.trace.TraceSQL;
+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;
+
+/**
+ * BCI for a constructor of PreparedStatement
+ * @author @author Paul S.J. Kim(sjkim@whatap.io)
+ * @author Gun Lee (gunlee01@gmail.com)
+ */
+public class PsInitMV extends LocalVariablesSorter implements Opcodes {
+ private final static String TRACE = TraceContextManager.class.getName().replace('.', '/');
+ private final static String METHOD = "getTraceSQL";
+ private final static String SIGNATURE = "(Ljava/lang/String;)Lscouter/agent/batch/trace/TraceSQL;";
+
+ private String owner;
+ private int sqlIdx = -1;
+ private boolean isUstatement = false;
+
+ public PsInitMV(int access, String desc, MethodVisitor mv, String owner) {
+ super(ASM4, access, desc, mv);
+ this.owner = owner;
+ this.sqlIdx = AsmUtil.getStringIdx(access, desc);
+
+ if(this.sqlIdx < 0) {
+ //CUBRID Case
+ this.sqlIdx = AsmUtil.getIdxByType(access, desc, Type.getType("Lcubrid/jdbc/jci/UStatement;"));
+ Logger.trace("CUBRID PSTMT LOAD - " + this.sqlIdx);
+ this.isUstatement = true;
+ }
+ }
+
+ @Override
+ public void visitInsn(int opcode) {
+ if (sqlIdx >= 0 && (opcode >= IRETURN && opcode <= RETURN)) {
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, sqlIdx);
+ if(isUstatement) {
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "cubrid/jdbc/jci/UStatement", "getQuery", "()Ljava/lang/String;", false);
+ }
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC, TRACE, METHOD, SIGNATURE, false);
+ mv.visitFieldInsn(PUTFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ }
+ mv.visitInsn(opcode);
+ }
+}
\ No newline at end of file
diff --git a/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/RsInitMV.java b/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/RsInitMV.java
new file mode 100644
index 000000000..0ce2623b8
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/RsInitMV.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 Scouter Project.
+ *
+ * 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.batch.asm.jdbc;
+
+import scouter.agent.batch.trace.TraceContextManager;
+import scouter.agent.batch.trace.TraceSQL;
+import scouter.org.objectweb.asm.MethodVisitor;
+import scouter.org.objectweb.asm.Opcodes;
+import scouter.org.objectweb.asm.commons.LocalVariablesSorter;
+
+/**
+ * BCI for a constructor of Resultset
+ * @author Gun Lee (gunlee01@gmail.com)
+ */
+public class RsInitMV extends LocalVariablesSorter implements Opcodes {
+
+ private final static String TRACECONTEXTMANAGER = TraceContextManager.class.getName().replace('.', '/');
+ private final static String METHOD = "getCurrentTraceSQL";
+ private final static String SIGNATURE = "()Lscouter/agent/batch/trace/TraceSQL;";
+
+ public RsInitMV(int access, String owner, String desc, MethodVisitor mv) {
+ super(ASM4, access, desc, mv);
+ this.owner = owner;
+ }
+ private String owner;
+ @Override
+ public void visitInsn(int opcode) {
+ if ((opcode >= IRETURN && opcode <= RETURN)) {
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC, TRACECONTEXTMANAGER, METHOD, SIGNATURE, false);
+ mv.visitFieldInsn(PUTFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ }
+ mv.visitInsn(opcode);
+ }
+}
\ No newline at end of file
diff --git a/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/RsNextMV.java b/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/RsNextMV.java
new file mode 100644
index 000000000..48c7701de
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/RsNextMV.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 Scouter Project.
+ *
+ * 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.batch.asm.jdbc;
+
+
+import scouter.agent.batch.trace.TraceSQL;
+import scouter.org.objectweb.asm.Label;
+import scouter.org.objectweb.asm.MethodVisitor;
+import scouter.org.objectweb.asm.Opcodes;
+
+public class RsNextMV extends MethodVisitor implements Opcodes {
+ private static final String TRACESQL = TraceSQL.class.getName().replace('.', '/');
+ private static final String METHOD = "addRow";
+ private static final String SIGNATURE = "()V";
+
+ public RsNextMV(String owner, MethodVisitor mv) {
+ super(ASM4, mv);
+ this.owner = owner;
+ }
+ private String owner;
+ @Override
+ public void visitInsn(int opcode) {
+ if ((opcode >= IRETURN && opcode <= RETURN)) {
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ Label dump = new Label();
+ mv.visitJumpInsn(IFNULL, dump);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TRACESQL, METHOD, SIGNATURE,false);
+ mv.visitLabel(dump);
+ }
+ mv.visitInsn(opcode);
+ }
+
+ @Override
+ public void visitMaxs(int maxStack, int maxLocals) {
+ mv.visitMaxs(maxStack + 4, maxLocals + 2);
+ }
+}
\ No newline at end of file
diff --git a/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/StExecuteMV.java b/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/StExecuteMV.java
new file mode 100644
index 000000000..6f887a4e8
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/asm/jdbc/StExecuteMV.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2016 Scouter Project.
+ *
+ * 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.batch.asm.jdbc;
+
+import scouter.agent.batch.trace.TraceContextManager;
+import scouter.agent.batch.trace.TraceSQL;
+import scouter.lang.step.SqlXType;
+import scouter.org.objectweb.asm.Label;
+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.HashSet;
+import java.util.Set;
+
+public class StExecuteMV extends LocalVariablesSorter implements Opcodes {
+ private static Set target = new HashSet();
+ static {
+ target.add("execute");
+ target.add("executeQuery");
+ target.add("executeUpdate");
+ target.add("executeBatch");
+ }
+
+ private final Type returnType;
+
+ public static boolean isTarget(String name) {
+ return target.contains(name);
+ }
+
+ private final static String TRACE_CONTEXT_MANAGER = TraceContextManager.class.getName().replace('.', '/');
+ private final static String START_METHOD = "startTraceSQL";
+ private final static String START_SIGNATURE = "(Ljava/lang/String;)Lscouter/agent/batch/trace/TraceSQL;";
+
+ private final static String TRACESQL = TraceSQL.class.getName().replace('.', '/');
+ private final static String END_METHOD = "end";
+ private static final String END_SIGNATURE = "()V";
+ private final static String ADD_METHOD = "addRow";
+ private static final String ADD_SIGNATURE = "(I)V";
+ private final static String ADDS_METHOD = "addRows";
+ private static final String ADDS_SIGNATURE = "([I)V";
+
+ public StExecuteMV(int access, String desc, MethodVisitor mv, String owner, String name) {
+ super(ASM4, access, desc, mv);
+ this.returnType = Type.getReturnType(desc);
+ this.owner = owner;
+ }
+
+ public static byte methodType(String name) {
+ if("execute".equals(name)){
+ return SqlXType.METHOD_EXECUTE;
+ }
+ if("executeQuery".equals(name)){
+ return SqlXType.METHOD_QUERY;
+ }
+ if("executeUpdate".equals(name)){
+ return SqlXType.METHOD_UPDATE;
+ }
+ return SqlXType.METHOD_KNOWN;
+ }
+
+ private Label startFinally = new Label();
+ private String owner;
+
+ @Override
+ public void visitCode() {
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 1);
+
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC, TRACE_CONTEXT_MANAGER, START_METHOD, START_SIGNATURE, false);
+ mv.visitFieldInsn(PUTFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ mv.visitLabel(startFinally);
+ mv.visitCode();
+ }
+
+ @Override
+ public void visitInsn(int opcode) {
+ if ((opcode >= IRETURN && opcode <= RETURN)) {
+ int lvPosReturn;
+ switch (returnType.getSort()) {
+ case Type.ARRAY:
+ if(returnType.getElementType().getSort() == Type.INT) {
+ lvPosReturn = newLocal(returnType);
+ mv.visitVarInsn(Opcodes.ASTORE, lvPosReturn);
+ mv.visitVarInsn(Opcodes.ALOAD, lvPosReturn);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ mv.visitVarInsn(Opcodes.ALOAD, lvPosReturn);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TRACESQL, ADDS_METHOD, ADDS_SIGNATURE,false);
+ }
+ break;
+ case Type.INT:
+ lvPosReturn = newLocal(returnType);
+ mv.visitVarInsn(Opcodes.ISTORE, lvPosReturn);
+ mv.visitVarInsn(Opcodes.ILOAD, lvPosReturn);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ mv.visitVarInsn(Opcodes.ILOAD, lvPosReturn);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TRACESQL, ADD_METHOD, ADD_SIGNATURE,false);
+ break;
+ }
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TRACESQL, END_METHOD, END_SIGNATURE,false);
+ }
+ mv.visitInsn(opcode);
+ }
+
+ @Override
+ public void visitMaxs(int maxStack, int maxLocals) {
+ Label endFinally = new Label();
+ mv.visitTryCatchBlock(startFinally, endFinally, endFinally, null);
+ mv.visitLabel(endFinally);
+
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, owner, TraceSQL.CURRENT_TRACESQL_FIELD, "Lscouter/agent/batch/trace/TraceSQL;");
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TRACESQL, END_METHOD, END_SIGNATURE,false);
+
+ int errIdx = newLocal(Type.getType(Throwable.class));
+ mv.visitVarInsn(Opcodes.ASTORE, errIdx);
+ mv.visitInsn(ATHROW);
+
+ mv.visitMaxs(maxStack + 8, maxLocals + 2);
+ }
+}
\ No newline at end of file
diff --git a/scouter.agent.batch/src/scouter/agent/batch/dump/ThreadDumpHandler.java b/scouter.agent.batch/src/scouter/agent/batch/dump/ThreadDumpHandler.java
new file mode 100644
index 000000000..31644284e
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/dump/ThreadDumpHandler.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2016 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.batch.dump;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import scouter.agent.batch.trace.TraceContext;
+import scouter.agent.proxy.IToolsMain;
+import scouter.agent.proxy.LoaderManager;
+import scouter.util.SystemUtil;
+import scouter.util.ThreadUtil;
+
+public class ThreadDumpHandler {
+ private static final String TOOLS_MAIN = "scouter.xtra.tools.ToolsMain";
+
+ public static void processDump(File stackFile, FileWriter stackWriter, FileWriter indexWriter, String [] filters, boolean headerExists) throws Throwable{
+ if(stackWriter == null){
+ return;
+ }
+
+ List dumpList = threadDump();
+ if(dumpList == null || dumpList.size() == 0){
+ return;
+ }
+
+ String stack = filter(dumpList, filters, headerExists);
+ if(stack == null || stack.length() == 0){
+ return;
+ }
+
+ TraceContext.getInstance().lastStack = stack;
+
+ indexWriter.write(new StringBuilder(50).append(System.currentTimeMillis()).append(' ').append(stackFile.length()).append(System.getProperty("line.separator")).toString());
+ indexWriter.flush();
+ stackWriter.write(stack);
+ stackWriter.flush();
+ }
+
+ private static String filter(List dumpList, String [] filters, boolean headerExists){
+ int i;
+ int size = dumpList.size();
+ int startIndex = 0;
+ String value;
+ String lineSeparator = System.getProperty("line.separator");
+
+ StringBuilder stackBuffer = new StringBuilder(4096);
+ if(headerExists){
+ for(i = startIndex; i < size; i++ ){
+ value = dumpList.get(i);
+ stackBuffer.append(value).append(lineSeparator);
+ if(value.length() == 0){
+ startIndex = i + 1;
+ break;
+ }
+ }
+
+ int ii;
+ boolean bSave = false;
+ boolean bScouter = false;
+ List stack = new ArrayList();
+ for(i = startIndex; i < size; i++ ){
+ value = dumpList.get(i);
+
+ if(value.length() == 0){
+ if(bSave && stack.size() > 1){
+ for(ii = 0; ii < stack.size(); ii++){
+ stackBuffer.append(stack.get(ii)).append(lineSeparator);
+ }
+ stackBuffer.append(lineSeparator);
+ }
+ stack.clear();
+ bSave = false;
+ bScouter = false;
+ continue;
+ }
+
+ if( stack.size() == 0 && !bScouter){
+ if(value.indexOf("Scouter-") >=0){
+ bScouter = true;
+ continue;
+ }
+ }
+ if(bScouter){
+ continue;
+ }
+
+ stack.add(value);
+ if(!bSave){
+ if(filters == null){
+ bSave = true;
+ continue;
+ }
+ for(ii = 0; ii < filters.length; ii++){
+ if(value.indexOf(filters[ii]) >= 0){
+ bSave = true;
+ }
+ }
+ }
+ }
+ if(bSave && stack.size() > 1){
+ for(ii = 0; ii < stack.size(); ii++){
+ stackBuffer.append(stack.get(ii)).append(lineSeparator);
+ }
+ stackBuffer.append(lineSeparator);
+ }
+ }
+ return stackBuffer.toString();
+ }
+
+ private static List threadDump() throws Throwable {
+ List out = null;
+ //Java 1.5 or IBM JDK
+ if (SystemUtil.IS_JAVA_1_5||SystemUtil.JAVA_VENDOR.startsWith("IBM")) {
+ out = ThreadUtil.getThreadDumpList();
+ return out;
+ }
+
+ ClassLoader loader = LoaderManager.getToolsLoader();
+ if (loader == null) {
+ out = ThreadUtil.getThreadDumpList();
+ return out;
+ }
+
+ try {
+ Class> c = Class.forName(TOOLS_MAIN, true, loader);
+ IToolsMain toolsMain = (IToolsMain) c.newInstance();
+ out = (List) toolsMain.threadDump(0, 100000);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return out;
+
+ }
+}
diff --git a/scouter.agent.batch/src/scouter/agent/batch/trace/LocalSQL.java b/scouter.agent.batch/src/scouter/agent/batch/trace/LocalSQL.java
new file mode 100644
index 000000000..702490ea6
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/trace/LocalSQL.java
@@ -0,0 +1,40 @@
+package scouter.agent.batch.trace;
+
+public class LocalSQL extends java.util.HashMap{
+ private static final long serialVersionUID = 1L;
+ private String currentThreadName;
+ private TraceSQL currentTraceSql;
+ private Thread currentThread;
+
+ public LocalSQL() {
+ super(100);
+ this.currentThread = Thread.currentThread();
+ this.currentThreadName = this.currentThread.getName();
+ }
+
+ public TraceSQL get(String sqlText){
+ int hashValue = sqlText.hashCode();
+ TraceSQL traceSql = super.get(hashValue);
+ if(traceSql == null){
+ hashValue = TraceContext.getInstance().getSQLHash(sqlText, hashValue);
+
+ traceSql = new TraceSQL();
+ traceSql.hashValue = hashValue;
+ super.put(hashValue, traceSql);
+ }
+ currentTraceSql = traceSql;
+ return traceSql;
+ }
+
+ public TraceSQL getCurrentTraceSQL(){
+ return currentTraceSql;
+ }
+
+ public Thread getThread(){
+ return currentThread;
+ }
+
+ public String toString(){
+ return currentThreadName + ": " + super.toString();
+ }
+}
diff --git a/scouter.agent.batch/src/scouter/agent/batch/trace/TraceContext.java b/scouter.agent.batch/src/scouter/agent/batch/trace/TraceContext.java
new file mode 100644
index 000000000..eb112e01b
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/trace/TraceContext.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2016 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.batch.trace;
+
+import java.io.File;
+import java.lang.management.ManagementFactory;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import scouter.agent.batch.Configure;
+import scouter.agent.batch.Logger;
+import scouter.util.SysJMX;
+
+public class TraceContext {
+ private static final String SQL_OTHERS = "Others";
+ private static final int SQL_OTHERS_HASH = SQL_OTHERS.hashCode();
+ private static TraceContext instance = null;
+
+ static {
+ instance = new TraceContext();
+ }
+
+ final public static TraceContext getInstance(){
+ return instance;
+ }
+
+ private TraceContext() {
+ startTime = ManagementFactory.getRuntimeMXBean().getStartTime();
+
+ readBatchId();
+ sqlMaxCount = Configure.getInstance().sql_max_count;
+ pID = SysJMX.getProcessPID();
+ startCpu = SysJMX.getProcessCPU();
+ }
+
+ private void readBatchId(){
+ Configure config = Configure.getInstance();
+ if("props".equals(config.batch_id_type)){
+ batchJobId = config.getValue(config.batch_id);
+ }else{
+ args = System.getProperty("sun.java.command");
+ StringTokenizer token = new StringTokenizer(args, " ");
+ if("args".equals(config.batch_id_type)){
+ int index = Integer.parseInt(config.batch_id);
+ int currentIndex = -1;
+ while(token.hasMoreTokens()){
+ if(currentIndex == index){
+ batchJobId = token.nextToken();
+ break;
+ }else{
+ token.nextToken();
+ }
+ currentIndex++;
+ }
+ }else if("class".equals(config.batch_id_type)){
+ if(token.hasMoreTokens()){
+ batchJobId = token.nextToken();
+ }
+ }
+ }
+
+ if(batchJobId == null || batchJobId.length() == 0){
+ batchJobId ="NoId[Scouter]";
+ }
+ Logger.println("Batch ID="+ batchJobId);
+ }
+
+ public int getSQLHash(String sqltext, int hashValue){
+ synchronized(uniqueSqls){
+ if(uniqueSqls.get(hashValue) != null){
+ return hashValue;
+ }
+
+ if(uniqueSqls.size() < sqlMaxCount){
+ uniqueSqls.put(hashValue, sqltext);
+ return hashValue;
+ }else if(uniqueSqls.size() == sqlMaxCount){
+ uniqueSqls.put(SQL_OTHERS_HASH, SQL_OTHERS);
+ }
+ return SQL_OTHERS_HASH;
+ }
+ }
+
+ public HashMap getUniqueSQLs(){
+ return uniqueSqls;
+ }
+
+ public String toString(){
+ StringBuilder buffer = new StringBuilder(100);
+ String lineSeparator = System.getProperty("line.separator");
+
+ buffer.append(lineSeparator);
+ buffer.append("-[Result]----------------------------------------------").append(lineSeparator);
+ buffer.append("Batch ID: ").append(this.batchJobId).append(lineSeparator);
+ buffer.append("Run Command: ").append(this.args).append(lineSeparator);
+ if(this.stackLogFile != null){
+ buffer.append("Stack Dump: ").append(this.stackLogFile).append(lineSeparator);
+ }
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+ buffer.append("Start Time: ").append(sdf.format(new Date(this.startTime))).append(lineSeparator);
+ buffer.append("Stop Time: ").append(sdf.format(new Date(this.endTime))).append(lineSeparator);
+ buffer.append("Elapsed Time: ").append((this.endTime - this.startTime)).append("ms").append(lineSeparator);
+ if(this.getCPUTimeByMillis() > 0){
+ buffer.append("CPU Time: ").append(this.getCPUTimeByMillis()).append("ms").append(lineSeparator);
+ }
+ if(sqlMap.size() > 0){
+ long SqlTime = 0L;
+ int sqlRunCount = 0;
+
+ for(TraceSQL traceSql : sqlMap.values()){
+ SqlTime += traceSql.totalTime;
+ sqlRunCount += traceSql.count;
+ }
+ buffer.append("SQL Time: ").append((SqlTime/1000000L)).append("ms").append(lineSeparator);
+ buffer.append("SQL Type: ").append(sqlMap.size()).append(lineSeparator);
+ buffer.append("SQL RunCount: ").append(sqlRunCount).append(lineSeparator);
+ }
+ if(threadCnt > 0){
+ buffer.append("Thread Count: ").append(this.threadCnt).append(lineSeparator);
+ }
+
+ if(sqlMap.size() > 0){
+ buffer.append(lineSeparator).append("").append(lineSeparator);
+ int index = 0;
+
+ for(TraceSQL traceSql : sortTraceSQLList()){
+ index++;
+ buffer.append("-----------").append(lineSeparator);
+ buffer.append(index).append(':').append(uniqueSqls.get(traceSql.hashValue)).append(lineSeparator);
+ buffer.append("Start Time:").append(sdf.format(new Date(traceSql.startTime))).append(lineSeparator);
+ buffer.append("End Time:").append(sdf.format(new Date(traceSql.endTime))).append(lineSeparator);
+ buffer.append("Count :").append(traceSql.count).append(lineSeparator);
+ buffer.append("Total Time:").append(traceSql.getTotalTimeByMillis()).append(lineSeparator);
+ buffer.append("Min Time:").append(traceSql.getMinTimeByMillis()).append(lineSeparator);
+ buffer.append("Max Time:").append(traceSql.getMaxTimeByMillis()).append(lineSeparator);
+ buffer.append("Rows :").append(traceSql.processedRows).append('(').append(traceSql.rowed).append(')').append(lineSeparator);
+ }
+ }
+ buffer.append("-------------------------------------------------------").append(lineSeparator);
+ return buffer.toString();
+ }
+
+ public void addSQLStats(LocalSQL localSql){
+ if(localSql == null || localSql.size() == 0){
+ return;
+ }
+
+ Integer hashValue;
+ TraceSQL statsSql;
+ for(TraceSQL sql : localSql.values()){
+ hashValue = sql.hashValue;
+ synchronized(sqlMap){
+ statsSql = sqlMap.get(hashValue);
+ if(statsSql == null){
+ statsSql = new TraceSQL();
+ statsSql.hashValue = hashValue;
+ sqlMap.put(hashValue, statsSql);
+ }
+ }
+ synchronized(statsSql){
+ statsSql.count += sql.count;
+ statsSql.totalTime += sql.totalTime;
+ statsSql.processedRows += sql.processedRows;
+ if( statsSql.startTime > sql.startTime || statsSql.startTime == -1L){
+ statsSql.startTime = sql.startTime;
+ }
+ if(statsSql.endTime < sql.endTime){
+ statsSql.endTime = sql.endTime;
+ }
+ if(statsSql.minTime > sql.minTime){
+ statsSql.minTime = sql.minTime;
+ }
+ if(statsSql.maxTime < sql.maxTime){
+ statsSql.maxTime = sql.maxTime;
+ }
+ if(sql.rowed){
+ statsSql.rowed = true;
+ }
+ }
+ }
+ }
+
+ public void caculateLast(){
+ synchronized(localSQLList){
+ for(LocalSQL localSql : localSQLList){
+ addSQLStats(localSql);
+ }
+ localSQLList.clear();
+ }
+ this.endCpu = SysJMX.getProcessCPU();
+ }
+
+ public void checkThread(){
+ Thread thread;
+ LocalSQL localSql;
+ int inx;
+
+ synchronized(localSQLList){
+ for(inx = localSQLList.size() - 1; inx >=0; inx--){
+ localSql = localSQLList.get(inx);
+ thread = localSql.getThread();
+ if(!thread.isAlive()){
+ addSQLStats(localSql);
+ localSQLList.remove(inx);
+ }
+ }
+ }
+ }
+
+ public void addLocalSQL(LocalSQL localSql){
+ synchronized(localSQLList){
+ localSQLList.add(localSql);
+ threadCnt++;
+ }
+ }
+
+ public void removeLocalSQL(LocalSQL localSql){
+ synchronized(localSQLList){
+ localSQLList.remove(localSql);
+ }
+ addSQLStats(localSql);
+ }
+
+ public List getLocalSQLList(){
+ return localSQLList;
+ }
+
+ public long getCPUTimeByMicro(){
+ return ((endCpu - startCpu)/1000L);
+ }
+
+ public long getCPUTimeByMillis(){
+ return ((endCpu - startCpu)/1000000L);
+ }
+
+ public String getLogFilename(){
+ Date dt = new Date(startTime);
+ String fileSeparator = System.getProperty("file.separator");
+ String date = new SimpleDateFormat("yyyyMMdd").format(dt);
+
+ File dir = new File(new StringBuilder(100).append(Configure.getInstance().sfa_dump_dir.getAbsolutePath()).append(fileSeparator).append(date).toString());
+ if(!dir.exists()){
+ dir.mkdirs();
+ }
+ return new StringBuilder(100).append(dir.getAbsolutePath()).append(fileSeparator).append(batchJobId).append('_').append(date).append('_').append(new SimpleDateFormat("HHmmss.SSS").format(dt)).append('_').append(pID).toString();
+ }
+
+ public List sortTraceSQLList(){
+ List inList = new ArrayList(sqlMap.size() + 1);
+ synchronized(sqlMap){
+ for(TraceSQL traceSql : sqlMap.values()){
+ inList.add(traceSql);
+ }
+ }
+ Collections.sort(inList,
+ new Comparator(){
+ @Override
+ public int compare(TraceSQL o1, TraceSQL o2) {
+ if(o1.totalTime < o2.totalTime){
+ return 1;
+ }else if(o1.totalTime > o2.totalTime){
+ return -1;
+ }
+ return 0;
+ }
+
+ });
+ return inList;
+ }
+
+ public String batchJobId;
+ public String args;
+ public Integer pID;
+
+ public long startTime;
+ public long endTime;
+
+ public int threadCnt = 0;
+ public long startCpu;
+ public long endCpu;
+
+ public String stackLogFile = null;
+ public String standAloneFile = null;
+
+ private HashMap uniqueSqls = new HashMap(100);
+ private HashMap sqlMap = new HashMap(100);
+ private List localSQLList = new ArrayList();
+
+ private int sqlMaxCount;
+
+ public String lastStack;
+}
\ No newline at end of file
diff --git a/scouter.agent.batch/src/scouter/agent/batch/trace/TraceContextManager.java b/scouter.agent.batch/src/scouter/agent/batch/trace/TraceContextManager.java
new file mode 100644
index 000000000..30cc39f72
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/trace/TraceContextManager.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 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.batch.trace;
+
+public class TraceContextManager {
+
+ private static ThreadLocal local = new ThreadLocal();
+
+ public static LocalSQL getLocalSQL(){
+ LocalSQL localSql = local.get();
+ if(localSql == null){
+ localSql = new LocalSQL();
+ local.set(localSql);
+ TraceContext.getInstance().addLocalSQL(localSql);
+ }
+ return localSql;
+ }
+
+ public static void endThread(){
+ LocalSQL localSql = local.get();
+ local.set(null);
+ TraceContext.getInstance().removeLocalSQL(localSql);
+ }
+
+ public static TraceSQL getTraceSQL(String sqlText){
+ TraceSQL traceSql = getLocalSQL().get(sqlText);
+ return traceSql;
+ }
+
+ public static TraceSQL getCurrentTraceSQL(){
+ return getLocalSQL().getCurrentTraceSQL();
+ }
+
+ public static TraceSQL startTraceSQL(String sqlText){
+ TraceSQL traceSql = getTraceSQL(sqlText);
+ traceSql.start();
+ return traceSql;
+ }
+}
\ No newline at end of file
diff --git a/scouter.agent.batch/src/scouter/agent/batch/trace/TraceSQL.java b/scouter.agent.batch/src/scouter/agent/batch/trace/TraceSQL.java
new file mode 100644
index 000000000..abdf6d66a
--- /dev/null
+++ b/scouter.agent.batch/src/scouter/agent/batch/trace/TraceSQL.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2016 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.batch.trace;
+
+public class TraceSQL {
+ public static final String CURRENT_TRACESQL_FIELD = "_current_trace_sql_";
+
+ public Integer hashValue;
+ public int count = 0;
+
+ public long startTime = -1L;
+ public long endTime = 0L;
+ public long totalTime = 0L;
+ public long minTime = Long.MAX_VALUE;
+ public long maxTime = 0L;
+ public long processedRows = 0L;
+ public boolean rowed = false;
+
+ public long sqlStartTime;
+
+ public void start(){
+ if(startTime == -1L){
+ startTime = System.currentTimeMillis();
+ }
+ sqlStartTime = System.nanoTime();
+ }
+
+ public void end(){
+ long responseTime = System.nanoTime() - sqlStartTime;
+ count++;
+ totalTime += responseTime;
+
+ if(minTime > responseTime){
+ minTime = responseTime;
+ }
+ if(maxTime < responseTime){
+ maxTime = responseTime;
+ }
+ endTime = System.currentTimeMillis();
+ }
+
+ public void addRow(){
+ if(!rowed) rowed = true;
+ processedRows++;
+ }
+
+ public void addRow(int rows){
+ if(!rowed) rowed = true;
+ if(rows > 0){
+ processedRows += rows;
+ }
+ }
+
+ public void addRows(int [] rows){
+ if(rows == null || rows.length < 1)
+ return;
+
+ if(!rowed) rowed = true;
+ for(int i = 0; i < rows.length; i++){
+ if(rows[i] > 0){
+ processedRows += rows[i];
+ }else if(rows[i] == -2){
+ processedRows++;
+ }
+ }
+ }
+
+ public long getTotalTimeByMillis(){
+ return totalTime / 1000000L;
+ }
+
+ public long getTotalTimeByMicro(){
+ return totalTime / 1000L;
+ }
+
+ public long getMinTimeByMillis(){
+ return minTime / 1000000L;
+ }
+
+ public long getMinTimeByMicro(){
+ return minTime / 1000L;
+ }
+
+ public long getMaxTimeByMillis(){
+ return maxTime / 1000000L;
+ }
+
+ public long getMaxTimeByMicro(){
+ return maxTime / 1000L;
+ }
+
+}
diff --git a/scouter.agent.host/src/scouter/agent/Configure.java b/scouter.agent.host/src/scouter/agent/Configure.java
index 5f29ecda2..055c23573 100644
--- a/scouter.agent.host/src/scouter/agent/Configure.java
+++ b/scouter.agent.host/src/scouter/agent/Configure.java
@@ -90,6 +90,7 @@ public final static synchronized Configure getInstance() {
public int cpu_fatal_pct = 90;
public int cpu_warning_history = 3;
public int cpu_fatal_history = 3;
+ public int _cpu_value_avg_sec = 10;
//Memory
public boolean mem_alert_enabled = false;
@@ -203,7 +204,7 @@ private void apply() {
this.counter_object_registry_path = getValue("counter_object_registry_path", "/tmp/scouter");
- this.disk_alert_enabled = getBoolean("disk_alert_enablee", true);
+ this.disk_alert_enabled = getBoolean("disk_alert_enabled", true);
this.disk_warning_pct = getInt("disk_warning_pct", 70);
this.disk_fatal_pct = getInt("disk_fatal_pct", 90);
this.disk_ignore_names = getStringSet("disk_ignore_names", ",");
@@ -215,6 +216,7 @@ private void apply() {
this.cpu_fatal_pct = getInt("cpu_fatal_pct", 90);
this.cpu_warning_history = getInt("cpu_warning_history", 3);
this.cpu_fatal_history = getInt("cpu_fatal_history", 3);
+ this._cpu_value_avg_sec = getInt("_cpu_value_avg_sec", 10);
this.mem_alert_enabled = getBoolean("mem_alert_enabled", false);
this.mem_alert_interval_ms = getLong("mem_alert_interval_ms", 30000);
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 d4db43aca..a27bf9eef 100644
--- a/scouter.agent.host/src/scouter/agent/counter/task/HostPerf.java
+++ b/scouter.agent.host/src/scouter/agent/counter/task/HostPerf.java
@@ -69,9 +69,9 @@ void domain(CounterBasket pw) throws SigarException {
float userCpu = (float) cpuPerc.getUser() * 100;
userCpuMeter.add(userCpu);
- cpu = (float) cpuMeter.getAvg(10);
- sysCpu = (float) sysCpuMeter.getAvg(10);
- userCpu = (float) userCpuMeter.getAvg(10);
+ cpu = (float) cpuMeter.getAvg(conf._cpu_value_avg_sec);
+ sysCpu = (float) sysCpuMeter.getAvg(conf._cpu_value_avg_sec);
+ userCpu = (float) userCpuMeter.getAvg(conf._cpu_value_avg_sec);
alertCpu(cpu);
@@ -308,7 +308,7 @@ public void disk(CounterBasket pw) {
}
} catch (Throwable t) {
- Logger.println("DISK", 10, "disk perf error", t);
+ Logger.println("DISK", 60, "disk perf error", t);
}
}
diff --git a/scouter.agent.host/src/scouter/agent/counter/task/ProcPerf.java b/scouter.agent.host/src/scouter/agent/counter/task/ProcPerf.java
index c54c3fe01..9f45b867b 100644
--- a/scouter.agent.host/src/scouter/agent/counter/task/ProcPerf.java
+++ b/scouter.agent.host/src/scouter/agent/counter/task/ProcPerf.java
@@ -1,6 +1,8 @@
package scouter.agent.counter.task;
import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
import org.hyperic.sigar.ProcCpu;
import org.hyperic.sigar.Sigar;
@@ -12,6 +14,7 @@
import scouter.agent.Logger;
import scouter.agent.counter.CounterBasket;
import scouter.agent.counter.anotation.Counter;
+import scouter.agent.counter.meter.MeterResource;
import scouter.lang.TimeTypeEnum;
import scouter.lang.conf.ConfObserver;
import scouter.lang.counters.CounterConstants;
@@ -25,8 +28,10 @@ public class ProcPerf {
static int SLEEP_TIME = 2000;
static Sigar sigarImpl = new Sigar();
static SigarProxy sigar = SigarProxyCache.newInstance(sigarImpl, SLEEP_TIME);
-
+
private static File regRoot = null;
+
+ Map meterMap = new HashMap();
public static void ready() {
String objReg = Configure.getInstance().counter_object_registry_path;
@@ -83,13 +88,20 @@ public void process(CounterBasket pw) {
String objname = new String(FileUtil.readAll(pids[i]));
+ MeterResource meter = meterMap.get(objname);
+ if (meter == null) {
+ meter = new MeterResource();
+ meterMap.put(objname, meter);
+ }
try {
ProcCpu cpu = sigar.getProcCpu(pid);
double value = cpu.getPercent() * 100.0D/cpuCores;
+ meter.add(value);
+ float procCpu = (float) meter.getAvg(Configure.getInstance()._cpu_value_avg_sec);
PerfCounterPack p = pw.getPack(objname, TimeTypeEnum.REALTIME);
- p.put(CounterConstants.PROC_CPU, new FloatValue((float) value));
+ p.put(CounterConstants.PROC_CPU, new FloatValue(procCpu));
p = pw.getPack(objname, TimeTypeEnum.FIVE_MIN);
- p.put(CounterConstants.PROC_CPU, new FloatValue((float) value));
+ p.put(CounterConstants.PROC_CPU, new FloatValue(procCpu));
} catch (Exception e) {
// ignore no proc
}
diff --git a/scouter.agent.java/src/scouter/agent/Configure.java b/scouter.agent.java/src/scouter/agent/Configure.java
index b4b8c5571..75fcb2be3 100644
--- a/scouter.agent.java/src/scouter/agent/Configure.java
+++ b/scouter.agent.java/src/scouter/agent/Configure.java
@@ -18,6 +18,7 @@
import scouter.Version;
import scouter.agent.netio.data.DataProxy;
+import scouter.agent.util.JarUtil;
import scouter.lang.conf.ConfObserver;
import scouter.lang.conf.ConfigValueUtil;
import scouter.lang.counters.CounterConstants;
@@ -36,6 +37,15 @@ public class Configure extends Thread {
private boolean running = true;
private File propertyFile;
long last_check = 0;
+ public static String agent_dir_path;
+ static {
+ File jarFile = JarUtil.getThisJarFile();
+ if (jarFile == null) {
+ agent_dir_path = new File("./").getAbsolutePath();
+ } else {
+ agent_dir_path = jarFile.getParent();
+ }
+ }
public final static synchronized Configure getInstance() {
if (instance == null) {
@@ -115,13 +125,14 @@ public final static synchronized Configure getInstance() {
public String trace_webserver_name_header_key = "X-Forwarded-Host";
public String trace_webserver_time_header_key = "X-Forwarded-Time";
public int _trace_fullstack_socket_open_port = 0;
+ public int _trace_sql_parameter_max_count = 128;
public boolean trace_rs_leak_enabled = false;
public boolean trace_stmt_leak_enabled = false;
//Dir
- public File plugin_dir = new File("./plugin");
- public File dump_dir = new File("./dump");
+ public File plugin_dir = new File(agent_dir_path + "/plugin");
+ public File dump_dir = new File(agent_dir_path + "/dump");
//public File mgr_agent_lib_dir = new File("./_scouter_");
//Manager
@@ -143,7 +154,7 @@ public final static synchronized Configure getInstance() {
//Alert
public int alert_message_length = 3000;
- public long alert_send_interval_ms = 3000;
+ public long alert_send_interval_ms = 10000;
public int alert_perm_warning_pct = 90;
//Log
@@ -280,7 +291,7 @@ public File getPropertyFile() {
if (propertyFile != null) {
return propertyFile;
}
- String s = System.getProperty("scouter.config", "./scouter.conf");
+ String s = System.getProperty("scouter.config", agent_dir_path + "/conf/scouter.conf");
propertyFile = new File(s.trim());
return propertyFile;
}
@@ -321,7 +332,7 @@ private void apply() {
this.trace_service_name_header_key = getValue("trace_service_name_header_key", null);
this.trace_service_name_get_key = getValue("trace_service_name_get_key");
this.trace_service_name_post_key = getValue("trace_service_name_post_key");
- this.dump_dir = new File(getValue("dump_dir", "./dump"));
+ this.dump_dir = new File(getValue("dump_dir", agent_dir_path + "/dump"));
try {
this.dump_dir.mkdirs();
} catch (Exception e) {
@@ -331,7 +342,7 @@ private void apply() {
// this.mgr_agent_lib_dir.mkdirs();
// } catch (Exception e) {
// }
- this.plugin_dir = new File(getValue("plugin_dir", "./plugin"));
+ this.plugin_dir = new File(getValue("plugin_dir", agent_dir_path + "/plugin"));
this.autodump_enabled = getBoolean("autodump_enabled", false);
this.autodump_trigger_active_service_cnt = getInt("autodump_trigger_active_service_cnt", 10000);
@@ -495,13 +506,14 @@ private void apply() {
this.alert_perm_warning_pct = getInt("alert_perm_warning_pct", 90);
this._hook_spring_rest_enabled = getBoolean("_hook_spring_rest_enabled", false);
this.alert_message_length = getInt("alert_message_length", 3000);
- this.alert_send_interval_ms = getInt("alert_send_interval_ms", 3000);
+ this.alert_send_interval_ms = getInt("alert_send_interval_ms", 10000);
this.xlog_error_jdbc_fetch_max = getInt("xlog_error_jdbc_fetch_max", 10000);
this.xlog_error_sql_time_max_ms = getInt("xlog_error_sql_time_max_ms", 30000);
this._log_asm_enabled = getBoolean("_log_asm_enabled", false);
this.obj_type_inherit_to_child_enabled = getBoolean("obj_type_inherit_to_child_enabled", false);
this._profile_fullstack_sql_connection_enabled = getBoolean("_profile_fullstack_sql_connection_enabled", false);
this._trace_fullstack_socket_open_port = getInt("_trace_fullstack_socket_open_port", 0);
+ this._trace_sql_parameter_max_count = getInt("_trace_sql_parameter_max_count", 128);
this.log_dir = getValue("log_dir", "");
this.log_rotation_enabled = getBoolean("log_rotation_enabled", true);
this.log_keep_days = getInt("log_keep_days", 7);
@@ -610,7 +622,7 @@ public synchronized void resetObjInfo() {
this.objHash = HashUtil.hash(objName);
System.setProperty("scouter.objname", this.objName);
System.setProperty("scouter.objtype", this.obj_type);
- System.setProperty("scouter.dir", new File(".").getAbsolutePath());
+ System.setProperty("scouter.dir", agent_dir_path);
}
public String getValue(String key) {
return StringUtil.trim(property.getProperty(key));
diff --git a/scouter.agent.java/src/scouter/agent/asm/JDBCResultSetASM.java b/scouter.agent.java/src/scouter/agent/asm/JDBCResultSetASM.java
index a39f883c1..a0cd2c08f 100644
--- a/scouter.agent.java/src/scouter/agent/asm/JDBCResultSetASM.java
+++ b/scouter.agent.java/src/scouter/agent/asm/JDBCResultSetASM.java
@@ -44,7 +44,7 @@ public JDBCResultSetASM() {
target.add("oracle/jdbc/driver/SensitiveScrollableResultSet");
target.add("org/hsqldb/jdbc/JDBCResultSet");
target.add("cubrid/jdbc/driver/CUBRIDResultSet");
- target.add("org.mariadb.jdbc.MariaDbResultSet");
+ target.add("org/mariadb/jdbc/MariaDbResultSet");
}
public ClassVisitor transform(ClassVisitor cv, String className, ClassDesc classDesc) {
diff --git a/scouter.agent.java/src/scouter/agent/counter/task/Debug.java b/scouter.agent.java/src/scouter/agent/counter/task/Debug.java
index 51515a0b2..1de035de1 100644
--- a/scouter.agent.java/src/scouter/agent/counter/task/Debug.java
+++ b/scouter.agent.java/src/scouter/agent/counter/task/Debug.java
@@ -8,9 +8,11 @@
import scouter.agent.Logger;
import scouter.agent.counter.CounterBasket;
import scouter.agent.counter.anotation.Counter;
+import scouter.agent.trace.AlertProxy;
import scouter.agent.trace.TraceContext;
import scouter.agent.trace.TraceContextManager;
import scouter.agent.util.DumpUtil;
+import scouter.lang.AlertLevel;
import scouter.util.DateUtil;
import scouter.util.FileUtil;
import scouter.util.Hexa32;
@@ -22,6 +24,7 @@ public void autoStack(CounterBasket pw) {
if (conf.autodump_stuck_thread_ms <= 0)
return;
PrintWriter out = null;
+ StringBuilder msg = new StringBuilder();
try {
Enumeration en = TraceContextManager.getContextEnumeration();
while (en.hasMoreElements()) {
@@ -57,11 +60,21 @@ public void autoStack(CounterBasket pw) {
FileUtil.close(out);
return;
}
+ msg.append(ctx.serviceName + System.getProperty("line.separator"));
+ msg.append(etime + " ms" + System.getProperty("line.separator"));
+ msg.append(ctx.thread.getName() + ":");
+ msg.append(ctx.thread.getState().name() + ":");
+ msg.append("cpu " + SysJMX.getThreadCpuTime(ctx.thread) + System.getProperty("line.separator"));
+ msg.append(Hexa32.toString32(ctx.txid) + System.getProperty("line.separator"));
+ msg.append(System.getProperty("line.separator"));
}
}
} finally {
FileUtil.close(out);
}
+ if (msg.length() > 0) {
+ AlertProxy.sendAlert(AlertLevel.WARN, "DELAYED_SERVICE", msg.toString());
+ }
}
public PrintWriter open() throws IOException {
File file = new File(Configure.getInstance().dump_dir, "longtx_" +Configure.getInstance().obj_name + "_"+DateUtil.timestampFileName()+".txt");
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 3f80f2996..d379b360f 100644
--- a/scouter.agent.java/src/scouter/agent/counter/task/TomcatJMXPerf.java
+++ b/scouter.agent.java/src/scouter/agent/counter/task/TomcatJMXPerf.java
@@ -174,10 +174,10 @@ private void getMBeanList() {
if (context != null && context.length() > 0) {
context = context.substring(1);
}
- if (StringUtil.isEmpty(context)) {
- context = "ROOT";
+ if (StringUtil.isNotEmpty(context)) {
+ name = context + "_" + name;
}
- String objName = conf.getObjName() + "/" + checkObjName(context + "_" + name);
+ String objName = conf.getObjName() + "/" + checkObjName(name);
String objType = getDataSourceType();
AgentHeartBeat.addObject(objType, HashUtil.hash(objName), objName);
add(objName, mbean, objType, ValueEnum.DECIMAL, "numActive",
diff --git a/scouter.agent.java/src/scouter/agent/netio/request/handle/AgentEnv.java b/scouter.agent.java/src/scouter/agent/netio/request/handle/AgentEnv.java
index dc1c6ccb8..7b0571441 100644
--- a/scouter.agent.java/src/scouter/agent/netio/request/handle/AgentEnv.java
+++ b/scouter.agent.java/src/scouter/agent/netio/request/handle/AgentEnv.java
@@ -92,7 +92,7 @@ public Pack getDumpFileList(Pack param) {
File dumpDir = Configure.getInstance().dump_dir;
if (dumpDir.canRead()) {
for (File file : dumpDir.listFiles()) {
- if (file.isFile() && file.getName().startsWith("scouter.") && file.getName().endsWith(".dump")) {
+ if (file.isFile()) {
nameLv.add(file.getName());
sizeLv.add(file.length());
lastModifedLv.add(file.lastModified());
diff --git a/scouter.agent.java/src/scouter/agent/netio/request/handle/AgentHeapDump.java b/scouter.agent.java/src/scouter/agent/netio/request/handle/AgentHeapDump.java
index f3f2e0063..88208641c 100644
--- a/scouter.agent.java/src/scouter/agent/netio/request/handle/AgentHeapDump.java
+++ b/scouter.agent.java/src/scouter/agent/netio/request/handle/AgentHeapDump.java
@@ -23,6 +23,7 @@
import java.lang.management.ManagementFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.Date;
import javax.management.MBeanServer;
@@ -36,6 +37,7 @@
import scouter.net.RequestCmd;
import scouter.net.TcpFlag;
import scouter.util.DateUtil;
+import scouter.util.FormatUtil;
import scouter.util.SystemUtil;
@@ -58,7 +60,7 @@ public Pack callHeapDump(Pack param) {
lastCallTime = curTime;
long time = ((MapPack) param).getLong("time");
String yyyymmdd = DateUtil.yyyymmdd(time);
- String hhmmss = DateUtil.hhmmss(time);
+ String hhmmss = FormatUtil.print(new Date(time), "HHmmss");
String fName = yyyymmdd + "-" + hhmmss + ((MapPack) param).getText("fName").replaceAll("/", "_") + fileExt;
File hprofDir = new File(folderName);
diff --git a/scouter.agent.java/src/scouter/agent/trace/SqlParameter.java b/scouter.agent.java/src/scouter/agent/trace/SqlParameter.java
index 2b7323496..1f1f69b1f 100644
--- a/scouter.agent.java/src/scouter/agent/trace/SqlParameter.java
+++ b/scouter.agent.java/src/scouter/agent/trace/SqlParameter.java
@@ -17,8 +17,10 @@
package scouter.agent.trace;
+import scouter.agent.Configure;
+
public class SqlParameter {
- private final static int MAX_SIZE = 128;
+ private final static int MAX_SIZE = Configure.getInstance()._trace_sql_parameter_max_count;
protected int count = 0;
protected String[] entry = new String[MAX_SIZE];
protected String sql;
@@ -39,11 +41,12 @@ public String getSql() {
}
public void put(int x, String value) {
- if (MAX_SIZE <= x)
+ int inx = x - 1;
+ if (MAX_SIZE <= inx || inx < 0)
return;
- entry[x] = value;
- if (x >= count) {
- count = x + 1;
+ entry[inx] = value;
+ if (inx >= count) {
+ count = inx + 1;
}
}
diff --git a/scouter.agent.java/src/scouter/agent/trace/TraceMain.java b/scouter.agent.java/src/scouter/agent/trace/TraceMain.java
index 872d4c071..c903aa1dd 100644
--- a/scouter.agent.java/src/scouter/agent/trace/TraceMain.java
+++ b/scouter.agent.java/src/scouter/agent/trace/TraceMain.java
@@ -220,13 +220,16 @@ public static void endHttpService(Object stat, Throwable thr) {
String emsg = thr.toString();
if (conf.profile_fullstack_service_error_enabled) {
StringBuffer sb = new StringBuffer();
- sb.append(emsg).append("\n");
+ sb.append(thr.getClass().getName()).append("\n");
ThreadUtil.getStackTrace(sb, thr, conf.profile_fullstack_max_lines);
- thr = thr.getCause();
- while (thr != null) {
- sb.append("\nCause...\n");
- ThreadUtil.getStackTrace(sb, thr, conf.profile_fullstack_max_lines);
- thr = thr.getCause();
+ Throwable thrCause = thr.getCause();
+ if(thrCause != null) {
+ thr = thrCause;
+ while (thr != null) {
+ sb.append("\nCause...\n");
+ ThreadUtil.getStackTrace(sb, thr, conf.profile_fullstack_max_lines);
+ thr = thr.getCause();
+ }
}
emsg = sb.toString();
}
@@ -328,11 +331,14 @@ public static void endHttpService(Object stat, Throwable thr) {
StringBuffer sb = new StringBuffer();
sb.append(emsg).append("\n");
ThreadUtil.getStackTrace(sb, thr, conf.profile_fullstack_max_lines);
- thr = thr.getCause();
- while (thr != null) {
- sb.append("\nCause...\n");
- ThreadUtil.getStackTrace(sb, thr, conf.profile_fullstack_max_lines);
- thr = thr.getCause();
+ Throwable thrCause = thr.getCause();
+ if(thrCause != null) {
+ thr = thrCause;
+ while (thr != null) {
+ sb.append("\nCause...\n");
+ ThreadUtil.getStackTrace(sb, thr, conf.profile_fullstack_max_lines);
+ thr = thr.getCause();
+ }
}
emsg = sb.toString();
}
@@ -520,11 +526,14 @@ private static int errorCheck(TraceContext ctx, Throwable thr) {
StringBuffer sb = new StringBuffer();
sb.append(emsg).append("\n");
ThreadUtil.getStackTrace(sb, thr, conf.profile_fullstack_max_lines);
- thr = thr.getCause();
- while (thr != null) {
- sb.append("\nCause...\n");
- ThreadUtil.getStackTrace(sb, thr, conf.profile_fullstack_max_lines);
- thr = thr.getCause();
+ Throwable thrCause = thr.getCause();
+ if(thrCause != null) {
+ thr = thrCause;
+ while (thr != null) {
+ sb.append("\nCause...\n");
+ ThreadUtil.getStackTrace(sb, thr, conf.profile_fullstack_max_lines);
+ thr = thr.getCause();
+ }
}
emsg = sb.toString();
}
diff --git a/scouter.agent.java/src/scouter/agent/util/JarUtil.java b/scouter.agent.java/src/scouter/agent/util/JarUtil.java
new file mode 100644
index 000000000..050394f43
--- /dev/null
+++ b/scouter.agent.java/src/scouter/agent/util/JarUtil.java
@@ -0,0 +1,45 @@
+/*
+ * 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.util;
+
+import java.io.File;
+
+import scouter.agent.JavaAgent;
+
+public class JarUtil {
+
+ public static File getThisJarFile() {
+ String path = "";
+ ClassLoader cl = JavaAgent.class.getClassLoader();
+ if (cl == null) {
+ path = ""
+ + ClassLoader.getSystemClassLoader().getResource(JavaAgent.class.getName().replace('.', '/') + ".class");
+ } else {
+ path = "" + cl.getResource(JavaAgent.class.getName().replace('.', '/') + ".class");
+ }
+ try {
+ path = path.substring("jar:file:/".length(), path.indexOf("!"));
+ if (path.indexOf(':') > 0)
+ return new File(path);
+ else
+ return new File("/" + path);
+ } catch (Throwable th) {
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/scouter.client/.classpath b/scouter.client/.classpath
index 7ca0cae0e..d86caac0b 100644
--- a/scouter.client/.classpath
+++ b/scouter.client/.classpath
@@ -1,5 +1,6 @@
+
diff --git a/scouter.client/META-INF/MANIFEST.MF b/scouter.client/META-INF/MANIFEST.MF
index 94739e892..d0c03478c 100644
--- a/scouter.client/META-INF/MANIFEST.MF
+++ b/scouter.client/META-INF/MANIFEST.MF
@@ -18,4 +18,5 @@ Bundle-ActivationPolicy: lazy
Bundle-ClassPath: .,
lib/scouter.common.jar,
lib/hibernate-core-3.3.2.GA.jar,
- lib/opencsv-2.4.jar
+ lib/opencsv-2.4.jar,
+ lib/opal-1.0.3.jar
diff --git a/scouter.client/lib/opal-1.0.3.jar b/scouter.client/lib/opal-1.0.3.jar
new file mode 100644
index 000000000..ac9d137b1
Binary files /dev/null and b/scouter.client/lib/opal-1.0.3.jar differ
diff --git a/scouter.client/src/scouter/client/configuration/views/ConfigureView.java b/scouter.client/src/scouter/client/configuration/views/ConfigureView.java
index 52210259f..cb3430520 100644
--- a/scouter.client/src/scouter/client/configuration/views/ConfigureView.java
+++ b/scouter.client/src/scouter/client/configuration/views/ConfigureView.java
@@ -226,7 +226,7 @@ private void saveConfigurations(){
TcpProxy tcp = TcpProxy.getTcpProxy(serverId);
try {
MapPack param = new MapPack();
- param.put("setConfig", text.getText());
+ param.put("setConfig", text.getText().replaceAll("\\\\", "\\\\\\\\"));
MapPack out = null;
if (objHash == 0) {
out = (MapPack) tcp.getSingle(RequestCmd.SET_CONFIGURE_SERVER, param);
diff --git a/scouter.client/src/scouter/client/net/LoginMgr.java b/scouter.client/src/scouter/client/net/LoginMgr.java
index 73bbfebee..6c9243c02 100644
--- a/scouter.client/src/scouter/client/net/LoginMgr.java
+++ b/scouter.client/src/scouter/client/net/LoginMgr.java
@@ -37,12 +37,21 @@ public static LoginResult login(int serverId, String user, String password){
return silentLogin(server, user, encrypted);
}
- public static LoginResult silentLogin(Server server, String user, String encryptedPwd){
+ public static LoginResult login(int serverId, String user, String password, boolean secureLogin){
+ Server server = ServerManager.getInstance().getServer(serverId);
+ if(secureLogin) {
+ password = CipherUtil.sha256(password);
+ }
+ server.setSecureMode(secureLogin);
+ return silentLogin(server, user, password);
+ }
+
+ public static LoginResult silentLogin(Server server, String user, String password){
LoginResult result = new LoginResult();
try {
MapPack param = new MapPack();
param.put("id", user);
- param.put("pass", encryptedPwd);
+ param.put("pass", password);
param.put("version", Version.getClientFullVersion());
param.put("hostname", SysJMX.getHostName());
@@ -71,7 +80,7 @@ public static LoginResult silentLogin(Server server, String user, String encrypt
server.setName(serverName);
server.setDelta(time);
server.setUserId(user);
- server.setPassword(encryptedPwd);
+ server.setPassword(password);
server.setGroup(type);
server.setVersion(version);
server.setEmail(email);
@@ -121,4 +130,5 @@ public static MapPack getCounterXmlServer(int serverId) {
}
return (MapPack) p;
}
+
}
diff --git a/scouter.client/src/scouter/client/net/TcpProxy.java b/scouter.client/src/scouter/client/net/TcpProxy.java
index 21b842d38..9ce1d6292 100644
--- a/scouter.client/src/scouter/client/net/TcpProxy.java
+++ b/scouter.client/src/scouter/client/net/TcpProxy.java
@@ -57,9 +57,11 @@ public static synchronized TcpProxy getTcpProxy(int serverId) {
public static synchronized void putTcpProxy(TcpProxy t) {
if (t == null)
return;
- if (t.isValid()) {
+ if (t.isValid() && t.getServer().isConnected()) {
ConnectionPool pool = t.getServer().getConnectionPool();
pool.put(t);
+ } else {
+ t.close();
}
}
@@ -152,9 +154,14 @@ public synchronized void process(String cmd, Object param, INetReader recv) {
out.writePack((Pack) param);
}
out.flush();
- while (in.readByte() == TcpFlag.HasNEXT) {
+ byte resFlag;
+ while ((resFlag = in.readByte()) == TcpFlag.HasNEXT) {
recv.process(in);
}
+ if (resFlag == TcpFlag.INVALID_SESSION) {
+ server.setSession(0); // SessionObserver will relogin
+ tcp.close();
+ }
} catch (Throwable e) {
tcp.close();
}
diff --git a/scouter.client/src/scouter/client/popup/AlertNotifierDialog.java b/scouter.client/src/scouter/client/popup/AlertNotifierDialog.java
index 52fd89f0c..df6103070 100644
--- a/scouter.client/src/scouter/client/popup/AlertNotifierDialog.java
+++ b/scouter.client/src/scouter/client/popup/AlertNotifierDialog.java
@@ -17,6 +17,7 @@
*/
package scouter.client.popup;
+import java.util.Date;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
@@ -47,6 +48,7 @@
import scouter.lang.AlertLevel;
import scouter.lang.pack.AlertPack;
import scouter.util.DateUtil;
+import scouter.util.FormatUtil;
public class AlertNotifierDialog {
@@ -133,7 +135,7 @@ private Shell setDialogLayout() {
mainComp.setLayout(UIUtil.formLayout(0, 0));
timeLbl = new Label(mainComp, SWT.RIGHT);
- timeLbl.setText(DateUtil.getLogTime(p.time));
+ timeLbl.setText(FormatUtil.print(new Date(p.time), "HH:mm:ss.sss"));
timeLbl.setLayoutData(UIUtil.formData(0, 5, 0, 0, 100, -5, null, -1));
FontData[] fD = timeLbl.getFont().getFontData();
fD[0].setStyle(SWT.BOLD);
diff --git a/scouter.client/src/scouter/client/popup/LoginDialog.java b/scouter.client/src/scouter/client/popup/LoginDialog.java
index e67eca326..adde90395 100644
--- a/scouter.client/src/scouter/client/popup/LoginDialog.java
+++ b/scouter.client/src/scouter/client/popup/LoginDialog.java
@@ -74,11 +74,11 @@ public class LoginDialog {
List list;
- Button autoLoginCheck, showPass;
+ Button autoLoginCheck, secureCheck;
boolean autoLogin;
+ boolean secureLogin = true;
String address = null;
- boolean showPassword = false;
public LoginDialog(Display display, ILoginDialog callback, int openType) {
this(display, callback, openType, null);
@@ -151,26 +151,11 @@ public void focusGained(FocusEvent e) {
passLabel.setText("Password :");
passLabel.setLayoutData(UIUtil.formData(null, -1, id, 10, null, -1, null, -1, 100));
- createPasswordInput(parentGroup, showPassword, "");
-
- showPass = new Button(parentGroup, SWT.CHECK);
- showPass.setText("Show password");
- showPass.setSelection(showPassword);
- showPass.setLayoutData(UIUtil.formData(null, -1, passLabel, 10, 100, -5, null, -1));
- showPass.addSelectionListener(new SelectionAdapter() {
- public void widgetSelected(SelectionEvent e) {
- String ontyping = pass.getText();
- if (pass != null && !pass.isDisposed()) {
- pass.dispose();
- }
- createPasswordInput(parentGroup, showPass.getSelection(), ontyping);
- parentGroup.layout();
- }
- });
+ createPasswordInput(parentGroup);
autoLoginCheck = new Button(parentGroup, SWT.CHECK);
autoLoginCheck.setText("Auto Login");
- autoLoginCheck.setLayoutData(UIUtil.formData(null, -1, showPass, 10, 100, -5, null, -1));
+ autoLoginCheck.setLayoutData(UIUtil.formData(null, -1, passLabel, 10, 100, -5, null, -1));
autoLoginCheck.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (autoLoginCheck.getSelection()) {
@@ -181,12 +166,28 @@ public void widgetSelected(SelectionEvent e) {
}
});
autoLoginCheck.setSelection(false);
-
+
+ // to hash password before transfer, default true
+ secureCheck = new Button(parentGroup, SWT.CHECK);
+ secureCheck.setText("Secure Login");
+ secureCheck.setLayoutData(UIUtil.formData(null, -1, passLabel, 10, autoLoginCheck, -5, null, -1));
+ secureCheck.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ if (secureCheck.getSelection()) {
+ secureLogin = true;
+ } else {
+ secureLogin = false;
+ }
+ }
+ });
+ secureCheck.setSelection(true);
+
list = new List(parentGroup, SWT.NONE);
- list.setLayoutData(UIUtil.formData(0, 5, autoLoginCheck, 10, 100, -5, null, -1, -1, 60));
+ list.setLayoutData(UIUtil.formData(0, 5, secureCheck, 10, 100, -5, null, -1, -1, 60));
list.add("Type your authentication info...");
list.select(list.getItemCount() - 1);
list.showSelection();
+
Composite footer = new Composite(shell, SWT.NONE);
footer.setLayoutData(UIUtil.formData(0, 5, parentGroup, 10, 100, -5, null, -1));
@@ -235,6 +236,7 @@ public void widgetDefaultSelected(SelectionEvent e) {
Server server = ServerManager.getInstance().getServer(address);
if (server != null && StringUtil.isNotEmpty(server.getUserId())) {
id.setText(server.getUserId());
+ secureCheck.setSelection(server.isSecureMode());
}
autoLoginCheck.setSelection(ServerPrefUtil.isAutoLoginAddress(address));
} else if (openType == TYPE_STARTUP){
@@ -284,13 +286,8 @@ public void close() {
}
}
- private void createPasswordInput(Composite parentGroup, boolean showPassword, String ontyping) {
- if (showPassword) {
- pass = new Text(parentGroup, SWT.SINGLE | SWT.BORDER);
- } else {
- pass = new Text(parentGroup, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
- }
- pass.setText(ontyping);
+ private void createPasswordInput(Composite parentGroup) {
+ pass = new Text(parentGroup, SWT.SINGLE | SWT.BORDER | SWT.PASSWORD);
pass.addFocusListener(new FocusListener() {
public void focusLost(FocusEvent e) {
}
@@ -336,7 +333,7 @@ public boolean loginInToServer(String address) {
existServer = true;
}
- LoginResult result = LoginMgr.login(server.getId(), id.getText(), pass.getText());
+ LoginResult result = LoginMgr.login(server.getId(), id.getText(), pass.getText(), secureLogin);
if (result.success) {
msg("Successfully log in to " + address);
ServerPrefUtil.addServerAddr(address);
diff --git a/scouter.client/src/scouter/client/popup/ObjectPropertiesDialog.java b/scouter.client/src/scouter/client/popup/ObjectPropertiesDialog.java
index 241def834..30ac25efe 100644
--- a/scouter.client/src/scouter/client/popup/ObjectPropertiesDialog.java
+++ b/scouter.client/src/scouter/client/popup/ObjectPropertiesDialog.java
@@ -18,6 +18,7 @@
package scouter.client.popup;
import java.util.ArrayList;
+import java.util.Date;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ArrayContentProvider;
@@ -52,6 +53,7 @@
import scouter.net.RequestCmd;
import scouter.util.CastUtil;
import scouter.util.DateUtil;
+import scouter.util.FormatUtil;
public class ObjectPropertiesDialog {
@@ -144,7 +146,7 @@ private void makeTableContents() {
propertyList.add(new PropertyData("address", this.objectPack.address));
propertyList.add(new PropertyData("version", this.objectPack.version));
propertyList.add(new PropertyData("alive", String.valueOf(this.objectPack.alive)));
- propertyList.add(new PropertyData("wakeUp", DateUtil.timestamp(this.objectPack.wakeup)));
+ propertyList.add(new PropertyData("wakeUp", FormatUtil.print(new Date(this.objectPack.wakeup), "yyyyMMdd HH:mm:ss.sss")));
propertyList.add(new PropertyData("color", AgentColorManager.getInstance().assignColor(this.objectPack.objType, objHash)));
for (String key : this.objectPack.tags.keySet()) {
propertyList.add(new PropertyData(key, CastUtil.cString(this.objectPack.tags.get(key))));
diff --git a/scouter.client/src/scouter/client/popup/SQLFormatDialog.java b/scouter.client/src/scouter/client/popup/SQLFormatDialog.java
index a913a34a5..5988b5402 100644
--- a/scouter.client/src/scouter/client/popup/SQLFormatDialog.java
+++ b/scouter.client/src/scouter/client/popup/SQLFormatDialog.java
@@ -39,6 +39,7 @@
import scouter.client.util.SqlFormatUtil;
import scouter.client.util.SqlMakerUtil;
import scouter.client.util.UIUtil;
+import scouter.util.StringUtil;
public class SQLFormatDialog {
public void show(final String message, final String error){
@@ -138,6 +139,19 @@ public void widgetSelected(SelectionEvent e) {
}
});
+ final Button bindBtn = new Button(bottomComp, SWT.PUSH);
+ bindBtn.setLayoutData(UIUtil.formData(null, -1, null, -1, copyBtn, -5, null, -1, 100));
+ bindBtn.setText("&Bind");
+ bindBtn.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ text.setText(SqlMakerUtil.replaceSQLParameter(message, params));
+ }
+ });
+
+ if (StringUtil.isEmpty(params)) {
+ bindBtn.setEnabled(false);
+ }
+
dialog.pack();
dialog.open();
}
diff --git a/scouter.client/src/scouter/client/popup/ServerPropertiesDialog.java b/scouter.client/src/scouter/client/popup/ServerPropertiesDialog.java
index 14cdd20ca..bf0ef7e44 100644
--- a/scouter.client/src/scouter/client/popup/ServerPropertiesDialog.java
+++ b/scouter.client/src/scouter/client/popup/ServerPropertiesDialog.java
@@ -78,6 +78,9 @@ private void makeTableContents() {
propertyList.add(new PropertyData("user id", server.getUserId()));
propertyList.add(new PropertyData("group", server.getGroup()));
propertyList.add(new PropertyData("timezone", server.getTimezone()));
+ propertyList.add(new PropertyData("session", server.getSession()));
+ propertyList.add(new PropertyData("time delta(ms)", server.getDelta()));
+ propertyList.add(new PropertyData("secure_mode", server.isSecureMode()));
propertyTableViewer.refresh();
dialog.pack();
dialog.open();
diff --git a/scouter.client/src/scouter/client/popup/TimeRangeDialog.java b/scouter.client/src/scouter/client/popup/TimeRangeDialog.java
index 798694f6d..cb410695e 100644
--- a/scouter.client/src/scouter/client/popup/TimeRangeDialog.java
+++ b/scouter.client/src/scouter/client/popup/TimeRangeDialog.java
@@ -84,7 +84,7 @@ public void handleEvent(Event event) {
long stime = DateUtil.getTime(fromTime, "yyyyMMddHHmm");
long etime = DateUtil.getTime(toTime, "yyyyMMddHHmm");
if (etime <= stime) {
- MessageDialog.openWarning(dialog, "Warning", "Time range is incorrect. " + DateUtil.timestamp(stime) + " ~ " + DateUtil.timestamp(etime));
+ MessageDialog.openWarning(dialog, "Warning", "Time range is incorrect. ");
} else {
callback.setTimeRange(stime, etime);
dialog.close();
diff --git a/scouter.client/src/scouter/client/server/Server.java b/scouter.client/src/scouter/client/server/Server.java
index 2bef37905..dfeb5f8e3 100644
--- a/scouter.client/src/scouter/client/server/Server.java
+++ b/scouter.client/src/scouter/client/server/Server.java
@@ -39,6 +39,7 @@ public class Server {
private String group;
private String version;
private String email;
+ private boolean secureMode = true;
private boolean open = false;
@@ -231,6 +232,14 @@ public int getSoTimeOut() {
public void setSoTimeOut(int soTimeOut) {
this.soTimeOut = soTimeOut;
}
+
+ public boolean isSecureMode() {
+ return secureMode;
+ }
+
+ public void setSecureMode(boolean secureMode) {
+ this.secureMode = secureMode;
+ }
public String toString() {
return "Server [id=" + id + ", name=" + name + ", ip=" + ip + ", port="
diff --git a/scouter.client/src/scouter/client/summary/modules/SqlSummaryComposite.java b/scouter.client/src/scouter/client/summary/modules/SqlSummaryComposite.java
index 635b2f251..2419bbb78 100644
--- a/scouter.client/src/scouter/client/summary/modules/SqlSummaryComposite.java
+++ b/scouter.client/src/scouter/client/summary/modules/SqlSummaryComposite.java
@@ -8,12 +8,16 @@
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import scouter.client.model.TextProxy;
import scouter.client.net.TcpProxy;
+import scouter.client.popup.SQLFormatDialog;
import scouter.client.util.ExUtil;
import scouter.lang.pack.MapPack;
import scouter.lang.pack.Pack;
@@ -93,6 +97,17 @@ public String getText(Object element) {
c.setLabelProvider(labelProvider);
}
}
+ viewer.addDoubleClickListener(new IDoubleClickListener() {
+ public void doubleClick(DoubleClickEvent event) {
+ StructuredSelection sel = (StructuredSelection) event.getSelection();
+ Object o = sel.getFirstElement();
+ if (o instanceof SummaryData) {
+ SummaryData data = (SummaryData) o;
+ String sql = TextProxy.sql.getText(data.hash);
+ new SQLFormatDialog().show(sql, null);
+ }
+ }
+ });
}
enum SqlColumnEnum {
diff --git a/scouter.client/src/scouter/client/tags/ServiceTableComposite.java b/scouter.client/src/scouter/client/tags/ServiceTableComposite.java
index 6fe77fd2a..7863a5011 100644
--- a/scouter.client/src/scouter/client/tags/ServiceTableComposite.java
+++ b/scouter.client/src/scouter/client/tags/ServiceTableComposite.java
@@ -17,6 +17,7 @@
package scouter.client.tags;
import java.util.ArrayList;
+import java.util.Date;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ArrayContentProvider;
@@ -167,9 +168,9 @@ public String getColumnText(Object element, int columnIndex) {
case SERVICE :
return TextProxy.service.getLoadText(yyyymmdd, p.service, serverId);
case START_TIME :
- return DateUtil.getLogTime(p.endTime - p.elapsed);
+ return FormatUtil.print(new Date(p.endTime - p.elapsed), "HH:mm:ss.sss");
case END_TIME :
- return DateUtil.getLogTime(p.endTime);
+ return FormatUtil.print(new Date(p.endTime), "HH:mm:ss.sss");
case TX_ID :
return Hexa32.toString32(p.txid);
case CPU :
diff --git a/scouter.client/src/scouter/client/util/SqlFormatUtil.java b/scouter.client/src/scouter/client/util/SqlFormatUtil.java
index 360fe646e..026d85fc8 100644
--- a/scouter.client/src/scouter/client/util/SqlFormatUtil.java
+++ b/scouter.client/src/scouter/client/util/SqlFormatUtil.java
@@ -35,7 +35,7 @@ public class SqlFormatUtil {
"group", "by", "create", "default", "use", "desc", "alter",
"fetch", "order", "and", "or", "as", "round", "decode", "nvl",
"instr", "sysdate", "sum", "rownum", "in", "left", "outer",
- "close", "continue" };
+ "close", "continue", "into", "values" };
public static void applyStyledFormat(StyledText text, String sql) {
if (StringUtil.isEmpty(sql)) return;
diff --git a/scouter.client/src/scouter/client/views/AlertView.java b/scouter.client/src/scouter/client/views/AlertView.java
index 6361014f3..e82c60895 100644
--- a/scouter.client/src/scouter/client/views/AlertView.java
+++ b/scouter.client/src/scouter/client/views/AlertView.java
@@ -17,6 +17,8 @@
*/
package scouter.client.views;
+import java.util.Date;
+
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.swt.SWT;
@@ -42,6 +44,7 @@
import scouter.lang.AlertLevel;
import scouter.lang.pack.AlertPack;
import scouter.util.DateUtil;
+import scouter.util.FormatUtil;
public class AlertView extends ViewPart implements IAlertListener {
public static final String ID = AlertView.class.getName();
@@ -172,7 +175,7 @@ public void run() {
AlertData data = new AlertData(serverId, alert);
TableItem t = new TableItem(table, SWT.NONE, 0);
t.setText(new String[] { //
- DateUtil.getLogTime(alert.time),//
+ FormatUtil.print(new Date(alert.time), "HH:mm:ss.sss"),
AlertLevel.getName(alert.level), //
alert.title, //
alert.message,//
diff --git a/scouter.client/src/scouter/client/views/ObjectThreadDetailView.java b/scouter.client/src/scouter/client/views/ObjectThreadDetailView.java
index 8fe7bd21d..8e955b074 100644
--- a/scouter.client/src/scouter/client/views/ObjectThreadDetailView.java
+++ b/scouter.client/src/scouter/client/views/ObjectThreadDetailView.java
@@ -273,6 +273,8 @@ public void run() {
if (stopBtn != null && interruptBtn != null) {
stopBtn.setEnabled(serviceThread);
interruptBtn.setEnabled(serviceThread);
+ resumeBtn.setEnabled(serviceThread);
+ suspendBtn.setEnabled(serviceThread);
}
sortTable();
}
diff --git a/scouter.client/src/scouter/client/xlog/ProfileText.java b/scouter.client/src/scouter/client/xlog/ProfileText.java
index 3d970e913..980d8a17a 100644
--- a/scouter.client/src/scouter/client/xlog/ProfileText.java
+++ b/scouter.client/src/scouter/client/xlog/ProfileText.java
@@ -20,6 +20,7 @@
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.ArrayList;
+import java.util.Date;
import java.util.HashMap;
import org.eclipse.swt.SWT;
@@ -110,7 +111,7 @@ public static void build(final String date, StyledText text, XLogData xperf, Ste
sr.add(underlineStyle(slen, sb.length() - slen, dmagenta, SWT.NORMAL, SWT.UNDERLINE_LINK));
}
sb.append("► objName = ").append(xperf.objName).append("\n");
- sb.append("► endtime = ").append(DateUtil.timestamp(xperf.p.endTime)).append("\n");
+ sb.append("► endtime = ").append(FormatUtil.print(new Date(xperf.p.endTime), "yyyyMMdd HH:mm:ss.sss")).append("\n");
sb.append("► elapsed = ").append(FormatUtil.print(xperf.p.elapsed, "#,##0")).append(" ms\n");
sb.append("► service = ").append(TextProxy.service.getText(xperf.p.service)).append("\n");
if (error != null) {
@@ -190,7 +191,7 @@ public static void build(final String date, StyledText text, XLogData xperf, Ste
sb.append(" ");
sb.append("[******]");
sb.append(" ");
- sb.append(DateUtil.getLogTime(stime));
+ sb.append(FormatUtil.print(new Date(stime), "HH:mm:ss.sss"));
sb.append(" ");
sb.append(String.format("%6s", "0"));
sb.append(" ");
@@ -263,7 +264,7 @@ public static void build(final String date, StyledText text, XLogData xperf, Ste
sb.append("[******]");
sb.append(" ");
- sb.append(DateUtil.getLogTime(tm));
+ sb.append(FormatUtil.print(new Date(tm), "HH:mm:ss.sss"));
sb.append(" ");
sb.append(String.format("%6s", FormatUtil.print(tm - prev_tm, "#,##0")));
sb.append(" ");
@@ -292,7 +293,7 @@ public static void build(final String date, StyledText text, XLogData xperf, Ste
sb.append(" ");
sb.append(String.format("[%06d]", stepSingle.index));
sb.append(" ");
- sb.append(DateUtil.getLogTime(tm));
+ sb.append(FormatUtil.print(new Date(tm), "HH:mm:ss.sss"));
sb.append(" ");
sb.append(String.format("%6s", FormatUtil.print(tm - prev_tm, "#,##0")));
sb.append(" ");
@@ -394,7 +395,7 @@ public static void build(final String date, StyledText text, XLogData xperf, Ste
sb.append(" ");
sb.append("[******]");
sb.append(" ");
- sb.append(DateUtil.getLogTime(tm));
+ sb.append(FormatUtil.print(new Date(tm), "HH:mm:ss.sss"));
sb.append(" ");
sb.append(String.format("%6s", FormatUtil.print(tm - prev_tm, "#,##0")));
sb.append(" ");
@@ -492,7 +493,7 @@ public static void buildThreadProfile(XLogData data, StyledText text, Step[] pro
sb.delete(sb.length() - 9, sb.length());
sb.append("[******]");
sb.append(" ");
- sb.append(DateUtil.getLogTime(data.p.endTime));
+ sb.append(FormatUtil.print(new Date(data.p.endTime), "HH:mm:ss.sss"));
sb.append(" ");
sb.append(String.format("%6s", FormatUtil.print(data.p.elapsed, "#,##0")));
sb.append(" ");
@@ -518,7 +519,7 @@ public static void buildThreadProfile(XLogData data, StyledText text, Step[] pro
sb.append(" ");
sb.append(String.format("[%06d]", stepSingle.index));
sb.append(" ");
- sb.append(DateUtil.getLogTime(tm));
+ sb.append(FormatUtil.print(new Date(tm), "HH:mm:ss.sss"));
sb.append(" ");
sb.append(String.format("%6s", FormatUtil.print(tm - prev_tm, "#,##0")));
sb.append(" ");
diff --git a/scouter.client/src/scouter/client/xlog/ProfileTextFull.java b/scouter.client/src/scouter/client/xlog/ProfileTextFull.java
index d8ccdf511..3afffd7bc 100644
--- a/scouter.client/src/scouter/client/xlog/ProfileTextFull.java
+++ b/scouter.client/src/scouter/client/xlog/ProfileTextFull.java
@@ -18,6 +18,7 @@
package scouter.client.xlog;
import java.util.ArrayList;
+import java.util.Date;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
@@ -43,7 +44,6 @@
import scouter.lang.step.StepEnum;
import scouter.lang.step.StepSingle;
import scouter.lang.step.StepSummary;
-import scouter.util.DateUtil;
import scouter.util.FormatUtil;
import scouter.util.Hexa32;
import scouter.util.IPUtil;
@@ -66,7 +66,7 @@ public static void buildXLogData(final String date, StyledText text, XLogPack p,
final StringBuffer sb = new StringBuffer();
sb.append("► txid = ").append(Hexa32.toString32(p.txid)).append("\n");
sb.append("► objName = ").append(objName).append("\n");
- sb.append("► endtime = ").append(DateUtil.timestamp(p.endTime)).append("\n");
+ sb.append("► endtime = ").append(FormatUtil.print(new Date(p.endTime), "yyyyMMdd HH:mm:ss.sss")).append("\n");
sb.append("► elapsed = ").append(FormatUtil.print(p.elapsed, "#,##0")).append(" ms\n");
sb.append("► service = ").append(TextProxy.service.getText(p.service)).append("\n");
if (error != null) {
@@ -176,7 +176,7 @@ public static void buildProfile(final String date, StyledText text, XLogPack pac
sb.append(" ");
sb.append("["+astarStr+"]");
sb.append(" ");
- sb.append(DateUtil.getLogTime(stime));
+ sb.append(FormatUtil.print(new Date(stime), "HH:mm:ss.sss"));
sb.append(" ");
sb.append(String.format("%6s", "0"));
sb.append(" ");
@@ -263,7 +263,7 @@ public static void buildProfile(final String date, StyledText text, XLogPack pac
sb.append(" ");
sb.append(String.format("[%0"+length+"d]", stepSingle.index));
sb.append(" ");
- sb.append(DateUtil.getLogTime(tm));
+ sb.append(FormatUtil.print(new Date(tm), "HH:mm:ss.sss"));
sb.append(" ");
sb.append(String.format("%6s", FormatUtil.print(tm - prev_tm, "#,##0")));
sb.append(" ");
@@ -378,7 +378,7 @@ public static void buildProfile(final String date, StyledText text, XLogPack pac
sb.append(" ");
sb.append("["+astarStr+"]");
sb.append(" ");
- sb.append(DateUtil.getLogTime(tm));
+ sb.append(FormatUtil.print(new Date(tm), "HH:mm:ss.sss"));
sb.append(" ");
if(!isSummary){
sb.append(String.format("%6s", FormatUtil.print(tm - prev_tm, "#,##0")));
diff --git a/scouter.client/src/scouter/client/xlog/XLogUtil.java b/scouter.client/src/scouter/client/xlog/XLogUtil.java
index a035d802c..20ad61220 100644
--- a/scouter.client/src/scouter/client/xlog/XLogUtil.java
+++ b/scouter.client/src/scouter/client/xlog/XLogUtil.java
@@ -149,6 +149,74 @@ public static int getStepElaspedTime(Step p) {
}
return 0;
}
+
+ public static String getStepContents(Step p) {
+ StringBuilder sb = new StringBuilder();
+ switch (p.getStepType()) {
+ case StepEnum.METHOD:
+ case StepEnum.METHOD2:
+ MethodStep ms = (MethodStep) p;
+ sb.append(TextProxy.method.getText(ms.hash));
+ break;
+ case StepEnum.SQL3:
+ case StepEnum.SQL2:
+ case StepEnum.SQL:
+ SqlStep ss = (SqlStep) p;
+ sb.append(TextProxy.sql.getText(ss.hash));
+ break;
+ case StepEnum.MESSAGE:
+ MessageStep mms = (MessageStep) p;
+ sb.append(mms.message);
+ break;
+ case StepEnum.HASHED_MESSAGE:
+ HashedMessageStep hms = (HashedMessageStep) p;
+ sb.append(TextProxy.hashMessage.getText(hms.hash) + " #" + FormatUtil.print(hms.value, "#,##0"));
+ break;
+ case StepEnum.APICALL:
+ ApiCallStep acs = (ApiCallStep) p;
+ sb.append("call:").append(TextProxy.apicall.getText(acs.hash));
+ if (acs.txid != 0) {
+ sb.append(" <" + Hexa32.toString32(acs.txid) + ">");
+ }
+ break;
+ case StepEnum.SOCKET:
+ SocketStep sos = (SocketStep) p;
+ String ip = IPUtil.toString(sos.ipaddr);
+ sb.append("socket: ").append(ip == null ? "unknown" : ip).append(":").append(sos.port);
+ break;
+ case StepEnum.THREAD_SUBMIT:
+ ThreadSubmitStep tss = (ThreadSubmitStep) p;
+ sb.append("thread: ").append(TextProxy.apicall.getText(tss.hash));
+ if (tss.txid != 0) {
+ sb.append(" <" + Hexa32.toString32(tss.txid) + ">");
+ }
+ break;
+ }
+ return sb.toString();
+ }
+
+ public static String getErrorMessage(Step p) {
+ switch (p.getStepType()) {
+ case StepEnum.METHOD2:
+ MethodStep2 ms2 = (MethodStep2) p;
+ return TextProxy.error.getText(ms2.error);
+ case StepEnum.SQL:
+ case StepEnum.SQL2:
+ case StepEnum.SQL3:
+ SqlStep ss = (SqlStep) p;
+ return TextProxy.error.getText(ss.error);
+ case StepEnum.APICALL:
+ ApiCallStep acs = (ApiCallStep) p;
+ return TextProxy.error.getText(acs.error);
+ case StepEnum.SOCKET:
+ SocketStep sos = (SocketStep) p;
+ return TextProxy.error.getText(sos.error);
+ case StepEnum.THREAD_SUBMIT:
+ ThreadSubmitStep tss = (ThreadSubmitStep) p;
+ return TextProxy.error.getText(tss.error);
+ }
+ return null;
+ }
public static String toStringStepSingleType(StepSingle step) {
switch (step.getStepType()) {
diff --git a/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryIPDialog.java b/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryIPDialog.java
index ce7039056..eb5edaccc 100644
--- a/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryIPDialog.java
+++ b/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryIPDialog.java
@@ -26,6 +26,7 @@
import org.eclipse.swt.widgets.Display;
import scouter.client.model.XLogData;
+import scouter.client.threads.ObjectSelectManager;
import scouter.client.util.ExUtil;
import scouter.util.DateUtil;
import scouter.util.IPUtil;
@@ -48,7 +49,7 @@ public void run() {
while (longEnumer.hasMoreElements()) {
XLogData d = dataMap.get(longEnumer.nextLong());
long time = d.p.endTime;
- if (d.filter_ok && time >= stime && time <= etime) {
+ if (d.filter_ok && time >= stime && time <= etime && !ObjectSelectManager.getInstance().isUnselectedObject(d.p.objHash)) {
String ip = IPUtil.toString(d.p.ipaddr);
IpSummary summary = summaryMap.get(ip);
if (summary == null) {
diff --git a/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryRefererDialog.java b/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryRefererDialog.java
index 75318148f..d5964bef2 100644
--- a/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryRefererDialog.java
+++ b/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryRefererDialog.java
@@ -29,6 +29,7 @@
import scouter.client.model.TextProxy;
import scouter.client.model.XLogData;
+import scouter.client.threads.ObjectSelectManager;
import scouter.client.util.ExUtil;
import scouter.util.DateUtil;
import scouter.util.LongEnumer;
@@ -51,7 +52,7 @@ public void run() {
while (longEnumer.hasMoreElements()) {
XLogData d = dataMap.get(longEnumer.nextLong());
long time = d.p.endTime;
- if (d.filter_ok && time >= stime && time <= etime) {
+ if (d.filter_ok && time >= stime && time <= etime && !ObjectSelectManager.getInstance().isUnselectedObject(d.p.objHash)) {
RefererSummary summary = summaryMap.get(d.p.referer);
if (summary == null) {
summary = new RefererSummary(d.p.referer);
diff --git a/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryServiceDialog.java b/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryServiceDialog.java
index e2e05674a..c0478488c 100644
--- a/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryServiceDialog.java
+++ b/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryServiceDialog.java
@@ -29,6 +29,7 @@
import scouter.client.model.TextProxy;
import scouter.client.model.XLogData;
+import scouter.client.threads.ObjectSelectManager;
import scouter.client.util.ExUtil;
import scouter.util.DateUtil;
import scouter.util.LongEnumer;
@@ -51,7 +52,7 @@ public void run() {
while (longEnumer.hasMoreElements()) {
XLogData d = dataMap.get(longEnumer.nextLong());
long time = d.p.endTime;
- if (d.filter_ok && time >= stime && time <= etime) {
+ if (d.filter_ok && time >= stime && time <= etime && !ObjectSelectManager.getInstance().isUnselectedObject(d.p.objHash)) {
ServiceSummary summary = summaryMap.get(d.p.service);
if (summary == null) {
summary = new ServiceSummary(d.p.service);
diff --git a/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryUserAgentDialog.java b/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryUserAgentDialog.java
index a48e3a863..fc11d5e56 100644
--- a/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryUserAgentDialog.java
+++ b/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryUserAgentDialog.java
@@ -29,6 +29,7 @@
import scouter.client.model.TextProxy;
import scouter.client.model.XLogData;
+import scouter.client.threads.ObjectSelectManager;
import scouter.client.util.ExUtil;
import scouter.util.DateUtil;
import scouter.util.LongEnumer;
@@ -51,7 +52,7 @@ public void run() {
while (longEnumer.hasMoreElements()) {
XLogData d = dataMap.get(longEnumer.nextLong());
long time = d.p.endTime;
- if (d.filter_ok && time >= stime && time <= etime) {
+ if (d.filter_ok && time >= stime && time <= etime && !ObjectSelectManager.getInstance().isUnselectedObject(d.p.objHash)) {
UserAgentSummary summary = summaryMap.get(d.p.userAgent);
if (summary == null) {
summary = new UserAgentSummary(d.p.userAgent);
diff --git a/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryUserDialog.java b/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryUserDialog.java
index 5a6316b45..c2e9411cc 100644
--- a/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryUserDialog.java
+++ b/scouter.client/src/scouter/client/xlog/dialog/XLogSummaryUserDialog.java
@@ -26,6 +26,7 @@
import org.eclipse.swt.widgets.Display;
import scouter.client.model.XLogData;
+import scouter.client.threads.ObjectSelectManager;
import scouter.client.util.ExUtil;
import scouter.util.CastUtil;
import scouter.util.DateUtil;
@@ -48,7 +49,7 @@ public void run() {
while (longEnumer.hasMoreElements()) {
XLogData d = dataMap.get(longEnumer.nextLong());
long time = d.p.endTime;
- if (d.filter_ok && time >= stime && time <= etime) {
+ if (d.filter_ok && time >= stime && time <= etime && !ObjectSelectManager.getInstance().isUnselectedObject(d.p.objHash)) {
UserSummary summary = summaryMap.get(d.p.userid);
if (summary == null) {
summary = new UserSummary();
diff --git a/scouter.client/src/scouter/client/xlog/views/XLogFlowView.java b/scouter.client/src/scouter/client/xlog/views/XLogFlowView.java
index fbc614f3e..7450a1f8e 100644
--- a/scouter.client/src/scouter/client/xlog/views/XLogFlowView.java
+++ b/scouter.client/src/scouter/client/xlog/views/XLogFlowView.java
@@ -344,15 +344,14 @@ private void stepToElement(final DependencyElement serviceElement, Step step, fi
SqlStep sqlstep = (SqlStep) step;
DependencyElement sqlElement = new DependencyElement(ElementType.SQL, sqlstep.hash);
sqlElement.elapsed = sqlstep.elapsed;
- String name = TextProxy.sql_tables.getLoadText(date, sqlstep.hash, serverId);
- if(name != null){
- String sql = TextProxy.sql.getLoadText(date, sqlstep.hash, serverId).trim();
- sqlElement.name = name;
- sqlElement.error = sqlstep.error;
- sqlElement.tags.put("serverId", serverId);
- sqlElement.tags.put("sql", sql);
- serviceElement.addChild(sqlElement);
- }
+ String table = TextProxy.sql_tables.getLoadText(date, sqlstep.hash, serverId);
+ String sql = TextProxy.sql.getLoadText(date, sqlstep.hash, serverId).trim();
+ sqlElement.name = StringUtil.isNotEmpty(table) ? table : StringUtil.truncate(sql, 20) + "...";
+ sqlElement.name = table;
+ sqlElement.error = sqlstep.error;
+ sqlElement.tags.put("serverId", serverId);
+ sqlElement.tags.put("sql", sql);
+ serviceElement.addChild(sqlElement);
break;
case StepEnum.SQL_SUM:
SqlSum sqlsum = (SqlSum) step;
@@ -360,14 +359,12 @@ private void stepToElement(final DependencyElement serviceElement, Step step, fi
sqlSumElement.dupleCnt = sqlsum.count;
sqlSumElement.elapsed = (int) sqlsum.elapsed;
sqlSumElement.error = sqlsum.error;
- name = TextProxy.sql_tables.getLoadText(date, sqlsum.hash, serverId);
- if(name!=null){
- String sql = TextProxy.sql.getLoadText(date, sqlsum.hash, serverId).trim();
- sqlSumElement.name = name;
- sqlSumElement.tags.put("serverId", serverId);
- sqlSumElement.tags.put("sql", sql);
- serviceElement.addChild(sqlSumElement);
- }
+ table = TextProxy.sql_tables.getLoadText(date, sqlsum.hash, serverId);
+ sql = TextProxy.sql.getLoadText(date, sqlsum.hash, serverId).trim();
+ sqlSumElement.name = StringUtil.isNotEmpty(table) ? table : StringUtil.truncate(sql, 20) + "...";
+ sqlSumElement.tags.put("serverId", serverId);
+ sqlSumElement.tags.put("sql", sql);
+ serviceElement.addChild(sqlSumElement);
break;
case StepEnum.THREAD_SUBMIT:
ThreadSubmitStep tsStep = (ThreadSubmitStep) step;
diff --git a/scouter.client/src/scouter/client/xlog/views/XLogLoadTimeView.java b/scouter.client/src/scouter/client/xlog/views/XLogLoadTimeView.java
index 30227aaa0..09ff23726 100644
--- a/scouter.client/src/scouter/client/xlog/views/XLogLoadTimeView.java
+++ b/scouter.client/src/scouter/client/xlog/views/XLogLoadTimeView.java
@@ -18,6 +18,7 @@
package scouter.client.xlog.views;
import java.io.IOException;
+import java.util.Date;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
@@ -72,6 +73,7 @@
import scouter.io.DataInputX;
import scouter.net.RequestCmd;
import scouter.util.DateUtil;
+import scouter.util.FormatUtil;
import scouter.util.ThreadUtil;
@@ -277,8 +279,8 @@ protected IStatus run(final IProgressMonitor monitor) {
}
ConsoleProxy.infoSafe("Load old XLog data");
- ConsoleProxy.infoSafe("stime :" + DateUtil.timestamp(stime));
- ConsoleProxy.infoSafe("etime :" + DateUtil.timestamp(etime));
+ ConsoleProxy.infoSafe("stime :" + FormatUtil.print(new Date(stime), "yyyyMMdd HH:mm:ss.sss"));
+ ConsoleProxy.infoSafe("etime :" + FormatUtil.print(new Date(etime), "yyyyMMdd HH:mm:ss.sss"));
ConsoleProxy.infoSafe("objType :" + objType);
ConsoleProxy.infoSafe("limit :" + limit + " max:"+max);
diff --git a/scouter.client/src/scouter/client/xlog/views/XLogProfileView.java b/scouter.client/src/scouter/client/xlog/views/XLogProfileView.java
index 8dbfa155b..5a2a22b71 100644
--- a/scouter.client/src/scouter/client/xlog/views/XLogProfileView.java
+++ b/scouter.client/src/scouter/client/xlog/views/XLogProfileView.java
@@ -45,6 +45,9 @@
import scouter.client.Activator;
import scouter.client.Images;
import scouter.client.model.XLogData;
+import scouter.client.server.GroupPolicyConstants;
+import scouter.client.server.Server;
+import scouter.client.server.ServerManager;
import scouter.client.util.ConsoleProxy;
import scouter.client.util.ImageUtil;
import scouter.client.xlog.ProfileText;
@@ -66,6 +69,8 @@ public class XLogProfileView extends ViewPart {
private XLogData xLogData;
private String txid;
Menu contextMenu;
+ MenuItem sqlSummary;
+ MenuItem bindSqlParamMenu;
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
@@ -96,14 +101,14 @@ public void createPartControl(Composite parent) {
private void createContextMenu() {
contextMenu = new Menu(text);
- MenuItem sqlSummary = new MenuItem(contextMenu, SWT.PUSH);
+ sqlSummary = new MenuItem(contextMenu, SWT.PUSH);
sqlSummary.setText("SQL Statistics");
sqlSummary.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
openSqlSummaryDialog.run();
}
});
- final MenuItem bindSqlParamMenu = new MenuItem(contextMenu, SWT.CHECK);
+ bindSqlParamMenu = new MenuItem(contextMenu, SWT.CHECK);
bindSqlParamMenu.setText("Bind SQL Parameter");
bindSqlParamMenu.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
@@ -134,6 +139,10 @@ public void setInput(Step[] steps, final XLogData item, int serverId) {
this.txid = Hexa32.toString32(item.p.txid);
this.serverId = serverId;
+ Server server = ServerManager.getInstance().getServer(serverId);
+ sqlSummary.setEnabled(server.isAllowAction(GroupPolicyConstants.ALLOW_SQLPARAMETER));
+ bindSqlParamMenu.setEnabled(server.isAllowAction(GroupPolicyConstants.ALLOW_SQLPARAMETER));
+
setPartName(txid);
text.setText("");
diff --git a/scouter.client/src/scouter/client/xlog/views/XLogSelectionView.java b/scouter.client/src/scouter/client/xlog/views/XLogSelectionView.java
index b4c00aad9..04e8a24ee 100644
--- a/scouter.client/src/scouter/client/xlog/views/XLogSelectionView.java
+++ b/scouter.client/src/scouter/client/xlog/views/XLogSelectionView.java
@@ -18,6 +18,7 @@
package scouter.client.xlog.views;
import java.util.ArrayList;
+import java.util.Date;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
@@ -189,9 +190,9 @@ public String getColumnText(Object element, int columnIndex) {
}
return d.serviceName;
case START_TIME :
- return DateUtil.getLogTime(d.p.endTime - d.p.elapsed);
+ return FormatUtil.print(new Date(d.p.endTime - d.p.elapsed), "HH:mm:ss.sss");
case END_TIME :
- return DateUtil.getLogTime(d.p.endTime);
+ return FormatUtil.print(new Date(d.p.endTime), "HH:mm:ss.sss");
case TX_ID :
return Hexa32.toString32(d.p.txid);
case CPU :
diff --git a/scouter.common/src/scouter/lang/counters/counters.xml b/scouter.common/src/scouter/lang/counters/counters.xml
index 18a58a85c..b7312aab0 100644
--- a/scouter.common/src/scouter/lang/counters/counters.xml
+++ b/scouter.common/src/scouter/lang/counters/counters.xml
@@ -9,8 +9,8 @@ mrhit : MariaDB HitRatio
-
-
+
+
@@ -29,6 +29,10 @@ mrhit : MariaDB HitRatio
+
+
+
+
diff --git a/scouter.common/src/scouter/net/RequestCmd.java b/scouter.common/src/scouter/net/RequestCmd.java
index 07fd545b7..3e7014db0 100644
--- a/scouter.common/src/scouter/net/RequestCmd.java
+++ b/scouter.common/src/scouter/net/RequestCmd.java
@@ -17,6 +17,9 @@
package scouter.net;
+import java.util.HashSet;
+import java.util.Set;
+
public class RequestCmd {
public static final String CLOSE = "CLOSE";
public static final String LOGIN = "LOGIN";
@@ -257,5 +260,17 @@ public class RequestCmd {
public static final String LOAD_ENDUSER_NAV_SUMMARY = "LOAD_ENDUSER_NAV_SUMMARY";
public static final String LOAD_ENDUSER_AJAX_SUMMARY = "LOAD_ENDUSER_AJAX_SUMMARY";
public static final String LOAD_ENDUSER_ERROR_SUMMARY = "LOAD_ENDUSER_ERROR_SUMMARY";
+
+ protected static Set freeCmdSet = new HashSet();
+
+ static {
+ freeCmdSet.add(LOGIN);
+ freeCmdSet.add(SERVER_VERSION);
+ freeCmdSet.add(SERVER_TIME);
+ }
+
+ public static boolean isFreeCmd(String cmd) {
+ return freeCmdSet.contains(cmd);
+ }
}
\ No newline at end of file
diff --git a/scouter.common/src/scouter/net/TcpFlag.java b/scouter.common/src/scouter/net/TcpFlag.java
index c2f147c1d..0cd5b4868 100644
--- a/scouter.common/src/scouter/net/TcpFlag.java
+++ b/scouter.common/src/scouter/net/TcpFlag.java
@@ -24,7 +24,8 @@ public class TcpFlag {
public final static byte HasNEXT = 0x03;
public final static byte NoNEXT = 0x04;
- public static final byte FAIL = 0x05;
+ public static final byte FAIL = 0x05;
+ public static final byte INVALID_SESSION = 0x44;
public static final byte CLUSTER_SEND_NEXT = 0x03;
public static final byte CLUSTER_SEND_STOP = 0x04;
diff --git a/scouter.common/src/scouter/util/CipherUtil.java b/scouter.common/src/scouter/util/CipherUtil.java
index ecb968b8a..591e3d500 100644
--- a/scouter.common/src/scouter/util/CipherUtil.java
+++ b/scouter.common/src/scouter/util/CipherUtil.java
@@ -1,32 +1,31 @@
-/*
- * 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.
- */
-
+/*
+ * 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.util;
-import java.security.GeneralSecurityException;
-import java.security.Key;
-import java.security.MessageDigest;
-
-import javax.crypto.Cipher;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.DESKeySpec;
-
-import scouter.io.DataInputX;
-import scouter.io.DataOutputX;
+import scouter.io.DataInputX;
+import scouter.io.DataOutputX;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.DESKeySpec;
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.MessageDigest;
public class CipherUtil {
public static String md5(String plainText) {
@@ -55,32 +54,32 @@ public static String md5(String plainText) {
}
return md5Text;
- }
-
- public static String sha256(String plainText) {
- String salt = "qwertyuiop!@#$%^&*()zxcvbnm,.";
- String sha256Text = null;
- if (plainText != null) {
- try {
- MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
- sha256.update(salt.getBytes());
- byte[] byteArray = plainText.getBytes();
- byte[] sha256Bytes = sha256.digest(byteArray);
- StringBuffer buf = new StringBuffer();
-
- for (int i = 0; i < sha256Bytes.length; i++) {
- if ((sha256Bytes[i] & 0xff) < 0x10) {
- buf.append("0");
- }
- buf.append(Long.toString(sha256Bytes[i] & 0xff, 16));
- }
-
- sha256Text = buf.toString();
- } catch (Throwable t) {
- return plainText;
- }
- }
- return sha256Text;
+ }
+
+ public static String sha256(String plainText) {
+ String salt = "qwertyuiop!@#$%^&*()zxcvbnm,.";
+ String sha256Text = null;
+ if (plainText != null) {
+ try {
+ MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
+ sha256.update(salt.getBytes());
+ byte[] byteArray = plainText.getBytes();
+ byte[] sha256Bytes = sha256.digest(byteArray);
+ StringBuffer buf = new StringBuffer();
+
+ for (int i = 0; i < sha256Bytes.length; i++) {
+ if ((sha256Bytes[i] & 0xff) < 0x10) {
+ buf.append("0");
+ }
+ buf.append(Long.toString(sha256Bytes[i] & 0xff, 16));
+ }
+
+ sha256Text = buf.toString();
+ } catch (Throwable t) {
+ return plainText;
+ }
+ }
+ return sha256Text;
}
private static Key genKey() throws GeneralSecurityException {
@@ -120,9 +119,7 @@ public static String encode(String plain) {
}
return null;
}
-
-
-
+
private static byte[] padding(byte[] src) {
int destlen = (src.length / 8 + 1) * 8;
byte[] dest = new byte[destlen];
@@ -130,16 +127,46 @@ private static byte[] padding(byte[] src) {
return dest;
}
+ public static String sha2562(String plainText) {
+ String salt = "qwertyuiop!@#$%^&*()zxcvbnm,.";
+ String sha256Text = null;
+
+ if (plainText != null) {
+ try {
+ String saltText = salt != null && !"".equals(salt)?plainText + "{" + salt.toString() + "}":plainText;
+
+ MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
+ byte[] byteArray = saltText.getBytes();
+ byte[] sha256Bytes = sha256.digest(byteArray);
+
+ StringBuffer buf = new StringBuffer();
+
+ for (int i = 0; i < sha256Bytes.length; i++) {
+ if ((sha256Bytes[i] & 0xff) < 0x10) {
+ buf.append("0");
+ }
+ buf.append(Long.toString(sha256Bytes[i] & 0xff, 16));
+ }
+ sha256Text = buf.toString();
+ } catch (Throwable t) {
+ return plainText;
+ }
+ }
+ return sha256Text;
+ }
+
public static void main(String[] args) {
- String pwd = "guest";
+ String pwd = "admin";
String md5 = md5(pwd);
String cnd = encode(pwd);
- String rtn = decode(cnd);
+ String rtn = decode(cnd);
String sha256 = sha256(pwd);
+ String sha2562 = sha2562(pwd);
System.out.println("'" + pwd + "'");
System.out.println("'" + md5 + "'");
System.out.println("'" + cnd + "'");
- System.out.println("'" + rtn + "'");
+ System.out.println("'" + rtn + "'");
System.out.println("'" + sha256 + "'");
+ System.out.println("'" + sha2562 + "'");
}
}
\ No newline at end of file
diff --git a/scouter.deploy/build-agent.batch.xml b/scouter.deploy/build-agent.batch.xml
new file mode 100644
index 000000000..478f0f342
--- /dev/null
+++ b/scouter.deploy/build-agent.batch.xml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Agent Java
+
+
+
+
+
+
+
diff --git a/scouter.deploy/scouter-batch.mf b/scouter.deploy/scouter-batch.mf
new file mode 100644
index 000000000..f83710b5e
--- /dev/null
+++ b/scouter.deploy/scouter-batch.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+Premain-Class: scouter.agent.batch.JavaAgent
+Agent-Class: scouter.agent.batch.JavaAgent
+Boot-Class-Path: scouter.agent.batch.jar
+Can-Redefine-Classes: true
+Can-Retransform-Classes: true
diff --git a/scouter.document/main/Plugin-Guide.md b/scouter.document/main/Plugin-Guide.md
index e6b8269b5..1f84012e9 100644
--- a/scouter.document/main/Plugin-Guide.md
+++ b/scouter.document/main/Plugin-Guide.md
@@ -1,23 +1,24 @@
-# Scouter Plugin Guide
+# Scouter Plugin Guide
 [](Plugin-Guide_kr.md)
-이 글에서는 Scouter를 확장 가능하게 만들어 주는 Plugin 기능에 대해 설명한다.
-Scouter collector sever의 Plugin 기능을 통하여 scouter의 수집 데이터를 선처리 하거나 타 소프트웨어로 전송할 수 있으며 agent plugin을 통하여 특정 데이터를 선처리하거나 업무적으로 의미있는 데이터를 XLog나 프로파일에 추가할 수 있다.
+This article explains plugin funtion which enables scouter's extensibility.
-> Scouter plugin을 통해 다른 open source들과 조합을 통한 구성 및 확장이 가능하다.
+With the plugin fuction of Scouter collector sever, data collected by scouter can be modified and can be shared to other softwares. With agent plugin, certain types of data can be modified (선 처리의 개념이 모호하여 modifed 로 번역 하였으나 의미에 따라 pre-handled 등으로 변경 해야 할 수 도 있음.) and other business-meaningful data can be added data to XLog or profile.
-Scouter의 프로파일은 collector server에 적용 가능한 **server plugin**, 그리고 Java agent에 적용할 수 있는 **agent Plugin**으로 구분이 되며 server plugin은 **scripting plugin**과 **built-in plugin**으로 나누어 진다.
-현재 agent plugin은 java agent용의 scripting plugin만 제공된다.
+> With Scouter plugin, configuration and extension can be done to enable collarboaration with other open source.
-## 제공되는 plugin 목록
-아래 항목들은 scouter project에서 공식 제공되거나 contributor에 의해 작성된 plugin들이다.
+Scouter's profiles has two parts. **server plug-in** is for to collector server and **agent Plugin** is for to Java agent. server plugin has two parts including **scripting plugin** and **built-in plugin**.
+Currently, scripting plugin is only one available plugin for java agent.
+
+## List of available plugins
+Below are the list of official plugins from scouter project and from contributors.
#### 1. server plugins
-* **[scouter-plugin-server-null](https://github.com/scouter-project/scouter-plugin-server-null)** : 수집데이터를 단순히 출력해 주는 sample plugin
-* **[scouter-plugin-server-email](https://github.com/scouter-project/scouter-plugin-server-alert-email)** : Scouter에서 발생하는 alert를 email로 전송하는 plugin
-* **[scouter-plugin-server-telegram](https://github.com/scouter-project/scouter-plugin-server-alert-telegram)** : Scouter에서 발생하는 alert를 telegram으로 전송하는 plugin
-* **[scouter-plugin-server-slack](https://github.com/scouter-project/scouter-plugin-server-alert-slack)** : Scouter에서 발생하는 alert를 slack으로 전송하는 plugin
-* **[scouter-plugin-server-influxdb](https://github.com/scouter-project/scouter-plugin-server-influxdb)** : Scouter의 성능 counter 데이터를 시계열 DB인 influxDB로 연동하는 plugin
+* **[scouter-plugin-server-null](https://github.com/scouter-project/scouter-plugin-server-null)** : sample plugin prints out data collected
+* **[scouter-plugin-server-email](https://github.com/scouter-project/scouter-plugin-server-alert-email)** : emails alters from Scouter
+* **[scouter-plugin-server-telegram](https://github.com/scouter-project/scouter-plugin-server-alert-telegram)** : transfer altert from Scouter to telegram
+* **[scouter-plugin-server-slack](https://github.com/scouter-project/scouter-plugin-server-alert-slack)** : transfer altert from Scouter to slack
+* **[scouter-plugin-server-influxdb](https://github.com/scouter-project/scouter-plugin-server-influxdb)** : transfer performance data from Scouter to influxDB(time series DB)
#### 2. agent plugins
* TBD
diff --git a/scouter.server/src/scouter/server/LoginManager.scala b/scouter.server/src/scouter/server/LoginManager.scala
index c77eb7b27..316a4b874 100644
--- a/scouter.server/src/scouter/server/LoginManager.scala
+++ b/scouter.server/src/scouter/server/LoginManager.scala
@@ -19,7 +19,7 @@ import scouter.server.account.AccountManager
import scouter.server.util.{EnumerScala, ThreadScala}
import scouter.util.{CacheTable, DateUtil, KeyGen, ThreadUtil}
object LoginManager {
- val sessionTable = new CacheTable[Long, LoginUser]().setDefaultKeepTime(DateUtil.MILLIS_PER_MINUTE);
+ val sessionTable = new CacheTable[Long, LoginUser]().setDefaultKeepTime(DateUtil.MILLIS_PER_HOUR * 3);
ThreadScala.startDaemon("scouter.server.LoginManager") {
while (true) {
sessionTable.clearExpiredItems();
diff --git a/scouter.server/src/scouter/server/account/AccountManager.scala b/scouter.server/src/scouter/server/account/AccountManager.scala
index db9fc98aa..04ba7f252 100644
--- a/scouter.server/src/scouter/server/account/AccountManager.scala
+++ b/scouter.server/src/scouter/server/account/AccountManager.scala
@@ -16,12 +16,23 @@
*
*/
package scouter.server.account;
+
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.util.ArrayList
import java.util.Enumeration
import java.util.List
+import java.util.Properties;
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
import scouter.server.Configure
import scouter.server.Logger
import scouter.lang.Account
@@ -34,12 +45,14 @@ import scouter.util.StringKeyLinkedMap
import scouter.util.ThreadUtil
import scouter.server.util.ThreadScala
import scouter.server.core.CoreRun
+
object AccountManager {
val ACCOUNT_FILENAME = "account.xml";
val GROUP_FILENAME = "account_group.xml";
var accountMap = new StringKeyLinkedMap[Account]();
var groupPolicyMap = new StringKeyLinkedMap[MapValue]();
- val confPath = Configure.CONF_DIR;
+ val confPath = Configure.CONF_DIR;
+ var conf = Configure.getInstance();
FileUtil.mkdirs(confPath);
val groupFile = new File(confPath + GROUP_FILENAME);
val accountFile = new File(confPath + ACCOUNT_FILENAME);
@@ -88,6 +101,7 @@ object AccountManager {
lastModifiedGroupFile = groupFile.lastModified();
} catch {
case e: Exception => e.printStackTrace();
+
}
}
}
@@ -128,12 +142,62 @@ object AccountManager {
}
}
def authorizeAccount(id: String, pass: String): Account = {
- val account = accountMap.get(id);
- if (account == null) {
- return null;
- }
- if (account.password.equals(pass)) {
- return account;
+ if(conf.getBoolean("account_use_ldap",false)){
+ var ctx : DirContext = null;
+ var props : Properties = new Properties();
+
+ props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+ props.setProperty(Context.PROVIDER_URL, conf.getValue("account_ldap_provider_url"));
+ props.setProperty(Context.SECURITY_AUTHENTICATION, conf.getValue("account_ldap_auth=","simple"));
+ props.setProperty(Context.SECURITY_PRINCIPAL, id+conf.getValue("account_ldap_principal_domain"));
+ props.setProperty(Context.SECURITY_CREDENTIALS, pass);
+
+ try{
+ ctx = new InitialDirContext(props);
+ var cons : SearchControls = new SearchControls();
+ cons.setSearchScope(SearchControls.SUBTREE_SCOPE);
+ var searchFilter : String = "(cn="+id+")";
+
+ if(conf.getBoolean("account_ldap_debug", false)){
+ Logger.println("ldap id : "+id);
+ Logger.println("ldap pass : "+pass);
+ Logger.println("ldap properties : "+props.toString());
+ }
+
+ var result = ctx.search(conf.getValue("account_ldap_basedn"), searchFilter, cons);
+ var nextEntry : SearchResult = null;
+ if(result.hasMore()){
+ var attrs = result.next().getAttributes();
+ var nmEnum = attrs.getIDs();
+ while(nmEnum.hasMore()){
+ var _id = nmEnum.next();
+
+ if( id.equals( attrs.get(_id).get().toString()) ){
+ var account : Account = new Account();
+ account.id = id
+ try{
+ account.email = attrs.get(conf.getValue("account_ldap_email_id","")).get().toString();
+ account.group = attrs.get(conf.getValue("account_ldap_group_id","")).get().toString();
+ }catch{
+ case ne : NullPointerException => ne.printStackTrace()
+ }
+ return account;
+ }
+ }
+ }
+ }catch{
+ case e: Exception => Logger.println("Ldap Account Error : "+e.toString()); e.printStackTrace();
+ }finally{
+ if(null != ctx) ctx.close();
+ }
+ }else{
+ val account = accountMap.get(id);
+ if (account == null) {
+ return null;
+ }
+ if (account.password.equals(pass)) {
+ return account;
+ }
}
return null;
}
diff --git a/scouter.server/src/scouter/server/netio/data/NetDataProcessor.scala b/scouter.server/src/scouter/server/netio/data/NetDataProcessor.scala
index 687b343af..55b71a6d5 100644
--- a/scouter.server/src/scouter/server/netio/data/NetDataProcessor.scala
+++ b/scouter.server/src/scouter/server/netio/data/NetDataProcessor.scala
@@ -152,7 +152,7 @@ object NetDataProcessor {
counterPack.timetype = TimeTypeEnum.REALTIME;
}
counterPack.data.put(CounterConstants.COMMON_OBJHASH, new DecimalValue(objHash)) //add objHash into datafile
- counterPack.data.put(CounterConstants.COMMON_TIME, new DecimalValue(counterPack.time)) //add objHash into datafile
+ counterPack.data.put(CounterConstants.COMMON_TIME, new DecimalValue(counterPack.time)) //add time into datafile
PerfCountCore.add(counterPack)
if (conf.log_udp_counter) {
diff --git a/scouter.server/src/scouter/server/netio/service/net/TcpServiceWorker.scala b/scouter.server/src/scouter/server/netio/service/net/TcpServiceWorker.scala
index 5fdda9667..f42d74f23 100644
--- a/scouter.server/src/scouter/server/netio/service/net/TcpServiceWorker.scala
+++ b/scouter.server/src/scouter/server/netio/service/net/TcpServiceWorker.scala
@@ -99,17 +99,23 @@ class ServiceWorker(_socket: Socket) extends Runnable {
try {
ServiceWorker.inc();
-
+ var sessionOk = false;
while (true) {
val cmd = in.readText();
if (RequestCmd.CLOSE.equals(cmd)) {
return
}
val session = in.readLong();
- val login = LoginManager.okSession(session);
-
+ if (sessionOk == false && RequestCmd.isFreeCmd(cmd) == false) {
+ sessionOk = LoginManager.okSession(session);
+ if (sessionOk == false) {
+ out.writeByte(TcpFlag.INVALID_SESSION);
+ out.flush();
+ throw new RuntimeException("Invalid session key : " + cmd);
+ }
+ }
RequestLogger.getInstance().add(cmd, session);
- ServiceHandlingProxy.process(cmd, in, out, login);
+ ServiceHandlingProxy.process(cmd, in, out, sessionOk);
out.writeByte(TcpFlag.NoNEXT);
out.flush();
@@ -133,7 +139,8 @@ class ServiceWorker(_socket: Socket) extends Runnable {
if (conf.log_tcp_action_enabled) {
Logger.println("Client : " + remoteAddr + " closed " + e + " workers=" + ServiceWorker.getActiveCount());
}
- case t: Throwable => t.printStackTrace();
+ case t: Throwable =>
+ Logger.println("SC-400", 30, "ServiceWorker closed", t)
} finally {
FileUtil.close(in);
FileUtil.close(out);