All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scouter.agent.batch.trace.TraceContext Maven / Gradle / Ivy

There is a newer version: 2.20.0
Show newest version
/*
 *  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.lang.pack.BatchPack;
import scouter.lang.pack.MapPack;
import scouter.lang.value.BooleanValue;
import scouter.lang.value.MapValue;
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;
	
	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 long gcTime= 0L;
	public long gcCount = 0L;
	

	public int sqlTotalCnt = 0;
	public long sqlTotalTime = 0L;
	public long sqlTotalRows = 0L;
	public long sqlTotalRuns = 0L;

	public boolean isStackLogFile = false;
	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 = 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("-[").append(this.batchJobId).append("]----------------------------------------------").append(lineSeparator);
		buffer.append("Run  Command: ").append(this.args).append(lineSeparator);
		if(this.isStackLogFile){
			buffer.append("Stack   Dump: ").append(this.getLogFullFilename()).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(this.gcCount > 0){
			buffer.append("GC     Count: ").append(this.gcCount).append(lineSeparator);
			buffer.append("GC      Time: ").append(this.gcTime).append("ms").append(lineSeparator);
		}
		
		if(sqlMap.size() > 0){
			buffer.append("SQL     Time: ").append((sqlTotalTime/1000000L)).append("ms").append(lineSeparator);
			buffer.append("SQL     Type: ").append(sqlMap.size()).append(lineSeparator);
			buffer.append("SQL     Runs: ").append(sqlTotalRuns).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;
			buffer.append("Index          Runs     TotalTime       MinTime       MaxTime          Rows (Measured) StartTime               EndTime").append(lineSeparator);
			buffer.append("--------------------------------------------------------------------------------------------------------------------------------------");
			List list = sortTraceSQLList();
			for(TraceSQL traceSql : list){
				index++;
				buffer.append(lineSeparator);
				buffer.append(String.format("%5s", index)).append(' ');
				buffer.append(String.format("%,13d", traceSql.runs)).append(' ');
				buffer.append(String.format("%,13d", traceSql.getTotalTimeByMillis())).append(' ');
				buffer.append(String.format("%,13d", traceSql.getMinTimeByMillis())).append(' ');
				buffer.append(String.format("%,13d", traceSql.getMaxTimeByMillis())).append(' ');
				buffer.append(String.format("%,13d", traceSql.processedRows)).append(' ').append(String.format("%10s", traceSql.rowed)).append(' ');
				buffer.append(sdf.format(new Date(traceSql.startTime))).append(' ');
				buffer.append(sdf.format(new Date(traceSql.endTime)));
			}
			buffer.append(lineSeparator).append("--------------------------------------------------------------------------------------------------------------------------------------").append(lineSeparator);

			buffer.append(lineSeparator).append("").append(lineSeparator);
			index = 0;
			for(TraceSQL traceSql : list){
				index++;
				buffer.append("-----------------").append(lineSeparator);
				buffer.append("#SQLINX-").append(index).append(lineSeparator);
				buffer.append(uniqueSqls.get(traceSql.hashValue)).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);
					this.sqlTotalCnt++;
				}
			}
			synchronized(statsSql){
				statsSql.runs += sql.runs;
				this.sqlTotalRuns += sql.runs;
				statsSql.totalTime += sql.totalTime;
				this.sqlTotalTime += sql.totalTime;
				statsSql.processedRows += sql.processedRows;
				this.sqlTotalRows += 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();
		}
		caculateResource();
	}
	
	public void caculateResource(){
		this.endCpu = SysJMX.getProcessCPU();
		long [] gcInfo = SysJMX.getCurrentProcGcInfo();
		this.gcCount = gcInfo[0];
		this.gcTime = gcInfo[1];
	}
	
	public MapPack caculateTemp(){
		MapPack map = new MapPack();
		map.put("batchJobId", this.batchJobId);
		map.put("args", this.args);
		map.put("pID", (long)this.pID);
		map.put("startTime", this.startTime);
		map.put("elapsedTime", (System.currentTimeMillis() - this.startTime));
		map.put("cPUTime", (this.endCpu - startCpu));
		map.put("gcCount", this.gcCount);
		map.put("gcTime", this.gcTime);

		long tempSqlTotalTime = this.sqlTotalTime;
		long tempSqlTotalRows = this.sqlTotalRows;
		long tempSqlTotalRuns = this.sqlTotalRuns;
		
		synchronized(localSQLList){
			for(LocalSQL localSql : localSQLList){
				for(TraceSQL sql : localSql.values()){
					tempSqlTotalTime += sql.totalTime;
					tempSqlTotalRows += sql.processedRows;
					tempSqlTotalRuns += sql.runs;
				}
			}
		}
		

		map.put("sqlTotalTime", tempSqlTotalTime);
		map.put("sqlTotalRows", tempSqlTotalRows);
		map.put("sqlTotalRuns", tempSqlTotalRuns);		
		
		if(this.lastStack == null){
			map.put("lastStack", "None");			
		}else{
			map.put("lastStack", this.lastStack);			
		}

		return map;
	}	
	
	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 getLogFullFilename(){
		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 BatchPack makePack(){
		BatchPack pack = new BatchPack();
		Configure config = Configure.getInstance();
		
		pack.objHash = config.getObjHash();	
		pack.objName = config.getObjName();
		pack.objType = config.obj_type;
		pack.batchJobId = this.batchJobId;
		pack.batchJobId =  this.batchJobId;
		pack.args =  this.args;
		pack.pID =  this.pID;
		pack.startTime =  this.startTime;
		pack.elapsedTime =  (this.endTime - this.startTime);
		pack.threadCnt =  this.threadCnt;
		pack.cpuTime =  (this.endCpu - this.startCpu);
		
		
		pack.sqlTotalCnt =  this.sqlTotalCnt;
		pack.sqlTotalTime =  this.sqlTotalTime;
		pack.sqlTotalRows =  this.sqlTotalRows;
		pack.sqlTotalRuns =  this.sqlTotalRuns;

		pack.isStack = isStackLogFile;
		
		if(this.sqlTotalCnt > 0){
			pack.uniqueSqls = this.uniqueSqls;		
			pack.sqlStats = new ArrayList((int)this.sqlTotalCnt);
			MapValue value;
			for(TraceSQL traceSql : sortTraceSQLList()){
				value = new MapValue();
				pack.sqlStats.add(value);
	
				value.put("hashValue", (long)traceSql.hashValue);
				value.put("runs", (long)traceSql.runs);
				value.put("startTime", traceSql.startTime);
				value.put("endTime", traceSql.endTime);
				value.put("totalTime", traceSql.totalTime);
				value.put("minTime", traceSql.minTime);
				value.put("maxTime", traceSql.maxTime);
				value.put("processedRows", traceSql.processedRows);
				value.put("rowed", new BooleanValue(traceSql.rowed));
			}
		}
		return pack;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy