mirror of
https://github.com/NationalSecurityAgency/timely.git
synced 2026-11-10 03:41:25 -10:00
Compare commits
80
Commits
0.0.3
..
TIMELY-164
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eaddee0d78 | ||
|
|
e947c1a497 | ||
|
|
4e7e07601b | ||
|
|
679a92c5b5 | ||
|
|
3f3b605c63 | ||
|
|
5580a2fa66 | ||
|
|
1a54c3ada3 | ||
|
|
2080764e0d | ||
|
|
e7dade04ee | ||
|
|
7ed337483e | ||
|
|
b070bc3c47 | ||
|
|
51f9103741 | ||
|
|
a97fa83e2f | ||
|
|
0b5c3544db | ||
|
|
186b60756a | ||
|
|
133a6bf5cf | ||
|
|
b684d7eefe | ||
|
|
73f1603f1e | ||
|
|
9267e0c915 | ||
|
|
1ce49628e5 | ||
|
|
acad3af083 | ||
|
|
b4635f1a55 | ||
|
|
4c1ede04df | ||
|
|
2841b0a3e9 | ||
|
|
6efa13909f | ||
|
|
368c572c67 | ||
|
|
554baf6af7 | ||
|
|
1ef11799be | ||
|
|
16b664297d | ||
|
|
4277b63bc3 | ||
|
|
5a9ad3cb27 | ||
|
|
f990e89ab3 | ||
|
|
c01ac80f23 | ||
|
|
35e8f99d09 | ||
|
|
847144d236 | ||
|
|
b3bfbc1e1f | ||
|
|
8d86e3894a | ||
|
|
99b9181902 | ||
|
|
3c0bf87b79 | ||
|
|
d2ba7f635e | ||
|
|
92510fdc83 | ||
|
|
4eac17fbb5 | ||
|
|
328ae075f4 | ||
|
|
cf12295ac8 | ||
|
|
df180504f2 | ||
|
|
021ff832ef | ||
|
|
6fc9066e70 | ||
|
|
f11b82b662 | ||
|
|
dcfd165a9b | ||
|
|
fd98558218 | ||
|
|
f47cd66ec2 | ||
|
|
ec4ba6e7f5 | ||
|
|
e698734e4b | ||
|
|
78b49fe44e | ||
|
|
f109f04162 | ||
|
|
4bf68fe328 | ||
|
|
9eb8da8e80 | ||
|
|
f54705374e | ||
|
|
5e166f0044 | ||
|
|
17527af6b4 | ||
|
|
64f7890f8b | ||
|
|
e7c058ef56 | ||
|
|
6415d100fc | ||
|
|
046000c16a | ||
|
|
d0f6534296 | ||
|
|
07c04425e1 | ||
|
|
113b6464f3 | ||
|
|
e2eda4c74a | ||
|
|
68b8d6cd51 | ||
|
|
458028d5df | ||
|
|
320f291785 | ||
|
|
95c2654357 | ||
|
|
045964c01d | ||
|
|
2f8759e32b | ||
|
|
451f001b9f | ||
|
|
044f6576fd | ||
|
|
520edee16f | ||
|
|
8034a673fc | ||
|
|
eb9e874a57 | ||
|
|
1658312512 |
No files matched your search
@@ -2,7 +2,7 @@
|
||||
|
||||
[![Apache License][li]][ll]
|
||||
|
||||
Timely is a time series database application that provides secure access to time series data. Timely is written in Java and designed to work with [Apache Accumulo] (http://accumulo.apache.org/) and [Grafana] (http://www.grafana.org). Documentation is located [here] (https://nationalsecurityagency.github.io/timely/).
|
||||
Timely is a time series database application that provides secure access to time series data. Timely is written in Java and designed to work with [Apache Accumulo](http://accumulo.apache.org/) and [Grafana](http://www.grafana.org). Documentation is located [here](https://nationalsecurityagency.github.io/timely/).
|
||||
|
||||
[li]: http://img.shields.io/badge/license-ASL-blue.svg
|
||||
[ll]: https://www.apache.org/licenses/LICENSE-2.0
|
||||
@@ -0,0 +1,2 @@
|
||||
/bin/
|
||||
/target
|
||||
@@ -0,0 +1,20 @@
|
||||
timelyHostname=
|
||||
timelyTcpPort=
|
||||
timelyHttpsPort=
|
||||
timelyWssPort=
|
||||
doLogin=
|
||||
#timelyUsername=
|
||||
#timelyPassword=
|
||||
keyStoreFile=
|
||||
keyStoreType=
|
||||
keyStorePass=
|
||||
trustStoreFile=
|
||||
trustStoreType=
|
||||
trustStorePass=
|
||||
hostVerificationEnabled=false
|
||||
bufferSize=10485760
|
||||
metrics=
|
||||
startTime=0
|
||||
endTime=0
|
||||
interval=1
|
||||
intervalUnits=HOURS
|
||||
@@ -0,0 +1,336 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<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>
|
||||
<artifactId>timely-analytics</artifactId>
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>0.0.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<properties>
|
||||
<flink.version>1.1.4</flink.version>
|
||||
</properties>
|
||||
<!--
|
||||
|
||||
Execute "mvn clean package -Pbuild-jar"
|
||||
to build a jar file out of this project!
|
||||
|
||||
How to use the Flink Quickstart pom:
|
||||
|
||||
a) Adding new dependencies:
|
||||
You can add dependencies to the list below.
|
||||
Please check if the maven-shade-plugin below is filtering out your dependency
|
||||
and remove the exclude from there.
|
||||
|
||||
b) Build a jar for running on the cluster:
|
||||
There are two options for creating a jar from this project
|
||||
|
||||
b.1) "mvn clean package" -> this will create a fat jar which contains all
|
||||
dependencies necessary for running the jar created by this pom in a cluster.
|
||||
The "maven-shade-plugin" excludes everything that is provided on a running Flink cluster.
|
||||
|
||||
b.2) "mvn clean package -Pbuild-jar" -> This will also create a fat-jar, but with much
|
||||
nicer dependency exclusion handling. This approach is preferred and leads to
|
||||
much cleaner jar files.
|
||||
-->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.flink</groupId>
|
||||
<artifactId>flink-java</artifactId>
|
||||
<version>${flink.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.flink</groupId>
|
||||
<artifactId>flink-streaming-java_2.11</artifactId>
|
||||
<version>${flink.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.flink</groupId>
|
||||
<artifactId>flink-clients_2.11</artifactId>
|
||||
<version>${flink.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely-client</artifactId>
|
||||
<version>${parent.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely-common</artifactId>
|
||||
<version>${parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<profiles>
|
||||
<profile>
|
||||
<!-- Profile for packaging correct JAR files -->
|
||||
<id>build-jar</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.flink</groupId>
|
||||
<artifactId>flink-java</artifactId>
|
||||
<version>${flink.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.flink</groupId>
|
||||
<artifactId>flink-streaming-java_2.11</artifactId>
|
||||
<version>${flink.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.flink</groupId>
|
||||
<artifactId>flink-clients_2.11</artifactId>
|
||||
<version>${flink.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- disable the exclusion rules -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<excludes combine.self="override"/>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>net.revelc.code</groupId>
|
||||
<artifactId>formatter-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<!-- We use the maven-shade plugin to create a fat jar that contains all dependencies
|
||||
except flink and it's transitive dependencies. The resulting fat-jar can be executed
|
||||
on a cluster. Change the value of Program-Class if your program entry point changes. -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<executions>
|
||||
<!-- Run shade goal on package phase -->
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<excludes>
|
||||
<!-- This list contains all dependencies of flink-dist
|
||||
Everything else will be packaged into the fat-jar
|
||||
-->
|
||||
<exclude>org.apache.flink:flink-annotations</exclude>
|
||||
<exclude>org.apache.flink:flink-shaded-hadoop1_2.11</exclude>
|
||||
<exclude>org.apache.flink:flink-shaded-hadoop2</exclude>
|
||||
<exclude>org.apache.flink:flink-shaded-curator-recipes</exclude>
|
||||
<exclude>org.apache.flink:flink-core</exclude>
|
||||
<exclude>org.apache.flink:flink-java</exclude>
|
||||
<exclude>org.apache.flink:flink-scala_2.11</exclude>
|
||||
<exclude>org.apache.flink:flink-runtime_2.11</exclude>
|
||||
<exclude>org.apache.flink:flink-optimizer_2.11</exclude>
|
||||
<exclude>org.apache.flink:flink-clients_2.11</exclude>
|
||||
<exclude>org.apache.flink:flink-avro_2.11</exclude>
|
||||
<exclude>org.apache.flink:flink-examples-batch_2.11</exclude>
|
||||
<exclude>org.apache.flink:flink-examples-streaming_2.11</exclude>
|
||||
<exclude>org.apache.flink:flink-streaming-java_2.11</exclude>
|
||||
<!-- Also exclude very big transitive dependencies of Flink
|
||||
WARNING: You have to remove these excludes if your code relies on other
|
||||
versions of these dependencies.
|
||||
-->
|
||||
<exclude>org.scala-lang:scala-library</exclude>
|
||||
<exclude>org.scala-lang:scala-compiler</exclude>
|
||||
<exclude>org.scala-lang:scala-reflect</exclude>
|
||||
<exclude>com.typesafe.akka:akka-actor_*</exclude>
|
||||
<exclude>com.typesafe.akka:akka-remote_*</exclude>
|
||||
<exclude>com.typesafe.akka:akka-slf4j_*</exclude>
|
||||
<exclude>io.netty:netty-all</exclude>
|
||||
<exclude>io.netty:netty</exclude>
|
||||
<exclude>commons-fileupload:commons-fileupload</exclude>
|
||||
<exclude>org.apache.avro:avro</exclude>
|
||||
<exclude>commons-collections:commons-collections</exclude>
|
||||
<exclude>org.codehaus.jackson:jackson-core-asl</exclude>
|
||||
<exclude>org.codehaus.jackson:jackson-mapper-asl</exclude>
|
||||
<exclude>com.thoughtworks.paranamer:paranamer</exclude>
|
||||
<exclude>org.xerial.snappy:snappy-java</exclude>
|
||||
<exclude>org.apache.commons:commons-compress</exclude>
|
||||
<exclude>org.tukaani:xz</exclude>
|
||||
<exclude>com.esotericsoftware.kryo:kryo</exclude>
|
||||
<exclude>com.esotericsoftware.minlog:minlog</exclude>
|
||||
<exclude>org.objenesis:objenesis</exclude>
|
||||
<exclude>com.twitter:chill_*</exclude>
|
||||
<exclude>com.twitter:chill-java</exclude>
|
||||
<exclude>commons-lang:commons-lang</exclude>
|
||||
<exclude>junit:junit</exclude>
|
||||
<exclude>org.apache.commons:commons-lang3</exclude>
|
||||
<exclude>org.slf4j:slf4j-api</exclude>
|
||||
<exclude>org.slf4j:slf4j-log4j12</exclude>
|
||||
<exclude>log4j:log4j</exclude>
|
||||
<exclude>org.apache.commons:commons-math</exclude>
|
||||
<exclude>org.apache.sling:org.apache.sling.commons.json</exclude>
|
||||
<exclude>commons-logging:commons-logging</exclude>
|
||||
<exclude>commons-codec:commons-codec</exclude>
|
||||
<exclude>com.fasterxml.jackson.core:jackson-core</exclude>
|
||||
<exclude>com.fasterxml.jackson.core:jackson-databind</exclude>
|
||||
<exclude>com.fasterxml.jackson.core:jackson-annotations</exclude>
|
||||
<exclude>stax:stax-api</exclude>
|
||||
<exclude>com.typesafe:config</exclude>
|
||||
<exclude>org.uncommons.maths:uncommons-maths</exclude>
|
||||
<exclude>com.github.scopt:scopt_*</exclude>
|
||||
<exclude>commons-io:commons-io</exclude>
|
||||
<exclude>commons-cli:commons-cli</exclude>
|
||||
</excludes>
|
||||
</artifactSet>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>org.apache.flink:*</artifact>
|
||||
<excludes>
|
||||
<!-- exclude shaded google but include shaded curator -->
|
||||
<exclude>org/apache/flink/shaded/com/**</exclude>
|
||||
<exclude>web-docs/**</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
<filter>
|
||||
<!-- Do not copy the signatures in the META-INF folder.
|
||||
Otherwise, this might cause SecurityExceptions when using the JAR.
|
||||
-->
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.DSA</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
<!-- If you want to use ./bin/flink run <quickstart jar> uncomment the following lines.
|
||||
This will add a Main-Class entry to the manifest file -->
|
||||
<!--
|
||||
<transformers>
|
||||
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>jar.StreamingJob</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
-->
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<compilerId>jdt</compilerId>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-jdt</artifactId>
|
||||
<version>0.21.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<versionRange>[2.4,)</versionRange>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore/>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<versionRange>[3.1,)</versionRange>
|
||||
<goals>
|
||||
<goal>testCompile</goal>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore/>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,169 @@
|
||||
package timely.analytics.flink;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.flink.streaming.util.serialization.SerializationSchema;
|
||||
|
||||
import timely.model.Tag;
|
||||
|
||||
public class MetricHistogram implements Serializable, SerializationSchema<MetricHistogram> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String SPACE = " ";
|
||||
private static final String AVG = " sample=avg\n";
|
||||
private static final String COUNT = " sample=count\n";
|
||||
private static final String MAX = " sample=max\n";
|
||||
private static final String MIN = " sample=min\n";
|
||||
private static final String SUM = " sample=sum\n";
|
||||
private static final String p50 = " sample=50p\n";
|
||||
private static final String p75 = " sample=75p\n";
|
||||
private static final String p90 = " sample=90p\n";
|
||||
private static final String p99 = " sample=99p\n";
|
||||
|
||||
private String metric = null;
|
||||
private List<Tag> tags = null;
|
||||
private long timestamp = 0L;
|
||||
private boolean initialized = false;
|
||||
private List<Double> values = new ArrayList<>();
|
||||
|
||||
public void initialize(String metric, List<Tag> tags) {
|
||||
this.metric = metric;
|
||||
this.tags = tags;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
public String getMetric() {
|
||||
return metric;
|
||||
}
|
||||
|
||||
public List<Tag> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void update(Double d, long timestamp) {
|
||||
values.add(d);
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public void done() {
|
||||
Collections.sort(values);
|
||||
}
|
||||
|
||||
public Double avg() {
|
||||
if (values.size() == 0) {
|
||||
return 0.0D;
|
||||
}
|
||||
return sum() / count();
|
||||
}
|
||||
|
||||
public Double min() {
|
||||
if (values.size() == 0) {
|
||||
return 0.0D;
|
||||
}
|
||||
return values.get(0);
|
||||
}
|
||||
|
||||
public Double max() {
|
||||
if (values.size() == 0) {
|
||||
return 0.0D;
|
||||
}
|
||||
return values.get(values.size() - 1);
|
||||
}
|
||||
|
||||
public Double getPercentile(int p) {
|
||||
if (values.size() == 0) {
|
||||
return 0.0D;
|
||||
}
|
||||
int position = Math.round((p * 1.0f / 100) * values.size());
|
||||
position = (0 == position) ? 0 : position - 1;
|
||||
return values.get(position);
|
||||
}
|
||||
|
||||
public Double count() {
|
||||
return values.size() * 1.0D;
|
||||
}
|
||||
|
||||
public Double sum() {
|
||||
double sum = 0.0D;
|
||||
for (Double d : values) {
|
||||
sum += d;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
done();
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("metric: ").append(metric);
|
||||
buf.append(" tags: ").append(tags);
|
||||
buf.append(" timestamp: ").append(timestamp);
|
||||
buf.append(" count: ").append(count());
|
||||
buf.append(" min: ").append(min());
|
||||
buf.append(" max: ").append(max());
|
||||
buf.append(" sum: ").append(sum());
|
||||
buf.append(" 50p: ").append(getPercentile(50));
|
||||
buf.append(" 75p: ").append(getPercentile(75));
|
||||
buf.append(" 99p: ").append(getPercentile(99));
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
public byte[] serialize(MetricHistogram histo) {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
String tags = histo.getTags().stream().map(t -> t.join()).collect(Collectors.joining(" "));
|
||||
|
||||
// @formatter:off
|
||||
buf.append("put ").append(histo.getMetric() + "_summarized")
|
||||
.append(SPACE).append(histo.getTimestamp())
|
||||
.append(SPACE).append(histo.min())
|
||||
.append(SPACE).append(tags).append(MIN);
|
||||
buf.append("put ").append(histo.getMetric() + "_summarized")
|
||||
.append(SPACE).append(histo.getTimestamp())
|
||||
.append(SPACE).append(histo.max())
|
||||
.append(SPACE).append(tags).append(MAX);
|
||||
buf.append("put ").append(histo.getMetric() + "_summarized")
|
||||
.append(SPACE).append(histo.getTimestamp())
|
||||
.append(SPACE).append(histo.count())
|
||||
.append(SPACE).append(tags).append(COUNT);
|
||||
buf.append("put ").append(histo.getMetric() + "_summarized")
|
||||
.append(SPACE).append(histo.getTimestamp())
|
||||
.append(SPACE).append(histo.sum())
|
||||
.append(SPACE).append(tags).append(SUM);
|
||||
buf.append("put ").append(histo.getMetric() + "_summarized")
|
||||
.append(SPACE).append(histo.getTimestamp())
|
||||
.append(SPACE).append(histo.avg())
|
||||
.append(SPACE).append(tags).append(AVG);
|
||||
buf.append("put ").append(histo.getMetric() + "_summarized")
|
||||
.append(SPACE).append(histo.getTimestamp())
|
||||
.append(SPACE).append(histo.getPercentile(50))
|
||||
.append(SPACE).append(tags).append(p50);
|
||||
buf.append("put ").append(histo.getMetric() + "_summarized")
|
||||
.append(SPACE).append(histo.getTimestamp())
|
||||
.append(SPACE).append(histo.getPercentile(75))
|
||||
.append(SPACE).append(tags).append(p75);
|
||||
buf.append("put ").append(histo.getMetric() + "_summarized")
|
||||
.append(SPACE).append(histo.getTimestamp())
|
||||
.append(SPACE).append(histo.getPercentile(90))
|
||||
.append(SPACE).append(tags).append(p90);
|
||||
buf.append("put ").append(histo.getMetric() + "_summarized")
|
||||
.append(SPACE).append(histo.getTimestamp())
|
||||
.append(SPACE).append(histo.getPercentile(99))
|
||||
.append(SPACE).append(tags).append(p99);
|
||||
// @formatter:off
|
||||
return buf.toString().getBytes();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package timely.analytics.flink;
|
||||
|
||||
import org.apache.flink.api.java.functions.KeySelector;
|
||||
|
||||
import timely.api.response.MetricResponse;
|
||||
|
||||
/**
|
||||
* Uniquely defines a time series in a Flink stream. A unique time series is the
|
||||
* metric name and all of its tags, to include visibility if it exists.
|
||||
*/
|
||||
public class MetricKeySelector implements KeySelector<MetricResponse, String> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public String getKey(MetricResponse m) throws Exception {
|
||||
return m.getMetric() + m.getTags().toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package timely.analytics.flink;
|
||||
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableLong;
|
||||
import org.apache.flink.api.common.accumulators.Accumulator;
|
||||
|
||||
/**
|
||||
* Custom accumulator that retains a sorted map of strings and their counts
|
||||
*
|
||||
*/
|
||||
public class SortedStringAccumulator implements Accumulator<String, ConcurrentSkipListMap<String, MutableLong>> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private ConcurrentSkipListMap<String, MutableLong> values = new ConcurrentSkipListMap<>();
|
||||
|
||||
@Override
|
||||
public void add(String value) {
|
||||
if (values.containsKey(value)) {
|
||||
values.get(value).increment();
|
||||
} else {
|
||||
values.put(value, new MutableLong(1));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConcurrentSkipListMap<String, MutableLong> getLocalValue() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetLocal() {
|
||||
values.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void merge(Accumulator<String, ConcurrentSkipListMap<String, MutableLong>> other) {
|
||||
other.getLocalValue().forEach((k, v) -> {
|
||||
if (values.containsKey(k)) {
|
||||
values.get(k).add(v.longValue());
|
||||
} else {
|
||||
values.put(k, v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Accumulator<String, ConcurrentSkipListMap<String, MutableLong>> clone() {
|
||||
SortedStringAccumulator a = new SortedStringAccumulator();
|
||||
a.getLocalValue().putAll(this.values);
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
package timely.analytics.flink;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.MessageHandler;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.apache.flink.api.common.accumulators.LongCounter;
|
||||
import org.apache.flink.api.common.functions.StoppableFunction;
|
||||
import org.apache.flink.configuration.Configuration;
|
||||
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
|
||||
import org.apache.flink.streaming.api.watermark.Watermark;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import timely.api.response.MetricResponse;
|
||||
import timely.api.response.MetricResponses;
|
||||
import timely.client.websocket.ClientHandler;
|
||||
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
||||
import timely.serialize.JsonSerializer;
|
||||
|
||||
public class SubscriptionSource extends RichSourceFunction<MetricResponse> implements Serializable, StoppableFunction {
|
||||
|
||||
private static class SubscriptionThreadFactory implements ThreadFactory {
|
||||
|
||||
private static final String NAME = "Subscription Source";
|
||||
private AtomicInteger threadNum = new AtomicInteger(1);
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
return new Thread(r, NAME + " " + threadNum.getAndIncrement());
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SubscriptionSource.class);
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private transient WebSocketSubscriptionClient client = null;
|
||||
private long start = 0L;
|
||||
private long end = 0L;
|
||||
private final String[] metrics;
|
||||
private final SummarizationJobParameters jp;
|
||||
private final long window;
|
||||
private final AtomicInteger subscriptionsRemaining;
|
||||
|
||||
public SubscriptionSource(SummarizationJobParameters jp) {
|
||||
this.jp = jp;
|
||||
start = jp.getStartTime();
|
||||
end = jp.getEndTime();
|
||||
metrics = jp.getMetrics();
|
||||
window = jp.getSummarizationInterval().toMilliseconds();
|
||||
subscriptionsRemaining = new AtomicInteger(metrics.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(Configuration parameters) throws Exception {
|
||||
LOG.info("Opening summarization job.");
|
||||
super.open(parameters);
|
||||
client = new WebSocketSubscriptionClient(jp.getTimelyHostname(), jp.getTimelyHttpsPort(),
|
||||
jp.getTimelyWssPort(), jp.isDoLogin(), jp.getTimelyUsername(), jp.getTimelyPassword(),
|
||||
jp.getKeyStoreFile(), jp.getKeyStoreType(), jp.getKeyStorePass(), jp.getTrustStoreFile(),
|
||||
jp.getTrustStoreType(), jp.getTrustStorePass(), jp.isHostVerificationEnabled(), jp.getBufferSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws Exception {
|
||||
super.close();
|
||||
if (null != client) {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(SourceContext<MetricResponse> ctx) throws Exception {
|
||||
LOG.info("Running summarization job");
|
||||
final SortedStringAccumulator dateTimeAccumulator = new SortedStringAccumulator();
|
||||
this.getRuntimeContext().addAccumulator("source hourly count", dateTimeAccumulator);
|
||||
final LongCounter sourceInputs = new LongCounter();
|
||||
this.getRuntimeContext().addAccumulator("source input counter", sourceInputs);
|
||||
final LongCounter inputProcessedInMainThread = new LongCounter();
|
||||
this.getRuntimeContext().addAccumulator("input processed in main thread", inputProcessedInMainThread);
|
||||
|
||||
// Use only one thread to ensure that time is still ordered
|
||||
final ExecutorService svc = Executors.newFixedThreadPool(1, new SubscriptionThreadFactory());
|
||||
|
||||
ClientHandler handler = new ClientHandler() {
|
||||
|
||||
@Override
|
||||
public void onOpen(Session session, EndpointConfig config) {
|
||||
session.addMessageHandler(new MessageHandler.Whole<String>() {
|
||||
|
||||
private final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd-HH");
|
||||
private long lastWatermarkTime = 0L;
|
||||
|
||||
@Override
|
||||
public void onMessage(final String message) {
|
||||
LOG.info("Message received on Websocket session {}, length: {}", session.getId(),
|
||||
message.length());
|
||||
try {
|
||||
// Deserialize in this thread
|
||||
final MetricResponses responses = JsonSerializer.getObjectMapper().readValue(message,
|
||||
MetricResponses.class);
|
||||
// Process in the other
|
||||
final Runnable r = () -> {
|
||||
responses.getResponses().forEach(response -> {
|
||||
if (response.isComplete()) {
|
||||
LOG.info("Received last message.");
|
||||
ctx.emitWatermark(new Watermark(Long.MAX_VALUE));
|
||||
subscriptionsRemaining.getAndDecrement();
|
||||
return;
|
||||
}
|
||||
LOG.trace("Received metric: {}", response);
|
||||
long time = response.getTimestamp();
|
||||
ctx.collectWithTimestamp(response, time);
|
||||
dateTimeAccumulator.add(formatter.format(new Date(response.getTimestamp())));
|
||||
sourceInputs.add(1);
|
||||
// Emit a watermark every second of event
|
||||
// time
|
||||
if (lastWatermarkTime == 0) {
|
||||
lastWatermarkTime = time;
|
||||
} else if ((time - lastWatermarkTime) > window) {
|
||||
lastWatermarkTime = time;
|
||||
ctx.emitWatermark(new Watermark(time - 1));
|
||||
}
|
||||
});
|
||||
};
|
||||
try {
|
||||
svc.execute(r);
|
||||
} catch (RejectedExecutionException e) {
|
||||
// Run it in this thread
|
||||
r.run();
|
||||
inputProcessedInMainThread.add(1);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Error deserializing metric response, closing", e);
|
||||
try {
|
||||
close();
|
||||
} catch (Exception e1) {
|
||||
LOG.error("Error closing client", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Session session, CloseReason reason) {
|
||||
super.onClose(session, reason);
|
||||
try {
|
||||
close();
|
||||
} catch (Exception e1) {
|
||||
LOG.error("Error closing client", e1);
|
||||
}
|
||||
// Signal done sending data
|
||||
ctx.emitWatermark(new Watermark(Long.MAX_VALUE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Session session, Throwable error) {
|
||||
super.onError(session, error);
|
||||
try {
|
||||
close();
|
||||
} catch (Exception e1) {
|
||||
LOG.error("Error closing client", e1);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
try {
|
||||
client.open(handler);
|
||||
for (String m : metrics) {
|
||||
LOG.info("Adding subscription for {}", m);
|
||||
client.addSubscription(m, null, start, end, 5000);
|
||||
}
|
||||
while (!client.isClosed() && subscriptionsRemaining.get() > 0) {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
LOG.error("Sleep interrupted.");
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
svc.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
LOG.info("Cancelling subscription source.");
|
||||
try {
|
||||
close();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error closing web socket client");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
LOG.info("Stopping subscription source.");
|
||||
try {
|
||||
close();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error closing web socket client");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package timely.analytics.flink;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.flink.api.common.accumulators.LongCounter;
|
||||
import org.apache.flink.api.common.functions.FoldFunction;
|
||||
import org.apache.flink.api.java.utils.ParameterTool;
|
||||
import org.apache.flink.configuration.Configuration;
|
||||
import org.apache.flink.streaming.api.TimeCharacteristic;
|
||||
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
|
||||
import org.apache.flink.streaming.api.functions.sink.SocketClientSink;
|
||||
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import timely.api.response.MetricResponse;
|
||||
|
||||
public class SummarizationJob {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SummarizationJob.class);
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
if (args.length != 1) {
|
||||
System.err.println("Usage: timely.analytics.flink.SummarizationJob <path_to_properties_file>");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
LOG.info("Loading properties from: {}", args[0]);
|
||||
ParameterTool params = ParameterTool.fromPropertiesFile(args[0]);
|
||||
|
||||
final SummarizationJobParameters jp = new SummarizationJobParameters(params);
|
||||
LOG.info("Properties: {}", jp);
|
||||
|
||||
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
|
||||
// @formatter:off
|
||||
env.getConfig().setGlobalJobParameters(jp);
|
||||
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
|
||||
env.addSource(new SubscriptionSource(jp), "Timely Metrics Subscription")
|
||||
// partition by unique metric
|
||||
.keyBy(new MetricKeySelector())
|
||||
.window(TumblingEventTimeWindows.of(jp.getSummarizationInterval()))
|
||||
.fold(new MetricHistogram(), new FoldFunction<MetricResponse, MetricHistogram>() {
|
||||
|
||||
private final Logger LOG = LoggerFactory
|
||||
.getLogger("timely.analytics.SummarizationJob.FoldFunction@");
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public MetricHistogram fold(MetricHistogram histo, MetricResponse metric) throws Exception {
|
||||
if (!histo.isInitialized()) {
|
||||
histo.initialize(metric.getMetric(), metric.getTags());
|
||||
} else {
|
||||
if (!histo.getMetric().equals(metric.getMetric())) {
|
||||
throw new RuntimeException("Metric name does not match - partitioning problem");
|
||||
}
|
||||
if (!histo.getTags().equals(metric.getTags())) {
|
||||
throw new RuntimeException("Tags don't not match - partitioning problem");
|
||||
}
|
||||
}
|
||||
LOG.trace("Updating histogram for {} with value {} at {} for metric {}", histo.getMetric()
|
||||
+ histo.getTags(), metric.getValue(), metric.getTimestamp(), metric.getMetric()
|
||||
+ metric.getTags());
|
||||
histo.update(metric.getValue(), metric.getTimestamp());
|
||||
return histo;
|
||||
}
|
||||
})
|
||||
.name("Metric Windows")
|
||||
.addSink(
|
||||
new SocketClientSink<MetricHistogram>(jp.getTimelyHostname(), jp.getTimelyTcpPort(),
|
||||
new MetricHistogram(), 2, true) {
|
||||
|
||||
private final Logger LOG = LoggerFactory
|
||||
.getLogger("timely.analytics.SummarizationJob.SocketClientSink");
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final LongCounter sinkCounter = new LongCounter();
|
||||
private final SortedStringAccumulator dateTimeAccumulator = new SortedStringAccumulator();
|
||||
private final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd-HH");
|
||||
|
||||
@Override
|
||||
public void open(Configuration parameters) throws Exception {
|
||||
super.open(parameters);
|
||||
this.getRuntimeContext().addAccumulator("sink counter", this.sinkCounter);
|
||||
this.getRuntimeContext().addAccumulator("sink hourly count", dateTimeAccumulator);
|
||||
LOG.info("Sink opened");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(MetricHistogram histo) throws Exception {
|
||||
histo.done();
|
||||
super.invoke(histo);
|
||||
this.sinkCounter.add(1);
|
||||
this.dateTimeAccumulator.add(formatter.format(new Date(histo.getTimestamp())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
super.close();
|
||||
LOG.info("Sink closed");
|
||||
}
|
||||
|
||||
}).name("Timely Metric Sink");
|
||||
// @formatter:on
|
||||
env.execute("Metric Summarization");
|
||||
// Looks like there is no way to stop Flink job if underlying web socket
|
||||
// is closed.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
package timely.analytics.flink;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.flink.api.common.ExecutionConfig.GlobalJobParameters;
|
||||
import org.apache.flink.api.java.utils.ParameterTool;
|
||||
import org.apache.flink.configuration.Configuration;
|
||||
import org.apache.flink.streaming.api.windowing.time.Time;
|
||||
|
||||
public class SummarizationJobParameters extends GlobalJobParameters implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String timelyHostname;
|
||||
private final int timelyTcpPort;
|
||||
private final int timelyHttpsPort;
|
||||
private final int timelyWssPort;
|
||||
private final boolean doLogin;
|
||||
private final String timelyUsername;
|
||||
private final String timelyPassword;
|
||||
private final String keyStoreFile;
|
||||
private final String keyStoreType;
|
||||
private final String keyStorePass;
|
||||
private final String trustStoreFile;
|
||||
private final String trustStoreType;
|
||||
private final String trustStorePass;
|
||||
private final boolean hostVerificationEnabled;
|
||||
private final int bufferSize;
|
||||
private final String[] metrics;
|
||||
private final long startTime;
|
||||
private final long endTime;
|
||||
private final String interval;
|
||||
private final String intervalUnits;
|
||||
|
||||
public SummarizationJobParameters(ParameterTool params) {
|
||||
timelyHostname = params.getRequired("timelyHostname");
|
||||
timelyTcpPort = params.getInt("timelyTcpPort", 4241);
|
||||
timelyHttpsPort = params.getInt("timelyHttpsPort", 4242);
|
||||
timelyWssPort = params.getInt("timelyWssPort", 4243);
|
||||
doLogin = params.getBoolean("doLogin", false);
|
||||
timelyUsername = params.get("timelyUsername", null);
|
||||
timelyPassword = params.get("timelyPassword", null);
|
||||
keyStoreFile = params.getRequired("keyStoreFile");
|
||||
keyStoreType = params.get("keyStoreType", "JKS");
|
||||
keyStorePass = params.getRequired("keyStorePass");
|
||||
trustStoreFile = params.getRequired("trustStoreFile");
|
||||
trustStoreType = params.get("trustStoreType", "JKS");
|
||||
trustStorePass = params.getRequired("trustStorePass");
|
||||
hostVerificationEnabled = params.getBoolean("hostVerificationEnabled", true);
|
||||
bufferSize = params.getInt("bufferSize", 10485760);
|
||||
String metricNames = params.getRequired("metrics");
|
||||
if (null != metricNames) {
|
||||
metrics = metricNames.split(",");
|
||||
} else {
|
||||
metrics = null;
|
||||
}
|
||||
startTime = params.getLong("startTime", 0L);
|
||||
endTime = params.getLong("endTime", 0L);
|
||||
interval = params.getRequired("interval");
|
||||
intervalUnits = params.getRequired("intervalUnits");
|
||||
}
|
||||
|
||||
public SummarizationJobParameters(Configuration conf) {
|
||||
System.out.println("Creating job parameters from configuration: " + conf);
|
||||
timelyHostname = conf.getString("timelyHostname", null);
|
||||
timelyTcpPort = conf.getInteger("timelyTcpPort", 4241);
|
||||
timelyHttpsPort = conf.getInteger("timelyHttpsPort", 4242);
|
||||
timelyWssPort = conf.getInteger("timelyWssPort", 4243);
|
||||
doLogin = conf.getBoolean("doLogin", false);
|
||||
timelyUsername = conf.getString("timelyUsername", null);
|
||||
timelyPassword = conf.getString("timelyPassword", null);
|
||||
keyStoreFile = conf.getString("keyStoreFile", null);
|
||||
keyStoreType = conf.getString("keyStoreType", "JKS");
|
||||
keyStorePass = conf.getString("keyStorePass", null);
|
||||
trustStoreFile = conf.getString("trustStoreFile", null);
|
||||
trustStoreType = conf.getString("trustStoreType", "JKS");
|
||||
trustStorePass = conf.getString("trustStorePass", null);
|
||||
hostVerificationEnabled = conf.getBoolean("hostVerificationEnabled", true);
|
||||
bufferSize = conf.getInteger("bufferSize", 10485760);
|
||||
String metricNames = conf.getString("metrics", null);
|
||||
if (null != metricNames) {
|
||||
metrics = metricNames.split(",");
|
||||
} else {
|
||||
metrics = null;
|
||||
}
|
||||
startTime = conf.getLong("startTime", 0L);
|
||||
endTime = conf.getLong("endTime", 0L);
|
||||
interval = conf.getString("interval", null);
|
||||
intervalUnits = conf.getString("intervalUnits", null);
|
||||
}
|
||||
|
||||
public Time getSummarizationInterval() {
|
||||
return Time.of(Long.parseLong(interval), TimeUnit.valueOf(intervalUnits));
|
||||
}
|
||||
|
||||
public String getTimelyHostname() {
|
||||
return timelyHostname;
|
||||
}
|
||||
|
||||
public int getTimelyTcpPort() {
|
||||
return timelyTcpPort;
|
||||
}
|
||||
|
||||
public int getTimelyHttpsPort() {
|
||||
return timelyHttpsPort;
|
||||
}
|
||||
|
||||
public int getTimelyWssPort() {
|
||||
return timelyWssPort;
|
||||
}
|
||||
|
||||
public boolean isDoLogin() {
|
||||
return doLogin;
|
||||
}
|
||||
|
||||
public String getTimelyUsername() {
|
||||
return timelyUsername;
|
||||
}
|
||||
|
||||
public String getTimelyPassword() {
|
||||
return timelyPassword;
|
||||
}
|
||||
|
||||
public String getKeyStoreFile() {
|
||||
return keyStoreFile;
|
||||
}
|
||||
|
||||
public String getKeyStoreType() {
|
||||
return keyStoreType;
|
||||
}
|
||||
|
||||
public String getKeyStorePass() {
|
||||
return keyStorePass;
|
||||
}
|
||||
|
||||
public String getTrustStoreFile() {
|
||||
return trustStoreFile;
|
||||
}
|
||||
|
||||
public String getTrustStoreType() {
|
||||
return trustStoreType;
|
||||
}
|
||||
|
||||
public String getTrustStorePass() {
|
||||
return trustStorePass;
|
||||
}
|
||||
|
||||
public boolean isHostVerificationEnabled() {
|
||||
return hostVerificationEnabled;
|
||||
}
|
||||
|
||||
public int getBufferSize() {
|
||||
return bufferSize;
|
||||
}
|
||||
|
||||
public String[] getMetrics() {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public long getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public String getInterval() {
|
||||
return interval;
|
||||
}
|
||||
|
||||
public String getIntervalUnits() {
|
||||
return intervalUnits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> toMap() {
|
||||
Map<String, String> m = new HashMap<>();
|
||||
m.put("timelyHostname", this.timelyHostname);
|
||||
m.put("timelyHttpsPort", Integer.toString(this.timelyHttpsPort));
|
||||
m.put("timelyWssPort", Integer.toString(this.timelyWssPort));
|
||||
m.put("doLogin", Boolean.toString(this.doLogin));
|
||||
m.put("timelyUsername", this.timelyUsername);
|
||||
m.put("timelyPassword", this.timelyPassword);
|
||||
m.put("keyStoreFile", this.keyStoreFile);
|
||||
m.put("keyStoreType", this.keyStoreType);
|
||||
m.put("keyStorePass", this.keyStorePass);
|
||||
m.put("trustStoreFile", this.trustStoreFile);
|
||||
m.put("trustStoreType", this.trustStoreType);
|
||||
m.put("trustStorePass", this.trustStorePass);
|
||||
m.put("hostVerificationEnabled", Boolean.toString(this.hostVerificationEnabled));
|
||||
m.put("bufferSize", Integer.toString(this.bufferSize));
|
||||
m.put("metrics", String.join(",", this.metrics));
|
||||
m.put("startTime", Long.toString(this.startTime));
|
||||
m.put("endTime", Long.toString(this.endTime));
|
||||
m.put("interval", this.interval);
|
||||
m.put("intervalUnits", this.intervalUnits);
|
||||
return m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toMap().toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package timely.analytics.flink;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import timely.model.Metric;
|
||||
import timely.model.Tag;
|
||||
import timely.model.parse.MetricParser;
|
||||
|
||||
public class MetricHistogramTest {
|
||||
|
||||
private MetricHistogram m = null;
|
||||
private long timestamp = System.currentTimeMillis();
|
||||
|
||||
@Before
|
||||
public void createMetric() throws Exception {
|
||||
m = new MetricHistogram();
|
||||
for (double d = 1.0D; d <= 100.0; d += 1.0) {
|
||||
timestamp += 1000;
|
||||
m.update(d, timestamp);
|
||||
}
|
||||
m.toString();
|
||||
Assert.assertEquals(timestamp, m.getTimestamp());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMin() throws Exception {
|
||||
Assert.assertEquals(1.0D, m.min(), 0.0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMax() throws Exception {
|
||||
Assert.assertEquals(100.0D, m.max(), 0.0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAvg() throws Exception {
|
||||
int sum = 0;
|
||||
for (int i = 1; i <= 100; i++) {
|
||||
sum += i;
|
||||
}
|
||||
Assert.assertEquals((sum / 100.0D), m.avg(), 0.0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCount() throws Exception {
|
||||
Assert.assertEquals(100.0D, m.count(), 0.0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test50thPercentile() throws Exception {
|
||||
Assert.assertEquals(50.0D, m.getPercentile(50), 0.0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test75thPercentile() throws Exception {
|
||||
Assert.assertEquals(75.0D, m.getPercentile(75), 0.0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test90thPercentile() throws Exception {
|
||||
Assert.assertEquals(90.0D, m.getPercentile(90), 0.0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test99thPercentile() throws Exception {
|
||||
Assert.assertEquals(99.0D, m.getPercentile(99), 0.0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerialization() throws Exception {
|
||||
MetricParser metricParser = new MetricParser();
|
||||
Tag t1 = new Tag("tag1=value1");
|
||||
Tag t2 = new Tag("tag2=value2");
|
||||
Tag avg = new Tag("sample=avg");
|
||||
Tag min = new Tag("sample=min");
|
||||
Tag max = new Tag("sample=max");
|
||||
Tag sum = new Tag("sample=sum");
|
||||
Tag count = new Tag("sample=count");
|
||||
Tag p50 = new Tag("sample=50p");
|
||||
Tag p75 = new Tag("sample=75p");
|
||||
Tag p90 = new Tag("sample=90p");
|
||||
Tag p99 = new Tag("sample=99p");
|
||||
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
tags.add(t1);
|
||||
tags.add(t2);
|
||||
m.initialize("sys.cpu.user", tags);
|
||||
|
||||
byte[] bytes = m.serialize(m);
|
||||
String puts = new String(bytes);
|
||||
for (String put : puts.split("\n")) {
|
||||
Metric metric = metricParser.parse(put);
|
||||
Assert.assertEquals("sys.cpu.user_summarized", metric.getName());
|
||||
metric.getTags().forEach(
|
||||
t -> {
|
||||
Assert.assertTrue(t.equals(t1) || t.equals(t2) || t.equals(avg) || t.equals(min)
|
||||
|| t.equals(max) || t.equals(sum) || t.equals(count) || t.equals(p50) || t.equals(p75)
|
||||
|| t.equals(p90) || t.equals(p99));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+83
-1
@@ -5,8 +5,12 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>0.0.3</version>
|
||||
<version>0.0.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<properties>
|
||||
<!-- PEP 440 compliant version gets supstituted into src/main/python/template/setup.py -->
|
||||
<python.client.version>0.0.6.dev0</python.client.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>timely</groupId>
|
||||
@@ -39,6 +43,14 @@
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
@@ -54,6 +66,16 @@
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.tyrus</groupId>
|
||||
<artifactId>tyrus-client</artifactId>
|
||||
<version>1.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.tyrus</groupId>
|
||||
<artifactId>tyrus-container-grizzly-client</artifactId>
|
||||
<version>1.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
@@ -77,6 +99,66 @@
|
||||
<groupId>net.revelc.code</groupId>
|
||||
<artifactId>formatter-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>filter-setup</id>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<phase>process-resources</phase>
|
||||
<configuration>
|
||||
<outputDirectory>${project.basedir}/src/main/python</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/src/main/python/template</directory>
|
||||
<includes>
|
||||
<include>setup.py</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!--
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>python-dist</id>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
<configuration>
|
||||
<executable>python</executable>
|
||||
<workingDirectory>${project.basedir}/src/main/python</workingDirectory>
|
||||
<commandlineArgs>setup.py sdist - -dist-dir ${project.build.directory}</commandlineArgs>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>python-clean</id>
|
||||
<goals>
|
||||
<goal>exec</goal>
|
||||
</goals>
|
||||
<phase>package</phase>
|
||||
<configuration>
|
||||
<executable>rm</executable>
|
||||
<workingDirectory>${project.basedir}/src/main/python</workingDirectory>
|
||||
<commandlineArgs>-rf timely.egg-info setup.py</commandlineArgs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
-->
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package timely.api;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class AddSubscription extends SubscriptionRequest {
|
||||
|
||||
private String operation = "add";
|
||||
private String metric = null;
|
||||
private Optional<Map<String, String>> tags = Optional.empty();
|
||||
private Optional<Long> startTime = Optional.empty();
|
||||
private Optional<Long> endTime = Optional.empty();
|
||||
private Optional<Long> delayTime = Optional.empty();
|
||||
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public String getMetric() {
|
||||
return metric;
|
||||
}
|
||||
|
||||
public Optional<Map<String, String>> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public Optional<Long> getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public Optional<Long> getDelayTime() {
|
||||
return delayTime;
|
||||
}
|
||||
|
||||
public void setMetric(String metric) {
|
||||
this.metric = metric;
|
||||
}
|
||||
|
||||
public void setTags(Optional<Map<String, String>> tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
public void setStartTime(Optional<Long> startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public void setDelayTime(Optional<Long> delayTime) {
|
||||
this.delayTime = delayTime;
|
||||
}
|
||||
|
||||
public Optional<Long> getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(Optional<Long> endTime) {
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (operation + subscriptionId + metric + tags + startTime + endTime + delayTime).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (null == obj) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof AddSubscription) {
|
||||
AddSubscription other = (AddSubscription) obj;
|
||||
return (this.subscriptionId.equals(other.subscriptionId) && this.metric.equals(other.metric)
|
||||
&& this.tags.equals(other.tags) && this.startTime.equals(other.startTime)
|
||||
&& this.endTime.equals(other.endTime) && this.delayTime.equals(other.delayTime));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package timely.api;
|
||||
|
||||
public class BasicAuthLogin {
|
||||
|
||||
protected String username;
|
||||
protected String password;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String user) {
|
||||
this.username = user;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (username + password).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (null == obj) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof BasicAuthLogin) {
|
||||
BasicAuthLogin other = (BasicAuthLogin) obj;
|
||||
return (this.username.equals(other.username) && this.password.equals(other.password));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package timely.api;
|
||||
|
||||
public class CloseSubscription extends SubscriptionRequest {
|
||||
|
||||
private String operation = "close";
|
||||
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (operation + subscriptionId).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (null == obj) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof CloseSubscription) {
|
||||
CloseSubscription other = (CloseSubscription) obj;
|
||||
return (this.subscriptionId.equals(other.subscriptionId));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package timely.api;
|
||||
|
||||
public class CreateSubscription extends SubscriptionRequest {
|
||||
|
||||
private String operation = "create";
|
||||
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (operation + subscriptionId).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (null == obj) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof CreateSubscription) {
|
||||
CreateSubscription other = (CreateSubscription) obj;
|
||||
return (this.subscriptionId.equals(other.subscriptionId));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package timely.api;
|
||||
|
||||
public class RemoveSubscription extends SubscriptionRequest {
|
||||
|
||||
private String operation = "remove";
|
||||
private String metric = null;
|
||||
|
||||
public String getOperation() {
|
||||
return operation;
|
||||
}
|
||||
|
||||
public String getMetric() {
|
||||
return metric;
|
||||
}
|
||||
|
||||
public void setMetric(String metric) {
|
||||
this.metric = metric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (operation + subscriptionId + metric).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (null == obj) {
|
||||
return false;
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof RemoveSubscription) {
|
||||
RemoveSubscription other = (RemoveSubscription) obj;
|
||||
return (this.subscriptionId.equals(other.subscriptionId) && this.metric.equals(other.metric));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package timely.api;
|
||||
|
||||
public abstract class SubscriptionRequest {
|
||||
|
||||
protected String subscriptionId = null;
|
||||
|
||||
public final String getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
public final void setSubscriptionId(String subscriptionId) {
|
||||
this.subscriptionId = subscriptionId;
|
||||
}
|
||||
|
||||
}
|
||||
+13
@@ -16,6 +16,7 @@ public class MetricResponse {
|
||||
private double value;
|
||||
private List<Tag> tags;
|
||||
private String subscriptionId;
|
||||
private boolean complete = false;
|
||||
|
||||
public String getMetric() {
|
||||
return metric;
|
||||
@@ -33,6 +34,10 @@ public class MetricResponse {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
public void setMetric(String metric) {
|
||||
this.metric = metric;
|
||||
}
|
||||
@@ -57,6 +62,10 @@ public class MetricResponse {
|
||||
this.subscriptionId = subscriptionId;
|
||||
}
|
||||
|
||||
public void setComplete(boolean closed) {
|
||||
this.complete = closed;
|
||||
}
|
||||
|
||||
public static MetricResponse fromMetric(Metric metric, String subscriptionId) {
|
||||
MetricResponse response = new MetricResponse();
|
||||
response.setMetric(metric.getName());
|
||||
@@ -64,6 +73,7 @@ public class MetricResponse {
|
||||
response.setTags(metric.getTags());
|
||||
response.setValue(metric.getValue().getMeasure());
|
||||
response.setSubscriptionId(subscriptionId);
|
||||
response.setComplete(false);
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -75,6 +85,7 @@ public class MetricResponse {
|
||||
hash.append(this.value);
|
||||
hash.append(this.tags);
|
||||
hash.append(this.subscriptionId);
|
||||
hash.append(this.complete);
|
||||
return hash.hashCode();
|
||||
}
|
||||
|
||||
@@ -96,6 +107,7 @@ public class MetricResponse {
|
||||
equals.append(this.value, other.value);
|
||||
equals.append(this.tags, other.tags);
|
||||
equals.append(this.subscriptionId, other.subscriptionId);
|
||||
equals.append(this.complete, other.complete);
|
||||
return equals.isEquals();
|
||||
}
|
||||
|
||||
@@ -107,6 +119,7 @@ public class MetricResponse {
|
||||
tsb.append("value", this.value);
|
||||
tsb.append("tags", this.tags);
|
||||
tsb.append("subscriptionId", this.subscriptionId);
|
||||
tsb.append("complete", this.complete);
|
||||
return tsb.toString();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package timely.api.response;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MetricResponses {
|
||||
|
||||
private List<MetricResponse> responses = new ArrayList<>();
|
||||
|
||||
public synchronized List<MetricResponse> getResponses() {
|
||||
return this.responses;
|
||||
}
|
||||
|
||||
public synchronized void setResponses(List<MetricResponse> responses) {
|
||||
this.responses = responses;
|
||||
}
|
||||
|
||||
public synchronized void addResponse(MetricResponse r) {
|
||||
this.responses.add(r);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return this.responses.size();
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
this.responses.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package timely.client.http;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.http.client.CookieStore;
|
||||
import org.apache.http.client.config.CookieSpecs;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.glassfish.tyrus.client.SslContextConfigurator;
|
||||
|
||||
public class HttpClient {
|
||||
|
||||
public static SSLContext getSSLContext(String trustStoreFile, String trustStoreType, String trustStorePass,
|
||||
String keyStoreFile, String keyStoreType, String keyStorePass) {
|
||||
SslContextConfigurator scc = new SslContextConfigurator();
|
||||
scc.setTrustStoreFile(trustStoreFile);
|
||||
scc.setTrustStoreType(trustStoreType);
|
||||
if (null != trustStorePass) {
|
||||
scc.setTrustStorePassword(trustStorePass);
|
||||
}
|
||||
scc.setKeyStoreFile(keyStoreFile);
|
||||
scc.setKeyStoreType(keyStoreType);
|
||||
if (null != keyStorePass) {
|
||||
scc.setKeyStorePassword(keyStorePass);
|
||||
}
|
||||
return scc.createSSLContext();
|
||||
}
|
||||
|
||||
public static CloseableHttpClient get(String trustStoreFile, String trustStoreType, String trustStorePass,
|
||||
String keyStoreFile, String keyStoreType, String keyStorePass, CookieStore cookieStore,
|
||||
boolean hostVerificationEnabled) {
|
||||
|
||||
SSLContext ssl = getSSLContext(trustStoreFile, trustStoreType, trustStorePass, keyStoreFile, keyStoreType,
|
||||
keyStorePass);
|
||||
return get(ssl, cookieStore, hostVerificationEnabled);
|
||||
}
|
||||
|
||||
public static CloseableHttpClient get(SSLContext ssl, CookieStore cookieStore, boolean hostVerificationEnabled) {
|
||||
RequestConfig defaultRequestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
|
||||
|
||||
HttpClientBuilder builder = HttpClients.custom().setSSLContext(ssl).setDefaultCookieStore(cookieStore)
|
||||
.setDefaultRequestConfig(defaultRequestConfig);
|
||||
if (hostVerificationEnabled) {
|
||||
builder.setSSLHostnameVerifier(new DefaultHostnameVerifier());
|
||||
} else {
|
||||
builder.setSSLHostnameVerifier(new NoopHostnameVerifier());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package timely.client.tcp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TcpClient implements AutoCloseable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TcpClient.class);
|
||||
|
||||
private final String host;
|
||||
private final int port;
|
||||
private Socket sock = null;
|
||||
private PrintWriter out = null;
|
||||
private long connectTime = 0L;
|
||||
private long backoff = 2000;
|
||||
|
||||
public TcpClient(String hostname, int port) {
|
||||
this.host = hostname;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a TCP connection to the specified host and port
|
||||
*
|
||||
* @throws IOException
|
||||
* if an error occurs
|
||||
*/
|
||||
public void open() throws IOException {
|
||||
if (connect() != 0) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a metric to Timely
|
||||
*
|
||||
* @param metric
|
||||
* newline terminated string representation of Timely metric
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized void write(String metric) throws IOException {
|
||||
if (connect() != 0) {
|
||||
throw new IOException();
|
||||
}
|
||||
out.write(metric);
|
||||
}
|
||||
|
||||
public synchronized void flush() {
|
||||
if (null != out) {
|
||||
out.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the tcp connection to Timely
|
||||
*
|
||||
* @throws IOException
|
||||
* if an error occurs
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
LOG.info("Shutting down connection to Timely at {}:{}", host, port);
|
||||
if (null != sock) {
|
||||
try {
|
||||
if (null != out) {
|
||||
out.close();
|
||||
}
|
||||
sock.close();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Error closing connection to Timely at " + host + ":" + port + ". Error: " + e.getMessage());
|
||||
} finally {
|
||||
sock = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized int connect() {
|
||||
if (null == sock || !sock.isConnected() || out.checkError()) {
|
||||
if (System.currentTimeMillis() > (connectTime + backoff)) {
|
||||
try {
|
||||
connectTime = System.currentTimeMillis();
|
||||
sock = new Socket(host, port);
|
||||
out = new PrintWriter(sock.getOutputStream(), false);
|
||||
backoff = 2000;
|
||||
LOG.info("Connected to Timely at {}:{}", host, port);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Error connecting to Timely at {}:" + host + ":" + port + ". Error: " + e.getMessage());
|
||||
backoff = backoff * 2;
|
||||
sock = null;
|
||||
out = null;
|
||||
LOG.warn("Will retry connection in {} ms.", backoff);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Not writing to Timely, waiting to reconnect");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package timely.client.udp;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class UdpClient implements AutoCloseable {
|
||||
|
||||
private final InetSocketAddress address;
|
||||
private final DatagramPacket packet;
|
||||
private DatagramSocket sock;
|
||||
|
||||
public UdpClient(String hostname, int port) {
|
||||
this.address = new InetSocketAddress(hostname, port);
|
||||
this.packet = new DatagramPacket("".getBytes(UTF_8), 0, 0, address.getAddress(), port);
|
||||
}
|
||||
|
||||
public void open() throws IOException {
|
||||
if (null == sock) {
|
||||
this.sock = new DatagramSocket();
|
||||
}
|
||||
}
|
||||
|
||||
public void write(String metric) throws IOException {
|
||||
if (null == this.sock) {
|
||||
throw new IllegalStateException("Must call open first");
|
||||
}
|
||||
this.packet.setData(metric.getBytes(UTF_8));
|
||||
this.sock.send(packet);
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
if (null != sock) {
|
||||
sock.close();
|
||||
sock = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package timely.client.websocket;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.Endpoint;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.MessageHandler;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class ClientHandler extends Endpoint {
|
||||
|
||||
private final static Logger LOG = LoggerFactory.getLogger(ClientHandler.class);
|
||||
|
||||
@Override
|
||||
public void onOpen(Session session, EndpointConfig config) {
|
||||
LOG.info("Websocket session {} opened.", session.getId());
|
||||
session.addMessageHandler(new MessageHandler.Whole<String>() {
|
||||
|
||||
@Override
|
||||
public void onMessage(String message) {
|
||||
LOG.info("Message received on Websocket session {}: {}", session.getId(), message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(Session session, CloseReason reason) {
|
||||
LOG.info("Websocket session {} closed.", session.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Session session, Throwable error) {
|
||||
LOG.error("Error occurred on Websocket session" + session.getId(), error);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package timely.client.websocket;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.Encoder;
|
||||
import javax.websocket.Extension;
|
||||
|
||||
import org.apache.http.cookie.Cookie;
|
||||
|
||||
public class TimelyEndpointConfig implements ClientEndpointConfig {
|
||||
|
||||
private String sessionCookie = null;
|
||||
|
||||
private static final String FORMAT = "%s=%s;";
|
||||
|
||||
public TimelyEndpointConfig(Cookie sessionCookie) {
|
||||
if (null != sessionCookie) {
|
||||
this.sessionCookie = String.format(FORMAT, sessionCookie.getName(), sessionCookie.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Encoder>> getEncoders() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Decoder>> getDecoders() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getUserProperties() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPreferredSubprotocols() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Extension> getExtensions() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configurator getConfigurator() {
|
||||
return new Configurator() {
|
||||
|
||||
@Override
|
||||
public void beforeRequest(Map<String, List<String>> headers) {
|
||||
super.beforeRequest(headers);
|
||||
if (null != sessionCookie) {
|
||||
headers.put("Cookie", Collections.singletonList(sessionCookie));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package timely.client.websocket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.HttpResponseException;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.client.utils.HttpClientUtils;
|
||||
import org.apache.http.cookie.Cookie;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.BasicCookieStore;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.glassfish.tyrus.client.ClientManager;
|
||||
import org.glassfish.tyrus.client.ClientProperties;
|
||||
import org.glassfish.tyrus.client.SslEngineConfigurator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import timely.api.BasicAuthLogin;
|
||||
import timely.client.http.HttpClient;
|
||||
import timely.serialize.JsonSerializer;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
public class WebSocketClient implements AutoCloseable {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WebSocketClient.class);
|
||||
|
||||
private final String timelyHostname;
|
||||
private final int timelyHttpsPort;
|
||||
private final int timelyWssPort;
|
||||
private final boolean doLogin;
|
||||
private final String timelyUsername;
|
||||
private final String timelyPassword;
|
||||
private final boolean hostVerificationEnabled;
|
||||
private final int bufferSize;
|
||||
private final SSLContext ssl;
|
||||
|
||||
private ClientManager webSocketClient = null;
|
||||
protected Session session = null;
|
||||
protected volatile boolean closed = true;
|
||||
|
||||
protected WebSocketClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort,
|
||||
boolean doLogin, String timelyUsername, String timelyPassword, boolean hostVerificationEnabled,
|
||||
int bufferSize) {
|
||||
this.ssl = ssl;
|
||||
this.timelyHostname = timelyHostname;
|
||||
this.timelyHttpsPort = timelyHttpsPort;
|
||||
this.timelyWssPort = timelyWssPort;
|
||||
this.doLogin = doLogin;
|
||||
this.timelyUsername = timelyUsername;
|
||||
this.timelyPassword = timelyPassword;
|
||||
this.hostVerificationEnabled = hostVerificationEnabled;
|
||||
this.bufferSize = bufferSize;
|
||||
|
||||
Preconditions.checkNotNull(timelyHostname, "%s must be supplied", "Timely host name");
|
||||
Preconditions.checkNotNull(timelyHttpsPort, "%s must be supplied", "Timely HTTPS port");
|
||||
Preconditions.checkNotNull(timelyWssPort, "%s must be supplied", "Timely WSS port");
|
||||
|
||||
if (doLogin
|
||||
&& ((StringUtils.isEmpty(timelyUsername) && !StringUtils.isEmpty(timelyPassword) || (!StringUtils
|
||||
.isEmpty(timelyUsername) && StringUtils.isEmpty(timelyPassword))))) {
|
||||
throw new IllegalArgumentException("Both Timely username and password must be empty or non-empty");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected WebSocketClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean doLogin,
|
||||
String timelyUsername, String timelyPassword, String keyStoreFile, String keyStoreType,
|
||||
String keyStorePass, String trustStoreFile, String trustStoreType, String trustStorePass,
|
||||
boolean hostVerificationEnabled, int bufferSize) {
|
||||
this(HttpClient.getSSLContext(trustStoreFile, trustStoreType, trustStorePass, keyStoreFile, keyStoreType,
|
||||
keyStorePass), timelyHostname, timelyHttpsPort, timelyWssPort, doLogin, timelyUsername, timelyPassword,
|
||||
hostVerificationEnabled, bufferSize);
|
||||
}
|
||||
|
||||
public void open(ClientHandler clientEndpoint) throws IOException, DeploymentException, URISyntaxException {
|
||||
|
||||
Cookie sessionCookie = null;
|
||||
if (doLogin) {
|
||||
BasicCookieStore cookieJar = new BasicCookieStore();
|
||||
try (CloseableHttpClient client = HttpClient.get(ssl, cookieJar, hostVerificationEnabled)) {
|
||||
|
||||
String target = "https://" + timelyHostname + ":" + timelyHttpsPort + "/login";
|
||||
|
||||
HttpRequestBase request = null;
|
||||
if (StringUtils.isEmpty(timelyUsername)) {
|
||||
// HTTP GET to /login to use certificate based login
|
||||
request = new HttpGet(target);
|
||||
LOG.trace("Performing client certificate login");
|
||||
} else {
|
||||
// HTTP POST to /login to use username/password
|
||||
BasicAuthLogin login = new BasicAuthLogin();
|
||||
login.setUsername(timelyUsername);
|
||||
login.setPassword(timelyPassword);
|
||||
String payload = JsonSerializer.getObjectMapper().writeValueAsString(login);
|
||||
HttpPost post = new HttpPost(target);
|
||||
post.setEntity(new StringEntity(payload));
|
||||
request = post;
|
||||
LOG.trace("Performing BasicAuth login");
|
||||
}
|
||||
|
||||
HttpResponse response = null;
|
||||
try {
|
||||
response = client.execute(request);
|
||||
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
|
||||
throw new HttpResponseException(response.getStatusLine().getStatusCode(), response
|
||||
.getStatusLine().getReasonPhrase());
|
||||
}
|
||||
for (Cookie c : cookieJar.getCookies()) {
|
||||
if (c.getName().equals("TSESSIONID")) {
|
||||
sessionCookie = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (null == sessionCookie) {
|
||||
throw new IllegalStateException(
|
||||
"Unable to find TSESSIONID cookie header in Timely login response");
|
||||
}
|
||||
} finally {
|
||||
HttpClientUtils.closeQuietly(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SslEngineConfigurator sslEngine = new SslEngineConfigurator(ssl);
|
||||
sslEngine.setClientMode(true);
|
||||
sslEngine.setHostVerificationEnabled(hostVerificationEnabled);
|
||||
|
||||
webSocketClient = ClientManager.createClient();
|
||||
webSocketClient.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngine);
|
||||
webSocketClient.getProperties().put(ClientProperties.INCOMING_BUFFER_SIZE, bufferSize);
|
||||
String wssPath = "wss://" + timelyHostname + ":" + timelyWssPort + "/websocket";
|
||||
session = webSocketClient.connectToServer(clientEndpoint, new TimelyEndpointConfig(sessionCookie), new URI(
|
||||
wssPath));
|
||||
|
||||
final ByteBuffer pingData = ByteBuffer.allocate(0);
|
||||
webSocketClient.getScheduledExecutorService().scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
session.getBasicRemote().sendPing(pingData);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error sending ping", e);
|
||||
}
|
||||
}, 30, 60, TimeUnit.SECONDS);
|
||||
closed = false;
|
||||
}
|
||||
|
||||
public synchronized void close() throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (null != webSocketClient) {
|
||||
webSocketClient.shutdown();
|
||||
}
|
||||
} finally {
|
||||
session = null;
|
||||
webSocketClient = null;
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isClosed() {
|
||||
return closed;
|
||||
}
|
||||
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package timely.client.websocket.subscription;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.DeploymentException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import timely.api.AddSubscription;
|
||||
import timely.api.CloseSubscription;
|
||||
import timely.api.CreateSubscription;
|
||||
import timely.api.RemoveSubscription;
|
||||
import timely.client.websocket.ClientHandler;
|
||||
import timely.client.websocket.WebSocketClient;
|
||||
import timely.serialize.JsonSerializer;
|
||||
|
||||
public class WebSocketSubscriptionClient extends WebSocketClient {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WebSocketSubscriptionClient.class);
|
||||
private final String subscriptionId;
|
||||
|
||||
public WebSocketSubscriptionClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort,
|
||||
boolean doLogin, String timelyUsername, String timelyPassword, boolean hostVerificationEnabled,
|
||||
int bufferSize) {
|
||||
super(ssl, timelyHostname, timelyHttpsPort, timelyWssPort, doLogin, timelyUsername, timelyPassword,
|
||||
hostVerificationEnabled, bufferSize);
|
||||
subscriptionId = UUID.randomUUID().toString();
|
||||
LOG.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
|
||||
}
|
||||
|
||||
public WebSocketSubscriptionClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean doLogin,
|
||||
String timelyUsername, String timelyPassword, String keyStoreFile, String keyStoreType,
|
||||
String keyStorePass, String trustStoreFile, String trustStoreType, String trustStorePass,
|
||||
boolean hostVerificationEnabled, int bufferSize) {
|
||||
super(timelyHostname, timelyHttpsPort, timelyWssPort, doLogin, timelyUsername, timelyPassword, keyStoreFile,
|
||||
keyStoreType, keyStorePass, trustStoreFile, trustStoreType, trustStorePass, hostVerificationEnabled,
|
||||
bufferSize);
|
||||
subscriptionId = UUID.randomUUID().toString();
|
||||
LOG.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(ClientHandler clientEndpoint) throws IOException, DeploymentException, URISyntaxException {
|
||||
super.open(clientEndpoint);
|
||||
CreateSubscription create = new CreateSubscription();
|
||||
create.setSubscriptionId(subscriptionId);
|
||||
session.getBasicRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(create));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
if (null != session) {
|
||||
CloseSubscription close = new CloseSubscription();
|
||||
close.setSubscriptionId(subscriptionId);
|
||||
try {
|
||||
session.getBasicRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(close));
|
||||
session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Client called close."));
|
||||
} catch (Exception e) {
|
||||
LOG.info("Unable to send close message to server: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
|
||||
public Future<Void> addSubscription(String metric, Map<String, String> tags, long startTime, long endTime,
|
||||
long delayTime) throws IOException {
|
||||
AddSubscription add = new AddSubscription();
|
||||
add.setSubscriptionId(subscriptionId);
|
||||
add.setMetric(metric);
|
||||
add.setTags(Optional.ofNullable(tags));
|
||||
add.setStartTime(Optional.ofNullable(startTime));
|
||||
add.setEndTime(Optional.ofNullable(endTime));
|
||||
add.setDelayTime(Optional.ofNullable(delayTime));
|
||||
return session.getAsyncRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(add));
|
||||
}
|
||||
|
||||
public Future<Void> removeSubscription(String metric) throws Exception {
|
||||
RemoveSubscription remove = new RemoveSubscription();
|
||||
remove.setSubscriptionId(subscriptionId);
|
||||
remove.setMetric(metric);
|
||||
return session.getAsyncRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(remove));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,18 @@
|
||||
package timely.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.*;
|
||||
import timely.model.parse.TagParser;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import timely.model.parse.TagParser;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||
import com.fasterxml.jackson.annotation.JsonUnwrapped;
|
||||
|
||||
/**
|
||||
* A Metric consists of a metric name, tags, and a Value
|
||||
*
|
||||
@@ -17,7 +23,9 @@ import java.util.List;
|
||||
@JsonRootName("metric")
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonPropertyOrder({ "name" })
|
||||
public class Metric {
|
||||
public class Metric implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String name;
|
||||
private List<Tag> tags;
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
package timely.model;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* A simple interface that objects can implement to return the object size.
|
||||
*/
|
||||
public interface ObjectSizeOf {
|
||||
|
||||
/**
|
||||
* The (approximate) size of the object
|
||||
*/
|
||||
long sizeInBytes();
|
||||
|
||||
public static class ObjectInstance {
|
||||
|
||||
private Object o;
|
||||
|
||||
public ObjectInstance(Object _o) {
|
||||
this.o = _o;
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
return o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof ObjectInstance)) {
|
||||
return false;
|
||||
}
|
||||
return ((ObjectInstance) obj).o == this.o;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Sizer {
|
||||
|
||||
private static final Logger log = Logger.getLogger(Sizer.class.getCanonicalName());
|
||||
public static final short OBJECT_OVERHEAD = 8;
|
||||
public static final short ARRAY_OVERHEAD = 12;
|
||||
public static final short REFERENCE = 4;
|
||||
// The size of the basic Number constructs (and Boolean and Character)
|
||||
// is 16: roundUp(8 + primitiveSize)
|
||||
public static final short NUMBER_SIZE = 16;
|
||||
|
||||
/**
|
||||
* Get the size of an object. Note that we want something relatively
|
||||
* fast that gives us an order of magnitude here. The java
|
||||
* Instrumentation agent mechanism is a little too costly for general
|
||||
* use here. This will look for the ObjectSizeOf interface and if
|
||||
* implemented on the object will use that. Otherwise it will do a
|
||||
* simple navigation of the fields using reflection.
|
||||
*
|
||||
* @param o
|
||||
* @return an approximation of the object size
|
||||
*/
|
||||
public static long getObjectSize(Object o, boolean useSizeInBytesMethod, boolean debug) {
|
||||
long estSize = getObjectSize(o, new HashSet<ObjectInstance>(), new Stack<ObjectInstance>(),
|
||||
useSizeInBytesMethod, debug);
|
||||
return estSize;
|
||||
}
|
||||
|
||||
public static long getObjectSize(Object o) {
|
||||
long estSize = getObjectSize(o, new HashSet<ObjectInstance>(), new Stack<ObjectInstance>(), true, false);
|
||||
return estSize;
|
||||
}
|
||||
|
||||
public static long getObjectSize(Object o, Set<ObjectInstance> visited, Stack<ObjectInstance> stack,
|
||||
boolean useSizeInBytesMethod, boolean debug) {
|
||||
long totalSize = 0;
|
||||
stack.add(new ObjectInstance(o));
|
||||
while (!stack.isEmpty()) {
|
||||
long size = 0;
|
||||
ObjectInstance oi = stack.pop();
|
||||
o = oi.getObject();
|
||||
if (o != null && !visited.contains(oi)) {
|
||||
visited.add(oi);
|
||||
try {
|
||||
if (useSizeInBytesMethod) {
|
||||
try {
|
||||
if (o instanceof ObjectSizeOf) {
|
||||
size = ((ObjectSizeOf) o).sizeInBytes();
|
||||
} else {
|
||||
Method sizeInBytes = o.getClass().getMethod("sizeInBytes", (Class<?>[]) null);
|
||||
size = (Long) sizeInBytes.invoke(o);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// ok, lets do this the hard way...
|
||||
}
|
||||
}
|
||||
if (size == 0) {
|
||||
// the hard way...
|
||||
// do not include Class related objects or
|
||||
// reflection objects
|
||||
if ((o instanceof Class)
|
||||
|| (o instanceof ClassLoader)
|
||||
|| (o.getClass().getPackage() != null && o.getClass().getPackage().getName()
|
||||
.startsWith("java.lang.reflect"))) {
|
||||
size = 0;
|
||||
} else if (o instanceof Number || o instanceof Boolean || o instanceof Character) {
|
||||
size = NUMBER_SIZE;
|
||||
} else {
|
||||
// lets do a simple sizing
|
||||
Class<?> c = o.getClass();
|
||||
if (c.isArray()) {
|
||||
size = ARRAY_OVERHEAD;
|
||||
int length = Array.getLength(o);
|
||||
if (c.getComponentType().isPrimitive()) {
|
||||
size += length * getPrimitiveObjectSize(c.getComponentType());
|
||||
} else {
|
||||
size += length * REFERENCE;
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object element = Array.get(o, i);
|
||||
if (element != null) {
|
||||
stack.add(new ObjectInstance(element));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
size += OBJECT_OVERHEAD;
|
||||
while (c != null) {
|
||||
for (Field field : c.getDeclaredFields()) {
|
||||
if (Modifier.isStatic(field.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
if (field.getType().isPrimitive()) {
|
||||
size += getPrimitiveObjectSize(field.getType());
|
||||
} else {
|
||||
size += REFERENCE;
|
||||
boolean accessible = field.isAccessible();
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
Object fieldObject = field.get(o);
|
||||
if (fieldObject != null) {
|
||||
stack.push(new ObjectInstance(fieldObject));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// cannot get to field, so
|
||||
// ignore it in this size
|
||||
// calculation
|
||||
e.printStackTrace();
|
||||
}
|
||||
field.setAccessible(accessible);
|
||||
}
|
||||
}
|
||||
c = c.getSuperclass();
|
||||
}
|
||||
}
|
||||
size = roundUp(size);
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
log.warning("Unable to determine object size for " + o);
|
||||
}
|
||||
if (debug) {
|
||||
System.out.println(o.getClass().getCanonicalName() + "=" + size);
|
||||
}
|
||||
}
|
||||
totalSize += size;
|
||||
}
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
public static long roundUp(long size) {
|
||||
long extra = size % 8;
|
||||
if (extra > 0) {
|
||||
size = size + 8 - extra;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public static short getPrimitiveObjectSize(Class<?> primitiveType) {
|
||||
if (primitiveType.equals(int.class) || primitiveType.equals(float.class)) {
|
||||
return 4;
|
||||
} else if (primitiveType.equals(boolean.class) || primitiveType.equals(byte.class)) {
|
||||
return 1;
|
||||
} else if (primitiveType.equals(char.class) || primitiveType.equals(short.class)) {
|
||||
return 2;
|
||||
} else if (primitiveType.equals(long.class) || primitiveType.equals(double.class)) {
|
||||
return 8;
|
||||
} else { // if (primitiveType.equals(void.class)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,8 +4,9 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.commons.lang3.builder.CompareToBuilder;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import timely.model.parse.TagParser;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -21,7 +22,6 @@ public class Tag implements Comparable<Tag>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final Joiner equalJoiner = Joiner.on("=");
|
||||
private static final TagParser tagParser = new TagParser();
|
||||
|
||||
private String key;
|
||||
@@ -81,12 +81,12 @@ public class Tag implements Comparable<Tag>, Serializable {
|
||||
* @return
|
||||
*/
|
||||
public String join() {
|
||||
return equalJoiner.join(key, value);
|
||||
return tagParser.combine(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Tag{" + equalJoiner.join(this.getKey(), this.getValue()) + "}";
|
||||
return "Tag{" + join() + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,12 +100,12 @@ public class Tag implements Comparable<Tag>, Serializable {
|
||||
return true;
|
||||
if (null == o || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
return this.toString().equals(o.toString());
|
||||
Tag other = (Tag) o;
|
||||
return new EqualsBuilder().append(this.key, other.key).append(this.value, other.value).isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Tag other) {
|
||||
return this.toString().compareTo(other.toString());
|
||||
return new CompareToBuilder().append(this.key, other.key).append(this.value, other.value).toComparison();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package timely.model.parse;
|
||||
|
||||
public interface Combiner<T> {
|
||||
|
||||
String combine(T o);
|
||||
}
|
||||
@@ -4,12 +4,16 @@ import com.google.common.base.Splitter;
|
||||
import timely.model.Tag;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Parses tag1=val1,tag2=val2,tag3=val3 into a {@code List} of {@code Tag}
|
||||
* Combines {@code List} of {@code Tag} into {@code String} of
|
||||
* tag1=val1,tag2=val2,tag3=val3.
|
||||
*/
|
||||
public class TagListParser implements Parser<List<Tag>> {
|
||||
public class TagListParser implements Parser<List<Tag>>, Combiner<Collection<Tag>> {
|
||||
|
||||
private static final Splitter commaSplitter = Splitter.on(",").omitEmptyStrings();
|
||||
private static final TagParser tagParser = new TagParser();
|
||||
@@ -20,4 +24,30 @@ public class TagListParser implements Parser<List<Tag>> {
|
||||
commaSplitter.splitToList(t).forEach(p -> tags.add(tagParser.parse(p)));
|
||||
return tags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String combine(Collection<Tag> tags) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (!tags.isEmpty()) {
|
||||
tags.forEach(p -> builder.append(tagParser.combine(p)).append(','));
|
||||
builder.setLength(builder.length() - 1);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* An alternative combiner for a map of string to string instead of a list
|
||||
* of tags
|
||||
*
|
||||
* @param tags
|
||||
* @return string representation
|
||||
*/
|
||||
public String combine(Map<String, String> tags) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
if (!tags.isEmpty()) {
|
||||
tags.forEach((k, v) -> builder.append(tagParser.combine(new Tag(k, v))).append(','));
|
||||
builder.setLength(builder.length() - 1);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,19 @@
|
||||
package timely.model.parse;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import timely.model.Tag;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TagParser implements Parser<Tag> {
|
||||
/**
|
||||
* Parses tag1=val1 into a {@code Tag} Combines {@code Tag} into {@code String}
|
||||
* of tag1=val1
|
||||
*/
|
||||
public class TagParser implements Parser<Tag>, Combiner<Tag> {
|
||||
|
||||
private static final Splitter equalSplitter = Splitter.on("=").trimResults();
|
||||
private static final Joiner equalsJoiner = Joiner.on("=");
|
||||
|
||||
@Override
|
||||
public Tag parse(String t) {
|
||||
@@ -17,4 +23,10 @@ public class TagParser implements Parser<Tag> {
|
||||
}
|
||||
return new Tag(parts.get(0), parts.get(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String combine(Tag t) {
|
||||
return equalsJoiner.join(t.getKey(), t.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package timely.serialize;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
|
||||
|
||||
public class JsonSerializer {
|
||||
|
||||
private static ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
static {
|
||||
mapper.registerModule(new Jdk8Module());
|
||||
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true);
|
||||
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
|
||||
mapper.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
|
||||
}
|
||||
|
||||
public static ObjectMapper getObjectMapper() {
|
||||
return mapper;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='timely',
|
||||
version='${python.client.version}',
|
||||
packages=['timely'],
|
||||
install_requires=[
|
||||
'seaborn',
|
||||
'plotly'
|
||||
],
|
||||
license='Apache License, Version 2.0'
|
||||
)
|
||||
@@ -0,0 +1,328 @@
|
||||
import time
|
||||
from datetime import timedelta
|
||||
from datetime import datetime
|
||||
from TimeDateRange import UTC
|
||||
import pandas
|
||||
import matplotlib.dates as mdates
|
||||
import plotly.graph_objs as go
|
||||
import plotly.offline as py
|
||||
import seaborn
|
||||
import matplotlib.ticker as tkr
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
utc = UTC()
|
||||
|
||||
def pivot(df, metric, groupByColumn=None):
|
||||
|
||||
dataFrame = pandas.DataFrame(df, copy=True)
|
||||
if dataFrame is not None:
|
||||
if groupByColumn is not None:
|
||||
dataFrame["date"] = dataFrame.index.to_pydatetime()
|
||||
dataFrame = dataFrame.pivot_table(index="date", columns=groupByColumn, values=metric)
|
||||
return dataFrame
|
||||
|
||||
|
||||
def resample(df, sample, how='mean'):
|
||||
|
||||
dataFrame = pandas.DataFrame(df, copy=True)
|
||||
if dataFrame is not None:
|
||||
if sample is not None:
|
||||
dataFrame = dataFrame.resample(sample, how=how).interpolate()
|
||||
return dataFrame
|
||||
|
||||
|
||||
def unpivot(df, metric, groupByColumn=None):
|
||||
dataFrame = pandas.DataFrame(df, copy=True)
|
||||
if dataFrame is not None:
|
||||
dataFrame['date'] = dataFrame.index.values
|
||||
dataFrame = pandas.melt(dataFrame, id_vars=['date'], value_name=metric, var_name=groupByColumn)
|
||||
dataFrame = dataFrame.set_index('date')
|
||||
return dataFrame
|
||||
|
||||
|
||||
def rolling_average(df, metric, rolling_average=None):
|
||||
|
||||
dataFrame = pandas.DataFrame(df, copy=True)
|
||||
if dataFrame is not None:
|
||||
if rolling_average is not None:
|
||||
dataFrame[metric] = pandas.rolling_mean(dataFrame[metric], rolling_average)
|
||||
return dataFrame
|
||||
|
||||
|
||||
def graph(analyticConfig, df, timelyMetric, seriesConfig={}, graphConfig={}, notebook=False, type='png'):
|
||||
if type == 'png':
|
||||
return graphSeaborn(analyticConfig, df, timelyMetric, seriesConfig=seriesConfig, graphConfig=graphConfig, notebook=notebook)
|
||||
else:
|
||||
return graphPlotly(analyticConfig, df, timelyMetric, seriesConfig=seriesConfig, graphConfig=graphConfig, notebook=notebook)
|
||||
|
||||
|
||||
def graphSeaborn(analyticConfig, df, timelyMetric, seriesConfig={}, graphConfig={}, notebook=False):
|
||||
|
||||
dataFrame = pandas.DataFrame(df, copy=True)
|
||||
if dataFrame is not None:
|
||||
dataFrame = ensureMinSeriesLength(dataFrame, analyticConfig.groupByColumn)
|
||||
dataFrame['date'] = dataFrame.index.values
|
||||
dataFrame['dateFloat'] = dataFrame['date'].apply(lambda x: datetime2graphdays(x))
|
||||
dataFrame['index'] = dataFrame['dateFloat']
|
||||
groupByColumn = analyticConfig.groupByColumn
|
||||
|
||||
if groupByColumn is not None:
|
||||
# sort on date and the groupByColumn so that the series legend is sorted
|
||||
dataFrame = dataFrame.sort_values(['index', analyticConfig.groupByColumn])
|
||||
else:
|
||||
dataFrame = dataFrame.sort_values(['index'])
|
||||
|
||||
#dataFrame = dataFrame.set_index('index', drop=True)
|
||||
dataFrame = dataFrame.dropna()
|
||||
seaborn.set(style="darkgrid", palette="Set2")
|
||||
fig, ax = seaborn.plt.subplots()
|
||||
|
||||
colors = np.random.random((len(dataFrame), 3))
|
||||
i = 0
|
||||
for col in df[analyticConfig.groupByColumn].unique():
|
||||
tempDataFrame = dataFrame.loc[dataFrame[analyticConfig.groupByColumn] == col]
|
||||
addlColConfig = seriesConfig.get(col, seriesConfig.get('default', dict()))
|
||||
markerDict = addlColConfig.get("marker", dict())
|
||||
color = markerDict.get("color", "")
|
||||
if color == "red":
|
||||
seaborn.tsplot(tempDataFrame, time="dateFloat", unit=None, interpolate=False, color="red", marker="d",
|
||||
estimator=np.nanmean, condition=groupByColumn, value=timelyMetric.metric, ax=ax)
|
||||
else:
|
||||
seaborn.tsplot(tempDataFrame, time="dateFloat", unit=None, interpolate=True, color=colors[i],
|
||||
estimator=np.nanmean, condition=groupByColumn, value=timelyMetric.metric, ax=ax)
|
||||
i = i + 1
|
||||
|
||||
ax.xaxis_date()
|
||||
ax.xaxis.set_major_locator(mdates.AutoDateLocator())
|
||||
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y/%m/%d %H:%M:%S'))
|
||||
ax.set_xlim(xmin=dataFrame['dateFloat'].min(), xmax=dataFrame['dateFloat'].max())
|
||||
|
||||
formatter = tkr.ScalarFormatter(useMathText=False)
|
||||
formatter.set_scientific(False)
|
||||
ax.yaxis.set_major_formatter(formatter)
|
||||
|
||||
graphTitle = getTitle(timelyMetric, analyticConfig)
|
||||
seaborn.plt.title(graphTitle, fontsize='large')
|
||||
seaborn.plt.xlabel('date/time')
|
||||
seaborn.plt.ylabel(timelyMetric.metric)
|
||||
|
||||
legendTitle = "Legend"
|
||||
if groupByColumn is not None:
|
||||
legendTitle = groupByColumn
|
||||
|
||||
seaborn.plt.legend(loc='upper center', prop={'size':8}, ncol=10, title=legendTitle, bbox_to_anchor=(0.5,-0.4))
|
||||
fig.autofmt_xdate(rotation=45)
|
||||
|
||||
seaborn.plt.autoscale(tight=False)
|
||||
|
||||
if notebook == True:
|
||||
seaborn.plt.show()
|
||||
return None
|
||||
else:
|
||||
directory = analyticConfig.output_dir
|
||||
try:
|
||||
os.makedirs(directory, mode=0755)
|
||||
except OSError, e:
|
||||
# be happy if someone already created the path
|
||||
pass
|
||||
baseFilename = getFilename(timelyMetric.metric, analyticConfig)
|
||||
filename = directory+'/'+baseFilename
|
||||
fig.savefig(filename + '.png')
|
||||
return baseFilename + '.png'
|
||||
|
||||
|
||||
def graphPlotly(analyticConfig, df, timelyMetric, seriesConfig={}, graphConfig={}, notebook=False):
|
||||
|
||||
dataFrame = pandas.DataFrame(df, copy=True)
|
||||
if dataFrame is not None:
|
||||
dataFrame['colFromIndex'] = dataFrame.index
|
||||
if analyticConfig.groupByColumn is not None:
|
||||
# sort on date and the groupByColumn so that the series legend is sorted
|
||||
dataFrame = dataFrame.sort_values(['colFromIndex', analyticConfig.groupByColumn])
|
||||
else:
|
||||
dataFrame = dataFrame.sort_values(['colFromIndex'])
|
||||
|
||||
title = getTitle(timelyMetric, analyticConfig)
|
||||
|
||||
dataFrame['date'] = dataFrame.index.values
|
||||
|
||||
layoutConfig = dict(
|
||||
title=title,
|
||||
autosize=False,
|
||||
width=1000,
|
||||
height=700,
|
||||
showlegend=True,
|
||||
xaxis=dict(
|
||||
autorange=True,
|
||||
tickangle=-45
|
||||
),
|
||||
yaxis=dict(
|
||||
autorange=True,
|
||||
title=timelyMetric.metric
|
||||
)
|
||||
)
|
||||
|
||||
layoutConfig.update(graphConfig)
|
||||
|
||||
layout = go.Layout(layoutConfig)
|
||||
|
||||
data = None
|
||||
groupByValues = sorted(dataFrame[analyticConfig.groupByColumn].unique())
|
||||
for col in groupByValues:
|
||||
tempDataFrame = dataFrame.loc[dataFrame[analyticConfig.groupByColumn] == col]
|
||||
|
||||
addlColConfig = seriesConfig.get(col, seriesConfig.get('default', dict()))
|
||||
|
||||
config = dict(
|
||||
name=col,
|
||||
x=tempDataFrame.index,
|
||||
y=tempDataFrame[timelyMetric.metric],
|
||||
hoverinfo='x+y+text',
|
||||
text=col
|
||||
)
|
||||
|
||||
config.update(addlColConfig)
|
||||
|
||||
s = go.Scatter(config)
|
||||
|
||||
if data is None:
|
||||
data = [s]
|
||||
else:
|
||||
data.append(s)
|
||||
|
||||
directory = analyticConfig.output_dir
|
||||
try:
|
||||
os.makedirs(directory, mode=0755)
|
||||
except OSError, e:
|
||||
# be happy if someone already created the path
|
||||
pass
|
||||
baseFilename = getFilename(timelyMetric.metric, analyticConfig)
|
||||
filename = directory+'/'+baseFilename
|
||||
|
||||
fig = go.Figure(data=data, layout=layout)
|
||||
if notebook:
|
||||
py.iplot(fig, filename=filename, show_link=False)
|
||||
return None
|
||||
else:
|
||||
py.plot(fig, output_type='file', filename=filename+'.html', image_filename=filename, image=None, auto_open=False, show_link=False)
|
||||
return baseFilename+'.html'
|
||||
|
||||
def ensureMinSeriesLength(df, groupByColumn):
|
||||
|
||||
dataFrame = df
|
||||
if groupByColumn is not None:
|
||||
dataFrame = pandas.DataFrame(df, copy=True)
|
||||
dataFrame = dataFrame.dropna()
|
||||
|
||||
extra = pandas.DataFrame()
|
||||
for c, (cond, df_c) in enumerate(dataFrame.groupby(groupByColumn, sort=False)):
|
||||
if len(df_c) <= 1:
|
||||
extra = extra.append(df_c)
|
||||
|
||||
extra.index = extra.index + pandas.DateOffset(seconds=1)
|
||||
dataFrame = dataFrame.append(extra)
|
||||
|
||||
return dataFrame
|
||||
|
||||
def datetime2graphdays(dt):
|
||||
|
||||
return mdates.epoch2num((time.mktime(dt.timetuple()) / 86400) * mdates.SEC_PER_DAY)
|
||||
|
||||
def graphdays2datetime(x):
|
||||
epoch = mdates.num2epoch(x)
|
||||
return datetime.fromtimestamp(int(epoch), utc)
|
||||
|
||||
|
||||
def getFilename(metric, analyticConfig):
|
||||
|
||||
now = datetime.now(tz=utc)
|
||||
format = "%Y%m%d%H%M%S"
|
||||
nowStr = time.strftime(format, now.timetuple())
|
||||
fileNameBase = metric
|
||||
if analyticConfig.sample is not None:
|
||||
fileNameBase += "-" + analyticConfig.sample
|
||||
if analyticConfig.how is not None:
|
||||
fileNameBase += "-" + analyticConfig.how
|
||||
|
||||
return fileNameBase + '-' + nowStr
|
||||
|
||||
def getDirectoryPathForDate(format='%Y/%m/%d'):
|
||||
now = datetime.now(tz=utc)
|
||||
return time.strftime(format, now.timetuple())
|
||||
|
||||
def getTitle(timelyMetric, config, separator='\n'):
|
||||
if config.orCondition:
|
||||
condition = "OR"
|
||||
else:
|
||||
condition = "AND"
|
||||
|
||||
metricTitle = timelyMetric.metric
|
||||
if timelyMetric.tags is not None and len(timelyMetric.tags) > 0:
|
||||
metricTitle += ' (' + timelyMetric.tags + ')'
|
||||
|
||||
sampleTitle = ""
|
||||
alertTitle = ""
|
||||
if config.sample_period is not None:
|
||||
sampleTitle = config.sample_period + " " + config.how + " samples"
|
||||
|
||||
if config.rolling_average_period is not None:
|
||||
sampleTitle += ', ' + config.rolling_average_period + ' rolling average'
|
||||
|
||||
if config.min_threshold is not None:
|
||||
if alertTitle != "":
|
||||
alertTitle += " " + condition + " "
|
||||
alertTitle += "(y < " + str(config.min_threshold) + ")"
|
||||
|
||||
if config.average_min_threshold is not None:
|
||||
if alertTitle != "":
|
||||
alertTitle += " " + condition + " "
|
||||
alertTitle += "(y-avg < " + str(config.average_min_threshold) + ")"
|
||||
|
||||
if config.max_threshold is not None:
|
||||
if alertTitle != "":
|
||||
alertTitle += " " + condition + " "
|
||||
alertTitle += "(y > " + str(config.max_threshold) + ")"
|
||||
|
||||
if config.average_max_threshold is not None:
|
||||
if alertTitle != "":
|
||||
alertTitle += " " + condition + " "
|
||||
alertTitle += "(y-avg > " + str(config.average_max_threshold) + ")"
|
||||
|
||||
if config.min_threshold_percentage is not None:
|
||||
if alertTitle != "":
|
||||
alertTitle += " " + condition + " "
|
||||
if config.min_threshold_percentage >= 0:
|
||||
descriptivePercentage = 100 + config.min_threshold_percentage
|
||||
else:
|
||||
descriptivePercentage = abs(config.min_threshold_percentage)
|
||||
alertTitle += "(y < " + str(descriptivePercentage) + "% of " + str(
|
||||
config.rolling_average_period) + " sample average)"
|
||||
|
||||
if config.max_threshold_percentage is not None:
|
||||
if alertTitle != "":
|
||||
alertTitle += " " + condition + " "
|
||||
if config.max_threshold_percentage >= 0:
|
||||
descriptivePercentage = 100 + config.max_threshold_percentage
|
||||
else:
|
||||
descriptivePercentage = abs(config.max_threshold_percentage)
|
||||
alertTitle += "(y > " + str(descriptivePercentage) + "% of " + str(
|
||||
config.rolling_average_period) + " sample average)"
|
||||
|
||||
if config.system_name is None:
|
||||
title = metricTitle
|
||||
else:
|
||||
title = config.system_name + ' - ' + metricTitle
|
||||
|
||||
if sampleTitle != "":
|
||||
title += separator + sampleTitle
|
||||
|
||||
if alertTitle != "":
|
||||
if config.min_alert_period is not None:
|
||||
alertTitle = '(' + alertTitle + ') for at least ' + config.min_alert_period
|
||||
if config.last_alert is not None:
|
||||
alertTitle = alertTitle + ' in last ' + config.last_alert
|
||||
title += separator + alertTitle
|
||||
|
||||
|
||||
return title
|
||||
@@ -0,0 +1,128 @@
|
||||
import time
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from datetime import tzinfo
|
||||
from pandas.tslib import Timedelta
|
||||
import pandas
|
||||
|
||||
class TimeDateError(ValueError):
|
||||
|
||||
def __init__(self, message, *args):
|
||||
self.message = message
|
||||
super(TimeDateError, self).__init__(message, *args)
|
||||
|
||||
|
||||
ZERO = timedelta(0)
|
||||
|
||||
# A UTC class.
|
||||
class UTC(tzinfo):
|
||||
"""UTC"""
|
||||
|
||||
def __str__(self):
|
||||
return "UTC"
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return ZERO
|
||||
|
||||
def tzname(self, dt):
|
||||
return "UTC"
|
||||
|
||||
def dst(self, dt):
|
||||
return ZERO
|
||||
|
||||
utc = UTC()
|
||||
|
||||
class TimeDateRange:
|
||||
|
||||
beginDt = None
|
||||
endDt = None
|
||||
format = "%Y%m%d %H%M%S"
|
||||
|
||||
def getBeginMs(self):
|
||||
if self.beginDt == None:
|
||||
return None
|
||||
return int(time.mktime(self.beginDt.timetuple()) * 1000)
|
||||
|
||||
def getBeginStr(self):
|
||||
if self.beginDt == None:
|
||||
return None
|
||||
return time.strftime(self.format, self.beginDt.timetuple())
|
||||
|
||||
def getEndMs(self):
|
||||
if self.endDt == None:
|
||||
return None
|
||||
return int(time.mktime(self.endDt.timetuple()) * 1000)
|
||||
|
||||
def getEndStr(self):
|
||||
if self.endDt == None:
|
||||
return None
|
||||
return time.strftime(self.format, self.endDt.timetuple())
|
||||
|
||||
def __init__(self, beginStr, endStr, period, format="%Y%m%d-%H%M%S"):
|
||||
|
||||
now = datetime.now(tz=utc)
|
||||
nowMs = TimeDateRange.unix_time_millis(now)
|
||||
|
||||
if beginStr != None and endStr != None and period != None:
|
||||
raise TimeDateError("You can not provide a begin, end, and period")
|
||||
elif (beginStr == None and endStr == None and period == None) or (period == None and beginStr == None):
|
||||
raise TimeDateError("You must provide a time range")
|
||||
|
||||
if period == None:
|
||||
# calculate begin time
|
||||
beginTuple = time.strptime(beginStr, self.format)
|
||||
self.beginDt = datetime(*beginTuple[0:6], tzinfo=utc)
|
||||
|
||||
# calculate end time
|
||||
# end is either specified or now
|
||||
if endStr == None or endStr == 'now':
|
||||
self.endDt = now
|
||||
else:
|
||||
|
||||
self.endDt = datetime(*time.strptime(endStr, self.format)[0:6], tzinfo=utc)
|
||||
if self.endDt > now:
|
||||
self.endDt = now
|
||||
else:
|
||||
# period must be specified
|
||||
td = pandas.to_timedelta(period)
|
||||
rangeInSec = td.total_seconds()
|
||||
|
||||
if beginStr == None:
|
||||
# calculate begin time from end tme and period
|
||||
|
||||
# calculate end time
|
||||
# end is either specified or now
|
||||
if endStr == None or endStr == 'now':
|
||||
self.endDt = now
|
||||
else:
|
||||
self.endDt = datetime(*time.strptime(endStr, self.format)[0:6], tzinfo=utc)
|
||||
if self.endDt > now:
|
||||
self.endDt = now
|
||||
|
||||
# calculate begin time
|
||||
self.beginDt = self.endDt - timedelta(milliseconds=rangeInSec * 1000)
|
||||
|
||||
else:
|
||||
# calculate end time from begin tme and period
|
||||
# calculate begin time
|
||||
self.beginDt = datetime(*time.strptime(beginStr, self.format)[0:6], tzinfo=utc)
|
||||
|
||||
# calculate end time
|
||||
self.endDt = self.beginDt + timedelta(milliseconds=rangeInSec * 1000)
|
||||
|
||||
if self.endDt > now:
|
||||
self.endDt = now
|
||||
|
||||
if self.beginDt > now:
|
||||
raise TimeDateError("begin date/time can not be in the future")
|
||||
|
||||
if self.beginDt > self.endDt:
|
||||
raise TimeDateError("begin date/time can not be past end date/time")
|
||||
|
||||
epoch = datetime.utcfromtimestamp(0).replace(tzinfo=utc)
|
||||
|
||||
@classmethod
|
||||
def unix_time_millis(cls, dt):
|
||||
return (dt - TimeDateRange.epoch).total_seconds() * 1000.0
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import smtplib
|
||||
from os.path import basename
|
||||
from email.mime.application import MIMEApplication
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.utils import COMMASPACE, formatdate
|
||||
import TimelyMetric
|
||||
import syslog
|
||||
import DataOperations
|
||||
|
||||
syslog.openlog("TimelyNotifications")
|
||||
|
||||
|
||||
class TimelyAlert():
|
||||
|
||||
def __init__(self, timelyMetric, dataFrame, message, seriesConfig, analyticConfig, notebook):
|
||||
self.timelyMetric = timelyMetric
|
||||
self.dataFrame = dataFrame
|
||||
self.seriesConfig = seriesConfig
|
||||
self.analyticConfig = analyticConfig
|
||||
self.notebook = notebook
|
||||
self.message = message
|
||||
|
||||
def email(self, send_from, send_to, subject, text, files=None, server="127.0.0.1"):
|
||||
assert isinstance(send_to, list)
|
||||
|
||||
msg = MIMEMultipart()
|
||||
msg['From'] = send_from
|
||||
msg['To'] = COMMASPACE.join(send_to)
|
||||
msg['Date'] = formatdate(localtime=True)
|
||||
msg['Subject'] = subject
|
||||
|
||||
msg.attach(MIMEText(text))
|
||||
|
||||
for f in files or []:
|
||||
with open(f, "rb") as fil:
|
||||
part = MIMEApplication(
|
||||
fil.read(),
|
||||
Name=basename(f)
|
||||
)
|
||||
part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
|
||||
msg.attach(part)
|
||||
|
||||
|
||||
smtp = smtplib.SMTP(server)
|
||||
smtp.sendmail(send_from, send_to, msg.as_string())
|
||||
smtp.close()
|
||||
|
||||
def log(self, message):
|
||||
|
||||
syslog.systlog(syslog.LOG_ALERT, message)
|
||||
|
||||
def graph(self, type="png"):
|
||||
|
||||
graphConfig = {}
|
||||
graphConfig["title"] = DataOperations.getTitle(self.timelyMetric, self.analyticConfig)
|
||||
return TimelyMetric.graph(self.analyticConfig, self.dataFrame, self.timelyMetric, seriesConfig=self.seriesConfig, graphConfig=graphConfig, notebook=self.notebook, type=type)
|
||||
|
||||
def getDataFrame(self):
|
||||
return self.dataFrame
|
||||
|
||||
def getAnalyticConfig(self):
|
||||
return self.analyticConfig
|
||||
|
||||
def getSeriesConfig(self):
|
||||
return self.seriesConfig
|
||||
|
||||
def getTimelyMetric(self):
|
||||
return self.timelyMetric
|
||||
|
||||
def getMessage(self):
|
||||
return self.message
|
||||
@@ -0,0 +1,224 @@
|
||||
import TimelyMetric
|
||||
from TimeDateRange import TimeDateRange
|
||||
from TimeDateRange import UTC
|
||||
from TimelyAnalyticConfiguration import TimelyAnalyticConfiguration
|
||||
import DataOperations
|
||||
import pandas
|
||||
import re
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
|
||||
from TimelyAlert import TimelyAlert
|
||||
import numpy as np
|
||||
|
||||
utc = UTC()
|
||||
|
||||
def logTiming(timelyMetric, startTime, stopTime):
|
||||
df = timelyMetric.getDataFrame()
|
||||
print("start: " + str(startTime))
|
||||
print("stop: " + str(stopTime))
|
||||
print("num records: " + str(len(df)))
|
||||
elapsedSec = (TimeDateRange.unix_time_millis(stopTime) - TimeDateRange.unix_time_millis(startTime)) / 1000
|
||||
print("elapsed seconds: " + str(elapsedSec))
|
||||
recPerSec = len(df) / elapsedSec
|
||||
print("records per second: " + recPerSec)
|
||||
|
||||
def addCondition(orCondition, currResult, condition):
|
||||
if orCondition:
|
||||
currResult = currResult | condition
|
||||
else:
|
||||
currResult = currResult & condition
|
||||
return currResult
|
||||
|
||||
def keepConsecutiveAlerts(dataFrame, exceptions, minimumSpan):
|
||||
|
||||
if exceptions.size > 0 and minimumSpan is not None:
|
||||
|
||||
currentFirst = None
|
||||
currentLast = None
|
||||
result_span_values = pandas.DataFrame()
|
||||
result_span_values['bool'] = np.zeros(exceptions.shape, bool)
|
||||
result_span_values = result_span_values.set_index(exceptions.index)
|
||||
current_result_span_values = pandas.DataFrame()
|
||||
current_result_span_values['bool'] = np.zeros(exceptions.shape, bool)
|
||||
current_result_span_values = current_result_span_values.set_index(exceptions.index)
|
||||
|
||||
for index, row in dataFrame.iterrows():
|
||||
if index in exceptions.index:
|
||||
current_result_span_values.loc[index]['bool'] = True
|
||||
currentLast = index
|
||||
if currentFirst is None:
|
||||
currentFirst = index
|
||||
if int((currentLast - currentFirst).total_seconds() / 60) >= int(minimumSpan):
|
||||
result_span_values['bool'] = result_span_values['bool'] | current_result_span_values['bool']
|
||||
else:
|
||||
current_result_span_values['bool'] = np.zeros(exceptions.shape, bool)
|
||||
currentFirst = None
|
||||
currentLast = None
|
||||
|
||||
return exceptions.loc[result_span_values['bool']]
|
||||
else:
|
||||
return exceptions
|
||||
|
||||
def convertCounterToRate(timelyMetric, analyticConfig):
|
||||
# Adjust counter metric into a rate metric
|
||||
df = timelyMetric.getDataFrame()
|
||||
columnNames = df[analyticConfig.groupByColumn].unique()
|
||||
df = DataOperations.pivot(df, timelyMetric.metric, analyticConfig.groupByColumn)
|
||||
df = DataOperations.resample(df, analyticConfig.sample, how=analyticConfig.how)
|
||||
for c in columnNames:
|
||||
df[c] = df[c].diff(1) / (analyticConfig.sample_minutes * 60 * 1000)
|
||||
df = DataOperations.unpivot(df, timelyMetric.metric, analyticConfig.groupByColumn)
|
||||
df = df.dropna()
|
||||
timelyMetric.setDataFrame(df)
|
||||
|
||||
def find_alerts(timelyMetric, analyticConfig, notebook=False):
|
||||
|
||||
if (analyticConfig.counter == True):
|
||||
convertCounterToRate(timelyMetric, analyticConfig)
|
||||
|
||||
df = timelyMetric.getDataFrame()
|
||||
|
||||
graphDF = TimelyMetric.pivot(df, timelyMetric.metric, groupByColumn=analyticConfig.groupByColumn)
|
||||
|
||||
if analyticConfig.excludeColRegex is not None:
|
||||
graphDF = graphDF.select(lambda x : not (re.search(analyticConfig.excludeColRegex, x)), axis=1)
|
||||
if analyticConfig.includeColRegex is not None:
|
||||
graphDF = graphDF.select(lambda x : re.search(analyticConfig.includeColRegex, x), axis=1)
|
||||
|
||||
if analyticConfig.sample is not None:
|
||||
graphDF = TimelyMetric.resample(graphDF, analyticConfig.sample, how=analyticConfig.how)
|
||||
|
||||
graphDF_avg = pandas.DataFrame(graphDF, copy=True)
|
||||
|
||||
combined = pandas.DataFrame()
|
||||
|
||||
seriesConfig = {}
|
||||
for i in graphDF_avg.columns:
|
||||
col = str(i)
|
||||
|
||||
any_conditions_values = False
|
||||
result_values = np.ones(graphDF[col].shape, bool)
|
||||
if analyticConfig.orCondition:
|
||||
result_values = np.zeros(graphDF[col].shape, bool)
|
||||
|
||||
any_conditions_average = False
|
||||
result_average = np.ones(graphDF_avg[col].shape, bool)
|
||||
if analyticConfig.orCondition:
|
||||
result_average = np.zeros(graphDF_avg[col].shape, bool)
|
||||
|
||||
if analyticConfig.min_threshold is not None:
|
||||
currCondition = graphDF[col].astype(float) < analyticConfig.min_threshold
|
||||
result_values = addCondition(analyticConfig.orCondition, result_values, currCondition)
|
||||
any_conditions_values = True
|
||||
|
||||
if analyticConfig.max_threshold is not None:
|
||||
currCondition = graphDF[col].astype(float) > analyticConfig.max_threshold
|
||||
result_values = addCondition(analyticConfig.orCondition, result_values, currCondition)
|
||||
any_conditions_values = True
|
||||
|
||||
if analyticConfig.rolling_average_samples is not None:
|
||||
graphDF_avg = TimelyMetric.rolling_average(graphDF_avg, col, rolling_average=analyticConfig.rolling_average_samples)
|
||||
if analyticConfig.min_threshold_percentage is not None:
|
||||
if analyticConfig.min_threshold_percentage >= 0:
|
||||
multiple = 1.0 + (float(abs(analyticConfig.min_threshold_percentage)) / float(100))
|
||||
else:
|
||||
multiple = 1.0 - (float(abs(analyticConfig.min_threshold_percentage)) / float(100))
|
||||
currCondition = graphDF[col].astype(float) < (graphDF_avg[col].astype(float) * multiple)
|
||||
result_values = addCondition(analyticConfig.orCondition, result_values, currCondition)
|
||||
any_conditions_values = True
|
||||
|
||||
if analyticConfig.max_threshold_percentage is not None:
|
||||
if analyticConfig.max_threshold_percentage >= 0:
|
||||
multiple = 1.0 + (float(abs(analyticConfig.max_threshold_percentage)) / float(100))
|
||||
else:
|
||||
multiple = 1.0 - (float(abs(analyticConfig.max_threshold_percentage)) / float(100))
|
||||
currCondition = graphDF[col].astype(float) > (graphDF_avg[col].astype(float) * multiple)
|
||||
result_values = addCondition(analyticConfig.orCondition, result_values, currCondition)
|
||||
any_conditions_values = True
|
||||
|
||||
if analyticConfig.average_min_threshold is not None:
|
||||
currCondition = graphDF_avg[col].astype(float) < analyticConfig.average_min_threshold
|
||||
result_average = addCondition(analyticConfig.orCondition, result_average, currCondition)
|
||||
any_conditions_average = True
|
||||
if analyticConfig.average_max_threshold is not None:
|
||||
currCondition = graphDF_avg[col].astype(float) > analyticConfig.average_max_threshold
|
||||
result_average = addCondition(analyticConfig.orCondition, result_average, currCondition)
|
||||
any_conditions_average = True
|
||||
|
||||
# if orCondition is AND and no exceptional conditions have been found, then result_values will be all True
|
||||
if any_conditions_values == False:
|
||||
result_values = np.zeros(graphDF[col].shape, bool)
|
||||
exceptional_values = graphDF.loc[result_values, col]
|
||||
|
||||
# if orCondition is AND and no exceptional conditions have been found, then result_average will be all True
|
||||
if any_conditions_average == False:
|
||||
result_average = np.zeros(graphDF_avg[col].shape, bool)
|
||||
exceptional_average = graphDF_avg.loc[result_average, col]
|
||||
|
||||
# only keep alerts that are in consecutive periods of length analyticConfig.min_alert_minutes
|
||||
exceptional_values = keepConsecutiveAlerts(graphDF, exceptional_values, analyticConfig.min_alert_minutes)
|
||||
exceptional_average = keepConsecutiveAlerts(graphDF_avg, exceptional_average, analyticConfig.min_alert_minutes)
|
||||
|
||||
# only evaluate the last analyticConfig.last_alert_minutes if set
|
||||
if analyticConfig.last_alert_minutes is not None:
|
||||
end = datetime.fromtimestamp(timelyMetric.timeDateRange.getEndMs() / 1000.00, DataOperations.utc)
|
||||
recentEnoughBegin = end - timedelta(minutes=analyticConfig.last_alert_minutes)
|
||||
exceptional_values = exceptional_values.ix[recentEnoughBegin:end]
|
||||
exceptional_average = exceptional_average.ix[recentEnoughBegin:end]
|
||||
|
||||
anyValueExceptions = exceptional_values.size > 0
|
||||
anyAverageExceptions = exceptional_average.size > 0
|
||||
|
||||
if (analyticConfig.display.lower() == "all") or (analyticConfig.display.lower() == "alerts" and anyValueExceptions):
|
||||
combined[col] = graphDF[col]
|
||||
|
||||
if analyticConfig.rolling_average_samples is not None:
|
||||
if (analyticConfig.display.lower() == "all"):
|
||||
combined[col + '_avg'] = graphDF_avg[col]
|
||||
else:
|
||||
if (anyAverageExceptions):
|
||||
combined[col + '_avg'] = graphDF_avg[col]
|
||||
if (anyValueExceptions and (analyticConfig.min_threshold_percentage is not None or analyticConfig.max_threshold_percentage is not None)):
|
||||
combined[col + '_avg'] = graphDF_avg[col]
|
||||
|
||||
if ((analyticConfig.display.lower() == "all") or (analyticConfig.display.lower() == "alerts" and anyValueExceptions)):
|
||||
combined[col + '_warn'] = exceptional_values.dropna()
|
||||
|
||||
seriesConfig[col + '_warn'] = {
|
||||
"mode" : "markers",
|
||||
"marker" : {
|
||||
"symbol" : "hash-open",
|
||||
"color" : "red"
|
||||
}
|
||||
}
|
||||
|
||||
if ((analyticConfig.display.lower() == "all") or (analyticConfig.display.lower() == "alerts" and anyAverageExceptions)):
|
||||
combined[col + '_avg_warn'] = exceptional_average.dropna()
|
||||
|
||||
seriesConfig[col + '_avg_warn'] = {
|
||||
"mode" : "markers",
|
||||
"marker" : {
|
||||
"symbol" : "hash-open",
|
||||
"color" : "red"
|
||||
}
|
||||
}
|
||||
|
||||
timelyAlert = None
|
||||
if not combined.empty:
|
||||
alertAnalyticConfig = TimelyAnalyticConfiguration(analyticConfig)
|
||||
if alertAnalyticConfig.groupByColumn is None:
|
||||
alertAnalyticConfig.groupByColumn = timelyMetric.metric + "_obs"
|
||||
combined = TimelyMetric.unpivot(combined, timelyMetric.metric, groupByColumn=alertAnalyticConfig.groupByColumn)
|
||||
combined = combined.sort_index()
|
||||
combined['date'] = combined.index.values
|
||||
combined = combined.sort_values(['date', alertAnalyticConfig.groupByColumn])
|
||||
combined = combined.drop(['date'], 1)
|
||||
combined = combined.dropna()
|
||||
combined = DataOperations.ensureMinSeriesLength(combined, alertAnalyticConfig.groupByColumn)
|
||||
|
||||
message = DataOperations.getTitle(timelyMetric, analyticConfig, separator=', ')
|
||||
|
||||
timelyAlert = TimelyAlert(timelyMetric, combined, message, seriesConfig, alertAnalyticConfig, notebook)
|
||||
|
||||
return timelyAlert
|
||||
@@ -0,0 +1,84 @@
|
||||
import pandas
|
||||
|
||||
|
||||
class TimelyAnalyticConfiguration():
|
||||
|
||||
|
||||
def __init__(self, analyticConfig):
|
||||
|
||||
if isinstance(analyticConfig, dict):
|
||||
self.groupByColumn = analyticConfig.get('groupByColumn', None)
|
||||
self.includeColRegex = analyticConfig.get('includeColRegex', None)
|
||||
self.excludeColRegex = analyticConfig.get('excludeColRegex', None)
|
||||
self.counter = analyticConfig.get('counter', False)
|
||||
self.sample_period = analyticConfig.get('sample', None)
|
||||
self.how = analyticConfig.get('how', 'mean')
|
||||
self.rolling_average_period = analyticConfig.get('rolling_average_period', None)
|
||||
self.min_threshold = analyticConfig.get('min_threshold', None)
|
||||
self.average_min_threshold = analyticConfig.get('average_min_threshold', None)
|
||||
self.max_threshold = analyticConfig.get('max_threshold', None)
|
||||
self.average_max_threshold = analyticConfig.get('average_max_threshold', None)
|
||||
self.min_threshold_percentage = analyticConfig.get('min_threshold_percentage', None)
|
||||
self.max_threshold_percentage = analyticConfig.get('max_threshold_percentage', None)
|
||||
self.min_alert_period = analyticConfig.get('min_alert_period', None)
|
||||
boolean = analyticConfig.get('boolean', 'or')
|
||||
self.orCondition = boolean == 'or' or boolean == 'OR'
|
||||
# alerts or all
|
||||
self.display = analyticConfig.get('display', 'alerts')
|
||||
self.send_alerts_to = analyticConfig.get('send_alerts_to', [])
|
||||
self.output_dir = analyticConfig.get('output_dir', '/tmp')
|
||||
self.last_alert = analyticConfig.get('last_alert', None)
|
||||
self.system_name = analyticConfig.get('system_name', None)
|
||||
|
||||
self.sample = None
|
||||
self.sample_minutes = None
|
||||
if self.sample_period is not None:
|
||||
td = pandas.to_timedelta(self.sample_period)
|
||||
self.sample_minutes = int(td.total_seconds() / 60)
|
||||
self.sample = str(self.sample_minutes) + 'min'
|
||||
|
||||
self.rolling_average_samples = None
|
||||
self.rolling_average_minutes = None
|
||||
if (self.rolling_average_period is not None) and (self.sample_minutes is not None):
|
||||
td = pandas.to_timedelta(self.rolling_average_period)
|
||||
self.rolling_average_minutes = int(td.total_seconds() / 60)
|
||||
self.rolling_average_samples = int(self.rolling_average_minutes / self.sample_minutes)
|
||||
|
||||
self.min_alert_minutes = None
|
||||
if self.min_alert_period is not None:
|
||||
td = pandas.to_timedelta(self.min_alert_period)
|
||||
self.min_alert_minutes = int(td.total_seconds() / 60)
|
||||
|
||||
self.last_alert_minutes = None
|
||||
if self.last_alert is not None:
|
||||
td = pandas.to_timedelta(self.last_alert)
|
||||
self.last_alert_minutes = int(td.total_seconds() / 60)
|
||||
|
||||
elif isinstance(analyticConfig, TimelyAnalyticConfiguration):
|
||||
self.groupByColumn = analyticConfig.groupByColumn
|
||||
self.includeColRegex = analyticConfig.includeColRegex
|
||||
self.excludeColRegex = analyticConfig.excludeColRegex
|
||||
self.counter = analyticConfig.counter
|
||||
self.sample_period = analyticConfig.sample_period
|
||||
self.sample_minutes = analyticConfig.sample_minutes
|
||||
self.sample = analyticConfig.sample
|
||||
self.how = analyticConfig.how
|
||||
self.rolling_average_period = analyticConfig.rolling_average_period
|
||||
self.rolling_average_samples = analyticConfig.rolling_average_samples
|
||||
self.rolling_average_minutes = analyticConfig.rolling_average_minutes
|
||||
self.min_threshold = analyticConfig.min_threshold
|
||||
self.average_min_threshold = analyticConfig.average_min_threshold
|
||||
self.max_threshold = analyticConfig.max_threshold
|
||||
self.average_max_threshold = analyticConfig.average_max_threshold
|
||||
self.min_threshold_percentage = analyticConfig.min_threshold_percentage
|
||||
self.max_threshold_percentage = analyticConfig.max_threshold_percentage
|
||||
self.min_alert_period = analyticConfig.min_alert_period
|
||||
self.min_alert_minutes = analyticConfig.min_alert_minutes
|
||||
self.orCondition = analyticConfig.orCondition
|
||||
# alerts or all
|
||||
self.display = analyticConfig.display
|
||||
self.send_alerts_to = analyticConfig.send_alerts_to
|
||||
self.output_dir = analyticConfig.output_dir
|
||||
self.last_alert = analyticConfig.last_alert
|
||||
self.last_alert_minutes = analyticConfig.last_alert_minutes
|
||||
self.system_name = analyticConfig.system_name
|
||||
@@ -0,0 +1,216 @@
|
||||
from TimeDateRange import TimeDateRange
|
||||
from TimeDateRange import TimeDateError
|
||||
from TimeDateRange import UTC
|
||||
from DataOperations import *
|
||||
import json
|
||||
import pandas
|
||||
import getopt
|
||||
import sys
|
||||
import random
|
||||
|
||||
from WebSocketClient import WebSocketClient
|
||||
from tornado import ioloop
|
||||
|
||||
utc = UTC()
|
||||
|
||||
class TimelyWebSocketClient(WebSocketClient):
|
||||
|
||||
def __init__(self, hostport, metric, tags, startTime, endTime, connect_timeout=WebSocketClient.DEFAULT_CONNECT_TIMEOUT,
|
||||
request_timeout=WebSocketClient.DEFAULT_REQUEST_TIMEOUT):
|
||||
|
||||
self.metric = metric
|
||||
self.tags = tags
|
||||
self.startTime = startTime
|
||||
self.endTime = endTime
|
||||
self.subscriptionId = random.randint(1000000000, 9999999999)
|
||||
WebSocketClient.__init__(self, hostport, connect_timeout, request_timeout)
|
||||
|
||||
def _on_message(self, msg):
|
||||
# implement in subclass
|
||||
pass
|
||||
|
||||
def _on_connection_success(self):
|
||||
print('Connected.')
|
||||
|
||||
create = {
|
||||
"operation": "create",
|
||||
"subscriptionId": self.subscriptionId,
|
||||
}
|
||||
self.send(create)
|
||||
self.send(create)
|
||||
|
||||
m1 = {
|
||||
"operation": "add",
|
||||
"subscriptionId": self.subscriptionId,
|
||||
"metric": self.metric,
|
||||
"startTime": self.startTime,
|
||||
"endTime" : self.endTime
|
||||
}
|
||||
|
||||
if self.tags is not None:
|
||||
t = self.tags.strip().split(',')
|
||||
tagDict = {}
|
||||
for pair in t:
|
||||
k = pair.split('=')[0].strip()
|
||||
v = pair.split('=')[1].strip()
|
||||
tagDict = dict(tagDict.items() + dict({k : v}).items())
|
||||
m1["tags"] = tagDict
|
||||
|
||||
self.send(m1)
|
||||
|
||||
def _on_connection_close(self):
|
||||
print('Connection closed!')
|
||||
exit()
|
||||
|
||||
def _on_connection_error(self, exception):
|
||||
print('Connection error: %s', exception)
|
||||
|
||||
|
||||
|
||||
|
||||
class TimelyMetric(TimelyWebSocketClient):
|
||||
|
||||
client = None
|
||||
endtime = None
|
||||
|
||||
def __init__(self, hostport, metric, tags, beginStr, endStr, period, sample):
|
||||
self.series = pandas.Series()
|
||||
self.metric = metric
|
||||
self.tags = tags
|
||||
self.sample = sample
|
||||
self.debug = False
|
||||
self.dataFrame = None
|
||||
self.data = []
|
||||
self.timeDateRange = TimeDateRange(beginStr, endStr, period)
|
||||
|
||||
TimelyWebSocketClient.__init__(self, hostport, metric, tags, self.timeDateRange.getBeginMs(), self.timeDateRange.getEndMs())
|
||||
|
||||
def debugOn(self):
|
||||
self.debug = True
|
||||
|
||||
def debugOff(self):
|
||||
self.debug = False
|
||||
|
||||
def fetch(self):
|
||||
|
||||
ioloop.IOLoop().make_current()
|
||||
self.connect(ioloop.IOLoop.current(instance=False))
|
||||
ioloop.IOLoop.current(instance=False).start()
|
||||
return self
|
||||
|
||||
|
||||
def _on_message(self, msg):
|
||||
|
||||
global df
|
||||
global endtime
|
||||
|
||||
responsesObj = json.loads(msg)
|
||||
responses = responsesObj.get("responses")
|
||||
|
||||
for obj in responses:
|
||||
complete = bool(obj.get("complete"))
|
||||
if complete:
|
||||
self._on_connection_close()
|
||||
return
|
||||
else:
|
||||
date = int(obj.get("timestamp")/1000)
|
||||
dt = pandas.datetime.utcfromtimestamp(date)
|
||||
metricName = str(obj.get("metric"))
|
||||
metricValue = obj.get("value")
|
||||
|
||||
newData = {}
|
||||
newData["date"] = dt
|
||||
newData[metricName] = metricValue
|
||||
|
||||
tags = obj.get("tags")
|
||||
for d in tags:
|
||||
for k,v in d.items():
|
||||
newData[k] = v
|
||||
|
||||
self.data.append(newData)
|
||||
|
||||
|
||||
def _on_connection_close(self):
|
||||
global client
|
||||
|
||||
self.dataFrame = pandas.DataFrame(self.data)
|
||||
if len(self.dataFrame) > 0:
|
||||
self.dataFrame['date'] = pandas.DatetimeIndex(self.dataFrame['date'])
|
||||
self.dataFrame = self.dataFrame.set_index('date')
|
||||
|
||||
self.close()
|
||||
ioloop.IOLoop.current(instance=False).stop()
|
||||
print("Exiting.")
|
||||
|
||||
def getDataFrame(self):
|
||||
|
||||
return self.dataFrame;
|
||||
|
||||
def setDataFrame(self, dataFrame):
|
||||
|
||||
self.dataFrame = dataFrame
|
||||
|
||||
def print_debug(self):
|
||||
if self.debug:
|
||||
print(self.dataFrame)
|
||||
|
||||
def graph(self, groupByColumn=None):
|
||||
return graph(self.dataFrame, self, sample=self.sample, how=self.how, groupByColumn=groupByColumn)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
period = None
|
||||
beginStr = None
|
||||
endStr = None
|
||||
|
||||
metric = "timely.metrics.received"
|
||||
sample = None
|
||||
how = None
|
||||
tags = None
|
||||
groupByColumn = None
|
||||
try:
|
||||
argv = sys.argv
|
||||
options, remainder = getopt.getopt(argv[1:], 'h', ['metric=', 'tags=', 'period=', 'groupByColumn=', 'begin=', 'end=', 'sample=', 'how=', 'hostport='])
|
||||
except getopt.GetoptError:
|
||||
print('TimelyMetric.py ---hostport=<host:port> --metric=<metric> --tags=<tag1=val1,tag2=val2> --period=<period>, --groupByColumn=<groupByColumn>, --sample=<sample_period> --how=<mean|min|max>')
|
||||
sys.exit(2)
|
||||
for opt, arg in options:
|
||||
if opt == '-h':
|
||||
print('TimelyMetric.py --hostport=<host:port> --metric=<metric> --tags=<tag1=val1,tag2=val2> --period=<period>, --groupByColumn=<groupByColumn>, --sample=<sample_period> --how=<mean|min|max>')
|
||||
sys.exit()
|
||||
elif opt in ("--metric"):
|
||||
metric = arg
|
||||
elif opt in ("--period"):
|
||||
period = arg
|
||||
elif opt in ("--begin"):
|
||||
beginStr = arg
|
||||
elif opt in ("--end"):
|
||||
endStr = arg
|
||||
elif opt in ("--groupByColumn"):
|
||||
groupByColumn = arg
|
||||
elif opt in ("--sample"):
|
||||
sample = arg
|
||||
elif opt in ("--how"):
|
||||
how = arg
|
||||
elif opt in ("--hostport"):
|
||||
hostport = arg
|
||||
try:
|
||||
|
||||
timelyMetric = TimelyMetric(hostport, metric, tags, beginStr, endStr, period, sample).fetch()
|
||||
dataFrame = timelyMetric.getDataFrame()
|
||||
|
||||
if dataFrame is not None:
|
||||
dataFrame = resample(dataFrame, metric, sample, how)
|
||||
dataFrame = pivot(dataFrame, metric, groupByColumn=groupByColumn)
|
||||
graph(dataFrame, timelyMetric, sample=sample, groupByColumn=groupByColumn, graphConfig={}, notebook=False)
|
||||
|
||||
except TimeDateError as e:
|
||||
print(e.message)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
from tornado import escape
|
||||
from tornado import gen
|
||||
from tornado import ioloop
|
||||
from tornado import websocket
|
||||
|
||||
import json
|
||||
|
||||
|
||||
class WebSocketClient():
|
||||
"""Base for web socket clients.
|
||||
"""
|
||||
|
||||
DEFAULT_CONNECT_TIMEOUT = 60
|
||||
DEFAULT_REQUEST_TIMEOUT = 60
|
||||
APPLICATION_JSON = 'application/json'
|
||||
|
||||
def __init__(self, hostport, connect_timeout=DEFAULT_CONNECT_TIMEOUT,
|
||||
request_timeout=DEFAULT_REQUEST_TIMEOUT):
|
||||
|
||||
self.connect_timeout = connect_timeout
|
||||
self.request_timeout = request_timeout
|
||||
self.url = 'wss://' + hostport + '/websocket'
|
||||
|
||||
def connect(self, ioloop=ioloop.IOLoop.current(instance=False)):
|
||||
"""Connect to the server.
|
||||
:param str url: server URL.
|
||||
"""
|
||||
request = websocket.httpclient.HTTPRequest(self.url, connect_timeout=self.connect_timeout, request_timeout=self.request_timeout, validate_cert=False)
|
||||
websocket.websocket_connect(request, io_loop=ioloop, callback=self._connect_callback)
|
||||
|
||||
def send(self, data):
|
||||
"""Send message to the server
|
||||
:param str data: message.
|
||||
"""
|
||||
if not self._ws_connection:
|
||||
raise RuntimeError('Web socket connection is closed.')
|
||||
|
||||
self._ws_connection.write_message(escape.utf8(json.dumps(data)))
|
||||
|
||||
def close(self):
|
||||
"""Close connection.
|
||||
"""
|
||||
if not self._ws_connection:
|
||||
raise RuntimeError('Web socket connection is already closed.')
|
||||
|
||||
self._ws_connection.close()
|
||||
self._ws_connection = None
|
||||
|
||||
def _connect_callback(self, future):
|
||||
if future.exception() is None:
|
||||
self._ws_connection = future.result()
|
||||
self._on_connection_success()
|
||||
self._read_messages()
|
||||
else:
|
||||
self._on_connection_error(future.exception())
|
||||
|
||||
@gen.coroutine
|
||||
def _read_messages(self):
|
||||
while True and not self._ws_connection is None:
|
||||
msg = yield self._ws_connection.read_message()
|
||||
if msg is None:
|
||||
self._on_connection_close()
|
||||
break
|
||||
|
||||
self._on_message(msg)
|
||||
|
||||
def _on_message(self, msg):
|
||||
"""This is called when new message is available from the server.
|
||||
:param str msg: server message.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
def _on_connection_success(self):
|
||||
"""This is called on successful connection ot the server.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
def _on_connection_close(self):
|
||||
"""This is called when server closed the connection.
|
||||
"""
|
||||
pass
|
||||
|
||||
def _on_connection_error(self, exception):
|
||||
"""This is called in case if connection to the server could
|
||||
not established.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
Whitespace-only changes.
@@ -0,0 +1,47 @@
|
||||
import TimelyMetric
|
||||
import TimelyAnalytic
|
||||
import DataOperations
|
||||
import os
|
||||
from TimelyAnalyticConfiguration import TimelyAnalyticConfiguration
|
||||
|
||||
hostport = "127.0.0.1:4244"
|
||||
timelyMetric = TimelyMetric.TimelyMetric(hostport, '', None, None, None, 48, None).fetch()
|
||||
|
||||
analyticConfig = TimelyAnalyticConfiguration({
|
||||
'system_name' : 'TestSystem',
|
||||
'counter' : False,
|
||||
'includeColRegex' : None,
|
||||
'excludeColRegex' : None,
|
||||
'groupByColumn' : 'instance',
|
||||
'sample' : '10 minutes',
|
||||
'how' : 'mean',
|
||||
'rolling_average_period' : '12 hours',
|
||||
'min_threshold' : None,
|
||||
'average_min_threshold' : None,
|
||||
'max_threshold' : None,
|
||||
'average_max_threshold' : None,
|
||||
'min_threshold_percentage' : -50,
|
||||
'max_threshold_percentage' : 50,
|
||||
'boolean' : 'and',
|
||||
'min_alert_period' : '5 minutes',
|
||||
'last_alert' : '1 hour',
|
||||
'display' : 'all',
|
||||
'output_dir' : '/path/to/output'
|
||||
})
|
||||
|
||||
alert = TimelyAnalytic.find_alerts(timelyMetric, analyticConfig)
|
||||
|
||||
if alert is not None:
|
||||
# write graph to file
|
||||
oldmask = os.umask(022)
|
||||
file = alert.graph(type='html')
|
||||
os.umask(oldmask)
|
||||
|
||||
text = DataOperations.getTitle(timelyMetric, analyticConfig)
|
||||
|
||||
# send email with graph attached
|
||||
alert.email("", "", text, text, [file])
|
||||
|
||||
# log to syslog
|
||||
alert.log(text)
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<FindBugsFilter>
|
||||
<Or>
|
||||
<Bug pattern="DM_DEFAULT_ENCODING"/>
|
||||
<Method name="connect" />
|
||||
<Class name="timely.client.tcp.TcpClient"/>
|
||||
</Or>
|
||||
</FindBugsFilter>
|
||||
@@ -0,0 +1,58 @@
|
||||
package timely.api;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import timely.serialize.JsonSerializer;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
public class SerializationTest {
|
||||
|
||||
private ObjectMapper mapper = JsonSerializer.getObjectMapper();
|
||||
|
||||
@Test
|
||||
public void testBasicAuth() throws Exception {
|
||||
BasicAuthLogin login = new BasicAuthLogin();
|
||||
login.setUsername("test");
|
||||
login.setPassword("pass");
|
||||
testSerialization(login);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSubscription() throws Exception {
|
||||
CreateSubscription create = new CreateSubscription();
|
||||
create.setSubscriptionId("1234");
|
||||
testSerialization(create);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloseSubscription() throws Exception {
|
||||
CloseSubscription close = new CloseSubscription();
|
||||
close.setSubscriptionId("1234");
|
||||
testSerialization(close);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddSubscription() throws Exception {
|
||||
AddSubscription add = new AddSubscription();
|
||||
add.setSubscriptionId("1234");
|
||||
add.setMetric("sys.cpu.user");
|
||||
testSerialization(add);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveSubscription() throws Exception {
|
||||
RemoveSubscription remove = new RemoveSubscription();
|
||||
remove.setSubscriptionId("1234");
|
||||
remove.setMetric("sys.cpu.user");
|
||||
testSerialization(remove);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> void testSerialization(T o) throws Exception {
|
||||
String ser = mapper.writeValueAsString(o);
|
||||
T des = mapper.readValue(ser, (Class<T>) o.getClass());
|
||||
Assert.assertEquals(o, des);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package timely.model;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import timely.model.parse.TagListParser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class TagListParserTest {
|
||||
|
||||
@Test
|
||||
public void testListParse() {
|
||||
String value = "tag1=value1,tag2=value2";
|
||||
List<Tag> tags = new TagListParser().parse(value);
|
||||
Assert.assertEquals(2, tags.size());
|
||||
Assert.assertEquals(new Tag("tag1", "value1"), tags.get(0));
|
||||
Assert.assertEquals(new Tag("tag2", "value2"), tags.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListCombine() {
|
||||
List<Tag> tags = new ArrayList<>();
|
||||
tags.add(new Tag("tag1", "value1"));
|
||||
tags.add(new Tag("tag2", "value2"));
|
||||
String combined = new TagListParser().combine(tags);
|
||||
Assert.assertEquals("tag1=value1,tag2=value2", combined);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListCombineMap() {
|
||||
Map<String, String> map = new TreeMap<>();
|
||||
map.put("tag1", "value1");
|
||||
map.put("tag2", "value2");
|
||||
String combined = new TagListParser().combine(map);
|
||||
Assert.assertEquals("tag1=value1,tag2=value2", combined);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>0.0.3</version>
|
||||
<version>0.0.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>collectd-nsq-plugin</artifactId>
|
||||
<dependencies>
|
||||
@@ -16,6 +16,10 @@
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>collectd-plugin-parent</artifactId>
|
||||
@@ -60,6 +64,10 @@
|
||||
<groupId>net.revelc.code</groupId>
|
||||
<artifactId>formatter-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package timely.collectd.plugin;
|
||||
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.PooledObjectFactory;
|
||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.collectd.api.OConfigItem;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class PooledCloseableHttpClientFactory implements PooledObjectFactory {
|
||||
|
||||
private int connectionRequestTimeout = 10000; // 10 seconds in milliseconds
|
||||
private int connectTimeout = 30000; // 30 seconds in milliseconds
|
||||
private int socketTimeout = 60000; // 60 seconds in milliseconds
|
||||
private long connectionTimeToLive = 300000; // 300 seconds in milliseconds
|
||||
|
||||
public int config(OConfigItem config) {
|
||||
for (OConfigItem child : config.getChildren()) {
|
||||
switch (child.getKey()) {
|
||||
case "connectionRequestTimeout":
|
||||
case "ConnectionRequestTimeout":
|
||||
connectionRequestTimeout = Integer.parseInt(child.getValues().get(0).getString());
|
||||
break;
|
||||
case "connectTimeout":
|
||||
case "ConnectTimeout":
|
||||
connectTimeout = Integer.parseInt(child.getValues().get(0).getString());
|
||||
break;
|
||||
case "socketTimeout":
|
||||
case "SocketTimeout":
|
||||
socketTimeout = Integer.parseInt(child.getValues().get(0).getString());
|
||||
break;
|
||||
case "connectionTimeToLive":
|
||||
case "ConnectionTimeToLive":
|
||||
connectionTimeToLive = Long.parseLong(child.getValues().get(0).getString());
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PooledObject makeObject() throws Exception {
|
||||
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout)
|
||||
.setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setDefaultRequestConfig(requestConfig);
|
||||
builder.setConnectionTimeToLive(connectionTimeToLive, TimeUnit.MILLISECONDS);
|
||||
return new DefaultPooledObject(builder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyObject(PooledObject pooledObject) throws Exception {
|
||||
try {
|
||||
((CloseableHttpClient) pooledObject.getObject()).close();
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
} finally {
|
||||
pooledObject.invalidate();
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateObject(PooledObject pooledObject) {
|
||||
return pooledObject.getObject() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activateObject(PooledObject pooledObject) throws Exception {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivateObject(PooledObject pooledObject) throws Exception {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public void setConnectionRequestTimeout(int connectionRequestTimeout) {
|
||||
this.connectionRequestTimeout = connectionRequestTimeout;
|
||||
}
|
||||
|
||||
public void setConnectTimeout(int connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
public void setSocketTimeout(int socketTimeout) {
|
||||
this.socketTimeout = socketTimeout;
|
||||
}
|
||||
|
||||
public void setConnectionTimeToLive(long connectionTimeToLive) {
|
||||
this.connectionTimeToLive = connectionTimeToLive;
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,11 @@ package timely.collectd.plugin;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Random;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.entity.EntityBuilder;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
@@ -33,10 +36,11 @@ public class WriteNSQPlugin extends CollectDPluginParent implements CollectdConf
|
||||
private int port = 0;
|
||||
private String topic = "metrics#ephemeral";
|
||||
private String endpoint = null;
|
||||
private ByteArrayOutputStream baos = null;
|
||||
private DataOutputStream out = null;
|
||||
private GenericObjectPool<CloseableHttpClient> clientPool = null;
|
||||
|
||||
private CloseableHttpClient client = HttpClients.createDefault();
|
||||
// pool should be limited by the number of WriteThreads configured in
|
||||
// collectd
|
||||
final private int POOL_MAX_SIZE = Integer.MAX_VALUE;
|
||||
|
||||
public WriteNSQPlugin() {
|
||||
Collectd.registerConfig(WriteNSQPlugin.class.getName(), this);
|
||||
@@ -44,16 +48,18 @@ public class WriteNSQPlugin extends CollectDPluginParent implements CollectdConf
|
||||
Collectd.registerWrite(WriteNSQPlugin.class.getName(), this);
|
||||
}
|
||||
|
||||
public synchronized int write(ValueList vl) {
|
||||
baos = new ByteArrayOutputStream();
|
||||
out = new DataOutputStream(baos);
|
||||
super.process(vl);
|
||||
public int write(ValueList vl) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DataOutputStream out = new DataOutputStream(baos);
|
||||
super.process(vl, out);
|
||||
CloseableHttpClient client = null;
|
||||
try {
|
||||
out.flush();
|
||||
HttpPost post = new HttpPost(endpoint);
|
||||
EntityBuilder request = EntityBuilder.create();
|
||||
request.setBinary(baos.toByteArray());
|
||||
post.setEntity(request.build());
|
||||
client = clientPool.borrowObject();
|
||||
CloseableHttpResponse response = client.execute(post);
|
||||
try {
|
||||
int code = response.getStatusLine().getStatusCode();
|
||||
@@ -66,13 +72,25 @@ public class WriteNSQPlugin extends CollectDPluginParent implements CollectdConf
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
Collectd.logError("Error sending metrics to NSQ: " + e.getMessage());
|
||||
if (client != null) {
|
||||
try {
|
||||
client.close();
|
||||
} catch (IOException e1) {
|
||||
}
|
||||
try {
|
||||
clientPool.invalidateObject(client);
|
||||
} catch (Exception e2) {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (client != null) {
|
||||
clientPool.returnObject(client);
|
||||
}
|
||||
if (null != out) {
|
||||
try {
|
||||
out.close();
|
||||
out = null;
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
@@ -81,9 +99,9 @@ public class WriteNSQPlugin extends CollectDPluginParent implements CollectdConf
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(String metric) {
|
||||
public void write(String metric, OutputStream out) {
|
||||
try {
|
||||
out.writeBytes(metric);
|
||||
((DataOutputStream) out).writeBytes(metric);
|
||||
} catch (IOException e) {
|
||||
Collectd.logError("Error writing metric: " + e.getMessage());
|
||||
try {
|
||||
@@ -93,21 +111,23 @@ public class WriteNSQPlugin extends CollectDPluginParent implements CollectdConf
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
public synchronized int shutdown() {
|
||||
public int shutdown() {
|
||||
Collectd.logInfo("Shutting down connection to NSQ at " + host + ":" + port);
|
||||
try {
|
||||
client.close();
|
||||
} catch (IOException e) {
|
||||
Collectd.logError("Error closing HttpClient: " + e.getMessage());
|
||||
}
|
||||
clientPool.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public synchronized int config(OConfigItem config) {
|
||||
public int config(OConfigItem config) {
|
||||
super.config(config);
|
||||
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
|
||||
// use max size for maxTotal and maxIdle
|
||||
// no need to activate or passivate
|
||||
poolConfig.setMaxTotal(POOL_MAX_SIZE);
|
||||
poolConfig.setMaxIdle(POOL_MAX_SIZE);
|
||||
poolConfig.setTestOnReturn(true);
|
||||
PooledCloseableHttpClientFactory pooledCloseableHttpClientFactory = new PooledCloseableHttpClientFactory();
|
||||
pooledCloseableHttpClientFactory.config(config);
|
||||
|
||||
for (OConfigItem child : config.getChildren()) {
|
||||
switch (child.getKey()) {
|
||||
case "host":
|
||||
@@ -133,17 +153,13 @@ public class WriteNSQPlugin extends CollectDPluginParent implements CollectdConf
|
||||
default:
|
||||
}
|
||||
}
|
||||
if (host == null || port == 0 || topic == null) {
|
||||
Collectd.logError("NSQ host, port, and topic must be configured");
|
||||
return -1;
|
||||
}
|
||||
this.clientPool = new GenericObjectPool(pooledCloseableHttpClientFactory, poolConfig);
|
||||
this.endpoint = "http://" + host + ":" + port + "/mpub?topic=" + topic;
|
||||
if (null != host) {
|
||||
return 0;
|
||||
}
|
||||
if (host == null) {
|
||||
Collectd.logError("NSQ host must be configured");
|
||||
}
|
||||
if (port == 0) {
|
||||
Collectd.logError("NSQ port must be configured");
|
||||
}
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>0.0.3</version>
|
||||
<version>0.0.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>collectd-plugin-parent</artifactId>
|
||||
<dependencies>
|
||||
@@ -55,6 +55,10 @@
|
||||
<groupId>net.revelc.code</groupId>
|
||||
<artifactId>formatter-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+22
-12
@@ -1,5 +1,6 @@
|
||||
package timely.collectd.plugin;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
@@ -17,6 +18,7 @@ public abstract class CollectDPluginParent {
|
||||
private static final Pattern HADOOP_STATSD_PATTERN = Pattern
|
||||
.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)");
|
||||
private static final String INSTANCE = " instance=";
|
||||
private static final String NAME = " name=";
|
||||
private static final String SAMPLE = " sample=";
|
||||
private static final String CODE = " code=";
|
||||
private static final String PERIOD = ".";
|
||||
@@ -32,7 +34,7 @@ public abstract class CollectDPluginParent {
|
||||
private static final Pattern ETHSTAT_PATTERN = Pattern.compile("([\\w-_]+)_queue_([\\w-_]+)_([\\w-_]+)");
|
||||
private static final String STATSD_PREFIX = "statsd";
|
||||
private static final String NSQ_PREFIX = STATSD_PREFIX + ".nsq.";
|
||||
private static final Pattern HAPROXY_PATTERN = Pattern.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)");
|
||||
private static final Pattern HAPROXY_PATTERN = Pattern.compile("\\[([\\w-_=]+),([\\w-_=]+)\\]");
|
||||
|
||||
private final SMARTCodeMapping smart = new SMARTCodeMapping();
|
||||
|
||||
@@ -53,9 +55,9 @@ public abstract class CollectDPluginParent {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public abstract void write(String metric);
|
||||
public abstract void write(String metric, OutputStream out);
|
||||
|
||||
public void process(ValueList vl) {
|
||||
public void process(ValueList vl, OutputStream out) {
|
||||
debugValueList(vl);
|
||||
|
||||
StringBuilder metric = new StringBuilder();
|
||||
@@ -158,13 +160,11 @@ public abstract class CollectDPluginParent {
|
||||
metric.append("sys.sensors.").append(vl.getType()).append(PERIOD).append(vl.getPluginInstance());
|
||||
tags.append(INSTANCE).append(instance);
|
||||
} else if (vl.getPlugin().equals("haproxy")) {
|
||||
Matcher m = HAPROXY_PATTERN.matcher(vl.getTypeInstance());
|
||||
metric.append("sys.haproxy.").append(vl.getTypeInstance());
|
||||
Matcher m = HAPROXY_PATTERN.matcher(vl.getPluginInstance());
|
||||
if (m.matches()) {
|
||||
metric.append("sys.haproxy.").append(m.group(3));
|
||||
tags.append(" proxy=").append(m.group(2));
|
||||
tags.append(" server=").append(m.group(1));
|
||||
} else {
|
||||
metric.append("sys.haproxy.").append(vl.getTypeInstance());
|
||||
tags.append(" ").append(m.group(1));
|
||||
tags.append(" ").append(m.group(2));
|
||||
}
|
||||
} else if (vl.getPlugin().equals("ipmi")) {
|
||||
metric.append("sys.ipmi.").append(vl.getType());
|
||||
@@ -172,17 +172,27 @@ public abstract class CollectDPluginParent {
|
||||
} else if (vl.getPlugin().equals("snmp")) {
|
||||
metric.append("sys.snmp.").append(vl.getType());
|
||||
tags.append(INSTANCE).append(vl.getTypeInstance().replaceAll(" ", "_"));
|
||||
} else if (vl.getPlugin().equals("GenericJMX")) {
|
||||
metric.append("sys.").append(vl.getPlugin()).append(PERIOD).append(vl.getType()).append(PERIOD)
|
||||
.append(vl.getTypeInstance());
|
||||
String[] pluginInstanceSplit = vl.getPluginInstance().split("-");
|
||||
if (pluginInstanceSplit.length > 0) {
|
||||
tags.append(INSTANCE).append(pluginInstanceSplit[0].replaceAll(" ", "_"));
|
||||
}
|
||||
if (pluginInstanceSplit.length > 1) {
|
||||
tags.append(NAME).append(pluginInstanceSplit[1].replaceAll(" ", "_"));
|
||||
}
|
||||
} else if (notEmpty(vl.getTypeInstance()) && notEmpty(vl.getType()) && notEmpty(vl.getPluginInstance())
|
||||
&& notEmpty(vl.getPlugin())) {
|
||||
metric.append("sys.").append(vl.getPlugin()).append(PERIOD).append(vl.getType()).append(PERIOD)
|
||||
.append(vl.getTypeInstance());
|
||||
tags.append(INSTANCE).append(vl.getPluginInstance());
|
||||
tags.append(INSTANCE).append(vl.getPluginInstance().replaceAll(" ", "_"));
|
||||
} else if (notEmpty(vl.getTypeInstance()) && notEmpty(vl.getType()) && notEmpty(vl.getPlugin())) {
|
||||
metric.append("sys.").append(vl.getPlugin()).append(PERIOD).append(vl.getType()).append(PERIOD)
|
||||
.append(vl.getTypeInstance());
|
||||
} else if (notEmpty(vl.getType()) && notEmpty(vl.getPluginInstance()) && notEmpty(vl.getPlugin())) {
|
||||
metric.append("sys.").append(vl.getPlugin()).append(PERIOD).append(vl.getType());
|
||||
tags.append(INSTANCE).append(vl.getPluginInstance());
|
||||
tags.append(INSTANCE).append(vl.getPluginInstance().replaceAll(" ", "_"));
|
||||
} else if (notEmpty(vl.getType()) && notEmpty(vl.getPlugin())) {
|
||||
metric.append("sys.").append(vl.getPlugin()).append(PERIOD).append(vl.getType());
|
||||
} else {
|
||||
@@ -205,7 +215,7 @@ public abstract class CollectDPluginParent {
|
||||
String datapoint = MessageFormat.format(PUT, metricName, timestamp.toString(), value.toString(),
|
||||
tagsWithSample.toString());
|
||||
Collectd.logDebug("Writing: " + datapoint);
|
||||
write(datapoint);
|
||||
write(datapoint, out);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package timely.collectd.plugin;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collections;
|
||||
|
||||
import net.jcip.annotations.NotThreadSafe;
|
||||
@@ -29,7 +30,7 @@ public class PluginParentTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(String metric) {
|
||||
public void write(String metric, OutputStream out) {
|
||||
result = metric;
|
||||
}
|
||||
|
||||
@@ -58,7 +59,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put statsd.dfs.BlocksRead 1456156976840 1.0 host=r01n01 rack=r01 addl1=foo instance=DataNode sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
@@ -78,7 +79,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals("put statsd.baz 1456156976840 1.0 host=r01n01 rack=r01 addl1=foo sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
}
|
||||
@@ -97,7 +98,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put statsd.baz 1456156976840 1.0 host=r01n01 rack=r01 addl1=foo instance=bar sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
@@ -117,7 +118,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put sys.hddtemp.temperature 1456156976840 35.0 host=r01n01 rack=r01 addl1=foo instance=sda sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
@@ -137,7 +138,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put sys.smart.smart_badsectors 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo instance=sda sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
@@ -158,7 +159,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put sys.smart.raw-read-error-rate 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo instance=sda sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
@@ -179,7 +180,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put sys.smart.Total_LBAs_Read 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo code=242 instance=sda sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
@@ -200,7 +201,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put sys.snmp.if_octets 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo instance=Ethernet1 sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
@@ -222,7 +223,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put sys.sensors.temperature.coretemp-isa-0000 1456156976840 35.0 host=r01n01 rack=r01 addl1=foo instance=1 sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
@@ -242,7 +243,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put sys.haproxy.run_queue 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
@@ -253,18 +254,19 @@ public class PluginParentTest {
|
||||
ValueList vl = new ValueList();
|
||||
vl.setHost(HOST);
|
||||
vl.setPlugin("haproxy");
|
||||
vl.setPluginInstance("[proxy_name=proxy1,service_name=server1]");
|
||||
vl.setTime(TIME);
|
||||
vl.setType("gauge");
|
||||
vl.setTypeInstance("server1.proxy1.queue_current");
|
||||
vl.setTypeInstance("queue_current");
|
||||
vl.setValues(Collections.singletonList((Number) 0.0D));
|
||||
DataSet ds = new DataSet("GAUGE");
|
||||
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put sys.haproxy.queue_current 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo proxy=proxy1 server=server1 sample=value sampleType=GAUGE\n",
|
||||
"put sys.haproxy.queue_current 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo proxy_name=proxy1 service_name=server1 sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
}
|
||||
|
||||
@@ -283,7 +285,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put sys.ethstat.tx_comp_queue_full 1456156976840 6.0 host=r01n01 rack=r01 addl1=foo instance=eth0 sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
@@ -305,7 +307,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put sys.ethstat.rx_bytes 1456156976840 6.0 host=r01n01 rack=r01 addl1=foo queue=1 instance=eth0 sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
@@ -326,7 +328,7 @@ public class PluginParentTest {
|
||||
vl.setDataSet(ds);
|
||||
|
||||
TestPlugin test = new TestPlugin();
|
||||
test.process(vl);
|
||||
test.process(vl, null);
|
||||
assertEquals(
|
||||
"put sys.ipmi.temperature 1456156976840 6.0 host=r01n01 rack=r01 addl1=foo instance=LAN_NIC_Temp_system_board_(3.2) sample=value sampleType=GAUGE\n",
|
||||
result);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>0.0.3</version>
|
||||
<version>0.0.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>collectd-timely-plugin</artifactId>
|
||||
<dependencies>
|
||||
@@ -12,6 +12,10 @@
|
||||
<groupId>collectd</groupId>
|
||||
<artifactId>collectd-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.jcip</groupId>
|
||||
<artifactId>jcip-annotations</artifactId>
|
||||
@@ -85,6 +89,10 @@
|
||||
<groupId>net.revelc.code</groupId>
|
||||
<artifactId>formatter-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,125 @@
|
||||
package timely.collectd.plugin;
|
||||
|
||||
import org.apache.commons.pool2.PooledObject;
|
||||
import org.apache.commons.pool2.PooledObjectFactory;
|
||||
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
import org.collectd.api.Collectd;
|
||||
import org.collectd.api.OConfigItem;
|
||||
|
||||
import java.net.Socket;
|
||||
|
||||
public class PooledSocketFactory implements PooledObjectFactory {
|
||||
|
||||
private String host = null;
|
||||
private int port = 0;
|
||||
private static final long initialBackoff = 2000;
|
||||
private int socketTimeout = 60000; // 60 seconds in milliseconds
|
||||
private long connectionTimeToLive = 300000; // 300 seconds in milliseconds
|
||||
|
||||
public int config(OConfigItem config) {
|
||||
for (OConfigItem child : config.getChildren()) {
|
||||
switch (child.getKey()) {
|
||||
case "host":
|
||||
case "hostname":
|
||||
case "Host":
|
||||
case "HostName":
|
||||
host = child.getValues().get(0).getString();
|
||||
break;
|
||||
case "Port":
|
||||
case "port":
|
||||
port = Integer.parseInt(child.getValues().get(0).getString());
|
||||
break;
|
||||
case "socketTimeout":
|
||||
case "SocketTimeout":
|
||||
socketTimeout = Integer.parseInt(child.getValues().get(0).getString());
|
||||
break;
|
||||
case "connectionTimeToLive":
|
||||
case "ConnectionTimeToLive":
|
||||
connectionTimeToLive = Long.parseLong(child.getValues().get(0).getString());
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
}
|
||||
if (null != host) {
|
||||
return 0;
|
||||
}
|
||||
if (host == null) {
|
||||
Collectd.logError("Timely host must be configured");
|
||||
}
|
||||
if (port == 0) {
|
||||
Collectd.logError("Timely port must be configured");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private Socket connect() {
|
||||
|
||||
Socket socket = null;
|
||||
long currentBackoff = initialBackoff;
|
||||
while (socket == null) {
|
||||
try {
|
||||
socket = new Socket(host, port);
|
||||
if (socketTimeout > -1) {
|
||||
socket.setSoTimeout(socketTimeout);
|
||||
}
|
||||
Collectd.logInfo("Connected to Timely at " + host + ":" + port + " from local port:"
|
||||
+ socket.getLocalPort());
|
||||
} catch (Exception e) {
|
||||
Collectd.logError("Error connecting to Timely at " + host + ":" + port + ". Error: " + e.getMessage()
|
||||
+ ". Will retry connection in " + currentBackoff + " ms.");
|
||||
try {
|
||||
Thread.sleep(currentBackoff);
|
||||
} catch (InterruptedException e1) {
|
||||
|
||||
}
|
||||
// max out reconnect period at one minute
|
||||
currentBackoff = (currentBackoff * 2 > 60000) ? 60000 : currentBackoff * 2;
|
||||
}
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PooledObject makeObject() throws Exception {
|
||||
return new DefaultPooledObject(connect());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyObject(PooledObject pooledObject) throws Exception {
|
||||
try {
|
||||
Collectd.logDebug("Shutting down connection to Timely at " + host + ":" + port);
|
||||
Socket socket = (Socket) pooledObject.getObject();
|
||||
if (socket != null) {
|
||||
socket.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Collectd.logError("Error closing connection to Timely at " + host + ":" + port + ". Error: "
|
||||
+ e.getMessage());
|
||||
} finally {
|
||||
pooledObject.invalidate();
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateObject(PooledObject pooledObject) {
|
||||
if (connectionTimeToLive > -1) {
|
||||
if (pooledObject.getCreateTime() + connectionTimeToLive > System.currentTimeMillis()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Socket socket = (Socket) pooledObject.getObject();
|
||||
return socket != null && !socket.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activateObject(PooledObject pooledObject) throws Exception {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivateObject(PooledObject pooledObject) throws Exception {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
+50
-83
@@ -1,9 +1,12 @@
|
||||
package timely.collectd.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
import org.collectd.api.Collectd;
|
||||
import org.collectd.api.CollectdConfigInterface;
|
||||
import org.collectd.api.CollectdShutdownInterface;
|
||||
@@ -19,12 +22,11 @@ import org.collectd.api.ValueList;
|
||||
public class WriteTimelyPlugin extends CollectDPluginParent implements CollectdConfigInterface,
|
||||
CollectdShutdownInterface, CollectdWriteInterface {
|
||||
|
||||
private String host = null;
|
||||
private int port = 0;
|
||||
private Socket sock = null;
|
||||
private PrintWriter out = null;
|
||||
private long connectTime = 0L;
|
||||
private long backoff = 2000;
|
||||
private GenericObjectPool<Socket> socketPool = null;
|
||||
|
||||
// pool should be limited by the number of WriteThreads configured in
|
||||
// collectd
|
||||
final private int POOL_MAX_SIZE = Integer.MAX_VALUE;
|
||||
|
||||
public WriteTimelyPlugin() {
|
||||
Collectd.registerConfig(WriteTimelyPlugin.class.getName(), this);
|
||||
@@ -32,98 +34,63 @@ public class WriteTimelyPlugin extends CollectDPluginParent implements CollectdC
|
||||
Collectd.registerWrite(WriteTimelyPlugin.class.getName(), this);
|
||||
}
|
||||
|
||||
private synchronized int connect() {
|
||||
if (null == sock || !sock.isConnected() || out.checkError()) {
|
||||
if (System.currentTimeMillis() > (connectTime + backoff)) {
|
||||
try {
|
||||
connectTime = System.currentTimeMillis();
|
||||
sock = new Socket(host, port);
|
||||
out = new PrintWriter(sock.getOutputStream(), false);
|
||||
backoff = 2000;
|
||||
Collectd.logInfo("Connected to Timely at " + host + ":" + port);
|
||||
} catch (IOException e) {
|
||||
Collectd.logError("Error connecting to Timely at " + host + ":" + port + ". Error: "
|
||||
+ e.getMessage());
|
||||
backoff = backoff * 2;
|
||||
sock = null;
|
||||
out = null;
|
||||
Collectd.logWarning("Will retry connection in " + backoff + " ms.");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
Collectd.logWarning("Not writing to Timely, waiting to reconnect");
|
||||
public int write(ValueList vl) {
|
||||
|
||||
Socket socket = null;
|
||||
try {
|
||||
socket = socketPool.borrowObject();
|
||||
if (socket == null) {
|
||||
return -1;
|
||||
}
|
||||
super.process(vl, socket.getOutputStream());
|
||||
} catch (Exception e) {
|
||||
Collectd.logWarning(e.getMessage());
|
||||
try {
|
||||
// close socket so that the object pool will discard it and
|
||||
// reconnect
|
||||
socket.close();
|
||||
} catch (IOException e1) {
|
||||
Collectd.logError(e1.getMessage());
|
||||
}
|
||||
return -1;
|
||||
} finally {
|
||||
if (socket != null) {
|
||||
socketPool.returnObject(socket);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public synchronized int write(ValueList vl) {
|
||||
|
||||
int c = connect();
|
||||
if (c != 0) {
|
||||
return c;
|
||||
}
|
||||
super.process(vl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(String metric) {
|
||||
out.write(metric);
|
||||
}
|
||||
|
||||
public synchronized void flush() {
|
||||
if (null != out) {
|
||||
out.flush();
|
||||
public void write(String metric, OutputStream out) {
|
||||
PrintWriter printWriter = new PrintWriter(out, false);
|
||||
printWriter.write(metric);
|
||||
printWriter.flush();
|
||||
if (printWriter.checkError()) {
|
||||
throw new RuntimeException("Error writing to Timely");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized int shutdown() {
|
||||
Collectd.logInfo("Shutting down connection to Timely at " + host + ":" + port);
|
||||
if (null != sock) {
|
||||
try {
|
||||
if (null != out) {
|
||||
out.close();
|
||||
}
|
||||
sock.close();
|
||||
} catch (IOException e) {
|
||||
Collectd.logError("Error closing connection to Timely at " + host + ":" + port + ". Error: "
|
||||
+ e.getMessage());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
public int shutdown() {
|
||||
socketPool.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public synchronized int config(OConfigItem config) {
|
||||
public int config(OConfigItem config) {
|
||||
super.config(config);
|
||||
for (OConfigItem child : config.getChildren()) {
|
||||
switch (child.getKey()) {
|
||||
case "host":
|
||||
case "hostname":
|
||||
case "Host":
|
||||
case "HostName":
|
||||
host = child.getValues().get(0).getString();
|
||||
break;
|
||||
case "Port":
|
||||
case "port":
|
||||
port = Integer.parseInt(child.getValues().get(0).getString());
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
int retval = 0;
|
||||
PooledSocketFactory socketFactory = new PooledSocketFactory();
|
||||
retval = socketFactory.config(config);
|
||||
if (retval == 0) {
|
||||
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
|
||||
// use max size for maxTotal and maxIdle
|
||||
// no need to activate and passivate
|
||||
poolConfig.setMaxTotal(POOL_MAX_SIZE);
|
||||
poolConfig.setMaxIdle(POOL_MAX_SIZE);
|
||||
poolConfig.setTestOnReturn(true);
|
||||
socketPool = new GenericObjectPool(socketFactory, poolConfig);
|
||||
}
|
||||
if (null != host) {
|
||||
return 0;
|
||||
}
|
||||
if (host == null) {
|
||||
Collectd.logError("Timely host must be configured");
|
||||
}
|
||||
if (port == 0) {
|
||||
Collectd.logError("Timely port must be configured");
|
||||
}
|
||||
return -1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
+7
-5
@@ -19,12 +19,14 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.powermock.api.easymock.PowerMock;
|
||||
import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({ Collectd.class })
|
||||
@NotThreadSafe
|
||||
@PowerMockIgnore("javax.management.*")
|
||||
public class WriteTimelyPluginTest {
|
||||
|
||||
private WriteTimelyPlugin plugin = null;
|
||||
@@ -63,7 +65,6 @@ public class WriteTimelyPluginTest {
|
||||
Assert.assertEquals(0, plugin.config(config));
|
||||
// Seed with one metric to create the connection
|
||||
Assert.assertEquals(0, plugin.write(createMetric()));
|
||||
plugin.flush();
|
||||
Thread.sleep(100);
|
||||
Assert.assertTrue(server.messageReceived());
|
||||
}
|
||||
@@ -77,7 +78,6 @@ public class WriteTimelyPluginTest {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
Assert.assertEquals(0, plugin.write(createMetric()));
|
||||
plugin.flush();
|
||||
Thread.sleep(100);
|
||||
Assert.assertTrue(server.messageReceived());
|
||||
plugin.shutdown();
|
||||
@@ -94,7 +94,6 @@ public class WriteTimelyPluginTest {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
Assert.assertEquals(0, plugin.write(createMetric()));
|
||||
plugin.flush();
|
||||
Thread.sleep(100);
|
||||
Assert.assertTrue(server.messageReceived());
|
||||
server.shutdown();
|
||||
@@ -104,16 +103,18 @@ public class WriteTimelyPluginTest {
|
||||
server.create();
|
||||
Thread t2 = new Thread(server);
|
||||
t2.start();
|
||||
// Need to call this again because the server is not guaranteed to be
|
||||
// listening on the same local port as the first time that it was
|
||||
// started
|
||||
setupPlugin();
|
||||
while (!server.ready()) {
|
||||
Thread.sleep(1000);
|
||||
// Keep sending metrics to plugin to force reconnect
|
||||
int result = plugin.write(createMetric());
|
||||
System.out.println("Wrote to client, result: " + result);
|
||||
Assert.assertEquals(0, result);
|
||||
plugin.flush();
|
||||
}
|
||||
Assert.assertEquals(0, plugin.write(createMetric()));
|
||||
plugin.flush();
|
||||
Thread.sleep(1000);
|
||||
Assert.assertTrue(server.messageReceived());
|
||||
plugin.shutdown();
|
||||
@@ -139,6 +140,7 @@ public class WriteTimelyPluginTest {
|
||||
server.setReceiveBufferSize(8192);
|
||||
host = server.getInetAddress().getHostAddress();
|
||||
port = server.getLocalPort();
|
||||
System.out.println("Local port " + port);
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
/target/
|
||||
+10
-2
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>0.0.3</version>
|
||||
<version>0.0.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>timely-common</artifactId>
|
||||
<dependencies>
|
||||
@@ -13,4 +13,12 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+6
-2
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>0.0.3</version>
|
||||
<version>0.0.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<build>
|
||||
<plugins>
|
||||
@@ -27,6 +27,10 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
</project>
|
||||
+213
-163
@@ -2,6 +2,8 @@
|
||||
"__inputs": [
|
||||
{
|
||||
"name": "DS_TIMELY",
|
||||
"label": "Timely",
|
||||
"description": "",
|
||||
"type": "datasource",
|
||||
"pluginId": "timely-datasource",
|
||||
"pluginName": "Timely"
|
||||
@@ -9,10 +11,10 @@
|
||||
],
|
||||
"__requires": [
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "singlestat",
|
||||
"name": "Singlestat",
|
||||
"version": ""
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "4.4.1"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
@@ -21,10 +23,10 @@
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "3.1.0"
|
||||
"type": "panel",
|
||||
"id": "singlestat",
|
||||
"name": "Singlestat",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
@@ -33,18 +35,18 @@
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"id": null,
|
||||
"title": "Accumulo Overview",
|
||||
"tags": [],
|
||||
"style": "dark",
|
||||
"timezone": "browser",
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"hideControls": false,
|
||||
"sharedCrosshair": false,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"rows": [
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "100",
|
||||
"panels": [
|
||||
{
|
||||
@@ -71,7 +73,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 2,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -105,6 +106,7 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "count",
|
||||
@@ -161,7 +163,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 3,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -195,6 +196,7 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
@@ -251,7 +253,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 4,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -285,6 +286,7 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
@@ -341,7 +343,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 5,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -375,6 +376,7 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
@@ -408,28 +410,28 @@
|
||||
"valueName": "avg"
|
||||
}
|
||||
],
|
||||
"title": "Row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "Row",
|
||||
"titleSize": "h6"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 1,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 6,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -448,6 +450,7 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
@@ -481,6 +484,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Minor Compactions",
|
||||
@@ -492,7 +496,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -516,18 +524,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 1,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 7,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -546,6 +550,7 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
@@ -579,6 +584,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Major Compactions",
|
||||
@@ -590,7 +596,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -614,18 +624,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 12,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -644,12 +650,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"counterMax": "",
|
||||
"currentTagKey": "",
|
||||
@@ -668,6 +675,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Thrift Ops",
|
||||
@@ -679,7 +687,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -703,18 +715,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 13,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -733,12 +741,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"counterMax": "",
|
||||
"currentTagKey": "",
|
||||
@@ -757,6 +766,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Thrift Avg Execution Time",
|
||||
@@ -768,7 +778,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -790,28 +804,28 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 8,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -830,12 +844,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -852,6 +867,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Write Ahead Logs Ops",
|
||||
@@ -863,7 +879,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -887,18 +907,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 9,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -917,12 +933,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -939,6 +956,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Write Ahead Logs Write Time Avg",
|
||||
@@ -950,7 +968,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -974,18 +996,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 18,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1004,12 +1022,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1026,6 +1045,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Write Ahead Logs Write Time Min",
|
||||
@@ -1037,7 +1057,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1061,18 +1085,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 19,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1091,12 +1111,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1113,6 +1134,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Write Ahead Logs Write Time Max",
|
||||
@@ -1124,7 +1146,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1146,28 +1172,28 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 11,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1186,12 +1212,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 4,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1208,6 +1235,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Mutation Array Num Ops",
|
||||
@@ -1219,7 +1247,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1243,18 +1275,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 10,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1273,12 +1301,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 4,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1293,6 +1322,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Mutation Array Avg Size",
|
||||
@@ -1304,7 +1334,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1328,18 +1362,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 17,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1358,12 +1388,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 4,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1378,6 +1409,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Mutation Array Max Size",
|
||||
@@ -1389,7 +1421,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1411,28 +1447,28 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 14,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1451,12 +1487,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 4,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1472,6 +1509,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Zookeeper Packets Received",
|
||||
@@ -1483,7 +1521,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1507,18 +1549,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 15,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1537,12 +1575,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 4,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1558,6 +1597,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Zookeeper Packets Sent",
|
||||
@@ -1569,7 +1609,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1593,18 +1637,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 16,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1623,12 +1663,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 4,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1644,6 +1685,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Zookeeper Average Latency",
|
||||
@@ -1655,7 +1697,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1677,9 +1723,20 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 14,
|
||||
"style": "dark",
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
@@ -1709,14 +1766,7 @@
|
||||
"30d"
|
||||
]
|
||||
},
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"schemaVersion": 12,
|
||||
"version": 19,
|
||||
"links": [],
|
||||
"gnetId": null
|
||||
}
|
||||
"timezone": "browser",
|
||||
"title": "Accumulo Overview",
|
||||
"version": 4
|
||||
}
|
||||
+434
-353
File diff suppressed because it is too large.
Load diff
+746
-696
File diff suppressed because it is too large.
Load diff
+88
-164
@@ -11,10 +11,10 @@
|
||||
],
|
||||
"__requires": [
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "singlestat",
|
||||
"name": "Singlestat",
|
||||
"version": ""
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "4.4.1"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
@@ -23,10 +23,10 @@
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "3.1.0"
|
||||
"type": "panel",
|
||||
"id": "singlestat",
|
||||
"name": "Singlestat",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
@@ -35,18 +35,19 @@
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"id": null,
|
||||
"title": "Timely Status",
|
||||
"tags": [],
|
||||
"style": "dark",
|
||||
"timezone": "browser",
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"hideControls": false,
|
||||
"sharedCrosshair": false,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"refresh": "1m",
|
||||
"rows": [
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "150",
|
||||
"panels": [
|
||||
{
|
||||
@@ -73,7 +74,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 8,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -107,9 +107,10 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "count",
|
||||
"aggregator": "sum",
|
||||
"downsampleAggregator": "sum",
|
||||
"downsampleFillPolicy": "none",
|
||||
"downsampleInterval": "1m",
|
||||
@@ -157,7 +158,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 9,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -191,6 +191,7 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "count",
|
||||
@@ -198,8 +199,8 @@
|
||||
"currentTagValue": "",
|
||||
"downsampleAggregator": "count",
|
||||
"downsampleFillPolicy": "none",
|
||||
"downsampleInterval": "1m",
|
||||
"metric": "sys.collectd.queue_length",
|
||||
"downsampleInterval": "1s",
|
||||
"metric": "sys.collectd.cache_size",
|
||||
"refId": "A",
|
||||
"tags": {}
|
||||
}
|
||||
@@ -243,7 +244,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 10,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -277,6 +277,7 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
@@ -306,28 +307,28 @@
|
||||
"valueName": "avg"
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 3,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -346,7 +347,8 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"span": 4,
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
@@ -364,6 +366,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Timely Metrics Inserted",
|
||||
@@ -375,7 +378,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -399,18 +406,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 4,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -429,7 +432,8 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"span": 4,
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
@@ -447,6 +451,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Timely Meta Inserted",
|
||||
@@ -458,7 +463,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -482,18 +491,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 5,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -512,7 +517,8 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"span": 4,
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
@@ -530,6 +536,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Timely Metrics Received",
|
||||
@@ -541,7 +548,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -561,30 +572,18 @@
|
||||
"show": true
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
},
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 7,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -603,12 +602,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"span": 6,
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -622,6 +622,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "CollectD Cache Sizes",
|
||||
@@ -633,91 +634,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"id": 11,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 2,
|
||||
"links": [],
|
||||
"nullPointMode": "connected",
|
||||
"percentage": false,
|
||||
"pointradius": 5,
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"span": 6,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
"downsampleAggregator": "sum",
|
||||
"downsampleFillPolicy": "none",
|
||||
"downsampleInterval": "1m",
|
||||
"metric": "sys.collectd.queue_length",
|
||||
"refId": "A",
|
||||
"tags": {
|
||||
"host": ".*"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "CollectD Queue Length",
|
||||
"tooltip": {
|
||||
"msResolution": true,
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "cumulative"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -739,9 +660,20 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 14,
|
||||
"style": "dark",
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
@@ -772,15 +704,7 @@
|
||||
"30d"
|
||||
]
|
||||
},
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"refresh": "1m",
|
||||
"schemaVersion": 12,
|
||||
"version": 8,
|
||||
"links": [],
|
||||
"gnetId": null
|
||||
"timezone": "browser",
|
||||
"title": "Timely Status",
|
||||
"version": 4
|
||||
}
|
||||
+108
-63
@@ -1,40 +1,59 @@
|
||||
{
|
||||
"__inputs": [
|
||||
{
|
||||
"name": "DS_NAME",
|
||||
"name": "DS_TIMELY-STANDALONE",
|
||||
"label": "Timely-Standalone",
|
||||
"description": "",
|
||||
"type": "datasource",
|
||||
"pluginId": "timely-datasource"
|
||||
"pluginId": "timely-datasource",
|
||||
"pluginName": "Timely"
|
||||
}
|
||||
],
|
||||
"id": null,
|
||||
"title": "Timely Standalone Demo",
|
||||
"originalTitle": "Timely Standalone Demo",
|
||||
"tags": ["imported"],
|
||||
"style": "dark",
|
||||
"timezone": "browser",
|
||||
"__requires": [
|
||||
{
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "4.4.1"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "graph",
|
||||
"name": "Graph",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "timely-datasource",
|
||||
"name": "Timely",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"hideControls": false,
|
||||
"sharedCrosshair": false,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"refresh": "5s",
|
||||
"rows": [
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"datasource": "${DS_NAME}",
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY-STANDALONE}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 1,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)",
|
||||
"thresholdLine": false
|
||||
},
|
||||
"grid": {},
|
||||
"id": 1,
|
||||
"legend": {
|
||||
"alignAsTable": true,
|
||||
@@ -56,6 +75,7 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 12,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
@@ -93,17 +113,23 @@
|
||||
"refId": "C"
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Timely Status",
|
||||
"tooltip": {
|
||||
"msResolution": true,
|
||||
"shared": false,
|
||||
"sort": 0,
|
||||
"value_type": "cumulative"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -124,28 +150,28 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "Row",
|
||||
"titleSize": "h6"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"datasource": "${DS_NAME}",
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY-STANDALONE}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 1,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 2,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"alignAsTable": true,
|
||||
"avg": false,
|
||||
@@ -166,12 +192,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 12,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "max",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -186,17 +213,23 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "CPU User by Host",
|
||||
"tooltip": {
|
||||
"msResolution": false,
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "cumulative"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -220,18 +253,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"datasource": "${DS_NAME}",
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY-STANDALONE}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 1,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 3,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"alignAsTable": true,
|
||||
"avg": false,
|
||||
@@ -252,12 +281,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 12,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "max",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_rack",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -272,17 +302,23 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "CPU User by Rack",
|
||||
"tooltip": {
|
||||
"msResolution": false,
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "cumulative"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -306,18 +342,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"datasource": "${DS_NAME}",
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY-STANDALONE}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 1,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 4,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"alignAsTable": true,
|
||||
"avg": false,
|
||||
@@ -338,12 +370,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 12,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "max",
|
||||
"aggregator": "none",
|
||||
"alias": "",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -356,17 +389,23 @@
|
||||
"tags": {}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Cumulative CPU",
|
||||
"tooltip": {
|
||||
"msResolution": false,
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "cumulative"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -388,9 +427,22 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 14,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"imported"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-15m",
|
||||
"to": "now"
|
||||
@@ -421,14 +473,7 @@
|
||||
"30d"
|
||||
]
|
||||
},
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"refresh": "5s",
|
||||
"schemaVersion": 12,
|
||||
"version": 1,
|
||||
"links": []
|
||||
}
|
||||
"timezone": "browser",
|
||||
"title": "Timely Standalone Demo",
|
||||
"version": 6
|
||||
}
|
||||
+2
-2
@@ -408,7 +408,7 @@ System.register(['lodash', 'angular', '../../../app/core/utils/datemath'], funct
|
||||
var tagData = [];
|
||||
|
||||
if (!_.isEmpty(md.tags)) {
|
||||
_.each(_.pairs(md.tags), function (tag) {
|
||||
_.each(_.toPairs(md.tags), function (tag) {
|
||||
if (_.has(groupByTags, tag[0])) {
|
||||
tagData.push(tag[0] + "=" + tag[1]);
|
||||
}
|
||||
@@ -493,7 +493,7 @@ System.register(['lodash', 'angular', '../../../app/core/utils/datemath'], funct
|
||||
if (target.filters && target.filters.length > 0) {
|
||||
return target.metric === metricData.metric;
|
||||
} else {
|
||||
return target.metric === metricData.metric && _.all(target.tags, function (tagV, tagK) {
|
||||
return target.metric === metricData.metric && _.every(target.tags, function (tagV, tagK) {
|
||||
interpolatedTagValue = this.templateSrv.replace(tagV, options.scopedVars, 'pipe');
|
||||
return metricData.tags[tagK] === interpolatedTagValue || interpolatedTagValue === "*";
|
||||
}.bind(this));
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"version":3,"sources":["../../src/datasource/datasource.js"],"names":["_","angular","dateMath","TimelyDatasource","instanceSettings","$q","backendSrv","templateSrv","contextSrv","type","name","jsonData","httpsPort","timelyHost","wsPort","basicAuths","url","_makeHttpsUrl","withCredentials","basicAuth","supportMetrics","tagKeys","aggregatorsPromise","filterTypesPromise","options","start","convertToTSDBTime","rangeRaw","from","end","to","qs","each","targets","target","metric","push","convertTargetToQuery","bind","queries","compact","isEmpty","d","defer","resolve","data","promise","groupByTags","query","filters","length","val","tagk","tags","key","performTimeSeriesQuery","then","response","metricToTargetMapping","mapMetricsToTargets","result","map","metricData","index","_saveTagKeys","transformMetricData","datasourceRequest","method","status","message","title","eventList","aggregator","annotation","results","annotationObject","annotations","isGlobal","globalAnnotations","event","description","time","Math","floor","startTime","text","notes","when","interpolated","replace","err","reject","responseTransform","value","metrics_regex","tag_names_regex","tag_values_regex","tag_names_suggest_regex","tag_values_suggest_regex","metrics_query","match","_performSuggestQuery","tag_names_query","_performMetricKeyLookup","tag_values_query","_performMetricKeyValueLookup","tag_names_suggest_query","tag_values_suggest_query","msResolution","reqBody","showQuery","_addCredentialOptions","headers","Object","keys","aggregateTags","tag","_get","q","max","keysArray","split","trim","keysQuery","splice","join","m","limit","tagvs","r","indexOf","tagks","tagv","relativeUrl","params","isArray","sort","md","metricLabel","createMetricLabel","dps","v","k","datapoints","alias","scopedVars","clone","label","tagData","pairs","has","hide","shouldComputeRate","rate","rateOptions","counter","isCounter","counterMax","parseInt","counterResetValue","resetValue","disableDownsampling","interval","downsampleInterval","parseFloat","downsample","downsampleAggregator","downsampleFillPolicy","copy","filter_key","filter","tag_key","metrics","interpolatedTagValue","findIndex","all","tagV","tagK","date","roundUp","parse","valueOf"],"mappings":";;;;;;;;;;;;;;;AAAOA,O;;AACAC,a;;AACKC,c;;;;;;;;;;;;;;;;;;;;;kCAECC,gB;;AAEX;AACA,kCAAYC,gBAAZ,EAA8BC,EAA9B,EAAkCC,UAAlC,EAA8CC,WAA9C,EAA2DC,UAA3D,EAAuE;AAAA;;AACrE,eAAKC,IAAL,GAAYL,iBAAiBK,IAA7B;AACA,eAAKC,IAAL,GAAYN,iBAAiBM,IAA7B;;AAEA,eAAKC,QAAL,GAAgBP,iBAAiBO,QAAjB,IAA6B,EAA7C;AACA,eAAKC,SAAL,GAAiBR,iBAAiBO,QAAjB,CAA0BC,SAA3C;AACA,eAAKC,UAAL,GAAkBT,iBAAiBO,QAAjB,CAA0BE,UAA5C;AACA,eAAKC,MAAL,GAAcV,iBAAiBO,QAAjB,CAA0BG,MAAxC;AACA,cAAI,CAACV,iBAAiBO,QAAjB,CAA0BI,UAA/B,EAA0C;AACxCX,6BAAiBO,QAAjB,CAA0BI,UAA1B,GAAuC,KAAvC;AACD;;AAED,eAAKC,GAAL,GAAW,KAAKC,aAAL,EAAX;AACA,eAAKC,eAAL,GAAuB,IAAvB;AACA,eAAKC,SAAL,GAAiB,KAAjB;;AAEA,eAAKC,cAAL,GAAsB,IAAtB;AACA,eAAKC,OAAL,GAAe,EAAf;;AAEA,eAAKhB,EAAL,GAAUA,EAAV;AACA,eAAKC,UAAL,GAAkBA,UAAlB;AACA,eAAKC,WAAL,GAAmBA,WAAnB;AACA,eAAKC,UAAL,GAAkBA,UAAlB;;AAEA,eAAKc,kBAAL,GAA0B,IAA1B;AACA,eAAKC,kBAAL,GAA0B,IAA1B;AAED;;AAED;;;;;gCACMC,O,EAAQ;AACZ,gBAAIC,QAAQ,KAAKC,iBAAL,CAAuBF,QAAQG,QAAR,CAAiBC,IAAxC,EAA8C,KAA9C,CAAZ;AACA,gBAAIC,MAAM,KAAKH,iBAAL,CAAuBF,QAAQG,QAAR,CAAiBG,EAAxC,EAA4C,IAA5C,CAAV;AACA,gBAAIC,KAAK,EAAT;;AAEA/B,cAAEgC,IAAF,CAAOR,QAAQS,OAAf,EAAwB,UAASC,MAAT,EAAiB;AACvC,kBAAI,CAACA,OAAOC,MAAZ,EAAoB;AAAE;AAAS;AAC/BJ,iBAAGK,IAAH,CAAQ,KAAKC,oBAAL,CAA0BH,MAA1B,EAAkCV,OAAlC,CAAR;AACD,aAHuB,CAGtBc,IAHsB,CAGjB,IAHiB,CAAxB;;AAKA,gBAAIC,UAAUvC,EAAEwC,OAAF,CAAUT,EAAV,CAAd;;AAEA;AACA,gBAAI/B,EAAEyC,OAAF,CAAUF,OAAV,CAAJ,EAAwB;AACtB,kBAAIG,IAAI,KAAKrC,EAAL,CAAQsC,KAAR,EAAR;AACAD,gBAAEE,OAAF,CAAU,EAAEC,MAAM,EAAR,EAAV;AACA,qBAAOH,EAAEI,OAAT;AACD;;AAED,gBAAIC,cAAc,EAAlB;AACA/C,cAAEgC,IAAF,CAAOO,OAAP,EAAgB,UAASS,KAAT,EAAgB;AAC9B,kBAAIA,MAAMC,OAAN,IAAiBD,MAAMC,OAAN,CAAcC,MAAd,GAAuB,CAA5C,EAA+C;AAC7ClD,kBAAEgC,IAAF,CAAOgB,MAAMC,OAAb,EAAsB,UAASE,GAAT,EAAc;AAClCJ,8BAAYI,IAAIC,IAAhB,IAAwB,IAAxB;AACD,iBAFD;AAGD,eAJD,MAIO;AACLpD,kBAAEgC,IAAF,CAAOgB,MAAMK,IAAb,EAAmB,UAASF,GAAT,EAAcG,GAAd,EAAmB;AACpCP,8BAAYO,GAAZ,IAAmB,IAAnB;AACD,iBAFD;AAGD;AACF,aAVD;;AAYA,mBAAO,KAAKC,sBAAL,CAA4BhB,OAA5B,EAAqCd,KAArC,EAA4CI,GAA5C,EAAiD2B,IAAjD,CAAsD,UAASC,QAAT,EAAmB;AAC9E,kBAAIC,wBAAwB,KAAKC,mBAAL,CAAyBF,SAASZ,IAAlC,EAAwCrB,OAAxC,CAA5B;AACA,kBAAIoC,SAAS5D,EAAE6D,GAAF,CAAMJ,SAASZ,IAAf,EAAqB,UAASiB,UAAT,EAAqBC,KAArB,EAA4B;AAC5DA,wBAAQL,sBAAsBK,KAAtB,CAAR;AACA,oBAAIA,UAAU,CAAC,CAAf,EAAkB;AAChBA,0BAAQ,CAAR;AACD;AACD,qBAAKC,YAAL,CAAkBF,UAAlB;;AAEA,uBAAO,KAAKG,mBAAL,CAAyBH,UAAzB,EAAqCf,WAArC,EAAkDvB,QAAQS,OAAR,CAAgB8B,KAAhB,CAAlD,EAA0EvC,OAA1E,CAAP;AACD,eARiC,CAQhCc,IARgC,CAQ3B,IAR2B,CAArB,CAAb;AASA,qBAAO,EAAEO,MAAMe,MAAR,EAAP;AACD,aAZ4D,CAY3DtB,IAZ2D,CAYtD,IAZsD,CAAtD,CAAP;AAaD;;;2CAGe;AACd,mBAAO,KAAKhC,UAAL,CAAgB4D,iBAAhB,CAAkC;AACvClD,mBAAK,KAAKA,GAAL,GAAW,UADuB;AAEvCmD,sBAAQ;AAF+B,aAAlC,EAGJX,IAHI,CAGC,oBAAY;AAClB,kBAAIC,SAASW,MAAT,KAAoB,GAAxB,EAA6B;AAC3B,uBAAO,EAAEA,QAAQ,SAAV,EAAqBC,SAAS,wBAA9B,EAAwDC,OAAO,SAA/D,EAAP;AACD;AALine truncated
|
||||
{"version":3,"sources":["../../src/datasource/datasource.js"],"names":["_","angular","dateMath","TimelyDatasource","instanceSettings","$q","backendSrv","templateSrv","contextSrv","type","name","jsonData","httpsPort","timelyHost","wsPort","basicAuths","url","_makeHttpsUrl","withCredentials","basicAuth","supportMetrics","tagKeys","aggregatorsPromise","filterTypesPromise","options","start","convertToTSDBTime","rangeRaw","from","end","to","qs","each","targets","target","metric","push","convertTargetToQuery","bind","queries","compact","isEmpty","d","defer","resolve","data","promise","groupByTags","query","filters","length","val","tagk","tags","key","performTimeSeriesQuery","then","response","metricToTargetMapping","mapMetricsToTargets","result","map","metricData","index","_saveTagKeys","transformMetricData","datasourceRequest","method","status","message","title","eventList","aggregator","annotation","results","annotationObject","annotations","isGlobal","globalAnnotations","event","description","time","Math","floor","startTime","text","notes","when","interpolated","replace","err","reject","responseTransform","value","metrics_regex","tag_names_regex","tag_values_regex","tag_names_suggest_regex","tag_values_suggest_regex","metrics_query","match","_performSuggestQuery","tag_names_query","_performMetricKeyLookup","tag_values_query","_performMetricKeyValueLookup","tag_names_suggest_query","tag_values_suggest_query","msResolution","reqBody","showQuery","_addCredentialOptions","headers","Object","keys","aggregateTags","tag","_get","q","max","keysArray","split","trim","keysQuery","splice","join","m","limit","tagvs","r","indexOf","tagks","tagv","relativeUrl","params","isArray","sort","md","metricLabel","createMetricLabel","dps","v","k","datapoints","alias","scopedVars","clone","label","tagData","toPairs","has","hide","shouldComputeRate","rate","rateOptions","counter","isCounter","counterMax","parseInt","counterResetValue","resetValue","disableDownsampling","interval","downsampleInterval","parseFloat","downsample","downsampleAggregator","downsampleFillPolicy","copy","filter_key","filter","tag_key","metrics","interpolatedTagValue","findIndex","every","tagV","tagK","date","roundUp","parse","valueOf"],"mappings":";;;;;;;;;;;;;;;AAAOA,O;;AACAC,a;;AACKC,c;;;;;;;;;;;;;;;;;;;;;kCAECC,gB;;AAEX;AACA,kCAAYC,gBAAZ,EAA8BC,EAA9B,EAAkCC,UAAlC,EAA8CC,WAA9C,EAA2DC,UAA3D,EAAuE;AAAA;;AACrE,eAAKC,IAAL,GAAYL,iBAAiBK,IAA7B;AACA,eAAKC,IAAL,GAAYN,iBAAiBM,IAA7B;;AAEA,eAAKC,QAAL,GAAgBP,iBAAiBO,QAAjB,IAA6B,EAA7C;AACA,eAAKC,SAAL,GAAiBR,iBAAiBO,QAAjB,CAA0BC,SAA3C;AACA,eAAKC,UAAL,GAAkBT,iBAAiBO,QAAjB,CAA0BE,UAA5C;AACA,eAAKC,MAAL,GAAcV,iBAAiBO,QAAjB,CAA0BG,MAAxC;AACA,cAAI,CAACV,iBAAiBO,QAAjB,CAA0BI,UAA/B,EAA0C;AACxCX,6BAAiBO,QAAjB,CAA0BI,UAA1B,GAAuC,KAAvC;AACD;;AAED,eAAKC,GAAL,GAAW,KAAKC,aAAL,EAAX;AACA,eAAKC,eAAL,GAAuB,IAAvB;AACA,eAAKC,SAAL,GAAiB,KAAjB;;AAEA,eAAKC,cAAL,GAAsB,IAAtB;AACA,eAAKC,OAAL,GAAe,EAAf;;AAEA,eAAKhB,EAAL,GAAUA,EAAV;AACA,eAAKC,UAAL,GAAkBA,UAAlB;AACA,eAAKC,WAAL,GAAmBA,WAAnB;AACA,eAAKC,UAAL,GAAkBA,UAAlB;;AAEA,eAAKc,kBAAL,GAA0B,IAA1B;AACA,eAAKC,kBAAL,GAA0B,IAA1B;AAED;;AAED;;;;;gCACMC,O,EAAQ;AACZ,gBAAIC,QAAQ,KAAKC,iBAAL,CAAuBF,QAAQG,QAAR,CAAiBC,IAAxC,EAA8C,KAA9C,CAAZ;AACA,gBAAIC,MAAM,KAAKH,iBAAL,CAAuBF,QAAQG,QAAR,CAAiBG,EAAxC,EAA4C,IAA5C,CAAV;AACA,gBAAIC,KAAK,EAAT;;AAEA/B,cAAEgC,IAAF,CAAOR,QAAQS,OAAf,EAAwB,UAASC,MAAT,EAAiB;AACvC,kBAAI,CAACA,OAAOC,MAAZ,EAAoB;AAAE;AAAS;AAC/BJ,iBAAGK,IAAH,CAAQ,KAAKC,oBAAL,CAA0BH,MAA1B,EAAkCV,OAAlC,CAAR;AACD,aAHuB,CAGtBc,IAHsB,CAGjB,IAHiB,CAAxB;;AAKA,gBAAIC,UAAUvC,EAAEwC,OAAF,CAAUT,EAAV,CAAd;;AAEA;AACA,gBAAI/B,EAAEyC,OAAF,CAAUF,OAAV,CAAJ,EAAwB;AACtB,kBAAIG,IAAI,KAAKrC,EAAL,CAAQsC,KAAR,EAAR;AACAD,gBAAEE,OAAF,CAAU,EAAEC,MAAM,EAAR,EAAV;AACA,qBAAOH,EAAEI,OAAT;AACD;;AAED,gBAAIC,cAAc,EAAlB;AACA/C,cAAEgC,IAAF,CAAOO,OAAP,EAAgB,UAASS,KAAT,EAAgB;AAC9B,kBAAIA,MAAMC,OAAN,IAAiBD,MAAMC,OAAN,CAAcC,MAAd,GAAuB,CAA5C,EAA+C;AAC7ClD,kBAAEgC,IAAF,CAAOgB,MAAMC,OAAb,EAAsB,UAASE,GAAT,EAAc;AAClCJ,8BAAYI,IAAIC,IAAhB,IAAwB,IAAxB;AACD,iBAFD;AAGD,eAJD,MAIO;AACLpD,kBAAEgC,IAAF,CAAOgB,MAAMK,IAAb,EAAmB,UAASF,GAAT,EAAcG,GAAd,EAAmB;AACpCP,8BAAYO,GAAZ,IAAmB,IAAnB;AACD,iBAFD;AAGD;AACF,aAVD;;AAYA,mBAAO,KAAKC,sBAAL,CAA4BhB,OAA5B,EAAqCd,KAArC,EAA4CI,GAA5C,EAAiD2B,IAAjD,CAAsD,UAASC,QAAT,EAAmB;AAC9E,kBAAIC,wBAAwB,KAAKC,mBAAL,CAAyBF,SAASZ,IAAlC,EAAwCrB,OAAxC,CAA5B;AACA,kBAAIoC,SAAS5D,EAAE6D,GAAF,CAAMJ,SAASZ,IAAf,EAAqB,UAASiB,UAAT,EAAqBC,KAArB,EAA4B;AAC5DA,wBAAQL,sBAAsBK,KAAtB,CAAR;AACA,oBAAIA,UAAU,CAAC,CAAf,EAAkB;AAChBA,0BAAQ,CAAR;AACD;AACD,qBAAKC,YAAL,CAAkBF,UAAlB;;AAEA,uBAAO,KAAKG,mBAAL,CAAyBH,UAAzB,EAAqCf,WAArC,EAAkDvB,QAAQS,OAAR,CAAgB8B,KAAhB,CAAlD,EAA0EvC,OAA1E,CAAP;AACD,eARiC,CAQhCc,IARgC,CAQ3B,IAR2B,CAArB,CAAb;AASA,qBAAO,EAAEO,MAAMe,MAAR,EAAP;AACD,aAZ4D,CAY3DtB,IAZ2D,CAYtD,IAZsD,CAAtD,CAAP;AAaD;;;2CAGe;AACd,mBAAO,KAAKhC,UAAL,CAAgB4D,iBAAhB,CAAkC;AACvClD,mBAAK,KAAKA,GAAL,GAAW,UADuB;AAEvCmD,sBAAQ;AAF+B,aAAlC,EAGJX,IAHI,CAGC,oBAAY;AAClB,kBAAIC,SAASW,MAAT,KAAoB,GAAxB,EAA6B;AAC3B,uBAAO,EAAEA,QAAQ,SAAV,EAAqBC,SAAS,wBAA9B,EAAwDC,OAAO,SAA/D,EAAP;AACLine truncated
|
||||
Vendored
+3
-3
@@ -23,8 +23,8 @@
|
||||
{"name": "Project site", "url": "https://github.com/NationalSecurityAgency/timely"},
|
||||
{"name": "License & Terms", "url": "https://raw.githubusercontent.com/NationalSecurityAgency/timely/master/LICENSE"}
|
||||
],
|
||||
"version": "0.0.3",
|
||||
"updated": "2016-06-30"
|
||||
"version": "0.0.6-SNAPSHOT",
|
||||
"updated": "2017-08-11"
|
||||
},
|
||||
|
||||
"includes": [
|
||||
@@ -34,7 +34,7 @@
|
||||
],
|
||||
|
||||
"dependencies": {
|
||||
"grafanaVersion": "3.x.x",
|
||||
"grafanaVersion": "4.x.x",
|
||||
"plugins": []
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
{"name": "Project site", "url": "https://github.com/NationalSecurityAgency/timely"},
|
||||
{"name": "License & Terms", "url": "https://raw.githubusercontent.com/NationalSecurityAgency/timely/master/LICENSE"}
|
||||
],
|
||||
"version": "0.0.3",
|
||||
"updated": "2016-06-30"
|
||||
"version": "0.0.6-SNAPSHOT",
|
||||
"updated": "2017-08-11"
|
||||
},
|
||||
|
||||
"includes": [
|
||||
@@ -34,7 +34,7 @@
|
||||
],
|
||||
|
||||
"dependencies": {
|
||||
"grafanaVersion": "3.x.x",
|
||||
"grafanaVersion": "4.x.x",
|
||||
"plugins": []
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
"__inputs": [
|
||||
{
|
||||
"name": "DS_TIMELY",
|
||||
"label": "Timely",
|
||||
"description": "",
|
||||
"type": "datasource",
|
||||
"pluginId": "timely-datasource",
|
||||
"pluginName": "Timely"
|
||||
@@ -9,10 +11,10 @@
|
||||
],
|
||||
"__requires": [
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "singlestat",
|
||||
"name": "Singlestat",
|
||||
"version": ""
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "4.4.1"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
@@ -21,10 +23,10 @@
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "3.1.0"
|
||||
"type": "panel",
|
||||
"id": "singlestat",
|
||||
"name": "Singlestat",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
@@ -33,18 +35,18 @@
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"id": null,
|
||||
"title": "Accumulo Overview",
|
||||
"tags": [],
|
||||
"style": "dark",
|
||||
"timezone": "browser",
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"hideControls": false,
|
||||
"sharedCrosshair": false,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"rows": [
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "100",
|
||||
"panels": [
|
||||
{
|
||||
@@ -71,7 +73,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 2,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -105,6 +106,7 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "count",
|
||||
@@ -161,7 +163,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 3,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -195,6 +196,7 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
@@ -251,7 +253,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 4,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -285,6 +286,7 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
@@ -341,7 +343,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 5,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -375,6 +376,7 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
@@ -408,28 +410,28 @@
|
||||
"valueName": "avg"
|
||||
}
|
||||
],
|
||||
"title": "Row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "Row",
|
||||
"titleSize": "h6"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 1,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 6,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -448,6 +450,7 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
@@ -481,6 +484,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Minor Compactions",
|
||||
@@ -492,7 +496,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -516,18 +524,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 1,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 7,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -546,6 +550,7 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
@@ -579,6 +584,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Major Compactions",
|
||||
@@ -590,7 +596,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -614,18 +624,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 12,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -644,12 +650,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"counterMax": "",
|
||||
"currentTagKey": "",
|
||||
@@ -668,6 +675,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Thrift Ops",
|
||||
@@ -679,7 +687,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -703,18 +715,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 13,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -733,12 +741,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"counterMax": "",
|
||||
"currentTagKey": "",
|
||||
@@ -757,6 +766,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Thrift Avg Execution Time",
|
||||
@@ -768,7 +778,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -790,28 +804,28 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 8,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -830,12 +844,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -852,6 +867,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Write Ahead Logs Ops",
|
||||
@@ -863,7 +879,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -887,18 +907,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 9,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -917,12 +933,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -939,6 +956,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Write Ahead Logs Write Time Avg",
|
||||
@@ -950,7 +968,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -974,18 +996,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 18,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1004,12 +1022,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1026,6 +1045,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Write Ahead Logs Write Time Min",
|
||||
@@ -1037,7 +1057,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1061,18 +1085,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 19,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1091,12 +1111,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1113,6 +1134,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Write Ahead Logs Write Time Max",
|
||||
@@ -1124,7 +1146,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1146,28 +1172,28 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 11,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1186,12 +1212,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 4,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1208,6 +1235,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Mutation Array Num Ops",
|
||||
@@ -1219,7 +1247,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1243,18 +1275,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 10,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1273,12 +1301,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 4,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1293,6 +1322,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Mutation Array Avg Size",
|
||||
@@ -1304,7 +1334,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1328,18 +1362,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 17,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1358,12 +1388,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 4,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1378,6 +1409,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Mutation Array Max Size",
|
||||
@@ -1389,7 +1421,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1411,28 +1447,28 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 14,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1451,12 +1487,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 4,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1472,6 +1509,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Zookeeper Packets Received",
|
||||
@@ -1483,7 +1521,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1507,18 +1549,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 15,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1537,12 +1575,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 4,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1558,6 +1597,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Zookeeper Packets Sent",
|
||||
@@ -1569,7 +1609,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1593,18 +1637,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 16,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -1623,12 +1663,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 4,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -1644,6 +1685,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Zookeeper Average Latency",
|
||||
@@ -1655,7 +1697,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -1677,9 +1723,20 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 14,
|
||||
"style": "dark",
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
@@ -1709,14 +1766,7 @@
|
||||
"30d"
|
||||
]
|
||||
},
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"schemaVersion": 12,
|
||||
"version": 19,
|
||||
"links": [],
|
||||
"gnetId": null
|
||||
}
|
||||
"timezone": "browser",
|
||||
"title": "Accumulo Overview",
|
||||
"version": 4
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -11,10 +11,10 @@
|
||||
],
|
||||
"__requires": [
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "singlestat",
|
||||
"name": "Singlestat",
|
||||
"version": ""
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "4.4.1"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
@@ -23,10 +23,10 @@
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "3.1.0"
|
||||
"type": "panel",
|
||||
"id": "singlestat",
|
||||
"name": "Singlestat",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
@@ -35,18 +35,19 @@
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"id": null,
|
||||
"title": "Timely Status",
|
||||
"tags": [],
|
||||
"style": "dark",
|
||||
"timezone": "browser",
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"hideControls": false,
|
||||
"sharedCrosshair": false,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"refresh": "1m",
|
||||
"rows": [
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "150",
|
||||
"panels": [
|
||||
{
|
||||
@@ -73,7 +74,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 8,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -107,9 +107,10 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "count",
|
||||
"aggregator": "sum",
|
||||
"downsampleAggregator": "sum",
|
||||
"downsampleFillPolicy": "none",
|
||||
"downsampleInterval": "1m",
|
||||
@@ -157,7 +158,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 9,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -191,6 +191,7 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "count",
|
||||
@@ -198,8 +199,8 @@
|
||||
"currentTagValue": "",
|
||||
"downsampleAggregator": "count",
|
||||
"downsampleFillPolicy": "none",
|
||||
"downsampleInterval": "1m",
|
||||
"metric": "sys.collectd.queue_length",
|
||||
"downsampleInterval": "1s",
|
||||
"metric": "sys.collectd.cache_size",
|
||||
"refId": "A",
|
||||
"tags": {}
|
||||
}
|
||||
@@ -243,7 +244,6 @@
|
||||
"hideTimeOverride": true,
|
||||
"id": 10,
|
||||
"interval": null,
|
||||
"isNew": true,
|
||||
"links": [],
|
||||
"mappingType": 1,
|
||||
"mappingTypes": [
|
||||
@@ -277,6 +277,7 @@
|
||||
"lineColor": "rgb(31, 120, 193)",
|
||||
"show": false
|
||||
},
|
||||
"tableColumn": "",
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
@@ -306,28 +307,28 @@
|
||||
"valueName": "avg"
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 3,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -346,7 +347,8 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"span": 4,
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
@@ -364,6 +366,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Timely Metrics Inserted",
|
||||
@@ -375,7 +378,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -399,18 +406,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 4,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -429,7 +432,8 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"span": 4,
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
@@ -447,6 +451,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Timely Meta Inserted",
|
||||
@@ -458,7 +463,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -482,18 +491,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 5,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -512,7 +517,8 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"span": 4,
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
@@ -530,6 +536,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Timely Metrics Received",
|
||||
@@ -541,7 +548,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -561,30 +572,18 @@
|
||||
"show": true
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
},
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 7,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
@@ -603,12 +602,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"span": 6,
|
||||
"spaceLength": 10,
|
||||
"span": 3,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -622,6 +622,7 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "CollectD Cache Sizes",
|
||||
@@ -633,91 +634,11 @@
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
},
|
||||
{
|
||||
"format": "short",
|
||||
"label": null,
|
||||
"logBase": 1,
|
||||
"max": null,
|
||||
"min": null,
|
||||
"show": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"datasource": "${DS_TIMELY}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 0,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"id": 11,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"avg": false,
|
||||
"current": false,
|
||||
"max": false,
|
||||
"min": false,
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"total": false,
|
||||
"values": false
|
||||
},
|
||||
"lines": true,
|
||||
"linewidth": 2,
|
||||
"links": [],
|
||||
"nullPointMode": "connected",
|
||||
"percentage": false,
|
||||
"pointradius": 5,
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"span": 6,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "sum",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
"downsampleAggregator": "sum",
|
||||
"downsampleFillPolicy": "none",
|
||||
"downsampleInterval": "1m",
|
||||
"metric": "sys.collectd.queue_length",
|
||||
"refId": "A",
|
||||
"tags": {
|
||||
"host": ".*"
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "CollectD Queue Length",
|
||||
"tooltip": {
|
||||
"msResolution": true,
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "cumulative"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -739,9 +660,20 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 14,
|
||||
"style": "dark",
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-1h",
|
||||
"to": "now"
|
||||
@@ -772,15 +704,7 @@
|
||||
"30d"
|
||||
]
|
||||
},
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"refresh": "1m",
|
||||
"schemaVersion": 12,
|
||||
"version": 8,
|
||||
"links": [],
|
||||
"gnetId": null
|
||||
"timezone": "browser",
|
||||
"title": "Timely Status",
|
||||
"version": 4
|
||||
}
|
||||
@@ -1,40 +1,59 @@
|
||||
{
|
||||
"__inputs": [
|
||||
{
|
||||
"name": "DS_NAME",
|
||||
"name": "DS_TIMELY-STANDALONE",
|
||||
"label": "Timely-Standalone",
|
||||
"description": "",
|
||||
"type": "datasource",
|
||||
"pluginId": "timely-datasource"
|
||||
"pluginId": "timely-datasource",
|
||||
"pluginName": "Timely"
|
||||
}
|
||||
],
|
||||
"id": null,
|
||||
"title": "Timely Standalone Demo",
|
||||
"originalTitle": "Timely Standalone Demo",
|
||||
"tags": ["imported"],
|
||||
"style": "dark",
|
||||
"timezone": "browser",
|
||||
"__requires": [
|
||||
{
|
||||
"type": "grafana",
|
||||
"id": "grafana",
|
||||
"name": "Grafana",
|
||||
"version": "4.4.1"
|
||||
},
|
||||
{
|
||||
"type": "panel",
|
||||
"id": "graph",
|
||||
"name": "Graph",
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "datasource",
|
||||
"id": "timely-datasource",
|
||||
"name": "Timely",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
],
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"editable": true,
|
||||
"gnetId": null,
|
||||
"graphTooltip": 0,
|
||||
"hideControls": false,
|
||||
"sharedCrosshair": false,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"refresh": "5s",
|
||||
"rows": [
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"datasource": "${DS_NAME}",
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY-STANDALONE}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 1,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)",
|
||||
"thresholdLine": false
|
||||
},
|
||||
"grid": {},
|
||||
"id": 1,
|
||||
"legend": {
|
||||
"alignAsTable": true,
|
||||
@@ -56,6 +75,7 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 12,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
@@ -93,17 +113,23 @@
|
||||
"refId": "C"
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Timely Status",
|
||||
"tooltip": {
|
||||
"msResolution": true,
|
||||
"shared": false,
|
||||
"sort": 0,
|
||||
"value_type": "cumulative"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -124,28 +150,28 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "Row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "Row",
|
||||
"titleSize": "h6"
|
||||
},
|
||||
{
|
||||
"collapse": false,
|
||||
"editable": true,
|
||||
"height": "250px",
|
||||
"panels": [
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"datasource": "${DS_NAME}",
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY-STANDALONE}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 1,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 2,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"alignAsTable": true,
|
||||
"avg": false,
|
||||
@@ -166,12 +192,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 12,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "max",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_host",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -186,17 +213,23 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "CPU User by Host",
|
||||
"tooltip": {
|
||||
"msResolution": false,
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "cumulative"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -220,18 +253,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"datasource": "${DS_NAME}",
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY-STANDALONE}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 1,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 3,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"alignAsTable": true,
|
||||
"avg": false,
|
||||
@@ -252,12 +281,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 12,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "max",
|
||||
"aggregator": "none",
|
||||
"alias": "$tag_rack",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -272,17 +302,23 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "CPU User by Rack",
|
||||
"tooltip": {
|
||||
"msResolution": false,
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "cumulative"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -306,18 +342,14 @@
|
||||
{
|
||||
"aliasColors": {},
|
||||
"bars": false,
|
||||
"datasource": "${DS_NAME}",
|
||||
"dashLength": 10,
|
||||
"dashes": false,
|
||||
"datasource": "${DS_TIMELY-STANDALONE}",
|
||||
"editable": true,
|
||||
"error": false,
|
||||
"fill": 1,
|
||||
"grid": {
|
||||
"threshold1": null,
|
||||
"threshold1Color": "rgba(216, 200, 27, 0.27)",
|
||||
"threshold2": null,
|
||||
"threshold2Color": "rgba(234, 112, 112, 0.22)"
|
||||
},
|
||||
"grid": {},
|
||||
"id": 4,
|
||||
"isNew": true,
|
||||
"legend": {
|
||||
"alignAsTable": true,
|
||||
"avg": false,
|
||||
@@ -338,12 +370,13 @@
|
||||
"points": false,
|
||||
"renderer": "flot",
|
||||
"seriesOverrides": [],
|
||||
"spaceLength": 10,
|
||||
"span": 12,
|
||||
"stack": false,
|
||||
"steppedLine": false,
|
||||
"targets": [
|
||||
{
|
||||
"aggregator": "max",
|
||||
"aggregator": "none",
|
||||
"alias": "",
|
||||
"currentTagKey": "",
|
||||
"currentTagValue": "",
|
||||
@@ -356,17 +389,23 @@
|
||||
"tags": {}
|
||||
}
|
||||
],
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Cumulative CPU",
|
||||
"tooltip": {
|
||||
"msResolution": false,
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
"value_type": "cumulative"
|
||||
},
|
||||
"type": "graph",
|
||||
"xaxis": {
|
||||
"show": true
|
||||
"buckets": null,
|
||||
"mode": "time",
|
||||
"name": null,
|
||||
"show": true,
|
||||
"values": []
|
||||
},
|
||||
"yaxes": [
|
||||
{
|
||||
@@ -388,9 +427,22 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"title": "New row"
|
||||
"repeat": null,
|
||||
"repeatIteration": null,
|
||||
"repeatRowId": null,
|
||||
"showTitle": false,
|
||||
"title": "New row",
|
||||
"titleSize": "h6"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 14,
|
||||
"style": "dark",
|
||||
"tags": [
|
||||
"imported"
|
||||
],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-15m",
|
||||
"to": "now"
|
||||
@@ -421,14 +473,7 @@
|
||||
"30d"
|
||||
]
|
||||
},
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"annotations": {
|
||||
"list": []
|
||||
},
|
||||
"refresh": "5s",
|
||||
"schemaVersion": 12,
|
||||
"version": 1,
|
||||
"links": []
|
||||
}
|
||||
"timezone": "browser",
|
||||
"title": "Timely Standalone Demo",
|
||||
"version": 6
|
||||
}
|
||||
@@ -347,7 +347,7 @@ export class TimelyDatasource {
|
||||
var tagData = [];
|
||||
|
||||
if (!_.isEmpty(md.tags)) {
|
||||
_.each(_.pairs(md.tags), function(tag) {
|
||||
_.each(_.toPairs(md.tags), function(tag) {
|
||||
if (_.has(groupByTags, tag[0])) {
|
||||
tagData.push(tag[0] + "=" + tag[1]);
|
||||
}
|
||||
@@ -430,9 +430,7 @@ export class TimelyDatasource {
|
||||
if (target.filters && target.filters.length > 0) {
|
||||
return target.metric === metricData.metric;
|
||||
} else {
|
||||
return target.metric === metricData.metric &&
|
||||
_.all(target.tags,
|
||||
function(tagV, tagK) {
|
||||
return target.metric === metricData.metric && _.every(target.tags, function(tagV, tagK) {
|
||||
interpolatedTagValue = this.templateSrv.replace(tagV, options.scopedVars, 'pipe');
|
||||
return metricData.tags[tagK] === interpolatedTagValue || interpolatedTagValue === "*";
|
||||
}.bind(this));
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<?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>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>0.0.3</version>
|
||||
<version>0.0.6-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Timely</name>
|
||||
<description>A secure and scalable time series database based on Apache Accumulo</description>
|
||||
@@ -26,10 +26,8 @@
|
||||
<module>common</module>
|
||||
<module>client</module>
|
||||
<module>server</module>
|
||||
<module>collectd-timely-plugin</module>
|
||||
<module>collectd-nsq-plugin</module>
|
||||
<module>collectd-plugin-parent</module>
|
||||
<module>grafana</module>
|
||||
<module>analytics</module>
|
||||
</modules>
|
||||
<properties>
|
||||
<!-- Configure the os-maven-plugin extension to expand the classifier on -->
|
||||
@@ -41,29 +39,29 @@
|
||||
<collectd-api-jar>/usr/share/collectd/java/collectd-api.jar</collectd-api-jar>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<version.accumulo>1.7.0</version.accumulo>
|
||||
<version.caffeine>2.2.0</version.caffeine>
|
||||
<version.accumulo>1.7.2</version.accumulo>
|
||||
<version.caffeine>2.3.3</version.caffeine>
|
||||
<version.collectd>5.5.1</version.collectd>
|
||||
<version.commons-configuration>1.10</version.commons-configuration>
|
||||
<version.commons-collections4>4.1</version.commons-collections4>
|
||||
<version.commons-lang3>3.1</version.commons-lang3>
|
||||
<version.disruptor>3.3.2</version.disruptor>
|
||||
<version.fast-classpath-scanner>1.10.4</version.fast-classpath-scanner>
|
||||
<version.commons-lang3>3.5</version.commons-lang3>
|
||||
<version.commons-pool2>2.4.2</version.commons-pool2>
|
||||
<version.disruptor>3.3.6</version.disruptor>
|
||||
<version.fast-classpath-scanner>2.0.5</version.fast-classpath-scanner>
|
||||
<version.google-flatbuffers>1.4.0</version.google-flatbuffers>
|
||||
<version.guava>19.0</version.guava>
|
||||
<version.hadoop>2.6.2</version.hadoop>
|
||||
<version.httpcomponents>4.5.1</version.httpcomponents>
|
||||
<version.jackson>2.6.1</version.jackson>
|
||||
<version.javassist>3.20.0-GA</version.javassist>
|
||||
<version.hadoop>2.7.3</version.hadoop>
|
||||
<version.httpcomponents>4.5.2</version.httpcomponents>
|
||||
<version.jackson>2.8.4</version.jackson>
|
||||
<version.javassist>3.21.0-GA</version.javassist>
|
||||
<version.jcip-annotations>1.0</version.jcip-annotations>
|
||||
<version.jsoup>1.9.2</version.jsoup>
|
||||
<version.junit>4.12</version.junit>
|
||||
<version.log4j>2.5</version.log4j>
|
||||
<version.netty>4.0.38.Final</version.netty>
|
||||
<version.netty-tcnative>1.1.33.Fork18</version.netty-tcnative>
|
||||
<version.log4j>2.6.2</version.log4j>
|
||||
<version.netty>4.0.46.Final</version.netty>
|
||||
<version.netty-tcnative>2.0.1.Final</version.netty-tcnative>
|
||||
<version.powermock>1.6.4</version.powermock>
|
||||
<version.slf4j>1.7.12</version.slf4j>
|
||||
<version.spring-boot>1.4.0.RELEASE</version.spring-boot>
|
||||
<version.slf4j>1.7.21</version.slf4j>
|
||||
<version.spring-boot>1.4.1.RELEASE</version.spring-boot>
|
||||
<!-- plugin versions -->
|
||||
<version.eclipse-lifecycle>1.0.0</version.eclipse-lifecycle>
|
||||
<version.findbugs-maven>3.0.3</version.findbugs-maven>
|
||||
@@ -74,6 +72,7 @@
|
||||
<version.maven-compiler>3.3</version.maven-compiler>
|
||||
<version.maven-dependency>2.10</version.maven-dependency>
|
||||
<version.maven-jar>3.0.1</version.maven-jar>
|
||||
<version.buildnumber-maven>1.4</version.buildnumber-maven>
|
||||
<version.os-maven>1.5.0.Final</version.os-maven>
|
||||
<version.maven-pmd>3.6</version.maven-pmd>
|
||||
<version.maven-rpm>2.1.4</version.maven-rpm>
|
||||
@@ -136,21 +135,10 @@
|
||||
<version>LATEST</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-configuration</groupId>
|
||||
<artifactId>commons-configuration</artifactId>
|
||||
<version>${version.commons-configuration}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>*</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.lukehutch</groupId>
|
||||
<artifactId>fast-classpath-scanner</artifactId>
|
||||
<version>${version.fast-classpath-scanner}</version>
|
||||
</dependency>
|
||||
<groupId>io.github.lukehutch</groupId>
|
||||
<artifactId>fast-classpath-scanner</artifactId>
|
||||
<version>${version.fast-classpath-scanner}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
@@ -212,6 +200,11 @@
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${version.commons-lang3}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-pool2</artifactId>
|
||||
<version>${version.commons-pool2}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.hadoop</groupId>
|
||||
<artifactId>hadoop-common</artifactId>
|
||||
@@ -379,7 +372,12 @@
|
||||
<archive>
|
||||
<manifest>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<Implementation-Build>${buildNumber}</Implementation-Build>
|
||||
<Implementation-Timestamp>${timestamp}</Implementation-Timestamp>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
@@ -403,6 +401,23 @@
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>${version.maven-build-helper}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
<version>${version.buildnumber-maven}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<doCheck>false</doCheck>
|
||||
<doUpdate>false</doUpdate>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
@@ -497,4 +512,17 @@
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>collectd</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
<modules>
|
||||
<module>collectd-timely-plugin</module>
|
||||
<module>collectd-nsq-plugin</module>
|
||||
<module>collectd-plugin-parent</module>
|
||||
</modules>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
/target/
|
||||
+1
-6
@@ -1,13 +1,8 @@
|
||||
FROM centos:centos7
|
||||
|
||||
MAINTAINER Jim Klucar "[email protected]"
|
||||
|
||||
VOLUME /timely-server-src
|
||||
VOLUME /timely
|
||||
|
||||
|
||||
|
||||
|
||||
RUN yum -y update && \
|
||||
yum -y install java-1.8.0-openjdk-devel maven openssl apr wget epel-release && \
|
||||
yum -y install bouncycastle && \
|
||||
@@ -20,5 +15,5 @@ ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk
|
||||
|
||||
EXPOSE 9804 54321 54322
|
||||
|
||||
ENV TIMELY_VERSION 0.0.3-SNAPSHOT
|
||||
ENV TIMELY_VERSION 0.0.6-SNAPSHOT
|
||||
|
||||
@@ -13,11 +13,22 @@
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="10" />
|
||||
</RollingRandomAccessFile>
|
||||
<RollingRandomAccessFile name="Subscription" fileName="logs/timely-subscriptions.log"
|
||||
filePattern="logs/$${date:yyyy-MM}/timely-subscriptions-%d{MM-dd-yyyy}-%i.log.gz">
|
||||
<PatternLayout pattern="${LOG_PATTERN}"/>
|
||||
<Policies>
|
||||
<SizeBasedTriggeringPolicy size="1024 MB" />
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="10" />
|
||||
</RollingRandomAccessFile>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="${LOG_PATTERN}"/>
|
||||
</Console>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Logger name="timely.subscription" level="trace" additivity="false">
|
||||
<AppenderRef ref="Subscription" />
|
||||
</Logger>
|
||||
<Root level="trace" includeLocation="false">
|
||||
<AppenderRef ref="Console" level="warn" />
|
||||
<AppenderRef ref="Rolling" level="trace" />
|
||||
|
||||
@@ -15,6 +15,7 @@ timely:
|
||||
bufferSize: 52428800
|
||||
scan:
|
||||
threads: 4
|
||||
max-downsample-memory: 10000000
|
||||
security:
|
||||
session-max-age: 86400
|
||||
allow-anonymous-access: true
|
||||
|
||||
@@ -15,6 +15,7 @@ timely:
|
||||
bufferSize: 52428800
|
||||
scan:
|
||||
threads: 4
|
||||
max-downsample-memory: 10000000
|
||||
security:
|
||||
session-max-age: 86400
|
||||
allow-anonymous-access: true
|
||||
@@ -47,6 +48,10 @@ timely:
|
||||
port: 54323
|
||||
timeout: 60
|
||||
subscription-lag: 120
|
||||
scanner-batch-size: 10000
|
||||
flush-interval-seconds: 30
|
||||
scanner-read-ahead: 1
|
||||
subscription-batch-size: 5000
|
||||
meta-cache:
|
||||
expiration-minutes: 60
|
||||
initial-capacity: 2000
|
||||
|
||||
@@ -15,6 +15,7 @@ timely:
|
||||
bufferSize: 52428800
|
||||
scan:
|
||||
threads: 4
|
||||
max-downsample-memory: 10000000
|
||||
security:
|
||||
session-max-age: 86400
|
||||
allow-anonymous-access: false
|
||||
@@ -48,6 +49,10 @@ timely:
|
||||
port:
|
||||
timeout: 60
|
||||
subscription-lag: 120
|
||||
scanner-batch-size: 10000
|
||||
flush-interval-seconds: 30
|
||||
scanner-read-ahead: 1
|
||||
subscription-batch-size: 5000
|
||||
meta-cache:
|
||||
expiration-minutes: 60
|
||||
initial-capacity: 2000
|
||||
|
||||
@@ -11,7 +11,7 @@ services:
|
||||
- ${PWD}/:/timely-server-src
|
||||
command: /timely-server-src/bin/docker/deploy-startup-standalone.sh
|
||||
environment:
|
||||
- TIMELY_VERSION=0.0.3-SNAPSHOT
|
||||
- TIMELY_VERSION=0.0.6-SNAPSHOT
|
||||
ingest:
|
||||
image: timely
|
||||
entrypoint: /timely-server-src/bin/docker/deploy-wait-and-insert.sh
|
||||
@@ -22,9 +22,9 @@ services:
|
||||
environment:
|
||||
- TIMELY_HOST=timely
|
||||
- TIMELY_PORT=54321
|
||||
- TIMELY_VERSION=0.0.3-SNAPSHOT
|
||||
- TIMELY_VERSION=0.0.6-SNAPSHOT
|
||||
grafana:
|
||||
image: grafana/grafana
|
||||
image: grafana/grafana:4.4.3
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
|
||||
+39
-6
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>0.0.3</version>
|
||||
<version>0.0.6-SNAPSHOT</version>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -45,10 +45,6 @@
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/lib/flatbuffers-java-1.4.0.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-configuration</groupId>
|
||||
<artifactId>commons-configuration</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
@@ -71,7 +67,7 @@
|
||||
<artifactId>netty-tcnative</artifactId>
|
||||
<version>${version.netty-tcnative}</version>
|
||||
<classifier>${os.detected.classifier}</classifier>
|
||||
<!-- Eclipse doesn't like this, but it works on the cmd line -->
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
@@ -287,6 +283,10 @@
|
||||
<groupId>net.revelc.code</groupId>
|
||||
<artifactId>formatter-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<reporting>
|
||||
@@ -334,4 +334,37 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>native-epoll-linux</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>!mac</family>
|
||||
</os>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-transport-native-epoll</artifactId>
|
||||
<version>${version.netty}</version>
|
||||
<classifier>linux-x86_64</classifier>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>native-epoll</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>mac</family>
|
||||
</os>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-transport-native-epoll</artifactId>
|
||||
<version>${version.netty}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -218,6 +218,7 @@ public class Configuration {
|
||||
public class Scan {
|
||||
|
||||
private int threads = 4;
|
||||
private long maxDownsampleMemory = -1;
|
||||
|
||||
public int getThreads() {
|
||||
return threads;
|
||||
@@ -227,6 +228,15 @@ public class Configuration {
|
||||
this.threads = threads;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public long getMaxDownsampleMemory() {
|
||||
return maxDownsampleMemory;
|
||||
}
|
||||
|
||||
public Configuration setMaxDownsampleMemory(long maxDownsampleMemory) {
|
||||
this.maxDownsampleMemory = maxDownsampleMemory;
|
||||
return Configuration.this;
|
||||
}
|
||||
}
|
||||
|
||||
public class Security {
|
||||
@@ -530,6 +540,10 @@ public class Configuration {
|
||||
private Integer port;
|
||||
public int timeout = 60;
|
||||
public int subscriptionLag = 120;
|
||||
public int scannerBatchSize = 5000;
|
||||
public int flushIntervalSeconds = 30;
|
||||
public int scannerReadAhead = 1;
|
||||
public int subscriptionBatchSize = 1000;
|
||||
|
||||
public String getIp() {
|
||||
return ip;
|
||||
@@ -566,6 +580,42 @@ public class Configuration {
|
||||
this.subscriptionLag = subscriptionLag;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getScannerBatchSize() {
|
||||
return this.scannerBatchSize;
|
||||
}
|
||||
|
||||
public Configuration setScannerBatchSize(int batchSize) {
|
||||
this.scannerBatchSize = batchSize;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getFlushIntervalSeconds() {
|
||||
return this.flushIntervalSeconds;
|
||||
}
|
||||
|
||||
public Configuration setFlushIntervalSeconds(int flushInterval) {
|
||||
this.flushIntervalSeconds = flushInterval;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getScannerReadAhead() {
|
||||
return this.scannerReadAhead;
|
||||
}
|
||||
|
||||
public Configuration setScannerReadAhead(int readAhead) {
|
||||
this.scannerReadAhead = readAhead;
|
||||
return Configuration.this;
|
||||
}
|
||||
|
||||
public int getSubscriptionBatchSize() {
|
||||
return this.subscriptionBatchSize;
|
||||
}
|
||||
|
||||
public Configuration setSubscriptionBatchSize(int batchSize) {
|
||||
this.subscriptionBatchSize = batchSize;
|
||||
return Configuration.this;
|
||||
}
|
||||
}
|
||||
|
||||
public class MetaCache {
|
||||
|
||||
@@ -3,7 +3,12 @@ package timely;
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.buffer.PooledByteBufAllocator;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.epoll.EpollDatagramChannel;
|
||||
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||
import io.netty.channel.epoll.EpollServerSocketChannel;
|
||||
@@ -58,7 +63,7 @@ import timely.auth.VisibilityCache;
|
||||
import timely.netty.http.HttpMetricPutHandler;
|
||||
import timely.netty.http.HttpStaticFileServerHandler;
|
||||
import timely.netty.http.HttpVersionRequestHandler;
|
||||
import timely.netty.http.NonSecureHttpHandler;
|
||||
import timely.netty.http.NonSslRedirectHandler;
|
||||
import timely.netty.http.StrictTransportHandler;
|
||||
import timely.netty.http.TimelyExceptionHandler;
|
||||
import timely.netty.http.auth.BasicAuthLoginRequestHandler;
|
||||
@@ -82,6 +87,7 @@ import timely.netty.websocket.subscription.WSAddSubscriptionRequestHandler;
|
||||
import timely.netty.websocket.subscription.WSCloseSubscriptionRequestHandler;
|
||||
import timely.netty.websocket.subscription.WSCreateSubscriptionRequestHandler;
|
||||
import timely.netty.websocket.subscription.WSRemoveSubscriptionRequestHandler;
|
||||
import timely.netty.websocket.subscription.WSTimelyExceptionHandler;
|
||||
import timely.netty.websocket.timeseries.WSAggregatorsRequestHandler;
|
||||
import timely.netty.websocket.timeseries.WSMetricsRequestHandler;
|
||||
import timely.netty.websocket.timeseries.WSQueryRequestHandler;
|
||||
@@ -396,6 +402,10 @@ public class Server {
|
||||
wsServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||
wsServer.option(ChannelOption.SO_BACKLOG, 128);
|
||||
wsServer.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
/* Not sure if next three lines are necessary */
|
||||
wsServer.option(ChannelOption.SO_SNDBUF, 1048576);
|
||||
wsServer.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 838860);
|
||||
wsServer.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 620145);
|
||||
wsChannelHandle = wsServer.bind(wsIp, wsPort).sync().channel();
|
||||
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
|
||||
|
||||
@@ -463,10 +473,9 @@ public class Server {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) throws Exception {
|
||||
|
||||
ch.pipeline().addLast("ssl", sslCtx.newHandler(ch.alloc()));
|
||||
ch.pipeline().addLast("ssl", new NonSslRedirectHandler(config, sslCtx));
|
||||
ch.pipeline().addLast("encoder", new HttpResponseEncoder());
|
||||
ch.pipeline().addLast("decoder", new HttpRequestDecoder());
|
||||
ch.pipeline().addLast("non-secure", new NonSecureHttpHandler(config));
|
||||
ch.pipeline().addLast("compressor", new HttpContentCompressor());
|
||||
ch.pipeline().addLast("decompressor", new HttpContentDecompressor());
|
||||
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
|
||||
@@ -558,7 +567,7 @@ public class Server {
|
||||
ch.pipeline().addLast("add", new WSAddSubscriptionRequestHandler());
|
||||
ch.pipeline().addLast("remove", new WSRemoveSubscriptionRequestHandler());
|
||||
ch.pipeline().addLast("close", new WSCloseSubscriptionRequestHandler());
|
||||
|
||||
ch.pipeline().addLast("error", new WSTimelyExceptionHandler());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ public class MetricAdapter {
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
public static Metric parse(Key k, Value v) {
|
||||
public static Metric parse(Key k, Value v, boolean includeVizTag) {
|
||||
ComparablePair<String, Long> row = rowCoder.decode(k.getRow().getBytes());
|
||||
// @formatter:off
|
||||
Metric.Builder builder = Metric.newBuilder()
|
||||
@@ -91,9 +91,16 @@ public class MetricAdapter {
|
||||
.tag(tagParser.parse(k.getColumnFamily().toString()));
|
||||
// @formatter:on
|
||||
tagListParser.parse(k.getColumnQualifier().toString()).forEach(builder::tag);
|
||||
if (includeVizTag && k.getColumnVisibility().getLength() > 0) {
|
||||
tagListParser.parse("viz=" + k.getColumnVisibility().toString()).forEach(builder::tag);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static Metric parse(Key k, Value v) {
|
||||
return parse(k, v, false);
|
||||
}
|
||||
|
||||
public static byte[] encodeRowKey(String metricName, Long timestamp) {
|
||||
return rowCoder.encode(new ComparablePair<>(metricName, timestamp));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package timely.api.annotation;
|
||||
|
||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner;
|
||||
import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -17,7 +18,7 @@ import timely.api.request.WebSocketRequest;
|
||||
public class AnnotationResolver {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AnnotationResolver.class);
|
||||
private static final FastClasspathScanner scanner = new FastClasspathScanner("timely.api").scan();
|
||||
private static final ScanResult result = new FastClasspathScanner("timely.api").scan();
|
||||
private static List<String> tcpClassNames;
|
||||
private static List<String> httpClassNames;
|
||||
private static List<String> wsClassNames;
|
||||
@@ -31,7 +32,7 @@ public class AnnotationResolver {
|
||||
}
|
||||
|
||||
static {
|
||||
tcpClassNames = scanner.getNamesOfClassesWithAnnotation(Tcp.class);
|
||||
tcpClassNames = result.getNamesOfClassesWithAnnotation(Tcp.class);
|
||||
LOG.trace("Found tcp classes: {}", tcpClassNames);
|
||||
if (null != tcpClassNames) {
|
||||
for (String cls : tcpClassNames) {
|
||||
@@ -43,7 +44,7 @@ public class AnnotationResolver {
|
||||
}
|
||||
}
|
||||
LOG.trace("Loaded tcp classes: {}", tcpClasses);
|
||||
httpClassNames = scanner.getNamesOfClassesWithAnnotation(Http.class);
|
||||
httpClassNames = result.getNamesOfClassesWithAnnotation(Http.class);
|
||||
LOG.trace("Found http class names: {}", httpClassNames);
|
||||
if (null != httpClassNames) {
|
||||
for (String cls : httpClassNames) {
|
||||
@@ -55,7 +56,7 @@ public class AnnotationResolver {
|
||||
}
|
||||
}
|
||||
LOG.trace("Loaded http classes: {}", httpClasses);
|
||||
wsClassNames = scanner.getNamesOfClassesWithAnnotation(WebSocket.class);
|
||||
wsClassNames = result.getNamesOfClassesWithAnnotation(WebSocket.class);
|
||||
LOG.trace("Found web socket class names: {}", wsClassNames);
|
||||
if (null != wsClassNames) {
|
||||
for (String cls : wsClassNames) {
|
||||
@@ -67,7 +68,7 @@ public class AnnotationResolver {
|
||||
}
|
||||
}
|
||||
LOG.trace("Loaded web socket classes: {}", wsClasses);
|
||||
udpClassNames = scanner.getNamesOfClassesWithAnnotation(Udp.class);
|
||||
udpClassNames = result.getNamesOfClassesWithAnnotation(Udp.class);
|
||||
LOG.trace("Found udp classes: {}", udpClassNames);
|
||||
if (null != udpClassNames) {
|
||||
for (String cls : udpClassNames) {
|
||||
|
||||
@@ -1,30 +1,12 @@
|
||||
package timely.api.request.auth;
|
||||
|
||||
import timely.api.BasicAuthLogin;
|
||||
import timely.api.annotation.Http;
|
||||
import timely.api.request.HttpPostRequest;
|
||||
import timely.util.JsonUtil;
|
||||
|
||||
@Http(path = "/login")
|
||||
public class BasicAuthLoginRequest implements HttpPostRequest {
|
||||
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String user) {
|
||||
this.username = user;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
public class BasicAuthLoginRequest extends BasicAuthLogin implements HttpPostRequest {
|
||||
|
||||
@Override
|
||||
public void validate() {
|
||||
|
||||
@@ -11,6 +11,7 @@ public class AddSubscription extends SubscriptionRequest {
|
||||
private String metric = null;
|
||||
private Optional<Map<String, String>> tags = Optional.empty();
|
||||
private Optional<Long> startTime = Optional.empty();
|
||||
private Optional<Long> endTime = Optional.empty();
|
||||
private Optional<Long> delayTime = Optional.empty();
|
||||
|
||||
public String getMetric() {
|
||||
@@ -37,6 +38,14 @@ public class AddSubscription extends SubscriptionRequest {
|
||||
this.startTime = Optional.ofNullable(startTime);
|
||||
}
|
||||
|
||||
public Optional<Long> getEndTime() {
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setEndTime(long endTime) {
|
||||
this.endTime = Optional.ofNullable(endTime);
|
||||
}
|
||||
|
||||
public Optional<Long> getDelayTime() {
|
||||
return delayTime;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public class QueryRequest extends AuthenticatedRequest implements HttpGetRequest
|
||||
public static class RateOption {
|
||||
|
||||
private boolean counter = false;
|
||||
private long counterMax = Long.MAX_VALUE;
|
||||
private long counterMax = 0;
|
||||
private long resetValue = 0;
|
||||
|
||||
public RateOption() {
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.util.List;
|
||||
|
||||
import timely.api.response.timeseries.AggregatorsResponse.AggregatorsResponseDeserializer;
|
||||
import timely.api.response.timeseries.AggregatorsResponse.AggregatorsResponseSerializer;
|
||||
import timely.sample.Aggregator;
|
||||
import timely.sample.aggregators.Avg;
|
||||
import timely.sample.aggregators.Count;
|
||||
import timely.sample.aggregators.Dev;
|
||||
@@ -57,6 +58,7 @@ public class AggregatorsResponse {
|
||||
RESPONSE.addAggregator(Min.class.getSimpleName().toLowerCase());
|
||||
RESPONSE.addAggregator(Sum.class.getSimpleName().toLowerCase());
|
||||
RESPONSE.addAggregator(Count.class.getSimpleName().toLowerCase());
|
||||
RESPONSE.addAggregator(Aggregator.NONE);
|
||||
}
|
||||
|
||||
private List<String> aggregators = new ArrayList<>();
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
package timely.netty.http;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.ssl.NotSslRecordException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.netty.Constants;
|
||||
|
||||
public class NonSecureHttpHandler extends ChannelInboundHandlerAdapter implements TimelyHttpHandler {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(NonSecureHttpHandler.class);
|
||||
private final String redirectAddress;
|
||||
|
||||
public NonSecureHttpHandler(Configuration conf) {
|
||||
String timelyHost = conf.getHttp().getHost();
|
||||
int timelyPort = conf.getHttp().getPort();
|
||||
String path = conf.getHttp().getRedirectPath();
|
||||
redirectAddress = "https://" + timelyHost + ":" + timelyPort + path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
ctx.pipeline().remove("ssl");
|
||||
if (cause instanceof NotSslRecordException) {
|
||||
LOG.trace("Received non-SSL request, returning redirect");
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
|
||||
HttpResponseStatus.MOVED_PERMANENTLY, Unpooled.EMPTY_BUFFER);
|
||||
response.headers().set(Names.LOCATION, redirectAddress);
|
||||
LOG.trace(Constants.LOG_RETURNING_RESPONSE, response);
|
||||
ctx.writeAndFlush(response);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package timely.netty.http;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.ssl.OptionalSslHandler;
|
||||
import io.netty.handler.ssl.SslContext;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import timely.Configuration;
|
||||
import timely.netty.Constants;
|
||||
|
||||
public class NonSslRedirectHandler extends OptionalSslHandler implements TimelyHttpHandler {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(NonSslRedirectHandler.class);
|
||||
private final String redirectAddress;
|
||||
|
||||
public NonSslRedirectHandler(Configuration conf, SslContext sslContext) {
|
||||
super(sslContext);
|
||||
String timelyHost = conf.getHttp().getHost();
|
||||
int timelyPort = conf.getHttp().getPort();
|
||||
String path = conf.getHttp().getRedirectPath();
|
||||
redirectAddress = "https://" + timelyHost + ":" + timelyPort + path;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String newSslHandlerName() {
|
||||
return "ssl";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String newNonSslHandlerName() {
|
||||
return "ssl";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ChannelHandler newNonSslHandler(ChannelHandlerContext context) {
|
||||
return new ChannelInboundHandlerAdapter() {
|
||||
|
||||
private HttpResponseEncoder encoder = new HttpResponseEncoder();
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||
LOG.trace("Received non-SSL request, returning redirect");
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
|
||||
HttpResponseStatus.MOVED_PERMANENTLY, Unpooled.EMPTY_BUFFER);
|
||||
response.headers().set(Names.LOCATION, redirectAddress);
|
||||
LOG.trace(Constants.LOG_RETURNING_RESPONSE, response);
|
||||
encoder.write(ctx, response, ctx.voidPromise());
|
||||
ctx.flush();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
|
||||
import io.netty.handler.ssl.SslCompletionEvent;
|
||||
import io.netty.handler.timeout.IdleState;
|
||||
import io.netty.handler.timeout.IdleStateEvent;
|
||||
|
||||
@@ -99,6 +100,11 @@ public class WebSocketRequestDecoder extends MessageToMessageDecoder<WebSocketFr
|
||||
LOG.warn("Channel idle, but no subscription id found on context. Unable to close subscriptions");
|
||||
}
|
||||
}
|
||||
} else if (evt instanceof SslCompletionEvent) {
|
||||
SslCompletionEvent ssl = (SslCompletionEvent) evt;
|
||||
if (!ssl.isSuccess()) {
|
||||
LOG.error("SSL error: {}", ssl.getClass().getSimpleName(), ssl.cause());
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Received unhandled user event {}", evt);
|
||||
}
|
||||
|
||||
+5
-1
@@ -28,6 +28,7 @@ public class WSAddSubscriptionRequestHandler extends SimpleChannelInboundHandler
|
||||
}
|
||||
Map<String, String> tags = null;
|
||||
Long startTime = 0L;
|
||||
Long endTime = 0L;
|
||||
Long delayTime = 5000L;
|
||||
if (add.getTags().isPresent()) {
|
||||
tags = add.getTags().get();
|
||||
@@ -35,10 +36,13 @@ public class WSAddSubscriptionRequestHandler extends SimpleChannelInboundHandler
|
||||
if (add.getStartTime().isPresent()) {
|
||||
startTime = add.getStartTime().get();
|
||||
}
|
||||
if (add.getEndTime().isPresent()) {
|
||||
endTime = add.getEndTime().get();
|
||||
}
|
||||
if (add.getDelayTime().isPresent()) {
|
||||
delayTime = add.getDelayTime().get();
|
||||
}
|
||||
s.addMetric(metric, tags, startTime, delayTime);
|
||||
s.addMetric(metric, tags, startTime, endTime, delayTime);
|
||||
} else {
|
||||
LOG.error("Unknown subscription id, create subscription first");
|
||||
ctx.writeAndFlush(new CloseWebSocketFrame(1003, "Unknown subscription id, create subscription first"));
|
||||
|
||||
+2
@@ -2,6 +2,7 @@ package timely.netty.websocket.subscription;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
|
||||
import timely.api.request.subscription.CloseSubscription;
|
||||
import timely.subscription.Subscription;
|
||||
import timely.subscription.SubscriptionRegistry;
|
||||
@@ -14,6 +15,7 @@ public class WSCloseSubscriptionRequestHandler extends SimpleChannelInboundHandl
|
||||
if (null != s) {
|
||||
s.close();
|
||||
}
|
||||
ctx.writeAndFlush(new CloseWebSocketFrame(1000, "Client requested close."));
|
||||
}
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package timely.netty.websocket.subscription;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
|
||||
import timely.api.response.TimelyException;
|
||||
|
||||
public class WSTimelyExceptionHandler extends SimpleChannelInboundHandler<TimelyException> {
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, TimelyException e) throws Exception {
|
||||
ctx.writeAndFlush(new CloseWebSocketFrame(1008, e.getMessage()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception {
|
||||
ctx.writeAndFlush(new CloseWebSocketFrame(1008, e.getMessage()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package timely.sample;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import timely.api.request.timeseries.QueryRequest;
|
||||
import timely.model.ObjectSizeOf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
public class Aggregation implements Iterable<Sample>, Serializable {
|
||||
|
||||
public static class AggregatedValue implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int count = 0;
|
||||
private double value = 0.0D;
|
||||
|
||||
public void incrementCount() {
|
||||
count++;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("{count: ").append(this.count);
|
||||
buf.append(" value: ").append(this.value).append("}");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
protected transient Aggregator aggregator;
|
||||
protected final String aggregatorClassname;
|
||||
|
||||
protected final TreeMap<Long, AggregatedValue> buckets = new TreeMap<>();
|
||||
|
||||
public Aggregation(Aggregator agg) {
|
||||
Preconditions.checkNotNull(agg, "Aggregator object cannot be null");
|
||||
this.aggregator = agg;
|
||||
this.aggregatorClassname = agg.getClass().getName();
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
try {
|
||||
aggregator = (Aggregator) getClass().getClassLoader().loadClass(aggregatorClassname).newInstance();
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(long ts, double value) {
|
||||
AggregatedValue val = buckets.get(ts);
|
||||
if (null == val) {
|
||||
buckets.put(ts, val = new AggregatedValue());
|
||||
}
|
||||
val.setValue(aggregator.aggregate(val.getValue(), val.getCount(), value));
|
||||
val.incrementCount();
|
||||
}
|
||||
|
||||
public void merge(Aggregation other) {
|
||||
for (Map.Entry<Long, AggregatedValue> e : other.buckets.entrySet()) {
|
||||
AggregatedValue thisVal = buckets.get(e.getKey());
|
||||
if (null == thisVal) {
|
||||
buckets.put(e.getKey(), e.getValue());
|
||||
} else {
|
||||
thisVal.setCount(thisVal.getCount() + e.getValue().getCount());
|
||||
thisVal.setValue(aggregator.aggregate(thisVal.getValue(), thisVal.getCount(), e.getValue().getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Sample> iterator() {
|
||||
return new Iterator<Sample>() {
|
||||
|
||||
Iterator<Long> keys = buckets.keySet().iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return keys.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sample next() {
|
||||
long time = keys.next();
|
||||
AggregatedValue val = buckets.get(time);
|
||||
double value = aggregator.last(val.getValue(), val.getCount());
|
||||
return new Sample(time, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringBuilder tsb = new ToStringBuilder(this);
|
||||
tsb.append("aggregator", this.aggregatorClassname);
|
||||
tsb.append("values={");
|
||||
for (Map.Entry<Long, AggregatedValue> e : this.buckets.entrySet()) {
|
||||
tsb.append(e.getKey()).append("=").append(e.getValue()).append(", ");
|
||||
}
|
||||
tsb.append("}");
|
||||
return tsb.toString();
|
||||
}
|
||||
|
||||
public static Aggregation combineAggregation(Collection<Aggregation> samples, QueryRequest.RateOption rateOption) {
|
||||
List<Aggregation> sampleList = new ArrayList<>(samples.size());
|
||||
if (samples.isEmpty()) {
|
||||
throw new IllegalArgumentException("Empty samples to combine");
|
||||
}
|
||||
for (Aggregation a : samples) {
|
||||
sampleList.add(a);
|
||||
}
|
||||
Iterator<Aggregation> iter = sampleList.iterator();
|
||||
Aggregation result = iter.next();
|
||||
while (iter.hasNext()) {
|
||||
result.merge(iter.next());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public int getNumBuckets() {
|
||||
return buckets.size();
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@ import timely.sample.aggregators.Sum;
|
||||
|
||||
public interface Aggregator {
|
||||
|
||||
String NONE = "none";
|
||||
|
||||
/**
|
||||
* Given the current value, and the current count, incorporate the new value
|
||||
* into current and return the result.
|
||||
@@ -36,6 +38,9 @@ public interface Aggregator {
|
||||
double last(double current, int count);
|
||||
|
||||
static Class<? extends Aggregator> getAggregator(String aggregatorName) {
|
||||
if (aggregatorName == null) {
|
||||
return null;
|
||||
}
|
||||
switch (aggregatorName) {
|
||||
case "sum":
|
||||
return Sum.class;
|
||||
@@ -50,7 +55,7 @@ public interface Aggregator {
|
||||
case "count":
|
||||
return Count.class;
|
||||
default:
|
||||
return Avg.class;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 127 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user