Compare commits

...
38 Commits
Author SHA1 Message Date
Bill Oley eaddee0d78 closes #164 - Limit memory consumed by DownsampleIterator and return iteratively on time bucket boundaries 2018-01-24 15:18:50 -05:00
Bill Oley e947c1a497 cwImproved implementation of DownsampleIterator.MemoryEstimator 2018-01-16 14:39:31 -05:00
Bill Oley 4e7e07601b More work 2018-01-12 16:26:56 -05:00
Bill Oley 679a92c5b5 Initial work 2018-01-12 15:59:38 -05:00
Bill Oley 3f3b605c63 re #160 - Close and invalidate CloseableHttpClient so that we can recover from bad connections 2017-11-17 10:19:11 -05:00
Bill Oley 5580a2fa66 re #160 - refactor config for WriteNSQPlugin, add socket timeouts to WriteTimelyPlugin 2017-11-09 16:08:08 -05:00
Bill Oley 1a54c3ada3 closes #161 - Add handling of a min and max percentage of a rolling average to python analytic 2017-11-03 12:20:13 -04:00
Bill Oley 2080764e0d closes #162 - Python analytic should be able to convert a counter metric into a rate 2017-11-03 09:57:38 -04:00
Bill Oley e7dade04ee closes #160 - Improve reliability and error recovery of WriteNSQPlugin and WriteTimelyPlugin 2017-10-31 14:52:49 -04:00
Bill Oley 7ed337483e fixes #159 TimelyAnalytic error when analyticConfig.groupByColumn is None 2017-10-18 12:21:28 -04:00
Bill Oley b070bc3c47 closes #158 Package python code so that it can be deployed and managed with pip 2017-10-18 11:10:41 -04:00
Bill Oley 51f9103741 closes #156: Use object pools in WriteNSQPlugin and WriteTimelyPlugin to support multithreaded use 2017-10-02 13:56:16 -04:00
Bill Oley a97fa83e2f closes #157 - Add query metrics to internal metrics 2017-09-26 12:59:59 -04:00
Drew Farris 0b5c3544db Merge pull request #154 from drewfarris/docker-update
Docker & Grafana updates for 0.0.6-SNAPSHOT
2017-08-15 16:21:15 -04:00
Dave Marion 186b60756a fixes #155 - log more information on ssl error 2017-08-14 09:18:32 -04:00
Drew Farris 133a6bf5cf Bumped grafana plugin reference to 0.0.6-SNAPSHOT 2017-08-12 12:24:51 -04:00
Drew Farris b684d7eefe Updated Docker config for 0.0.6-SNAPSHOT and grafana 4.4.3 2017-08-12 12:21:34 -04:00
Dave Marion 73f1603f1e Bump version to 0.0.6-SNAPSHOT 2017-08-11 11:24:36 -04:00
Dave Marion 9267e0c915 Change pom versions for 0.0.5 tag 2017-08-11 11:21:44 -04:00
Dave Marion 1ce49628e5 Closes #123 - Updates to Timely App and Dashboards for latest Grafana 2017-08-08 10:30:38 -04:00
Bill Oley acad3af083 fixes #149: Add funtionality to CollectDPluginParent to handle GenericJMX metrics 2017-08-01 16:39:32 -04:00
Dave Marion b4635f1a55 re #123 - update pairs() to toPairs() 2017-07-12 14:15:00 -04:00
alerman 4c1ede04df Update datasource.js for grafana 4 (#147)
fixes #123 - Update _.all to _.every as the newer version of lodash has changed the term. This fixes error seen with Timely Standalon and Grafana >4.2
2017-07-12 13:44:49 -04:00
Dave Marion 2841b0a3e9 closes #143 : set sock to null in close, fixed some warnings 2017-05-04 16:09:57 -04:00
Dave Marion 6efa13909f closes #144: Update to Netty 4.0.46.Final 2017-05-04 12:45:42 -04:00
Dave Marion 368c572c67 closes #141 - build collectd plugins only when collectd profile is activated 2017-04-14 09:34:17 -04:00
Dave Marion 554baf6af7 Updated readme to new markdown syntax 2017-04-13 12:59:50 -04:00
Dave Marion 1ef11799be fixes #138 - don't close source until all subscriptions have completed. 2017-03-24 08:52:51 -04:00
Dave Marion 16b664297d fixes #138 - synchronize the response list and exit the subscription source when the last message is received 2017-03-23 16:35:16 -04:00
Bill Oley 4277b63bc3 re #130 - Improvements to python code 2017-03-22 10:57:42 -04:00
Bill Oley 5a9ad3cb27 re #130 - Corrections to python code 2017-03-20 08:22:34 -04:00
Bill Oley f990e89ab3 re #130 - Improvements to python code 2017-03-17 17:05:19 -04:00
Bill Oley c01ac80f23 re #130 - Corrections to python code 2017-03-16 08:59:20 -04:00
Bill Oley 35e8f99d09 re #130 - Additional development on Python client and analytics 2017-03-15 18:21:43 -04:00
Bill Oley 847144d236 re #130 - Update to seaborn graphing for python client 2017-02-13 17:55:22 -05:00
Ivan Bella b3bfbc1e1f fixes #136 removed the encoding and decoding of tag names and values from the tag parser 2017-02-06 13:48:07 -05:00
Bill Oley 8d86e3894a re #130 - Try seaborn graphing to generate png file programmatically - in progress 2017-02-03 16:43:47 -05:00
Dave Marion 99b9181902 Bumped version to 0.0.5-SNAPSHOT 2017-02-02 10:48:56 -05:00
73 changed files with 5093 additions and 3662 deletions

No files matched your search

+1 -1
View File
@@ -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
+1 -1
View File
@@ -23,7 +23,7 @@ under the License.
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.4</version>
<version>0.0.6-SNAPSHOT</version>
</parent>
<properties>
<flink.version>1.1.4</flink.version>
@@ -51,6 +51,7 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
private final String[] metrics;
private final SummarizationJobParameters jp;
private final long window;
private final AtomicInteger subscriptionsRemaining;
public SubscriptionSource(SummarizationJobParameters jp) {
this.jp = jp;
@@ -58,6 +59,7 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
end = jp.getEndTime();
metrics = jp.getMetrics();
window = jp.getSummarizationInterval().toMilliseconds();
subscriptionsRemaining = new AtomicInteger(metrics.length);
}
@Override
@@ -102,7 +104,8 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
@Override
public void onMessage(final String message) {
LOG.info("Message received on Websocket session {}: {}", session.getId(), 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,
@@ -113,9 +116,10 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
if (response.isComplete()) {
LOG.info("Received last message.");
ctx.emitWatermark(new Watermark(Long.MAX_VALUE));
subscriptionsRemaining.getAndDecrement();
return;
}
LOG.trace("Sending metric: {}", response);
LOG.trace("Received metric: {}", response);
long time = response.getTimestamp();
ctx.collectWithTimestamp(response, time);
dateTimeAccumulator.add(formatter.format(new Date(response.getTimestamp())));
@@ -178,7 +182,7 @@ public class SubscriptionSource extends RichSourceFunction<MetricResponse> imple
LOG.info("Adding subscription for {}", m);
client.addSubscription(m, null, start, end, 5000);
}
while (!client.isClosed()) {
while (!client.isClosed() && subscriptionsRemaining.get() > 0) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
+61 -1
View File
@@ -5,8 +5,12 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.4</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>
@@ -99,6 +103,62 @@
<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>
@@ -38,6 +38,7 @@ public class UdpClient implements AutoCloseable {
public void close() throws IOException {
if (null != sock) {
sock.close();
sock = null;
}
}
@@ -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,7 +4,6 @@ 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;
@@ -11,8 +11,7 @@ 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 NOTE: the tag and the value are both URL
* encoded and subsequently URL decoded.
* tag1=val1,tag2=val2,tag3=val3.
*/
public class TagListParser implements Parser<List<Tag>>, Combiner<Collection<Tag>> {
@@ -4,16 +4,11 @@ import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import timely.model.Tag;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
/**
* Parses tag1=val1 into a {@code Tag} Combines {@code Tag} into {@code String}
* of tag1=val1 NOTE: the tag and the value are both URL encoded and
* subsequently URL decoded.
* of tag1=val1
*/
public class TagParser implements Parser<Tag>, Combiner<Tag> {
@@ -26,28 +21,12 @@ public class TagParser implements Parser<Tag>, Combiner<Tag> {
if (parts.size() != 2) {
throw new IllegalArgumentException("Invalid tag format: " + t);
}
return new Tag(unescape(parts.get(0)), unescape(parts.get(1)));
return new Tag(parts.get(0), parts.get(1));
}
@Override
public String combine(Tag t) {
return equalsJoiner.join(escape(t.getKey()), escape(t.getValue()));
}
private String escape(String tag) {
try {
return URLEncoder.encode(tag, "UTF8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
private String unescape(String tag) {
try {
return URLDecoder.decode(tag, "UTF8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return equalsJoiner.join(t.getKey(), t.getValue());
}
}
-128
View File
@@ -1,128 +0,0 @@
import time
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
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 = dataFrame.pivot_table(index="date", columns=groupByColumn, values=metric)
return dataFrame
def resample(df, sample, how='mean', fill_method='ffill'):
dataFrame = pandas.DataFrame(df, copy=True)
if dataFrame is not None:
if sample is not None:
dataFrame = dataFrame.resample(sample, how=how, fill_method=fill_method)
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(dataFrame['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, metric, 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 = None
if analyticConfig.sample is None:
title = metric
else:
title = metric + '\rsample ' + analyticConfig.sample
dataFrame['date'] = dataFrame.index
layoutConfig = dict(
title=title,
autosize=False,
width=1000,
height=700,
showlegend=True,
xaxis=dict(
autorange=True,
tickangle=-45
),
yaxis=dict(
autorange=True,
title=title
)
)
layoutConfig.update(graphConfig)
layout = go.Layout(layoutConfig)
data = None
for col in df[analyticConfig.groupByColumn].unique():
tempDataFrame = dataFrame.loc[dataFrame[analyticConfig.groupByColumn] == col]
addlColConfig = graphConfig.get(col, graphConfig.get('default', dict()))
config = dict(
name=col,
x=tempDataFrame.index,
y=tempDataFrame[metric],
hoverinfo='x+y+text',
text=col
)
config.update(addlColConfig)
s = go.Scatter(config)
if data is None:
data = [s]
else:
data.append(s)
now = datetime.now(tz=utc)
format = "%Y%m%d%H%M%S"
nowStr = time.strftime(format, now.timetuple())
fileNameBase = analyticConfig.output_dir + "/" + metric
if analyticConfig.sample is not None:
fileNameBase += "-" + analyticConfig.sample
if analyticConfig.how is not None:
fileNameBase += "-" + analyticConfig.how
fig = go.Figure(data=data, layout=layout)
if notebook:
py.iplot(fig, filename=fileNameBase+'-'+nowStr, show_link=False)
else:
py.plot(fig, output_type='file', filename=fileNameBase+'-'+nowStr+'.html', auto_open=False, show_link=False)
def datetime2graphdays(dt):
return mdates.epoch2num((time.mktime(dt.timetuple()) / 86400) * mdates.SEC_PER_DAY)
-123
View File
@@ -1,123 +0,0 @@
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
from TimelyMetric import graph
import syslog
syslog.openlog("TimelyNotifications")
#def __init__(self, file, send_to, subject, text, analyticConfig, notebook):
class TimelyAlert():
def __init__(self, timelyMetric, dataFrame, seriesConfig, analyticConfig, notebook):
self.timelyMetric = timelyMetric
self.dataFrame = dataFrame
self.seriesConfig = seriesConfig
self.analyticConfig = analyticConfig
self.notebook = notebook
def createFilename(self, metric, config):
metricTitle = metric
if config.sample is not None:
sampleTitle = config.sample + "-" + config.how
filename = metricTitle
if sampleTitle != "":
filename += "-" + sampleTitle
return filename
def createTitle(self, metric, config):
if config.orCondition:
condition = "OR"
else:
condition = "AND"
metricTitle = metric
sampleTitle = ""
alertTitle = ""
if config.sample is not None:
sampleTitle = config.sample + " " + config.how + " samples"
if config.min_threshold is not None:
if alertTitle != "":
alertTitle += " " + condition + " "
alertTitle += "(y < " + str(config.min_threshold) + ")"
if config.max_threshold is not None:
if alertTitle != "":
alertTitle += " " + condition + " "
alertTitle += "(y > " + str(config.max_threshold) + ")"
if config.alert_percentage is not None:
if alertTitle != "":
alertTitle += " " + condition + " "
if config.alert_percentage > 0:
alertTitle += "(y > " + str(config.alert_percentage) + "% above " + str(config.rolling_average) + " sample average)"
else:
alertTitle += "(y < " + str(-config.alert_percentage) + "% below " + str(config.rolling_average) + " sample average)"
title = metricTitle
if sampleTitle != "":
title += "\n" + sampleTitle
if alertTitle != "":
title += "\n" + alertTitle
return title
def notify(self, send_from, send_to, server="127.0.0.1"):
self.graph()
return
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 graph(self):
graphConfig = {}
graphConfig["title"] = self.createTitle(self.timelyMetric.metric, self.analyticConfig)
graph(self.analyticConfig, self.dataFrame, self.timelyMetric.metric, seriesConfig=self.seriesConfig, graphConfig=graphConfig, notebook=self.notebook)
def main():
#syslog.syslog(syslog.LOG_ALERT, "Example message")
a = TimelyAlert(None, None, None, None, False)
a.email_alert("wwoley@localhost", ["wwoley@localhost"], "Test1", "This is a sendmail test")
if __name__ == '__main__':
main()
-105
View File
@@ -1,105 +0,0 @@
import TimelyMetric
from TimeDateRange import TimeDateRange
from TimeDateRange import UTC
from datetime import datetime
import pandas
import re
import plotly
from TimelyAlert import TimelyAlert
utc = UTC()
plotly.offline.init_notebook_mode()
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 find_alerts(timelyMetric, analyticConfig, notebook=False):
if analyticConfig.groupByColumn is None:
return
df = timelyMetric.getDataFrame()
graphDF = TimelyMetric.pivot(df, timelyMetric.metric, groupByColumn=analyticConfig.groupByColumn)
if analyticConfig.sample is not None:
graphDF = TimelyMetric.resample(graphDF, analyticConfig.sample, how=analyticConfig.how)
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)
graphDF_avg = pandas.DataFrame(graphDF, copy=True)
combined = pandas.DataFrame()
seriesConfig = {}
for i in graphDF_avg.columns:
col = str(i)
result = True
if analyticConfig.orCondition:
result = False
if analyticConfig.min_threshold is not None:
currCondition = graphDF[col].astype(float) < analyticConfig.min_threshold
result = addCondition(analyticConfig.orCondition, result, currCondition)
if analyticConfig.max_threshold is not None:
currCondition = graphDF[col].astype(float) > analyticConfig.max_threshold
result = addCondition(analyticConfig.orCondition, result, currCondition)
graphDF_avg = TimelyMetric.rolling_average(graphDF_avg, str(i), rolling_average=analyticConfig.rolling_average)
if (analyticConfig.alert_percentage is not None) and (analyticConfig.rolling_average is not None):
if analyticConfig.alert_percentage > 0:
multiple = 1.0 + (float(abs(analyticConfig.alert_percentage)) / float(100))
currCondition = graphDF[col].astype(float) > (graphDF_avg[col].astype(float) * multiple)
result = addCondition(analyticConfig.orCondition, result, currCondition)
if analyticConfig.alert_percentage < 0:
multiple = 1.0 - (float(abs(analyticConfig.alert_percentage)) / float(100))
if multiple > 0:
currCondition = graphDF[col].astype(float) < (graphDF_avg[col].astype(float) * multiple)
result = addCondition(analyticConfig.orCondition, result, currCondition)
exceptional = graphDF.loc[result, col]
if (analyticConfig.display.lower() == "all") or (analyticConfig.display.lower() == "alerts" and exceptional.size > 0):
combined[col] = graphDF[col]
if (analyticConfig.display.lower() == "all") or (analyticConfig.display.lower() == "alerts" and exceptional.size > 0 and analyticConfig.alert_percentage is not None and analyticConfig.rolling_average is not None):
combined[col+'_avg'] = graphDF_avg[col]
if (exceptional.size > 0):
combined[col+'_warn'] = exceptional.dropna()
seriesConfig[col+'_warn'] = {
"mode" : "markers",
"marker" : {
"symbol" : "hash-open",
"color" : "red"
}
}
timelyAlert = None
if not combined.empty:
combined = TimelyMetric.unpivot(combined, timelyMetric.metric, groupByColumn=analyticConfig.groupByColumn)
combined = combined.sort_index()
combined = combined.sort_values(['date', analyticConfig.groupByColumn])
timelyAlert = TimelyAlert(timelyMetric, combined, seriesConfig, analyticConfig, notebook)
return timelyAlert
@@ -1,25 +0,0 @@
class TimelyAnalyticConfiguration():
def __init__(self, analyticConfig):
self.groupByColumn = analyticConfig.get('groupByColumn', None)
self.includeColRegex = analyticConfig.get('includeColRegex', None)
self.excludeColRegex = analyticConfig.get('excludeColRegex', None)
self.sample = analyticConfig.get('sample', None)
self.how = analyticConfig.get('how', 'mean')
self.rolling_average = analyticConfig.get('rolling_average', None)
self.min_threshold = analyticConfig.get('min_threshold', None)
self.max_threshold = analyticConfig.get('max_threshold', None)
self.alert_percentage = analyticConfig.get('alert_percentage', 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')
-23
View File
@@ -1,23 +0,0 @@
import TimelyMetric
import TimelyAnalytic
hostport = "127.0.0.1:4244"
timelyMetric = TimelyMetric.TimelyMetric(hostport, '', None, None, None, 48, None).fetch()
TimelyAnalytic.find_alerts(timelyMetric, TimelyAnalyticConfiguration({
'includeColRegex' : None,
'excludeColRegex' : None,
'groupByColumn' : 'instance',
'sample' : '10min',
'how' : 'mean',
'rolling_average' : 12,
'min_threshold' : None,
'max_threshold' : None,
'alert_percentage' : 25,
'boolean' : 'and'
'display' : 'all',
'output_dir' : '/path/to/output'
}))
if alert is not None:
alert.graph()
+12
View File
@@ -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
@@ -2,6 +2,8 @@ import time
from datetime import datetime
from datetime import timedelta
from datetime import tzinfo
from pandas.tslib import Timedelta
import pandas
class TimeDateError(ValueError):
@@ -56,17 +58,17 @@ class TimeDateRange:
return None
return time.strftime(self.format, self.endDt.timetuple())
def __init__(self, beginStr, endStr, hours, format="%Y%m%d-%H%M%S"):
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 hours != None:
raise TimeDateError("You can not privide a begin, end, and hours")
elif (beginStr == None and endStr == None and hours == None) or (hours == None and beginStr == None):
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 hours == None:
if period == None:
# calculate begin time
beginTuple = time.strptime(beginStr, self.format)
self.beginDt = datetime(*beginTuple[0:6], tzinfo=utc)
@@ -81,10 +83,12 @@ class TimeDateRange:
if self.endDt > now:
self.endDt = now
else:
# hours must be specified
rangeInSec = hours * 3600
# period must be specified
td = pandas.to_timedelta(period)
rangeInSec = td.total_seconds()
if beginStr == None:
# calculate begin time from end tme and hours
# calculate begin time from end tme and period
# calculate end time
# end is either specified or now
@@ -99,7 +103,7 @@ class TimeDateRange:
self.beginDt = self.endDt - timedelta(milliseconds=rangeInSec * 1000)
else:
# calculate end time from begin tme and hours
# calculate end time from begin tme and period
# calculate begin time
self.beginDt = datetime(*time.strptime(beginStr, self.format)[0:6], tzinfo=utc)
@@ -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
@@ -73,7 +73,7 @@ class TimelyMetric(TimelyWebSocketClient):
client = None
endtime = None
def __init__(self, hostport, metric, tags, beginStr, endStr, hours, sample):
def __init__(self, hostport, metric, tags, beginStr, endStr, period, sample):
self.series = pandas.Series()
self.metric = metric
self.tags = tags
@@ -81,10 +81,9 @@ class TimelyMetric(TimelyWebSocketClient):
self.debug = False
self.dataFrame = None
self.data = []
self.timeDateRange = TimeDateRange(beginStr, endStr, period)
timeDateRange = TimeDateRange(beginStr, endStr, hours)
TimelyWebSocketClient.__init__(self, hostport, metric, tags, timeDateRange.getBeginMs(), timeDateRange.getEndMs())
TimelyWebSocketClient.__init__(self, hostport, metric, tags, self.timeDateRange.getBeginMs(), self.timeDateRange.getEndMs())
def debugOn(self):
self.debug = True
@@ -135,8 +134,9 @@ class TimelyMetric(TimelyWebSocketClient):
global client
self.dataFrame = pandas.DataFrame(self.data)
self.dataFrame = self.dataFrame.set_index(self.dataFrame['date'].apply(lambda x: pandas.DatetimeIndex([x])))
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()
@@ -146,18 +146,22 @@ class TimelyMetric(TimelyWebSocketClient):
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):
graph(self.dataFrame, self.metric, sample=self.sample, how=self.how, groupByColumn=groupByColumn)
return graph(self.dataFrame, self, sample=self.sample, how=self.how, groupByColumn=groupByColumn)
def main():
hours = None
period = None
beginStr = None
endStr = None
@@ -168,18 +172,18 @@ def main():
groupByColumn = None
try:
argv = sys.argv
options, remainder = getopt.getopt(argv[1:], 'h', ['metric=', 'tags=', 'hours=', 'groupByColumn=', 'begin=', 'end=', 'sample=', 'how=', 'hostport='])
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> --hours=<hours>, --groupByColumn=<groupByColumn>, --sample=<sample_period> --how=<mean|min|max>')
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> --hours=<hours>, --groupByColumn=<groupByColumn>, --sample=<sample_period> --how=<mean|min|max>')
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 ("--hours"):
hours = int(arg)
elif opt in ("--period"):
period = arg
elif opt in ("--begin"):
beginStr = arg
elif opt in ("--end"):
@@ -194,13 +198,13 @@ def main():
hostport = arg
try:
timelyMetric = TimelyMetric(hostport, metric, tags, beginStr, endStr, hours, sample).fetch()
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, metric, sample=sample, groupByColumn=groupByColumn, graphConfig={}, notebook=False)
graph(dataFrame, timelyMetric, sample=sample, groupByColumn=groupByColumn, graphConfig={}, notebook=False)
except TimeDateError as e:
print(e.message)
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)
@@ -20,15 +20,6 @@ public class TagListParserTest {
Assert.assertEquals(new Tag("tag2", "value2"), tags.get(1));
}
@Test
public void testListParseEncoded() {
String value = "tag%2C%3D%31=value%2C%3D%31,tag%2C%3D%32=value%2C%3D%32";
List<Tag> tags = new TagListParser().parse(value);
Assert.assertEquals(2, tags.size());
Assert.assertEquals(new Tag("tag,=1", "value,=1"), tags.get(0));
Assert.assertEquals(new Tag("tag,=2", "value,=2"), tags.get(1));
}
@Test
public void testListCombine() {
List<Tag> tags = new ArrayList<>();
@@ -38,15 +29,6 @@ public class TagListParserTest {
Assert.assertEquals("tag1=value1,tag2=value2", combined);
}
@Test
public void testListCombineEncoded() {
List<Tag> tags = new ArrayList<>();
tags.add(new Tag("tag,=1", "value,=1"));
tags.add(new Tag("tag,=2", "value,=2"));
String combined = new TagListParser().combine(tags);
Assert.assertEquals("tag%2C%3D1=value%2C%3D1,tag%2C%3D2=value%2C%3D2", combined);
}
@Test
public void testListCombineMap() {
Map<String, String> map = new TreeMap<>();
+5 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.4</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>
@@ -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;
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.4</version>
<version>0.0.6-SNAPSHOT</version>
</parent>
<artifactId>collectd-plugin-parent</artifactId>
<dependencies>
@@ -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 = ".";
@@ -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();
@@ -170,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 {
@@ -203,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);
@@ -263,7 +264,7 @@ public class PluginParentTest {
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_name=proxy1 service_name=server1 sample=value sampleType=GAUGE\n",
result);
@@ -284,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);
@@ -306,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);
@@ -327,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);
+5 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.4</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>
@@ -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
}
}
@@ -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;
}
}
@@ -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() {
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.4</version>
<version>0.0.6-SNAPSHOT</version>
</parent>
<artifactId>timely-common</artifactId>
<dependencies>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.4</version>
<version>0.0.6-SNAPSHOT</version>
</parent>
<build>
<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
}
+2 -2
View File
@@ -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
View File
@@ -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
+3 -3
View File
@@ -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.4-SNAPSHOT",
"updated": "2016-10-27"
"version": "0.0.6-SNAPSHOT",
"updated": "2017-08-11"
},
"includes": [
@@ -34,7 +34,7 @@
],
"dependencies": {
"grafanaVersion": "3.x.x",
"grafanaVersion": "4.x.x",
"plugins": []
}
+3 -3
View File
@@ -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.4-SNAPSHOT",
"updated": "2016-10-27"
"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));
+22 -6
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.4</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,9 +26,6 @@
<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>
@@ -47,6 +44,7 @@
<version.collectd>5.5.1</version.collectd>
<version.commons-collections4>4.1</version.commons-collections4>
<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>
@@ -59,8 +57,8 @@
<version.jsoup>1.9.2</version.jsoup>
<version.junit>4.12</version.junit>
<version.log4j>2.6.2</version.log4j>
<version.netty>4.0.38.Final</version.netty>
<version.netty-tcnative>1.1.33.Fork18</version.netty-tcnative>
<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.21</version.slf4j>
<version.spring-boot>1.4.1.RELEASE</version.spring-boot>
@@ -202,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>
@@ -509,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>
+1 -6
View File
@@ -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
+1
View File
@@ -15,6 +15,7 @@ timely:
bufferSize: 52428800
scan:
threads: 4
max-downsample-memory: 10000000
security:
session-max-age: 86400
allow-anonymous-access: true
+1
View File
@@ -15,6 +15,7 @@ timely:
bufferSize: 52428800
scan:
threads: 4
max-downsample-memory: 10000000
security:
session-max-age: 86400
allow-anonymous-access: true
+1
View File
@@ -15,6 +15,7 @@ timely:
bufferSize: 52428800
scan:
threads: 4
max-downsample-memory: 10000000
security:
session-max-age: 86400
allow-anonymous-access: false
+3 -3
View File
@@ -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:
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.4</version>
<version>0.0.6-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
@@ -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 {
+2 -3
View File
@@ -63,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;
@@ -473,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));
@@ -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);
}
@@ -3,6 +3,7 @@ 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;
@@ -140,4 +141,7 @@ public class Aggregation implements Iterable<Sample>, Serializable {
return result;
}
public int getNumBuckets() {
return buckets.size();
}
}
@@ -3,6 +3,7 @@ package timely.sample;
import com.google.common.base.Preconditions;
import org.apache.commons.lang3.builder.ToStringBuilder;
import timely.api.request.timeseries.QueryRequest.RateOption;
import timely.model.ObjectSizeOf;
import java.io.Serializable;
import java.util.ArrayList;
@@ -64,5 +65,4 @@ public class Downsample extends Aggregation implements Iterable<Sample>, Seriali
}
return result;
}
}
@@ -5,10 +5,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
import org.apache.accumulo.core.client.IteratorSetting;
import org.apache.accumulo.core.data.Key;
@@ -17,8 +14,10 @@ import org.apache.accumulo.core.iterators.IteratorEnvironment;
import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
import org.apache.accumulo.core.iterators.WrappingIterator;
import org.apache.log4j.Logger;
import timely.adapter.accumulo.MetricAdapter;
import timely.model.Metric;
import timely.model.ObjectSizeOf;
import timely.model.Tag;
import timely.api.response.TimelyException;
import timely.sample.Aggregator;
@@ -30,20 +29,125 @@ public class DownsampleIterator extends WrappingIterator {
private static final String START = "downsample.start";
private static final String END = "downsample.end";
private static final String PERIOD = "downsample.period";
private static final String MAX_DOWNSAMPLE_MEMORY = "downsample.maxDownsampleMemory";
private static final String AGGCLASS = "downsample.aggclass";
private DownsampleFactory factory;
private final Map<Set<Tag>, Downsample> value = new HashMap<>();
private long start;
private long end;
private long period;
private Key last;
private MemoryEstimator memoryEstimator = null;
static public class MemoryEstimator {
private boolean newBucket = false;
private long start;
private long period;
private long startOfCurrentBucket;
private long bucketsCompleted = 0;
private long bytesPerBucket = 0;
boolean highVolumeBuckets = false;
long maxDownsampleMemory = 0; // max aggregation memory (bytes) before
// current batch is returned (after
// bucket is complete)
LinkedList<Long> percentageChecks = new LinkedList<>();
public void reset() {
newBucket = false;
bucketsCompleted = 0;
bytesPerBucket = 0;
percentageChecks.add(5l);
percentageChecks.add(25l);
percentageChecks.add(50l);
percentageChecks.add(75l);
}
public MemoryEstimator(long maxDownsampleMemory, long start, long period) {
this.maxDownsampleMemory = maxDownsampleMemory;
this.start = start;
this.period = period;
this.startOfCurrentBucket = this.start;
reset();
}
public double getMemoryUsedPercentage() {
return (bucketsCompleted * bytesPerBucket) / (double) maxDownsampleMemory * 100;
}
public long getBucketsCompleted() {
return bucketsCompleted;
}
public long getBytesPerBucket() {
return bytesPerBucket;
}
public boolean isHighVolumeBuckets() {
return highVolumeBuckets;
}
public boolean shouldReturnBasedOnMemoryUsage(long timestamp, Object value) {
boolean shouldReturn = false;
if (maxDownsampleMemory >= 0) {
sample(timestamp);
if (isNewBucket()) {
bucketsCompleted++;
double memoryUsedPercentage = getMemoryUsedPercentage();
if (memoryUsedPercentage >= 100) {
shouldReturn = true;
} else {
boolean checkMemoryNow = false;
Long check = percentageChecks.peek();
if (check != null && memoryUsedPercentage >= check) {
checkMemoryNow = true;
percentageChecks.removeFirst();
}
// recalculate bytesPerBucket
if (bytesPerBucket == 0 || highVolumeBuckets || checkMemoryNow) {
long memoryUsed = ObjectSizeOf.Sizer.getObjectSize(value);
bytesPerBucket = memoryUsed / bucketsCompleted;
}
// bucket average greater than 10% of max
highVolumeBuckets = (bytesPerBucket / (double) maxDownsampleMemory) >= 0.1;
shouldReturn = false;
}
}
}
return shouldReturn;
}
public boolean isNewBucket() {
return newBucket;
}
private void sample(long timestamp) {
if (timestamp >= (startOfCurrentBucket + period)) {
newBucket = true;
startOfCurrentBucket = timestamp - ((timestamp - start) % period);
} else {
newBucket = false;
}
}
}
@SuppressWarnings("unchecked")
@Override
public void init(SortedKeyValueIterator<Key, Value> source, Map<String, String> options, IteratorEnvironment env)
throws IOException {
super.init(source, options, env);
long start = Long.parseLong(options.get(START));
long end = Long.parseLong(options.get(END));
long period = Long.parseLong(options.get(PERIOD));
start = Long.parseLong(options.get(START));
end = Long.parseLong(options.get(END));
period = Long.parseLong(options.get(PERIOD));
// default = 100 MB
long maxDownsampleMemory = -1;
if (options.containsKey(MAX_DOWNSAMPLE_MEMORY)) {
maxDownsampleMemory = Long.parseLong(options.get(MAX_DOWNSAMPLE_MEMORY));
}
memoryEstimator = new MemoryEstimator(maxDownsampleMemory, start, period);
String aggClassname = options.get(AGGCLASS);
Class<?> aggClass;
try {
@@ -56,26 +160,38 @@ public class DownsampleIterator extends WrappingIterator {
@Override
public boolean hasTop() {
while (super.hasTop()) {
last = super.getTopKey();
Metric metric = MetricAdapter.parse(super.getTopKey(), super.getTopValue());
Set<Tag> tags = new HashSet<Tag>(metric.getTags());
Downsample sample = value.get(tags);
if (sample == null) {
if (super.hasTop()) {
while (super.hasTop()) {
Key topKey = super.getTopKey();
Value topValue = super.getTopValue();
Metric metric = MetricAdapter.parse(topKey, topValue);
long timestamp = metric.getValue().getTimestamp();
if (memoryEstimator.shouldReturnBasedOnMemoryUsage(timestamp, value)) {
break;
}
last = topKey;
Set<Tag> tags = new HashSet<Tag>(metric.getTags());
Downsample sample = value.get(tags);
if (sample == null) {
try {
value.put(tags, sample = factory.create());
} catch (TimelyException e) {
throw new RuntimeException(e);
}
}
sample.add(metric.getValue().getTimestamp(), metric.getValue().getMeasure());
try {
value.put(tags, sample = factory.create());
} catch (TimelyException e) {
throw new RuntimeException(e);
super.next();
} catch (IOException e) {
throw new RuntimeException("Downstream next() failed", e);
}
}
sample.add(metric.getValue().getTimestamp(), metric.getValue().getMeasure());
try {
super.next();
} catch (IOException e) {
throw new RuntimeException("Downstream next() failed", e);
}
return last != null;
} else {
return false;
}
return last != null;
}
@Override
@@ -89,6 +205,9 @@ public class DownsampleIterator extends WrappingIterator {
ObjectOutputStream out = new ObjectOutputStream(bos)) {
out.writeObject(value);
out.flush();
// empty for next batch of downsamples
value.clear();
memoryEstimator.reset();
return new Value(bos.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
@@ -97,13 +216,17 @@ public class DownsampleIterator extends WrappingIterator {
@Override
public void next() throws IOException {
last = null;
if (!super.hasTop()) {
last = null;
}
}
public static void setDownsampleOptions(IteratorSetting is, long start, long end, long period, String classname) {
public static void setDownsampleOptions(IteratorSetting is, long start, long end, long period,
long maxDownsampleMemory, String classname) {
is.addOption(START, "" + start);
is.addOption(END, "" + end);
is.addOption(PERIOD, "" + period);
is.addOption(MAX_DOWNSAMPLE_MEMORY, "" + maxDownsampleMemory);
is.addOption(AGGCLASS, classname);
}
@@ -80,7 +80,6 @@ import timely.model.Metric;
import timely.model.Tag;
import timely.sample.Aggregation;
import timely.sample.Aggregator;
import timely.sample.Downsample;
import timely.sample.Sample;
import timely.sample.aggregators.Avg;
import timely.sample.iterators.AggregationIterator;
@@ -126,6 +125,7 @@ public class DataStoreImpl implements DataStore {
private final InternalMetrics internalMetrics = new InternalMetrics();
private final Timer internalMetricsTimer = new Timer(true);
private final int scannerThreads;
private final long maxDownsampleMemory;
private final BatchWriterConfig bwConfig;
private final List<BatchWriter> writers = new ArrayList<>();
private final ThreadLocal<BatchWriter> metaWriter = new ThreadLocal<>();
@@ -150,6 +150,7 @@ public class DataStoreImpl implements DataStore {
bwConfig.setMaxMemory(getMemoryInBytes(accumuloConf.getWrite().getBufferSize()) / numWriteThreads);
bwConfig.setMaxWriteThreads(accumuloConf.getWrite().getThreads());
scannerThreads = accumuloConf.getScan().getThreads();
maxDownsampleMemory = accumuloConf.getScan().getMaxDownsampleMemory();
anonAccessAllowed = conf.getSecurity().isAllowAnonymousAccess();
metricsTable = conf.getMetricsTable();
@@ -507,7 +508,7 @@ public class DataStoreImpl implements DataStore {
LOG.trace("Downsample Aggregator type {}", daggClass.getSimpleName());
IteratorSetting is = new IteratorSetting(500, DownsampleIterator.class);
DownsampleIterator.setDownsampleOptions(is, startOfFirstPeriod, endOfLastPeriod, downsample,
daggClass.getName());
maxDownsampleMemory, daggClass.getName());
scanner.addScanIterator(is);
}
@@ -551,6 +552,7 @@ public class DataStoreImpl implements DataStore {
}
}
LOG.debug("Query time: {}", (System.currentTimeMillis() - now));
internalMetrics.addQueryResponse(result.size(), (System.currentTimeMillis() - now));
return result;
} catch (ClassNotFoundException | IOException | TableNotFoundException ex) {
LOG.error("Error during query: " + ex.getMessage(), ex);
@@ -20,12 +20,21 @@ public class InternalMetrics {
private static final String METRICS_RECEIVED_METRIC = "timely.metrics.received";
private static final String META_KEYS_METRIC = "timely.keys.meta.inserted";
private static final String METRIC_KEYS_METRIC = "timely.keys.metric.inserted";
private static final String QUERIES_COMPLETED = "timely.query.num.completed";
private static final String QUERY_RETURN_TIME = "timely.query.return.time";
private static final String METRICS_RETURNED = "timely.query.metrics.returned";
private static final String METRIC_RETURN_RATE = "timely.query.metrics.returned.rate";
private static final String HOSTNAME_TAG = "host";
private String hostName = "localhost";
private AtomicDouble numMetricsReceived = new AtomicDouble(0);
private AtomicDouble numMetaKeysInserted = new AtomicDouble(0);
private AtomicDouble numMetricKeysInserted = new AtomicDouble(0);
private AtomicDouble numQueriesCompleted = new AtomicDouble(0);
private AtomicDouble numMetricsReturned = new AtomicDouble(0);
private AtomicDouble elapsedQueryTime = new AtomicDouble(0);
private List<Tag> tags = new ArrayList<Tag>();
public InternalMetrics() {
@@ -50,6 +59,12 @@ public class InternalMetrics {
numMetricKeysInserted.addAndGet(num);
}
public void addQueryResponse(long numMetrics, long elapsedTime) {
numQueriesCompleted.addAndGet(1);
numMetricsReturned.addAndGet(numMetrics);
elapsedQueryTime.addAndGet(elapsedTime);
}
public List<Metric> getMetricsAndReset() {
List<Metric> metrics = new ArrayList<Metric>();
long ts = System.currentTimeMillis();
@@ -59,6 +74,25 @@ public class InternalMetrics {
numMetaKeysInserted.set(0);
metrics.add(new Metric(METRIC_KEYS_METRIC, ts, numMetricKeysInserted.get(), tags));
numMetricKeysInserted.set(0);
metrics.add(new Metric(QUERIES_COMPLETED, ts, numQueriesCompleted.get(), tags));
metrics.add(new Metric(METRICS_RETURNED, ts, numMetricsReturned.get(), tags));
if (elapsedQueryTime.get() > 0) {
// average response time per query
double averageQueryTime = (numQueriesCompleted.get() / elapsedQueryTime.get());
metrics.add(new Metric(QUERY_RETURN_TIME, ts, averageQueryTime, tags));
// metrics returned per minute
double rate = (numMetricsReturned.get() / (elapsedQueryTime.get() / (1000 * 60)));
metrics.add(new Metric(METRIC_RETURN_RATE, ts, rate, tags));
} else {
// if no elapsed time, then rate is zero
metrics.add(new Metric(METRIC_RETURN_RATE, ts, 0, tags));
}
numQueriesCompleted.set(0);
numMetricsReturned.set(0);
elapsedQueryTime.set(0);
return metrics;
}
@@ -86,13 +86,15 @@ public class MetricScanner extends Thread implements UncaughtExceptionHandler {
}
public synchronized void flush() {
if (responses.size() > 0) {
try {
String json = om.writeValueAsString(responses);
this.ctx.writeAndFlush(new TextWebSocketFrame(json));
responses.clear();
} catch (JsonProcessingException e) {
LOG.error("Error serializing metrics: " + responses, e);
synchronized (responses) {
if (responses.size() > 0) {
try {
String json = om.writeValueAsString(responses);
this.ctx.writeAndFlush(new TextWebSocketFrame(json));
responses.clear();
} catch (JsonProcessingException e) {
LOG.error("Error serializing metrics: " + responses, e);
}
}
}
}
@@ -152,9 +154,12 @@ public class MetricScanner extends Thread implements UncaughtExceptionHandler {
}
public void close() {
LOG.info("Marking metric scanner closed: {}", name);
this.flusher.cancel(false);
this.closed = true;
if (!closed) {
LOG.info("Marking metric scanner closed: {}", name);
flush();
this.flusher.cancel(false);
this.closed = true;
}
}
@Override
+2 -1
View File
@@ -11,6 +11,7 @@ import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import timely.netty.http.NonSslRedirectHandler;
import timely.netty.tcp.MetricsBufferDecoder;
import timely.netty.tcp.TcpDecoder;
import timely.netty.udp.UdpDecoder;
@@ -33,7 +34,7 @@ public class TestServer extends 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("decompressor", new HttpContentDecompressor());
ch.pipeline().addLast("decoder", new HttpRequestDecoder());
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(8192));
@@ -4,13 +4,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.accumulo.core.client.IteratorSetting;
import org.apache.accumulo.core.data.ColumnUpdate;
@@ -26,8 +21,10 @@ import org.junit.Test;
import timely.Configuration;
import timely.adapter.accumulo.MetricAdapter;
import timely.model.Metric;
import timely.model.ObjectSizeOf;
import timely.model.Tag;
import timely.auth.VisibilityCache;
import timely.model.parse.TagListParser;
import timely.sample.Downsample;
import timely.sample.Sample;
import timely.sample.aggregators.Avg;
@@ -72,6 +69,7 @@ public class DownsampleIteratorTest {
}
private void createTestData2() {
List<List<Tag>> listOfTagVariations = new ArrayList<>();
List<Tag> tags = Collections.singletonList(new Tag("host", "host1"));
List<Tag> tags2 = Collections.singletonList(new Tag("host", "host2"));
@@ -85,7 +83,7 @@ public class DownsampleIteratorTest {
public void simpleGetOneSample() throws Exception {
// check that data gets pulled out
DownsampleIterator iter = new DownsampleIterator();
Map<Set<Tag>, Downsample> samples = runQuery(iter, testData1, 100);
Map<Set<Tag>, Downsample> samples = runQuery(iter, testData1, 100, -1);
assertEquals(1, samples.size());
for (Entry<Set<Tag>, Downsample> entry : samples.entrySet()) {
Set<Tag> tags = entry.getKey();
@@ -104,7 +102,7 @@ public class DownsampleIteratorTest {
@Test
public void simpleGetTwoSamples() throws Exception {
DownsampleIterator iter = new DownsampleIterator();
Map<Set<Tag>, Downsample> samples = runQuery(iter, testData2, 100);
Map<Set<Tag>, Downsample> samples = runQuery(iter, testData2, 100, -1);
assertEquals(2, samples.size());
for (Tag tag : new Tag[] { new Tag("host", "host1"), new Tag("host", "host2") }) {
Downsample dsample = samples.get(Collections.singleton(tag));
@@ -128,7 +126,7 @@ public class DownsampleIteratorTest {
@Test
public void simpleTestDownsampling() throws Exception {
DownsampleIterator iter = new DownsampleIterator();
Map<Set<Tag>, Downsample> samples = runQuery(iter, testData2, 200);
Map<Set<Tag>, Downsample> samples = runQuery(iter, testData2, 200, -1);
assertEquals(2, samples.size());
for (Tag tag : new Tag[] { new Tag("host", "host1"), new Tag("host", "host2") }) {
Downsample dsample = samples.get(Collections.singleton(tag));
@@ -149,17 +147,143 @@ public class DownsampleIteratorTest {
}
}
static public class SampleObject implements ObjectSizeOf {
private long sizeInBytes = 0;
public void setSizeInBytes(long sizeInBytes) {
this.sizeInBytes = sizeInBytes;
}
@Override
public long sizeInBytes() {
return sizeInBytes;
}
}
@Test
public void memoryEstimatorTestSmallObjects() {
long maxMemory = 1000;
long start = System.currentTimeMillis();
long period = 500l;
long sizeOfObjects = 20;
SampleObject o = new SampleObject();
DownsampleIterator.MemoryEstimator memoryEstimator = new DownsampleIterator.MemoryEstimator(maxMemory, start,
period);
boolean shouldReturn = false;
for (long x = 100; x <= 5000; x += 100) {
long timestamp = start + x;
o.setSizeInBytes(o.sizeInBytes() + sizeOfObjects);
shouldReturn = memoryEstimator.shouldReturnBasedOnMemoryUsage(timestamp, o);
if (memoryEstimator.isNewBucket()) {
long memoryPercentageUsedCalculated = Math.round((double) o.sizeInBytes() / maxMemory * 100);
long memoryPercentageUsedEstimate = Math.round(memoryEstimator.getMemoryUsedPercentage());
long percentError = Math.round(Math.abs(memoryPercentageUsedCalculated - memoryPercentageUsedEstimate)
/ memoryPercentageUsedCalculated * 100);
assertTrue(percentError == 0);
}
if (shouldReturn) {
o.setSizeInBytes(0);
memoryEstimator.reset();
}
}
assertTrue(shouldReturn);
}
@Test
public void memoryEstimatorTestLargeObjects() {
long maxMemory = 10000;
long start = System.currentTimeMillis();
long period = 500l;
long sizeOfObjects = 200;
SampleObject o = new SampleObject();
DownsampleIterator.MemoryEstimator memoryEstimator = new DownsampleIterator.MemoryEstimator(maxMemory, start,
period);
boolean shouldReturn = false;
for (long x = 100; x <= 5000; x += 100) {
long timestamp = start + x;
o.setSizeInBytes(o.sizeInBytes() + sizeOfObjects);
shouldReturn = memoryEstimator.shouldReturnBasedOnMemoryUsage(timestamp, o);
if (memoryEstimator.isNewBucket()) {
long memoryPercentageUsedCalculated = Math.round((double) o.sizeInBytes() / maxMemory * 100);
long memoryPercentageUsedEstimate = Math.round(memoryEstimator.getMemoryUsedPercentage());
long percentError = Math.round(Math.abs(memoryPercentageUsedCalculated - memoryPercentageUsedEstimate)
/ memoryPercentageUsedCalculated * 100);
assertTrue(percentError == 0);
assertTrue(memoryEstimator.isHighVolumeBuckets());
}
if (shouldReturn) {
o.setSizeInBytes(0);
memoryEstimator.reset();
}
}
assertTrue(shouldReturn);
}
private SortedMap<Key, Value> createTestData3(int elapsedTime, int skipInterval, int numTagVariations) {
SortedMap<Key, Value> testData3 = new TreeMap<>();
List<List<Tag>> listOfTagVariations = new ArrayList<>();
for (int x = 1; x <= numTagVariations; x++) {
listOfTagVariations.add(Collections.singletonList(new Tag("instance", Integer.toString(x))));
}
for (long i = 0; i < elapsedTime; i += skipInterval) {
for (List<Tag> tags : listOfTagVariations) {
put(testData3, new Metric("sys.loadAvg", i, i * 2, tags));
}
}
return testData3;
}
@Test
public void testDownsampleCombining() throws Exception {
int numTagVariations = 2;
int sampleInterval = 50;
int elapsedTime = 100;
int skipInterval = 10;
SortedMap<Key, Value> testData3 = createTestData3(elapsedTime, skipInterval, numTagVariations);
DownsampleIterator iter = new DownsampleIterator();
Map<Set<Tag>, Downsample> samples = runQuery(iter, testData3, sampleInterval, 1000);
assertEquals(numTagVariations, samples.size());
long totalBuckets = 0;
for (Entry<Set<Tag>, Downsample> entry : samples.entrySet()) {
totalBuckets = totalBuckets + entry.getValue().getNumBuckets();
}
assertEquals((elapsedTime / sampleInterval) * numTagVariations, totalBuckets);
}
private Map<Set<Tag>, Downsample> runQuery(SortedKeyValueIterator<Key, Value> iter, SortedMap<Key, Value> testData,
long period) throws Exception {
long period, long maxDownsampleMemory) throws Exception {
IteratorSetting is = new IteratorSetting(100, DownsampleIterator.class);
DownsampleIterator.setDownsampleOptions(is, 0, 1000, period, Avg.class.getName());
DownsampleIterator.setDownsampleOptions(is, 0, 1000, period, maxDownsampleMemory, Avg.class.getName());
SortedKeyValueIterator<Key, Value> source = new SortedMapIterator(testData);
iter.init(source, is.getOptions(), null);
iter.seek(new Range(), Collections.emptyList(), true);
assertTrue(iter.hasTop());
Key key = iter.getTopKey();
boolean hasTop = iter.hasTop();
assertTrue(hasTop);
Key key = null;
Map<Set<Tag>, Downsample> samples = new HashMap<>();
do {
Map<Set<Tag>, Downsample> currentSamples = DownsampleIterator.decodeValue(iter.getTopValue());
List<Downsample> downsampleArray = new ArrayList<>();
for (Entry<Set<Tag>, Downsample> entry : currentSamples.entrySet()) {
Downsample downsample = samples.get(entry.getKey());
if (downsample == null) {
samples.put(entry.getKey(), entry.getValue());
} else {
downsampleArray.clear();
downsampleArray.add(downsample);
downsampleArray.add(entry.getValue());
samples.put(entry.getKey(), Downsample.combineDownsample(downsampleArray, null));
}
}
key = iter.getTopKey();
} while (iter.hasTop());
assertEquals(testData.lastKey(), key);
Map<Set<Tag>, Downsample> samples = DownsampleIterator.decodeValue(iter.getTopValue());
return samples;
}
@@ -112,38 +112,6 @@ public class HttpApiIT extends OneWaySSLBase {
}
}
@Test
public void testMetricsURLEncoded() throws Exception {
final Server s = new Server(conf);
s.run();
try {
// @formatter:off
put("sys.cpu.user " + TEST_TIME + " 1.0 tag%31=value%31 tag%32=value%32",
"sys.cpu.idle " + (TEST_TIME + 1) + " 1.0 tag%33=value%33 tag%34=value%34",
"sys.cpu.idle " + (TEST_TIME + 2) + " 1.0 tag%33=value%33 tag%34=value%34 viz=(a|b|c)",
"zzzz 1234567892 1.0 host=localhost");
// Latency in TestConfiguration is 2s, wait for it
sleepUninterruptibly(TestConfiguration.WAIT_SECONDS, TimeUnit.SECONDS);
String metrics = "https://localhost:54322/api/metrics";
// Test prefix matching
String result = query(metrics);
Document doc = Jsoup.parse(result);
Elements tableData = doc.select("td");
assertEquals(1, tableData.select(":contains(sys.cpu.user)").size());
assertEquals(1, tableData.select(":contains(tag1=value1 tag2=value2)").size());
assertEquals(1, tableData.select(":contains(sys.cpu.idle)").size());
assertEquals(1, tableData.select(":contains(tag3=value3 tag4=value4)").size());
assertEquals(1, tableData.select(":contains(zzzz)").size());
assertEquals(1, tableData.select(":contains(host=localhost)").size());
// @formatter:on
} finally {
s.shutdown();
}
}
@Test
public void testMetricsJson() throws Exception {
// @formatter:off