package com.intrbiz.bergamot.agent.handler; import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.log4j.Logger; import org.hyperic.sigar.Humidor; import org.hyperic.sigar.ProcCredName; import org.hyperic.sigar.ProcExe; import org.hyperic.sigar.ProcMem; import org.hyperic.sigar.ProcStat; import org.hyperic.sigar.ProcState; import org.hyperic.sigar.ProcTime; import org.hyperic.sigar.SigarException; import org.hyperic.sigar.SigarPermissionDeniedException; import org.hyperic.sigar.SigarProxy; import com.intrbiz.bergamot.model.message.agent.AgentMessage; import com.intrbiz.bergamot.model.message.agent.check.CheckProcess; import com.intrbiz.bergamot.model.message.agent.error.GeneralError; import com.intrbiz.bergamot.model.message.agent.stat.ProcessStat; import com.intrbiz.bergamot.model.message.agent.stat.process.ProcessInfo; import com.intrbiz.bergamot.util.AgentUtil; public class ProcessInfoHandler extends AbstractAgentHandler { private Logger logger = Logger.getLogger(ProcessInfoHandler.class); private SigarProxy sigar = Humidor.getInstance().getSigar(); public ProcessInfoHandler() { super(); } @Override public Class<?>[] getMessages() { return new Class[] { CheckProcess.class }; } @Override public AgentMessage handle(AgentMessage request) { CheckProcess checkProc = (CheckProcess) request; try { ProcessStat stat = new ProcessStat(request); // stats ProcStat ps = this.sigar.getProcStat(); stat.setTotal(ps.getTotal()); stat.setSleeping(ps.getSleeping()); stat.setIdle(ps.getIdle()); stat.setRunning(ps.getRunning()); stat.setStopped(ps.getStopped()); stat.setThreads(ps.getThreads()); stat.setZombie(ps.getZombie()); // enumerate the processes if (checkProc.isListProcesses()) { long[] pids = this.sigar.getProcList(); for (long pid : pids) { try { // get basic information about the process List<String> commandLine = Arrays.asList(this.sigar.getProcArgs(pid)); ProcCredName creds = this.sigar.getProcCredName(pid); ProcState state = this.sigar.getProcState(pid); // filtered? if (matchesFilter(checkProc, state, creds, commandLine)) { // detailed info ProcExe exe = this.sigar.getProcExe(pid); ProcMem mem = this.sigar.getProcMem(pid); ProcTime time = this.sigar.getProcTime(pid); // build the info ProcessInfo info = new ProcessInfo(); info.setPid(pid); info.setTitle(state.getName()); info.setState(new String(new char[] { state.getState() })); info.setParentPid(state.getPpid()); info.setThreads(state.getThreads()); info.setCommandLine(commandLine); info.setUser(creds.getUser()); info.setGroup(creds.getGroup()); info.setExecutable(exe.getName()); info.setCurrentWorkingDirectory(exe.getCwd()); info.setSize(mem.getSize()); info.setResident(mem.getResident()); info.setShare(mem.getShare()); info.setStartedAt(time.getStartTime()); info.setTotalTime(time.getTotal()); info.setUserTime(time.getUser()); info.setSysTime(time.getSys()); // add stat.getProcesses().add(info); } } catch (SigarPermissionDeniedException e) { } catch (SigarException e) { // quite often get errors for short lived PIDs, so ignore, // a specific exception class would be nice if (logger.isDebugEnabled()) logger.debug("Cannot get process information", e); } } } return stat; } catch (SigarException e) { return new GeneralError(e.getMessage()); } } private static boolean matchesFilter(CheckProcess check, ProcState state, ProcCredName creds, List<String> commandLine) { // user if (! AgentUtil.isEmpty(check.getUser())) { if (creds.getUser() != null && (! creds.getUser().equalsIgnoreCase(check.getUser()))) return false; } // group if (! AgentUtil.isEmpty(check.getGroup())) { if (creds.getGroup() != null && (! creds.getGroup().equalsIgnoreCase(check.getGroup()))) return false; } // state if (check.getState() != null && check.getState().size() > 0) { if (! isStateInList(check.getState(), new String(new char[] { state.getState() }))) return false; } // process title if (! AgentUtil.isEmpty(check.getTitle())) { String title = state.getName(); // regex? if (check.isRegex()) { Pattern pattern = Pattern.compile(check.getTitle()); Matcher matcher = pattern.matcher(title); if (! matcher.find()) return false; } else { if (! title.contains(check.getTitle())) return false; } } // command name if (! AgentUtil.isEmpty(check.getCommand())) { if (commandLine.size() == 0) return false; // flatten command line String command = check.isFlattenCommand() ? flattenCommandLine(commandLine) : commandLine.get(0); // regex? if (check.isRegex()) { Pattern pattern = Pattern.compile(check.getCommand()); Matcher matcher = pattern.matcher(command); if (! matcher.find()) return false; } else { if (! command.contains(check.getCommand())) return false; } } // arguments if (check.getArguments() != null && check.getArguments().size() > 0) { // match each argument against the command line arguments int matched = 0; for (String argument : check.getArguments()) { for (int i = 0; i < commandLine.size(); i++) { String processArgument = commandLine.get(i); if (check.isRegex()) { Pattern pattern = Pattern.compile(argument); Matcher matcher = pattern.matcher(processArgument); if (matcher.find()) { matched++; break; } } else { if (processArgument.contains(argument)) { matched ++; break; } } } } // did we match each required argument if (matched != check.getArguments().size()) return false; } return true; } private static String flattenCommandLine(List<String> commandLine) { StringBuilder sb = new StringBuilder(); boolean ns = false; for (String part : commandLine) { if (ns) sb.append(" "); sb.append(part); ns = true; } return sb.toString().trim(); } private static boolean isStateInList(List<String> states, String state) { for (String x : states) { if (state.equals(x)) return true; } return false; } }