OraMon.java 8.39 KB
package se.lil.om;

import java.sql.*;
import java.util.Properties;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class OraMon {
	Connection conn = null;
	String conString = "jdbc:oracle:thin:@//hostname:1521/SID";
	String conUser = "system";
	String conPass = "passw0rd";
	String dbName = null;
	
	public static final int SYSSTAT = 1;
	public static final int OSSTAT = 2;
	
	Collector colSysStat = new Collector();
	Collector colOsStat = new Collector();
	
	int getDataCalls = 0;
	int getDataSucess = 0;
	
	public int getDataCalled() {
		return getDataCalls;
	}
	
	public int getDataSucceeded() {
		return getDataSucess;
	}
	
	public int getDataFailed() {
		return getDataCalls - getDataSucess;
	}
	
	public String getConString() {
		return this.conString;
	}
	
	//NUM_CPUS
	int numCpus = 0;
	public long getNumberOfCPUs() throws Throwable {
		return numCpus;
	}
	
	//DB CPU
	LongDelta cpuTime = new LongDelta(true);
	LongDelta niwTime = new LongDelta(true);
	public double getCPUPercent(boolean excludeNonIdleWaitTime) throws Throwable {
		double perSec = cpuTime.getPerSecondValue();
		if(excludeNonIdleWaitTime) {
			double newPerSec = perSec - (niwTime.getPerSecondValue() * 1000);
			if(newPerSec > 0) perSec = newPerSec; else perSec = 0;
		}
		double totSec = numCpus * 1000 * 1000;
		double percent = (perSec / totSec) * 100;
		if(percent > 100D) percent=100D;
		if(percent < 0D) percent=0D;
		return percent;
	}
	public double getCPUPercent() throws Throwable {
		return getCPUPercent(false);
	}
	public double getCPUAvailableSeconds() throws Throwable {
		return cpuTime.getSeconds()*numCpus;
	}
	public long getCPURawValue() throws Throwable {
		return cpuTime.getCurrentValue();
	}
	public long getCPURawDiff() {
		if(cpuTime != null && cpuTime.lastValue != null)
			return cpuTime.curValue - cpuTime.lastValue;
		else
			return 0;
	}
	
	public double getCPUTimePerSecond() throws Throwable {
		return cpuTime.getPerSecondValue();
	}
	
	public double getPerSecondValue(String name) throws Throwable {
		return getPerSecondValue(name, SYSSTAT);
	}
	
	public double getPerSecondValue(String name, int table) throws Throwable {
		switch (table) {
		case OSSTAT:
			return colOsStat.getPerSecValue(name);
		case SYSSTAT:
			return colSysStat.getPerSecValue(name);
		default:
			return colSysStat.getPerSecValue(name);
		}
	}
	
	public String getDBName() {
		return this.dbName;
	}
	
	public double getOsBusyPercent() throws Throwable {
		double idle = getPerSecondValue("IDLE_TIME", OSSTAT);
		double busy = getPerSecondValue("BUSY_TIME", OSSTAT);
		if(idle != 0 && busy != 0)
			return 100*(busy/(busy+idle));
		else {
			if(busy == 0)
				return 0;
			else
				return 100;
		}
	}
	
	// OS LOAD
	DoubleDelta osLoad = new DoubleDelta();
	
	public double getOsLoad() throws Throwable {
		return osLoad.getCurrentValue();
	}
	
	public double getOsLoadPerCPU() throws Throwable {
		double num = this.numCpus;
		double load = getOsLoad();
		return load / num;
	}
	
	public double getBufferCacheHitRatioPercent() throws Throwable {
		double conGetsCache = getPerSecondValue("consistent gets from cache");
		double dbBlocksCache = getPerSecondValue("db block gets from cache");
		double physReadsCache = getPerSecondValue("physical reads cache");
		if (conGetsCache + dbBlocksCache + physReadsCache == 0) {
			return 100;
		}
		if (conGetsCache + dbBlocksCache == 0 && physReadsCache > 0) {
			return 0;
		}
		double buffCacheHitRatio = 1 - (physReadsCache/(conGetsCache + dbBlocksCache));
		if(buffCacheHitRatio > 0)
			return buffCacheHitRatio * 100;
		else
			return 0;
		
	}
	
	public double getCacheHitRatioPercent() throws Throwable {
		double conGets = getPerSecondValue("consistent gets");
		double dbBlocks = getPerSecondValue("db block gets");
		double physReads = getPerSecondValue("physical reads");
		if (conGets + dbBlocks + physReads == 0) {
			return 100;
		}
		if (conGets + dbBlocks == 0 && physReads > 0) {
			return 0;
		}
		double cacheHitRatio = 1 - (physReads/(conGets + dbBlocks));
		if(cacheHitRatio > 0)
			return cacheHitRatio * 100;
		else
			return 0;
	}
	
	public double getLogicalReadsPerSecond() throws Throwable {
		return getPerSecondValue("consistent gets") + getPerSecondValue("db block gets");
	}
	
	long lastRTns = 0;
	public long getLastRTms() {
		return lastRTns / (1000 * 1000);
	}
	
	long lastFetchTSns = 0;
	public boolean getData(long ageTs) throws Throwable {
		if ((System.nanoTime() - lastFetchTSns) > (ageTs * 1000 * 1000 * 1000)) return getData();
		else return false;
	}
	
	public long getAgeTs() {
		return (System.nanoTime() - lastFetchTSns)/(1000*1000*1000);
	}
	
	Lock lock = new ReentrantLock();
	Throwable lastEx = null;
	
 	public boolean getData() throws Throwable {
 		// Start thread safe
 		// Try to get a lock
 		boolean haveLock = lock.tryLock();
		if( haveLock == false) {
			// We could not get the lock, someone else is updating. Wait for it to complete by waiting for a lock, then unlock and return.
			try {
				lock.lock();
			} finally {
				lock.unlock();
			}
			return false;
		}
		// We do have the lock. Do the rest in a try catch everything and if we catch anything, re throw the catch but always release the lock.
		try {
	 		long startTSns = System.nanoTime();
	 		getDataCalls++;
	 		if(conn == null) open();
	 		if(conn.isClosed()) open();
	 		boolean stale = true;
	 		try {
	 			if (conn.isValid(20)) {
	 				stale = false;
	 			}
	 		} catch (SQLException e) {
	 			stale = true;
	 		}
	 		if(stale) {
	 			open();
	 		}
			Statement stmt = conn.createStatement();
			Statement scrollStmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
			ResultSet rset = null;
			
			//Get the database name once
			if(this.dbName == null) {
				rset = stmt.executeQuery("select value from V$SYSTEM_PARAMETER where name = 'db_name'");
				rset.next();
				this.dbName = rset.getString(1);
				rset.close(); 
			}
			
			//Get the entire V_$OSSTAT table from DB
			colOsStat.update(stmt.executeQuery("select systimestamp, stat_name, value from V$OSSTAT"));
			
			//Set numCpus
			this.numCpus = (int) colOsStat.getCurrentValue("NUM_CPUS");
			
			// Get DB CPU use time
			rset = scrollStmt.executeQuery("select systimestamp, s.value as NIWT, t.value as DBCPU from V$SYSSTAT s, V$SYS_TIME_MODEL t where s.name='non-idle wait time' and t.STAT_NAME='DB CPU'");
			cpuTime.update(rset, 3, false, false);
			rset.beforeFirst();
			niwTime.update(rset, 2, false);
			
//			cpuTime.update(stmt.executeQuery("select systimestamp, value from V$SYS_TIME_MODEL where stat_name='DB CPU'"));
//			niwTime.update(stmt.executeQuery("select systimestamp, value from V$SYSSTAT where name='non-idle wait time'"));
			
			// Get OS Load
			osLoad.update(stmt.executeQuery("select systimestamp, value from V$OSSTAT where stat_name='LOAD'"));
	
			//Get the entire V_$SYSSTAT table from DB
			colSysStat.update(stmt.executeQuery("select systimestamp, name, value from V$SYSSTAT"));
			
			stmt.close(); 
			getDataSucess++;
			lastFetchTSns = System.nanoTime();
			lastRTns = lastFetchTSns - startTSns;
			return true;
		} catch (Throwable e) {
			Throwable lastCause = e.getCause();
			Throwable thisCause = e;
			while(lastCause != null) { thisCause = lastCause; lastCause = thisCause.getCause(); }
			lastEx = thisCause;
			throw (e);
		} finally {
			lock.unlock();
		}
		// End thread safe
	}
 	
	public Throwable getLastEx() {
		return lastEx;
	}
	
	public OraMon() {
		// TODO Auto-generated constructor stub
	}
	
	public OraMon(String con, String user, String pass) {
		this.conString = con;
		this.conUser = user;
		this.conPass = pass;
	}
	
	public void open() throws Throwable {
		Class.forName ("oracle.jdbc.OracleDriver");
		Properties jdbcProps = new Properties();
		jdbcProps.put("user", conUser);
		jdbcProps.put("password", conPass);
		jdbcProps.put("v$session.program","LIL Oracle Monitor");
		this.conn = DriverManager.getConnection(conString, jdbcProps);
		
	}
	
	public void open(String con, String user, String pass) throws Throwable {
		Class.forName ("oracle.jdbc.OracleDriver");
		if(con != null) this.conString = con;
		if(user != null) this.conUser = user;
		if(pass != null) this.conPass = pass;
		Properties jdbcProps = new Properties();
		jdbcProps.put("user", conUser);
		jdbcProps.put("password", conPass);
		jdbcProps.put("v$session.program","LIL Oracle Monitor");
		this.conn = DriverManager.getConnection(conString, jdbcProps);
	}
	
	public void close() throws Throwable {
		if(conn != null) conn.close();
	}
}