/* * Copyright 2012 dominictootell * * 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 org.greencheek.processio.agent; import org.greencheek.processio.service.usage.BasicProcessIOUsage; import org.greencheek.processio.service.pid.JMXJVMProcessIdObtainer; import org.greencheek.processio.service.pid.JVMProcessIdObtainer; import org.greencheek.processio.service.usage.ProcessIOUsage; import org.greencheek.processio.service.io.FileSystemProcIOProcessIOReader; import org.greencheek.processio.service.io.ProcessIOReader; import org.greencheek.processio.service.persistence.ProcessIOUsagePersistence; import org.greencheek.processio.service.persistence.jmx.ProcessIOUsagePersistenceViaJmx; import org.greencheek.processio.service.scheduler.ProcessIOScheduler; import org.greencheek.processio.service.scheduler.ScheduledExecutorServiceProcessIOScheduler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.instrument.Instrumentation; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * <p> * Agent that is responsible for setting up a scheduler that periodically reads * the amount of read and write io that the current jvm process has performed. * The java is enabled via the -javaagent flag on the jvm. For example on a tomcat it can be * controlled via the following (example for enabling in tomcat): * <pre> * export CATALINA_OPTS="-javaagent:$CATALINA_HOME/lib/processio-0.0.1-SNAPSHOT-relocated-shade.jar=frequency=300000,jmxbeanname=io,jmxdomainname=my.domain" * </pre> * </p> * <p> * The following arguments are available: * <ul> * <li>frequency : The frequency of the io collection in millis</li> * <li>jmxbeanname : The name of the bean to register in jmx</li> * <li>jmxdomainname : Then name of the domain under which to register the bean in jmx</li> * </ul> * </p> * <p> * The agent registers the io that is being used by the jvm within the jvm's MBeanServer * </p> */ public class ProcessIOAgent { // // order by greatest (top 5), just for example of using /proc/PID/io // grep read_bytes /proc/[0-9]*/io | sort -nrk2 | head -5 // private static final Logger log = LoggerFactory.getLogger(ProcessIOAgent.class); private static final Pattern FREQUENCY_OPTION = Pattern.compile(".*frequency=(\\d+).*"); private static final Pattern JMX_BEAN_NAME = Pattern.compile(".*jmxbeanname=(\\w+).*"); private static final Pattern JMX_DOMAIN_NAME = Pattern.compile(".*jmxdomainname=([\\w\\.]+).*"); private static final long DEFAULT_SCHEDULING_FREQUENCY = ProcessIOScheduler.DEFAULT_FREQUENCY_IN_MILLIS; private static final JVMProcessIdObtainer pidParser = new JMXJVMProcessIdObtainer(); private static final ProcessIOReader processIOReader; private static volatile ProcessIOScheduler scheduler; private static final ProcessIOUsage calculator = new BasicProcessIOUsage(); private static volatile ProcessIOUsagePersistence persistence; private static final int CURRENT_JVM_PID; private static boolean foundPID; static { CURRENT_JVM_PID = pidParser.getProcessId(); foundPID = (CURRENT_JVM_PID!=JVMProcessIdObtainer.PID_NOT_FOUND); ProcessIOReader ioReader = null; if(foundPID) { ioReader = new FileSystemProcIOProcessIOReader(CURRENT_JVM_PID); } processIOReader = ioReader; } // Required method for instrumentation agent. public static void premain(String arglist, Instrumentation inst) { if(!foundPID) { log.error("Unabled to Determine pid for current jvm process to agent has no effect"); } else { String beanName = null; String domainName = null; long frequencyOfScheduler = DEFAULT_SCHEDULING_FREQUENCY; if(arglist!=null && arglist.trim().length()>0) { Matcher m = FREQUENCY_OPTION.matcher(arglist); if(m.matches()) { try { frequencyOfScheduler = Long.parseLong(m.group(1)); } catch(NumberFormatException e) {} } m = JMX_BEAN_NAME.matcher(arglist); // got a bean name if(m.matches()) { beanName = m.group(1); } m = JMX_DOMAIN_NAME.matcher(arglist); if(m.matches()) domainName = m.group(1); if(beanName == null || beanName.trim().length()==0) beanName = ProcessIOUsagePersistenceViaJmx.DEFAULT_JMX_BEAN_NAME; if(domainName == null || domainName.trim().length()==0) domainName = ProcessIOUsagePersistenceViaJmx.DEFAULT_JMX_DOMAIN_NAME; persistence = new ProcessIOUsagePersistenceViaJmx(calculator,domainName,beanName); } else { persistence = new ProcessIOUsagePersistenceViaJmx(calculator); } scheduler = new ScheduledExecutorServiceProcessIOScheduler(processIOReader,persistence); scheduler.start(frequencyOfScheduler); log.info("ProcessIOAgent Running, io will be obtain every {}ms",frequencyOfScheduler); } } }