Commit d03cdf8e authored by Matteo Melli's avatar Matteo Melli

Initial commit

parents
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
**.idea/
*.iml
**/nbproject/**
**/nbactions.xml
**/nb-configuration.xml
/bin/
.project
.classpath
.settings/
.checkstyle
hs_err*.log
/documentation/static
/documentation/site
.DS_Store
This diff is collapsed.
# pgio
A Java CLI turned in executable using GraalVM that is able to capture stats on disk IO usage per process and to turn this info into a stream of data that can be stored and interpreted by Prometheus to draw graphs that explain which process or group of processes is using the disk most during a period of time.
## Stats reads
pgio runs only on Linux modern kernel (> 2.2.x) reading /proc/vmstat (help no docs available on this one) and /proc/<pid>/io (http://man7.org/linux/man-pages/man5/proc.5.html)
Taking iotop as an explample (using this as a source of info: https://unix.stackexchange.com/questions/248197/iotop-showing-1-5-mb-s-of-disk-write-but-all-programs-have-0-00-b-s/248218#248218):
iotop read information per process from /proc/<pid>/io, in particular:
```
rchar: characters read
The number of bytes which this task has caused to be
read from storage. This is simply the sum of bytes
which this process passed to read(2) and similar system
calls. It includes things such as terminal I/O and is
unaffected by whether or not actual physical disk I/O
was required (the read might have been satisfied from
pagecache).
wchar: characters written
The number of bytes which this task has caused, or
shall cause to be written to disk. Similar caveats
apply here as with rchar.
```
iotop read information globally from /proc/vmstat, in particular:
```
pgpgin – Number of kilobytes the system has paged in from disk per second.
pgpgout – Number of kilobytes the system has paged out to disk per second.
```
Comnining per process info with global info iotop calculate the % of write/read throughput each process is consuming.
Anyway the iotop commented in stackexchange seems to be a python remake of original iotop (https://github.com/analogue/iotop).
In real iotop code (https://github.com/Tomas-M/iotop) is uses Taskstats (https://www.kernel.org/doc/Documentation/accounting/taskstats.txt).
Since we want to know per process bytes read and written we should look for:
```
read_bytes: bytes read
Attempt to count the number of bytes which this process
really did cause to be fetched from the storage layer.
This is accurate for block-backed filesystems.
write_bytes: bytes written
Attempt to count the number of bytes which this process
caused to be sent to the storage layer.
cancelled_write_bytes:
The big inaccuracy here is truncate. If a process
writes 1MB to a file and then deletes the file, it will
in fact perform no writeout. But it will have been
accounted as having caused 1MB of write. In other
words: this field represents the number of bytes which
this process caused to not happen, by truncating page‐
cache. A task can cause "negative" I/O too. If this
task truncates some dirty pagecache, some I/O which
another task has been accounted for (in its
write_bytes) will not be happening.
```
## Build
To build the project as a tar.gz with all Java dependencies:
```
mvn clean package -P assembler
```
To build the project as a tar.gz with an executable built using GraalVM `native-image` tool:
```
mvn clean package -P executable
```
## Run
This will generate output with collected stats of all processes (should be run as root) every 3 seconds:
```
bin/pgio
```
## Options
```
Option Description
------ -----------
-g, --group <String> Group results using specified group configuration file
-h, --help Displays this help message and quit
-i, --interval <String> Interval in milliseconds to gather stats (default:
3000)
-o, --show-other Print read/write data not accounted by any listed
process
--ppid <String> Parent pid of the process to scan (if not specified
will scan all processes)
--print-header Print header
-s, --show-system Print read/write data for the whole system
-v, --version Show version and quit
```
### Group configuration file
Specifing this file will enable a special mode where instead of single processes groups with aggregated data will be printed.
A JSON indicating groups has the following syntax (regular expression will use pattern from [java.util.regex.Pattern](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html):
```
{
"<group name>" [ <list of regexp> ],
...
}
```
## Prometheus
TODO
\ No newline at end of file
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ongres.pgio</groupId>
<artifactId>build-resources</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>pgio: Build Resources</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<checkstyle.skipExec>true</checkstyle.skipExec>
<license.skip>true</license.skip>
</properties>
<profiles>
<profile>
<id>deploy</id> <!-- It must be manually turn on when mvn deploy is executed -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<configuration>
<failOnError>false</failOnError>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="ALL_TRACE" target="SYSTEM_OUT">
<PatternLayout pattern="%d{hh:mm:ss.SSS} %highlight{%-5level} %-30.-30replace{'%t'}{\s}{-} %-30.30logger{1.} - %msg%n"/>
</Console>
<Console name="SIMPLE_TRACE" target="SYSTEM_OUT">
<PatternLayout pattern="%d{hh:mm:ss.SSS} %highlight{%-5level} %-30.-30replace{'%t'}{\s}{-} %-30.30logger{1.} - %msg%n%throwable{short.localizedMessage}%n"/>
</Console>
<Console name="WITHOUT_TRACE" target="SYSTEM_OUT">
<PatternLayout pattern="%d{hh:mm:ss.SSS} %highlight{%-5level} %-30.-30replace{'%t'}{\s}{-} %-30.30logger{1.} - %msg%n%throwable{none}"/>
</Console>
<Async name="ASYNC">
<AppenderRef ref="router"/>
</Async>
<Routing name="router">
<Routes>
<Script name="RoutingInit" language="JavaScript">
<![CDATA[
if (logEvent.getLevel().compareTo(org.apache.logging.log4j.Level.INFO) < 0) {
"ALL_TRACE";
}
else if (logEvent.getThrown() != null) {
"SIMPLE_TRACE"
} else {
"WITHOUT_TRACE"
}
]]>
</Script>
<Route ref="WITHOUT_TRACE"/>
<Route key="ALL_TRACE" ref="ALL_TRACE"/>
<Route key="SIMPLE_TRACE" ref="SIMPLE_TRACE"/>
</Routes>
</Routing>
</Appenders>
<Loggers>
<Logger name="com.ongres.pgio" level="DEBUG" additivity="false">
<AppenderRef ref="ASYNC" />
</Logger>
<Logger name="com.ongres.pgio.testing" level="WARN" additivity="false">
<AppenderRef ref="ASYNC" />
</Logger>
<!-- Root -->
<Root level="WARN">
<AppenderRef ref="ASYNC"/>
</Root>
</Loggers>
</Configuration>
<?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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ongres.pgio</groupId>
<artifactId>build-tools</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<name>pgio: Build tools</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<modules>
<module>build-resources</module>
</modules>
</project>
{
"firefox": [ ".*firefox.*" ]
}
\ No newline at end of file
{
"wal-e": [ "/?(\\w+/)*wal-e .*" ],
"wal-e gpg": [ "/?(\\w+/)*wal-e -e -z 0 -r [^ ]+" ],
"pgbouncer": [ ".*=pgbouncer gitlabhq_production .*", ".*/var/opt/gitlab/pgbouncer/pgbouncer.ini.*" ],
"gitlab-monitor": [ ".*gitlab-monitor.*" ],
"archiver": [ ".*archiver.*" ],
"wal sender": [ ".*wal sender.*" ],
"repmgr": [ ".*gitlab_repmgr gitlab_repmgr.*" ],
"query": [ ".*gitlab gitlabhq_production" ],
"bgwriter": [ ".*writer process.*" ],
"autovacuum": [ ".*autovacuum worker process.*" ],
"stats": [ ".*stats collector process.*" ],
"wal writer": [ ".*wal writer process.*" ],
"checkpoint": [ ".*checkpointer process.*" ]
}
\ No newline at end of file
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<!--<id>bin</id>-->
<formats>
<format>tar.gz</format>
</formats>
<fileSets>
<fileSet>
<directory>${project.build.directory}/dist/run</directory>
<outputDirectory>bin</outputDirectory>
<directoryMode>0755</directoryMode>
<fileMode>0755</fileMode>
</fileSet>
<fileSet>
<directory>${project.build.directory}/dist/lib</directory>
<outputDirectory>lib</outputDirectory>
<directoryMode>0755</directoryMode>
<fileMode>0644</fileMode>
</fileSet>
<fileSet>
<directory>${project.build.directory}/dist/conf</directory>
<outputDirectory>conf</outputDirectory>
<directoryMode>0755</directoryMode>
<fileMode>0644</fileMode>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<!--<id>bin</id>-->
<formats>
<format>tar.gz</format>
</formats>
<files>
<file>
<source>${project.build.directory}/dist/bin/${assembler.name}-${project.version}</source>
<destName>bin/${assembler.name}</destName>
<fileMode>0755</fileMode>
</file>
</files>
<fileSets>
<fileSet>
<directory>${project.build.directory}/dist/conf</directory>
<outputDirectory>conf</outputDirectory>
<directoryMode>0755</directoryMode>
<fileMode>0644</fileMode>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
#!/bin/bash
# ----------------------------------------------------------------------------
# Copyright 2001-2006 The Apache Software Foundation.
#
# 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.
# ----------------------------------------------------------------------------
#
# Copyright (c) 2001-2006 The Apache Software Foundation. All rights
# reserved.
[ "$DEBUG" == "true" ] && set -x
[ "$DEBUG" == "true" ] && set -v
set -e
# resolve links - $0 may be a softlink
PRG="$(which "$0" 2>/dev/null||echo "$0")"
while [ -h "$PRG" ]; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`/"$link"
fi
done
PRGDIR=`dirname "$PRG"`
BASEDIR=`cd "$PRGDIR/.." >/dev/null; pwd`
# Reset the LIBDIR variable. If you need to influence this use the environment setup file.
LIBDIR=@{assembler.libdir}
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
case "`uname`" in
CYGWIN*) cygwin=true ;;
Darwin*) darwin=true
if [ -z "$JAVA_VERSION" ] ; then
JAVA_VERSION="CurrentJDK"
else
echo "Using Java version: $JAVA_VERSION"
fi
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
JAVA_HOME=`/usr/libexec/java_home`
else
JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/${JAVA_VERSION}/Home
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# If a specific java binary isn't specified search for the standard 'java' binary
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD=`which java`
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." 1>&2
echo " We cannot execute $JAVACMD" 1>&2
exit 1
fi
if [ -z "$LIBDIR" ]
then
LIBDIR="$BASEDIR"/lib
else
LIBDIR="$BASEDIR/$LIBDIR"
fi
if [ ! -z "$HYDRA_LIBDIR" ]
then
LIBDIR="$BASEDIR/$HYDRA_LIBDIR"
fi
if [ -z "$HYDRACONFIG" ]
then
HYDRACONFIG="$BASEDIR"/conf/@{assembler.name}.yml
fi
HYDRACONFIG_OPTS=()
if [ -f "$HYDRACONFIG" ]
then
HYDRACONFIG_OPTS=(-c "$HYDRACONFIG")
fi
CLASSPATH="$LIBDIR"/@{assembler.name}[email protected]{version}.jar
ENDORSED_DIR=
if [ -n "$ENDORSED_DIR" ] ; then
CLASSPATH=$BASEDIR/$ENDORSED_DIR/*:$CLASSPATH
fi
if [ -n "$CLASSPATH_PREFIX" ] ; then
CLASSPATH=$CLASSPATH_PREFIX:$CLASSPATH
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$HOME" ] && HOME=`cygpath --path --windows "$HOME"`
[ -n "$BASEDIR" ] && BASEDIR=`cygpath --path --windows "$BASEDIR"`
[ -n "$LIBDIR" ] && LIBDIR=`cygpath --path --windows "$LIBDIR"`
fi
exec "$JAVACMD" $JAVA_OPTS \
-cp "$CLASSPATH" \
@{assembler.mainClass} \
"${HYDRACONFIG_OPTS[@]}" \
"[email protected]"
version=${project.version}
\ No newline at end of file
This diff is collapsed.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 com.ongres.pgio.main.config;
import com.google.common.collect.ImmutableList;
import com.ongres.pgio.main.stats.ProcessGroupInfo;
import java.util.Optional;
public class Config {
private final long interval;
private final Optional<Integer> ppid;
private final boolean prometheusFormat;
private final boolean printHeader;
private final boolean showSystem;
private final boolean showOther;
private final Optional<ImmutableList<ProcessGroupInfo>> processGroups;
private Config(long interval, Optional<Integer> ppid,
boolean prometheusFormat,
boolean printHeader, boolean showSystem, boolean showOther,
Optional<ImmutableList<ProcessGroupInfo>> processGroups) {
super();
this.interval = interval;
this.ppid = ppid;
this.prometheusFormat = prometheusFormat;
this.printHeader = printHeader;
this.showSystem = showSystem;
this.showOther = showOther;
this.processGroups = processGroups;
}
public long getInterval() {
return interval;
}
public Optional<Integer> getPpid() {
return ppid;
}
public boolean isPrometheusFormat() {
return prometheusFormat;
}
public boolean isPrintHeader() {
return printHeader;
}
public boolean isShowOther() {
return showOther;
}
public boolean isShowSystem() {
return showSystem;
}
public Optional<ImmutableList<ProcessGroupInfo>> getProcessGroups() {
return processGroups;
}
public static class Builder {
private long interval;
private Optional<Integer> ppid = Optional.empty();
private boolean prometheusFormat;
private boolean printHeader;
private boolean showSystem;
private boolean showOther;
private Optional<ImmutableList<ProcessGroupInfo>> processGroups = Optional.empty();
public Builder withInterval(long interval) {
this.interval = interval;
return this;
}
public Builder withPpid(Integer ppid) {
this.ppid = Optional.ofNullable(ppid);
return this;
}
public Builder withPrometheusFormat(boolean prometheusFormat) {
this.prometheusFormat = prometheusFormat;
return this;
}
public Builder withPrintHeader(boolean printHeader) {
this.printHeader = printHeader;
return this;
}
public Builder withShowSystem(boolean showSystem) {
this.showSystem = showSystem;
return this;
}
public Builder withShowOther(boolean showOther) {
this.showOther = showOther;
return this;
}
public Builder withProcessGroups(ImmutableList<ProcessGroupInfo> processGroups) {
this.processGroups = Optional.of(processGroups);
return this;
}
public Config build() {
return new Config(interval, ppid,
prometheusFormat, printHeader, showSystem, showOther,
processGroups);
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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,