1
0
Fork 0
mirror of https://github.com/munin-monitoring/contrib.git synced 2025-07-22 02:51:03 +00:00

remove plugin in main munin distribution (jmx), and extract jmx2munin

This commit is contained in:
Kenyon Ralph 2012-03-05 00:00:56 -08:00
parent 7dbdcedaf0
commit 933f0ea70b
23 changed files with 685 additions and 0 deletions

8
plugins/java/jmx2munin/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
.DS_Store
.classpath
.project
.fatjar
target
eclipse
old
bin

View file

@ -0,0 +1,79 @@
# jmx2munin
The [jmx2munin](http://github.com/tcurdt/jmx2munin) project exposes JMX MBean attributes to [Munin](http://munin-monitoring.org/).
Some of it's features:
* strictly complies to the plugin format
* exposes composite types like Lists, Maps, Set as useful as possible
* String values can be mapped to numbers
# How to use
This is what the Munin script will call. So you should test this first. Of course with your parameters. This example expose all Cassandra information to Munin.
java -jar jmx2munin.jar \
-url service:jmx:rmi:///jndi/rmi://localhost:8080/jmxrmi \
-query "org.apache.cassandra.*:*"
The "url" parameters specifies the JMX URL, the query selects the MBeans (and optionally also the attributes) to expose.
java -jar jmx2munin.jar \
-url service:jmx:rmi:///jndi/rmi://localhost:8080/jmxrmi \
-query "org.apache.cassandra.*:*" \
-attribute org_apache_cassandra_db_storageservice_livenodes_size
The script that does the actual interaction with munin you can find in the contrib section. It's the one you should link in the your Munin plugin directory.
:/etc/munin/plugins$ ls -la cassandra_*
lrwxrwxrwx 1 root root 37 2011-04-07 19:58 cassandra_nodes_in_cluster -> /usr/share/munin/plugins/jmx2munin.sh
In the plugin conf you point to the correct configuration
[cassandra_*]
env.query org.apache.cassandra.*:*
[cassandra_nodes_in_cluster]
env.config cassandra/nodes_in_cluster
A possible configuration could look like this
graph_title Number of Nodes in Cluster
graph_vlabel org_apache_cassandra_db_storageservice_livenodes_size
org_apache_cassandra_db_storageservice_livenodes_size.label number of nodes
The script will extract the attributes from the config and caches the JMX results to reduce the load when showing many values.
# More advanced
Sometimes it can be useful to track String values by mapping them into an enum as they really describe states. To find this possible candidates you can call:
java -jar jmx2munin.jar \
-url service:jmx:rmi:///jndi/rmi://localhost:8080/jmxrmi \
-query "org.apache.cassandra.*:*" \
list
It should output a list of possible candidates. This can now be turned into a enum configuration file:
[org.apache.cassandra.db.StorageService:OperationMode]
0 = ^Normal
1 = ^Client
2 = ^Joining
3 = ^Bootstrapping
4 = ^Leaving
5 = ^Decommissioned
6 = ^Starting drain
7 = ^Node is drained
Which you then can provide:
java -jar jmx2munin.jar \
-url service:jmx:rmi:///jndi/rmi://localhost:8080/jmxrmi \
-query "org.apache.cassandra.*:*" \
-enums /path/to/enums.cfg
Now matching values get replaced by their numerical representation. On the left needs to be a unique number on the right side is a regular expression. If a string cannot be matched according to the spec "U" for "undefined" will be returned.
# License
Licensed under the Apache License, Version 2.0 (the "License")
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

View file

@ -0,0 +1,3 @@
graph_title Number of Nodes in Cluster
graph_vlabel org_apache_cassandra_db_storageservice_livenodes_size
org_apache_cassandra_db_storageservice_livenodes_size.label number of nodes

View file

@ -0,0 +1,55 @@
#!/bin/bash
# [cassandra_nodes_in_cluster]
# env.config cassandra/nodes_in_cluster
# env.query org.apache.cassandra.*:*
if [ -z "$MUNIN_LIBDIR" ]; then
MUNIN_LIBDIR="`dirname $(dirname "$0")`"
fi
if [ -f "$MUNIN_LIBDIR/plugins/plugin.sh" ]; then
. $MUNIN_LIBDIR/plugins/plugin.sh
fi
if [ "$1" = "autoconf" ]; then
echo yes
exit 0
fi
if [ -z "$url" ]; then
# this is very common so make it a default
url="service:jmx:rmi:///jndi/rmi://127.0.0.1:8080/jmxrmi"
fi
if [ -z "$config" -o -z "$query" -o -z "$url" ]; then
echo "Configuration needs attributes config, query and optinally url"
exit 1
fi
JMX2MUNIN_DIR="$MUNIN_LIBDIR/plugins"
CONFIG="$JMX2MUNIN_DIR/jmx2munin.cfg/$config"
if [ "$1" = "config" ]; then
cat "$CONFIG"
exit 0
fi
JAR="$JMX2MUNIN_DIR/jmx2munin.jar"
CACHED="/tmp/jmx2munin"
if test ! -f $CACHED || test `find "$CACHED" -mmin +2`; then
java -jar "$JAR" \
-url "$url" \
-query "$query" \
$ATTRIBUTES \
> $CACHED
echo "cached.value `date +%s`" >> $CACHED
fi
ATTRIBUTES=`awk '/\.label/ { gsub(/\.label/,""); print $1 }' $CONFIG`
for ATTRIBUTE in $ATTRIBUTES; do
grep $ATTRIBUTE $CACHED
done

View file

@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.vafer</groupId>
<artifactId>jmx2munin</artifactId>
<name>jmx2munin</name>
<version>1.0</version>
<description>
Munin plugin to access JMX information
</description>
<url>http://github.com/tcurdt/jmx2munin</url>
<developers>
<developer>
<id>tcurdt</id>
<name>Torsten Curdt</name>
<email>tcurdt at vafer.org</email>
<timezone>+1</timezone>
</developer>
</developers>
<licenses>
<license>
<name>Apache License 2</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<scm>
<connection>scm:git:git://github.com:tcurdt/jmx2munin.git</connection>
<developerConnection>scm:git:git://github.com:tcurdt/jmx2munin.git</developerConnection>
<url>http://github.com/tcurdt/jmx2munin/tree/master</url>
</scm>
<dependencies>
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>1.17</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkMode>never</forkMode>
<includes>
<include>**/*TestCase.java</include>
</includes>
<excludes>
<exclude>**/Abstract*</exclude>
</excludes>
<testFailureIgnore>true</testFailureIgnore>
<skip>false</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.1</version>
<configuration>
<attach>true</attach>
</configuration>
<executions>
<execution>
<id>create-source-jar</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<artifactSet>
<includes>
<include>com.beust:jcommander</include>
</includes>
</artifactSet>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.vafer.jmx.munin.Munin</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View file

@ -0,0 +1,77 @@
package org.vafer.jmx;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Pattern;
import javax.management.ObjectName;
public final class Enums {
private TreeMap<String, LinkedHashMap<Integer, Pattern>> sections = new TreeMap<String, LinkedHashMap<Integer, Pattern>>();
public boolean load(String filePath) throws IOException {
BufferedReader input = null;
LinkedHashMap<Integer, Pattern> section = new LinkedHashMap<Integer, Pattern>();
try {
input = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));
String line;
int linenr = 0;
while((line = input.readLine()) != null) {
linenr += 1;
line = line.trim();
if (line.startsWith("#")) {
continue;
}
if (line.startsWith("[") && line.endsWith("]")) {
// new section
String id = line.substring(1, line.length() - 1);
section = new LinkedHashMap<Integer, Pattern>();
sections.put(id, section);
} else {
String[] pair = line.split("=");
if (pair.length == 2) {
Integer number = Integer.parseInt(pair[0].trim());
Pattern pattern = Pattern.compile(pair[1].trim());
if (section.put(number, pattern) != null) {
System.err.println("Line " + linenr + ": previous definitions of " + number);
}
}
}
}
} finally {
if (input != null) {
input.close();
}
}
return false;
}
public static String id(ObjectName beanName, String attributeName) {
StringBuilder sb = new StringBuilder();
sb.append(beanName.getDomain());
sb.append('.');
sb.append(beanName.getKeyProperty("type"));
sb.append(':');
sb.append(attributeName);
return sb.toString();
}
public Number resolve(String id, String value) {
LinkedHashMap<Integer, Pattern> section = sections.get(id);
if (section == null) {
return null;
}
for(Map.Entry<Integer, Pattern> entry : section.entrySet()) {
if (entry.getValue().matcher(value).matches()) {
return entry.getKey();
}
}
return null;
}
}

View file

@ -0,0 +1,9 @@
package org.vafer.jmx;
import javax.management.ObjectName;
public interface Filter {
public boolean include(ObjectName bean, String attribute);
}

View file

@ -0,0 +1,26 @@
package org.vafer.jmx;
import java.util.HashSet;
import java.util.Set;
import javax.management.ObjectName;
public final class ListOutput implements Output {
private final Set<String> seen = new HashSet<String>();
public void output(ObjectName beanName, String attributeName, Object value) {
Value.flatten(beanName, attributeName, value, new Value.Listener() {
public void value(ObjectName beanName, String attributeName, String value) {
final String id = Enums.id(beanName, attributeName);
if (!seen.contains(id)) {
System.out.println("[" + id + "]");
seen.add(id);
}
}
public void value(ObjectName beanName, String attributeName, Number value) {
}
});
}
}

View file

@ -0,0 +1,10 @@
package org.vafer.jmx;
import javax.management.ObjectName;
public final class NoFilter implements Filter {
public boolean include(ObjectName bean, String attribute) {
return true;
}
}

View file

@ -0,0 +1,9 @@
package org.vafer.jmx;
import javax.management.ObjectName;
public interface Output {
public void output(ObjectName beanName, String attributeName, Object value);
}

View file

@ -0,0 +1,52 @@
package org.vafer.jmx;
import java.io.IOException;
import java.util.Collection;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public final class Query {
public void run(String url, String expression, Filter filter, Output output) throws IOException, MalformedObjectNameException, InstanceNotFoundException, ReflectionException, IntrospectionException, AttributeNotFoundException, MBeanException {
JMXConnector connector = JMXConnectorFactory.connect(new JMXServiceURL(url));
MBeanServerConnection connection = connector.getMBeanServerConnection();
final Collection<ObjectInstance> mbeans = connection.queryMBeans(new ObjectName(expression), null);
for(ObjectInstance mbean : mbeans) {
final ObjectName mbeanName = mbean.getObjectName();
final MBeanInfo mbeanInfo = connection.getMBeanInfo(mbeanName);
final MBeanAttributeInfo[] attributes = mbeanInfo.getAttributes();
for (final MBeanAttributeInfo attribute : attributes) {
if (attribute.isReadable()) {
if (filter.include(mbeanName, attribute.getName())) {
final String attributeName = attribute.getName();
try {
output.output(
mbean.getObjectName(),
attributeName,
connection.getAttribute(mbeanName, attributeName)
);
} catch(Exception e) {
// System.err.println("Failed to read " + mbeanName + "." + attributeName);
}
}
}
}
}
connector.close();
}
}

View file

@ -0,0 +1,52 @@
package org.vafer.jmx;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.ObjectName;
public final class Value {
public interface Listener {
public void value(ObjectName beanName, String attributeName, String value);
public void value(ObjectName beanName, String attributeName, Number value);
}
public static void flatten(ObjectName beanName, String attributeName, Object value, Listener listener) {
if (value instanceof Number) {
listener.value(beanName, attributeName, (Number) value);
} else if (value instanceof String) {
listener.value(beanName, attributeName, (String) value);
} else if (value instanceof Set) {
final Set set = (Set) value;
flatten(beanName, attributeName + ".size", set.size(), listener);
for(Object entry : set) {
flatten(beanName, attributeName + "[" + entry + "]", 1, listener);
}
} else if (value instanceof List) {
final List list = (List)value;
listener.value(beanName, attributeName + ".size", list.size());
for(int i = 0; i<list.size(); i++) {
flatten(beanName, attributeName + "[" + i + "]", list.get(i), listener);
}
} else if (value instanceof Map) {
final Map<?,?> map = (Map<?,?>) value;
listener.value(beanName, attributeName + ".size", map.size());
for(Map.Entry<?, ?> entry : map.entrySet()) {
flatten(beanName, attributeName + "[" + entry.getKey() + "]", entry.getValue(), listener);
}
} else {
// System.err.println("Failed to convert " + beanName + "." + attributeName);
}
}
}

View file

@ -0,0 +1,67 @@
package org.vafer.jmx.munin;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.vafer.jmx.Enums;
import org.vafer.jmx.Filter;
import org.vafer.jmx.ListOutput;
import org.vafer.jmx.NoFilter;
import org.vafer.jmx.Query;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
public final class Munin {
@Parameter(description = "")
private List<String> args = new ArrayList<String>();
@Parameter(names = "-url", description = "jmx url", required = true)
private String url;
@Parameter(names = "-query", description = "query expression", required = true)
private String query;
@Parameter(names = "-enums", description = "file string to enum config")
private String enumsPath;
@Parameter(names = "-attribute", description = "attributes to return")
private List<String> attributes = new ArrayList<String>();
private void run() throws Exception {
final Filter filter;
if (attributes == null || attributes.isEmpty()) {
filter = new NoFilter();
} else {
filter = new MuninAttributesFilter(attributes);
}
final Enums enums = new Enums();
if (enumsPath != null) {
enums.load(enumsPath);
}
final String cmd = args.toString().toLowerCase(Locale.US);
if ("[list]".equals(cmd)) {
new Query().run(url, query, filter, new ListOutput());
} else {
new Query().run(url, query, filter, new MuninOutput(enums));
}
}
public static void main(String[] args) throws Exception {
Munin m = new Munin();
JCommander cli = new JCommander(m);
try {
cli.parse(args);
} catch(Exception e) {
cli.usage();
System.exit(1);
}
m.run();
}
}

View file

@ -0,0 +1,24 @@
package org.vafer.jmx.munin;
import java.util.HashSet;
import java.util.List;
import javax.management.ObjectName;
import org.vafer.jmx.Filter;
public final class MuninAttributesFilter implements Filter {
private final HashSet<String> attributes = new HashSet<String>();
public MuninAttributesFilter(List<String> pAttributes) {
for (String attribute : pAttributes) {
attributes.add(attribute.trim().replaceAll("_size$", ""));
}
}
public boolean include(ObjectName bean, String attribute) {
return attributes.contains(MuninOutput.attributeName(bean, attribute));
}
}

View file

@ -0,0 +1,93 @@
package org.vafer.jmx.munin;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Locale;
import javax.management.ObjectName;
import org.vafer.jmx.Enums;
import org.vafer.jmx.Output;
import org.vafer.jmx.Value;
public final class MuninOutput implements Output {
private final Enums enums;
public MuninOutput(Enums enums) {
this.enums = enums;
}
public static String attributeName(ObjectName bean, String attribute) {
StringBuilder sb = new StringBuilder();
sb.append(fieldname(beanString(bean)));
sb.append('_');
sb.append(fieldname(attribute));
return sb.toString().toLowerCase(Locale.US);
}
private static String fieldname(String s) {
return s.replaceAll("[^A-Za-z0-9]", "_");
}
private static String beanString(ObjectName beanName) {
StringBuilder sb = new StringBuilder();
sb.append(beanName.getDomain());
Hashtable<String, String> properties = beanName.getKeyPropertyList();
String keyspace = "keyspace";
if (properties.containsKey(keyspace)) {
sb.append('.');
sb.append(properties.get(keyspace));
properties.remove(keyspace);
}
String type = "type";
if (properties.containsKey(type)) {
sb.append('.');
sb.append(properties.get(type));
properties.remove(type);
}
ArrayList<String> keys = new ArrayList(properties.keySet());
Collections.sort(keys);
for(String key : keys) {
sb.append('.');
sb.append(properties.get(key));
}
return sb.toString();
// return beanName.getCanonicalName();
}
public void output(ObjectName beanName, String attributeName, Object value) {
Value.flatten(beanName, attributeName, value, new Value.Listener() {
public void value(ObjectName beanName, String attributeName, String value) {
final Number v = enums.resolve(Enums.id(beanName, attributeName), value);
if (v != null) {
value(beanName, attributeName, v);
} else {
value(beanName, attributeName, Double.NaN);
}
}
public void value(ObjectName beanName, String attributeName, Number value) {
final String v;
if (Double.isNaN(value.doubleValue())) {
v = "U";
} else {
final NumberFormat f = NumberFormat.getInstance();
f.setMaximumFractionDigits(2);
f.setGroupingUsed(false);
v = f.format(value);
}
System.out.println(attributeName(beanName, attributeName) + ".value " + v);
}
});
}
}

218
plugins/java/jstat__gccount Executable file
View file

@ -0,0 +1,218 @@
#!/bin/bash
#
# Plugin for monitor JVM activity - GC Count -
#
# Usage:
#
# Symlink into /etc/munin/plugins/ and add the monitored
# alias name like :
#
# ln -s /usr/share/munin/plugins/jstat__gccount \
# /etc/munin/plugins/jstat_<jvm alias>_gccount
# This should, however, be given through autoconf and suggest.
#
# Requirements:
#
# You need to execute your Java program under jsvc provided by
# http://jakarta.apache.org/commons/daemon/
# which enables you to run your Java program with specified
# pid file with -pidfile option.
# A Brief setup documentation is also available at
# http://tomcat.apache.org/tomcat-5.5-doc/setup.html
#
# Target:
#
# Target Java Virtual Machine to monitor are:
# Sun JDK 5.0 (http://java.sun.com/javase/) (default)
# BEA JRockit 5.0 (http://dev2dev.bea.com/jrockit/)
#
# Parameters:
#
# config (required)
#
# Config variables:
#
# pidfilepath - Which file path use. Defaults to '/var/run/jsvc.pid'
# javahome - Defaults to '/usr/local/java/jdk'
#
DefaultPidFile="/var/run/jsvc.pid"
DefaultJavaHome="/usr/local/java/jdk"
#
# Environment Variables
#
if [ -z "${pidfilepath}" ]; then
pidfilepath="${DefaultPidFile}"
fi
if [ -z "${graphtitle}" ]; then
graphtitle="${pidfilepath}"
fi
if [ -z "${javahome}" ]; then
JAVA_HOME="${DefaultJavaHome}"
else
JAVA_HOME="${javahome}"
fi
export JAVA_HOME
#
# Functions
#
chk_jdk()
{
isJRockit=`${JAVA_HOME}/bin/java -version 2>&1 | egrep -i 'jrockit'`
if [ -n "${isJRockit}" ]; then
JDK_TYPE="bea"
else
JDK_TYPE="sun"
fi
}
chk_version()
{
Version=`${JAVA_HOME}/bin/java -version 2>&1 | egrep '^java version' | awk '{print $3}' | sed -e 's/\"//g' | cut -d'_' -f 1`
if [ "${Version}" != "1.5.0" ]; then
return 1
else
return 0
fi
}
config_common()
{
echo 'graph_title GC Count' $graphtitle
echo 'graph_args -l 0'
echo 'graph_vlabel GC Count(times)'
echo 'graph_total total'
echo 'graph_info GC Count'
echo 'graph_category JVM'
}
config_sun_jdk()
{
config_common
echo 'Young_GC.label Young_GC'
echo 'Young_GC.min 0'
echo 'Full_GC.label Full_GC'
echo 'Full_GC.min 0'
}
config_bea_jdk()
{
config_common
echo 'Young_GC.label Young_GC'
echo 'Young_GC.min 0'
echo 'Old_GC.label Old_GC'
echo 'Old_GC.min 0'
}
print_sun_stats()
{
${JAVA_HOME}/bin/jstat -gc ${PidNum} | tail -1 | awk \
'{\
S0C = $1; \
S1C = $2; \
S0U = $3; \
S1U = $4; \
EC = $5; \
EU = $6; \
OC = $7; \
OU = $8; \
PC = $9; \
PU = $10; \
YGC = $11; \
YGCT = $12; \
FGC = $13; \
FGCT = $14; \
GCT = $15; \
\
S0F = S0C - S0U; \
S1F = S1C - S1U; \
EF = EC - EU; \
OF = OC - OU; \
PF = PC - PU; \
\
print "Young_GC.value " YGC; \
print "Full_GC.value " FGC; \
}'
}
print_bea_stats()
{
${JAVA_HOME}/bin/jstat -gc ${PidNum} | tail -1 | awk \
'{\
HeapSize = $1; \
NurserySize = $2; \
UsedHeapSize = $3; \
YC = $4; \
OC = $5; \
YCTime = $6; \
OCTime = $7; \
GCTime = $8; \
YCPauseTime = $9; \
OCPauseTime = $10; \
PauseTime = $11; \
Finalizers = $12; \
\
print "Young_GC.value " YC; \
print "Old_GC.value " OC;\
}'
}
#
# common for all argument
#
chk_jdk
#
# autoconf
#
if [ "$1" = "autoconf" ]; then
if [ ! -x "${JAVA_HOME}/bin/jstat" ]; then
echo "no (No jstat found in ${JAVA_HOME}/bin)"
exit 1
fi
chk_version
if [ $? != 0 ]; then
echo "no (Java version is invalid)"
exit 1
fi
if [ ! -f "${pidfilepath}" -o ! -r "${pidfilepath}" ]; then
echo "no (No such file ${pidfilepath} or cannot read ${pidfilepath}"
exit 1
fi
echo "yes"
exit 0
fi
#
# config
#
if [ "$1" = "config" ]; then
if [ "${JDK_TYPE}" == "bea" ]; then
config_bea_jdk
else
config_sun_jdk
fi
exit 0
fi
#
# Main
#
PidNum=`cat ${pidfilepath}`
if [ "${JDK_TYPE}" == "bea" ]; then
print_bea_stats
else
print_sun_stats
fi

226
plugins/java/jstat__gctime Executable file
View file

@ -0,0 +1,226 @@
#!/bin/bash
#
# Plugin for monitor JVM activity - GC Time -
#
# Usage:
#
# Symlink into /etc/munin/plugins/ and add the monitored
# alias name like :
#
# ln -s /usr/share/munin/plugins/jstat__gctime \
# /etc/munin/plugins/jstat_<jvm alias>_gctime
# This should, however, be given through autoconf and suggest.
#
# Requirements:
#
# You need to execute your Java program under jsvc provided by
# http://jakarta.apache.org/commons/daemon/
# which enables you to run your Java program with specified
# pid file with -pidfile option.
# A Brief setup documentation is also available at
# http://tomcat.apache.org/tomcat-5.5-doc/setup.html
#
# Target:
#
# Target Java Virtual Machine to monitor are:
# Sun JDK 5.0 (http://java.sun.com/javase/) (default)
# BEA JRockit 5.0 (http://dev2dev.bea.com/jrockit/)
#
# Parameters:
#
# config (required)
#
# Config variables:
#
# pidfilepath - Which file path use. Defaults to '/var/run/jsvc.pid'
# javahome - Defaults to '/usr/local/java/jdk'
#
DefaultPidFile="/var/run/jsvc.pid"
DefaultJavaHome="/usr/local/java/jdk"
#
# Environment Variables
#
if [ -z "${pidfilepath}" ]; then
pidfilepath="${DefaultPidFile}"
fi
if [ -z "${graphtitle}" ]; then
graphtitle="${pidfilepath}"
fi
if [ -z "${javahome}" ]; then
JAVA_HOME="${DefaultJavaHome}"
else
JAVA_HOME="${javahome}"
fi
export JAVA_HOME
#
# Functions
#
chk_jdk()
{
isJRockit=`${JAVA_HOME}/bin/java -version 2>&1 | egrep -i 'jrockit'`
if [ -n "${isJRockit}" ]; then
JDK_TYPE="bea"
else
JDK_TYPE="sun"
fi
}
chk_version()
{
Version=`${JAVA_HOME}/bin/java -version 2>&1 | egrep '^java version' | awk '{print $3}' | sed -e 's/\"//g' | cut -d'_' -f 1`
if [ "${Version}" != "1.5.0" ]; then
return 1
else
return 0
fi
}
config_common()
{
echo 'graph_title GC Time' $graphtitle
echo 'graph_args -l 0'
echo 'graph_vlabel GC Time(sec)'
echo 'graph_total total'
echo 'graph_info GC Time'
echo 'graph_category JVM'
}
config_sun_jdk()
{
config_common
echo 'Young_GC.label Young_GC'
echo 'Young_GC.min 0'
echo 'Full_GC.label Full_GC'
echo 'Full_GC.min 0'
}
config_bea_jdk()
{
config_common
echo 'Young_GC.label Young_GC'
echo 'Young_GC.min 0'
echo 'Old_GC.label Old_GC'
echo 'Old_GC.min 0'
echo 'Young_Pause.label Young_GC Pause'
echo 'Young_Pause.min 0'
echo 'Old_Pause.label Old_GC Pause'
echo 'Old_Pause.min 0'
}
print_sun_stats()
{
${JAVA_HOME}/bin/jstat -gc ${PidNum} | tail -1 | awk \
'{\
S0C = $1; \
S1C = $2; \
S0U = $3; \
S1U = $4; \
EC = $5; \
EU = $6; \
OC = $7; \
OU = $8;
PC = $9; \
PU = $10; \
YGC = $11; \
YGCT = $12; \
FGC = $13; \
FGCT = $14; \
GCT = $15; \
\
S0F = S0C - S0U; \
S1F = S1C - S1U; \
EF = EC - EU; \
OF = OC - OU; \
PF = PC - PU; \
\
print "Young_GC.value " YGCT; \
print "Full_GC.value " FGCT; \
}'
}
print_bea_stats()
{
${JAVA_HOME}/bin/jstat -gc ${PidNum} | tail -1 | awk \
'{\
HeapSize = $1; \
NurserySize = $2; \
UsedHeapSize = $3; \
YC = $4; \
OC = $5; \
YCTime = $6; \
OCTime = $7; \
GCTime = $8; \
YCPauseTime = $9; \
OCPauseTime = $10; \
PauseTime = $11; \
Finalizers = $12; \
\
print "Young_GC.value " YCTime; \
print "Old_GC.value " OCTime; \
print "Young_Pause.value " YCPauseTime; \
print "Old_Pause.value " OCPauseTime
}'
}
#
# common for all argument
#
chk_jdk
#
# autoconf
#
if [ "$1" = "autoconf" ]; then
if [ ! -x "${JAVA_HOME}/bin/jstat" ]; then
echo "no (No jstat found in ${JAVA_HOME}/bin)"
exit 1
fi
chk_version
if [ $? != 0 ]; then
echo "no (Java version is invalid)"
exit 1
fi
if [ ! -f "${pidfilepath}" -o ! -r "${pidfilepath}" ]; then
echo "no (No such file ${pidfilepath} or cannot read ${pidfilepath}"
exit 1
fi
echo "yes"
exit 0
fi
#
# config
#
if [ "$1" = "config" ]; then
if [ "${JDK_TYPE}" == "bea" ]; then
config_bea_jdk
else
config_sun_jdk
fi
exit 0
fi
#
# Main
#
PidNum=`cat ${pidfilepath}`
if [ "${JDK_TYPE}" == "bea" ]; then
print_bea_stats
else
print_sun_stats
fi

238
plugins/java/jstat__heap Executable file
View file

@ -0,0 +1,238 @@
#!/bin/bash
#
# Plugin for monitor JVM activity - Heap Usage -
#
# Usage:
#
# Symlink into /etc/munin/plugins/ and add the monitored
# alias name like :
#
# ln -s /usr/share/munin/plugins/jstat__heap \
# /etc/munin/plugins/jstat_<jvm alias>_heap
# This should, however, be given through autoconf and suggest.
#
# Requirements:
#
# You need to execute your Java program under jsvc provided by
# http://jakarta.apache.org/commons/daemon/
# which enables you to run your Java program with specified
# pid file with -pidfile option.
# A Brief setup documentation is also available at
# http://tomcat.apache.org/tomcat-5.5-doc/setup.html
#
# Target:
#
# Target Java Virtual Machine to monitor are:
# Sun JDK 5.0 (http://java.sun.com/javase/) (default)
# BEA JRockit 5.0 (http://dev2dev.bea.com/jrockit/)
#
# Parameters:
#
# config (required)
#
# Config variables:
#
# pidfilepath - Which file path use. Defaults to '/var/run/jsvc.pid'
# javahome - Defaults to '/usr/local/java/jdk'
#
DefaultPidFile="/var/run/jsvc.pid"
DefaultJavaHome="/usr/local/java/jdk"
#
# Environment Variables
#
if [ -z "${pidfilepath}" ]; then
pidfilepath="${DefaultPidFile}"
fi
if [ -z "${graphtitle}" ]; then
graphtitle="${pidfilepath}"
fi
if [ -z "${javahome}" ]; then
JAVA_HOME="${DefaultJavaHome}"
else
JAVA_HOME="${javahome}"
fi
export JAVA_HOME
#
# Functions
#
chk_jdk()
{
isJRockit=`${JAVA_HOME}/bin/java -version 2>&1 | egrep -i 'jrockit'`
if [ -n "${isJRockit}" ]; then
JDK_TYPE="bea"
else
JDK_TYPE="sun"
fi
}
chk_version()
{
Version=`${JAVA_HOME}/bin/java -version 2>&1 | egrep '^java version' | awk '{print $3}' | sed -e 's/\"//g' | cut -d'_' -f 1`
if [ "${Version}" != "1.5.0" ]; then
return 1
else
return 0
fi
}
config_common()
{
echo "graph_title Heap Usage" $graphtitle
echo "graph_args --base 1024 -l 0"
echo "graph_vlabel Heap Usage(Bytes)"
echo "graph_info Heap Usage"
echo "graph_category JVM"
}
config_sun_jdk()
{
config_common
echo "Eden_Used.label Eden_Used"
echo "Eden_Free.label Eden_Free"
echo "Survivor0_Used.label Survivor0_Used"
echo "Survivor0_Free.label Survivor0_Free"
echo "Survivor1_Used.label Survivor1_Used"
echo "Survivor1_Free.label Survivor1_Free"
echo "Old_Used.label Old_Used"
echo "Old_Free.label Old_Free"
echo "Permanent_Used.label Permanent_Used"
echo "Permanent_Free.label Permanent_Free"
echo "Eden_Used.draw AREA"
echo "Eden_Free.draw STACK"
echo "Survivor0_Used.draw STACK"
echo "Survivor0_Free.draw STACK"
echo "Survivor1_Used.draw STACK"
echo "Survivor1_Free.draw STACK"
echo "Old_Used.draw STACK"
echo "Old_Free.draw STACK"
echo "Permanent_Used.draw STACK"
echo "Permanent_Free.draw STACK"
}
config_bea_jdk()
{
config_common
echo "NurserySize.label NurserySize"
echo "HeapSize.label HeapSize"
echo "UsedHeapSize.label UsedHeapSize"
echo "NurserySize.draw AREA"
echo "HeapSize.draw STACK"
echo "UsedHeapSize.draw STACK"
}
print_sun_stats()
{
${JAVA_HOME}/bin/jstat -gc ${PidNum} | tail -1 | awk \
'{\
S0C = $1; \
S1C = $2; \
S0U = $3; \
S1U = $4; \
EC = $5; \
EU = $6; \
OC = $7; \
OU = $8;
PC = $9; \
PU = $10; \
\
S0F = S0C - S0U; \
S1F = S1C - S1U; \
EF = EC - EU; \
OF = OC - OU; \
PF = PC - PU; \
\
print "Eden_Used.value " EU * 1024; \
print "Eden_Free.value " EF * 1024; \
print "Survivor0_Used.value " S0U * 1024; \
print "Survivor0_Free.value " S0F * 1024; \
print "Survivor1_Used.value " S1U * 1024; \
print "Survivor1_Free.value " S1F * 1024; \
print "Old_Used.value " OU * 1024; \
print "Old_Free.value " OF * 1024; \
print "Permanent_Used.value " PU * 1024; \
print "Permanent_Free.value " PF * 1024; \
}'
}
print_bea_stats()
{
${JAVA_HOME}/bin/jstat -gc ${PidNum} | tail -1 | awk \
'{\
HeapSize = $1; \
NurserySize = $2; \
UsedHeapSize = $3; \
YC = $4; \
OC = $5; \
YCTime = $6; \
OCTime = $7; \
GCTime = $8; \
YCPauseTime = $9; \
OCPauseTime = $10; \
PauseTime = $11; \
Finalizers = $12; \
\
print "NurserySize.value " NurserySize * 1024; \
print "HeapSize.value " UsedHeapSize * 1024; \
print "UsedHeapSize.value " UsedHeapSize * 1024; \
}'
}
#
# common for all argument
#
chk_jdk
#
# autoconf
#
if [ "$1" = "autoconf" ]; then
if [ ! -x "${JAVA_HOME}/bin/jstat" ]; then
echo "no (No jstat found in ${JAVA_HOME}/bin)"
exit 1
fi
chk_version
if [ $? != 0 ]; then
echo "no (Java version is invalid)"
exit 1
fi
if [ ! -f "${pidfilepath}" -o ! -r "${pidfilepath}" ]; then
echo "no (No such file ${pidfilepath} or cannot read ${pidfilepath}"
exit 1
fi
echo "yes"
exit 0
fi
#
# config
#
if [ "$1" = "config" ]; then
if [ "${JDK_TYPE}" == "bea" ]; then
config_bea_jdk
else
config_sun_jdk
fi
exit 0
fi
#
# Main
#
PidNum=`cat ${pidfilepath}`
if [ "${JDK_TYPE}" == "bea" ]; then
print_bea_stats
else
print_sun_stats
fi

182
plugins/java/jvm_sun_memory Executable file
View file

@ -0,0 +1,182 @@
#!/usr/bin/perl -w
# Sun JVM memory statistics. Parses a verbose log of minor GC and
# tenured GC stats.
# To determine the totalheap value it looks for maxmem stats (from a
# tenured gc) in the last 5 minutes of the log file. If there are no
# log lines in the last 5 minutes the value will be U(ndefined).
# Since the log lines are timestamped with seconds since the JVM
# started we look at the last line of the log to determine when "now"
# is for the JVM. In a reasonably active JVM there will be several
# minor GCs a minute so the "now" approximation based on these log
# lines are close enough.
# Configuration (common with the other sun_jvm_* plugins in this family):
# [jvm_sun_*]
# env.logfile /var/foo/java.log (default: /var/log/app/jvm/gc.log)
# env.graphtitle (default: "Sun Java")
# You need to configure your Sun JVM with these options:
# -verbose:gc
# -Xloggc:/var/log/app/jvm/gc.log
# -XX:+PrintGCTimeStamps
# -XX:+PrintGCDetails
# History:
# This plugin was developed by various people over some time - no logs
# of this has been found. - In 2006 significant contributions was
# financed by NRK (Norwegian Broadcasting Coproration) and performed
# by Nicolai Langfeldt of Linpro AS in Oslo, Norway.
# $Id: $
use strict;
use warnings;
use Fcntl qw(:seek);
# Full path to jvm log file
my $logfile = $ENV{logfile} || "/var/log/app/jvm/gc.log";
my $grtitle = $ENV{graphtitle} || "Sun Java";
# Title that appears on munin graph
my $title = "$grtitle memory usage";
# Extended information that appears below munin graph
my $info = "Write som info about this graph...";
sub analyze_record {
# Match all interesting elements of a record and insert them
# into a hash
my $record = shift;
my %elements;
if ( $record =~
m/(\d+\.\d+).+?(\d+\.\d+).+?DefNew: (\d+).+?(\d+).+?(\d+).+?(\d+\.\d+).+?(\d+\.\d+): \[Tenured(\[U.+\])*: (\d+).+?(\d+).+?(\d+).+?(\d+\.\d+).+?(\d+).+?(\d+).+?(\d+).+?(\d+\.\d+).+/
) {
%elements = (
total_timestamp => $1,
defnew_timestamp => $2,
defnew_mem_from => $3*1024,
defnew_mem_to => $4*1024,
defnew_mem_max => $5*1024,
defnew_time_used => $6,
tenured_timestamp => $7,
tenured_mem_from => $9*1024,
tenured_mem_to => $10*1024,
tenured_mem_max => $11*1024,
tenured_time_used => $12,
total_mem_from => $13*1024,
total_mem_to => $14*1024,
total_mem_max => $15*1024,
total_time_used => $16 );
}
return %elements;
}
my $record='';
# Print config information to munin server
if ( $ARGV[0] and $ARGV[0] eq "config" ) {
print "graph_title $title\n";
print "graph_vlabel Bytes Memory\n";
print "graph_category Java\n";
print "graph_args --lower-limit 0\n";
print "graph_info Show heap memory usage of JVM\n";
print "graph_order defnew_max tenured_max tenured_start tenured_end defnew_start defnew_end totalheap totalheapmax\n";
print "defnew_max.label DefNew max\n";
print "defnew_max.draw AREA\n";
print "tenured_max.label Tenured max\n";
print "tenured_max.draw STACK\n";
print "tenured_max.info DefNew max and Tenured max are stacked to show the total heap memory usage\n";
print "tenured_start.label Tenured start\n";
print "tenured_start.info Tenured (long term) memory used at start of GC\n";
print "tenured_end.label Tenured end\n";
print "tenured_end.info Tenured (long term) memory used at end of GC\n";
print "defnew_start.label DefNew start\n";
print "defnew_start.info Short term memory used by objects at start of GC\n";
print "defnew_end.label DefNew end\n";
print "defnew_end.info Short term memory claimed by objects that survived the GC\n";
print "totalheapmax.label Maximum total heap\n";
print "totalheapmax.info Maximum used total heap last 5 minutes\n";
print "totalheaptomax.label Total heap end\n";
print "totalheaptomax.info Heapsize at maximum after GC\n";
exit 0;
}
# Scan through the log file and keep the last instance of a
# Tenured record in $record.
my %last;
# We can't be sure that there is a totalmemto in the log.
my $totalmemto_atmax = 0;
my $totalmemfrom_max = 0;
open( FILE, "< $logfile" ) or die "Can't open $logfile: $!\n";
# We want to collect the highest total_mem_max in the last 5 minute period.
seek(FILE,-4096,SEEK_END);
my $now;
my $lastnow = 0;
while (<FILE>) {
chomp;
if (/:/) {
($now,undef) = split(/:/,$_,2);
$now = $lastnow unless $now;
}
}
my $noolderthan = $now - 300;
# print "Latest time is: $now. 5 min ago is $noolderthan\n";
seek(FILE,0,SEEK_SET);
$lastnow = 0;
$now=0;
while (<FILE>) {
chomp;
if (/:/) {
($now,undef) = split(/:/,$_,2);
$now = $lastnow unless $now;
}
if (/.+Tenured.+/) {
$record = $_;
} elsif (/^:.+/) {
$record .= $_;
}
if ($record =~ /Tenured.+secs\]$/) {
%last = analyze_record($record);
#print "($now > $noolderthan and $last{total_mem_from} > $totalmemfrom_max)\n";
if ($now > $noolderthan and $last{total_mem_from} > $totalmemfrom_max) {
$totalmemfrom_max = $last{total_mem_max};
$totalmemto_atmax = $last{total_mem_to};
# print "New larger at $now: $totalmemto_max\n";
}
$record = '';
}
$lastnow=$now;
}
close FILE;
$totalmemfrom_max=$totalmemto_atmax='U' if $totalmemfrom_max==0;
# Print the values to be represented in the munin graph
print "tenured_max.value $last{total_mem_max}\n";
print "tenured_start.value $last{total_mem_from}\n";
print "tenured_end.value $last{total_mem_to}\n";
print "defnew_max.value $last{defnew_mem_max}\n";
print "defnew_start.value $last{defnew_mem_from}\n";
print "defnew_end.value $last{defnew_mem_to}\n";
print "totalheapmax.value $totalmemfrom_max\n";
print "totalheaptomax.value $totalmemto_atmax\n";

130
plugins/java/jvm_sun_minorgcs Executable file
View file

@ -0,0 +1,130 @@
#!/usr/bin/perl -w
# Sun JVM minor GC statistics. Parses a verbose log of minor GC
# stats. Reads the log file and sums time in seconds spent on GC and
# number of times it is performed. These numbers are saved in a state
# file. The next time the plugin is run it only reads from the point
# it quit the last time and increases the sums based on the lines
# found in the last portion of the log. Thus we obtain counters. The
# counters are reset when the log is rotated.
# The two numbers are graphed in _one_ graph. Where it has been used
# until now these two numbers have been in the same order of
# magnitude.
# Configuration (common with the other sun_jvm_* plugins in this family):
# [jvm_sun_*]
# env.logfile /var/foo/java.log (default: /var/log/munin/java.log)
# env.graphtitle (default: "Sun Java")
# env.grname (default: "sun-jvm". Used for state file-name)
# You need to configure your Sun JVM with these options:
# -verbose:gc
# -Xloggc:/var/log/app/jvm/gc.log
# -XX:+PrintGCTimeStamps
# -XX:+PrintGCDetails
# History:
# This plugin was developed by various people over some time - no logs
# of this has been found. - In 2006 significant contributions was
# financed by NRK (Norwegian Broadcasting Coproration) and performed
# by Nicolai Langfeldt of Linpro AS in Oslo, Norway.
# $Id: $
use strict;
my $logfile = $ENV{logfile} || "/var/log/app/jvm/gc.log";
my $grtitle = $ENV{graphtitle} || 'Sun Java';
my $grname = $ENV{graphtitle} || 'sun-jvm';
my $statefile = "/var/lib/munin/plugin-state/plugin-java_sun_${grname}_minorgcs.state";
my $pos = 0;
my $count = 0;
my $seconds = 0;
my $startsize;
my $timespent;
my $totaltimespent=0;
if ( $ARGV[0] and $ARGV[0] eq "config" ) {
print "graph_title $grtitle minor GCs pr minute\n";
print "graph_args --base 1000 -l 0 --rigid\n";
print "graph_scale no\n";
print "graph_category Java\n";
print "graph_period minute\n";
print "gcs.label Number of GCs\n";
print "gcs.type DERIVE\n";
print "gcs.min 0\n";
print "time.label Seconds spent on GC\n";
print "time.type DERIVE\n";
print "time.min 0\n";
exit 0;
}
if (-l $statefile) {
die("$statefile is a symbolic link, refusing to touch it.");
}
if (! -f $logfile) {
print "gcs.value U\n";
print "time.value U\n";
exit 0;
}
if (-f "$statefile") {
open (IN, "$statefile") or exit 4;
($pos,$count,$timespent) = split(/:/,<IN>);
close IN;
}
$startsize = (stat $logfile)[7];
if ($startsize < $pos) {
# Log rotated
$pos = 0;
}
($pos, $count, $timespent) = parseFile ($logfile, $pos, $count, $timespent);
print "gcs.value $count\n";
print "time.value ",int($timespent),"\n";
open (OUT, ">$statefile") or die "Could not open $statefile for reading: $!\n";
print OUT "$pos:$count:$timespent\n";
close OUT;
sub parseFile {
my ($fname, $start, $count, $timespent) = @_;
my @secs;
open (LOGFILE, $fname) or die "Could not open $fname: $!\n";
# Stat filehandle after open - avoids race with logrotater or
# restart or whatever.
my $stop = $startsize = (stat LOGFILE)[7];
if ($startsize < $start) {
# Log rotated
$start = 0;
}
seek (LOGFILE, $start, 0) or
die "Could not seek to $start in $fname: $!\n";
while (tell (LOGFILE) < $stop) {
my $line =<LOGFILE>;
chomp ($line);
# Log format: 35.037: [GC 35.038: [DefNew: 166209K->11364K(174080K), 0.2106410 secs] 175274K->26037K(1721472K), 0.2107680 secs]
if ($line =~ /\[GC.+ (\d+\.\d+) secs\]/) {
$count++;
$timespent += $1;
}
}
close(LOGFILE);
return($stop,$count,$timespent);
}
# vim:syntax=perl

92
plugins/java/jvm_sun_tenuredgcs Executable file
View file

@ -0,0 +1,92 @@
#!/usr/bin/perl -w
# Sun JVM tenured GC statistics. Parses a verbose log of tenured GC
# stats. Reads the entire log file and sums time in seconds spent on
# GC and number of times it is performed. Thus we obtain counters.
# The counters are reset when the log is rotated. (note: the minorgcs
# plugin uses a state file, we did not make it a priority to use a
# state file in this plugin...)
# The two numbers are graphed in _one_ graph. Where it has been used
# until now these two numbers have been in the same order of
# magnitude.
# Configuration (common with the other sun_jvm_* plugins in this family):
# [jvm_sun_*]
# env.logfile /var/foo/java.log (default: /var/log/munin/java.log)
# env.graphtitle (default: "Sun Java")
# You need to configure your Sun JVM with these options:
# -verbose:gc
# -Xloggc:/var/log/app/jvm/gc.log
# -XX:+PrintGCTimeStamps
# -XX:+PrintGCDetails
# History:
# This plugin was developed by various people over some time - no logs
# of this has been found. - In 2006 significant contributions was
# financed by NRK (Norwegian Broadcasting Coproration) and performed
# by Nicolai Langfeldt of Linpro AS in Oslo, Norway.
# $Id: $
use strict;
use warnings;
# Full path to jvm log file
my $logfile = $ENV{logfile} || "/var/log/app/jvm/gc.log";
my $grtitle = $ENV{graphtitle} || 'Sun Java';
# Title that appears on munin graph
my $title = "$grtitle tenured GCs pr second";
# Extended information that appears below munin graph
my $info = "Amount is the number of Tenured GC pr. second.\nSeconds spent is the total time spent on those Tenured GCs.";
my $record = "";
my %elements;
# Print config information to munin server
if ( $ARGV[0] and $ARGV[0] eq "config" ) {
print "graph_title $grtitle tenured GCs pr minute\n";
print "graph_period minute\n";
print "graph_category Java\n";
print "graph_args --lower-limit 0\n";
print "graph_info $info\n";
print "activity.label Number of GCs\n";
print "activity.type DERIVE\n";
print "activity.min 0\n";
print "time.label Seconds spent on GCs\n";
print "time.type DERIVE\n";
print "time.min 0\n";
exit 0;
}
# Scan through the log file and keep the last instance of a
# Tenured record in $record.
open( FILE, "< $logfile" ) or die "Can't open $logfile : $!";
my $counter = 0;
my $record_time_spent;
my $time_spent;
while (<FILE>) {
chomp;
if (m/.+Tenured.+/) {
$record = $_;
} elsif (m/^:.+/) {
$record .= $_;
}
if ( $record =~ m/(\d+)\..+Tenured.+(\d+\.\d+) secs\]/ ) {
# print "Record: $record\n";
$record_time_spent = $2;
# print "Time spent: ",$record_time_spent,"\n";
$counter++;
$time_spent += $record_time_spent;
}
$record = "";
}
close FILE;
print "activity.value $counter\n";
print "time.value ",int($time_spent),"\n";