Compare commits

..
136 Commits
Author SHA1 Message Date
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
Dave Marion 3c0bf87b79 0.0.4 release 2017-02-02 10:43:02 -05:00
Bill Oley d2ba7f635e re #130 - Refactor python code in preparation to automate 2017-01-23 15:08:42 -05:00
Ivan Bella 92510fdc83 Aggregation (#135)
fixes #108 - Implemented the aggregation across time series separate after downsampling
2017-01-23 10:33:04 -05:00
Dave Marion 4eac17fbb5 re #73 - change map in accumulator to a concurrent map, it was failing to serialize with a ConcurrentModificationException from the task manager to the job manager 2017-01-20 12:13:36 -05:00
Dave Marion 328ae075f4 fixes #134 - remove log4j2 transitive dependency so that flink job logging works 2017-01-19 13:15:27 -05:00
Ivan Bella cf12295ac8 fixes 133 - added the buildnumber-maven-plugin, and put the buildNumber and timestamp into each of the jar's MANIFEST 2017-01-18 14:37:28 -05:00
Ivan Bella df180504f2 fixes #132 - Ensure we do not seek past the end key in the initial range when skipping aged off data. 2017-01-18 13:15:00 -05:00
Dave Marion 021ff832ef fixes #131 - bring back the old ageoff filter and apply to meta table, use new iterator on metrics table 2017-01-18 09:10:40 -05:00
Drew Farris 6fc9066e70 Closes #128 modify server pom for netty-transport-native-epoll dep
- remove runtime scope
2017-01-10 21:14:38 -05:00
Bill Oley f11b82b662 re #130 - Create analytics library - correct errors and add ability to display all series regardless of detected conditions 2017-01-09 17:29:15 -05:00
Bill Oley dcfd165a9b re #130 - Add sample analytic script 2017-01-06 18:32:39 -05:00
Bill Oley fd98558218 re #130 - Create analytics library and graphing capability using plot.ly 2017-01-06 18:26:02 -05:00
Dave Marion f47cd66ec2 re #128 - use no classifier for the native transport epoll dependency, use one for the linux environments though 2017-01-05 16:49:58 -05:00
Dave Marion ec4ba6e7f5 closes #129 - update Apache Flink version to 1.1.4 2017-01-05 15:14:29 -05:00
Dave Marion e698734e4b closes #126: Added udp and tcp client 2016-12-21 16:53:11 -05:00
Dave Marion 78b49fe44e closes #124 - change ageoff filter to an iterator so that it can seek smartly 2016-12-13 12:25:23 -05:00
Dave Marion f109f04162 closes #125 - use a smarter start time when zero is supplied by using the age off configuration 2016-12-08 09:59:35 -05:00
Dave Marion 4bf68fe328 closes #122: use netty native epoll 2016-12-07 15:03:05 -05:00
Dave Marion 9eb8da8e80 re #73 - changes from testing Flink summarization job
closes #121 - made metric scanner options configurable
2016-11-30 15:23:45 -05:00
Bill Oley f54705374e Add more robust begin/end time options 2016-11-29 17:16:52 -05:00
Dave Marion 5e166f0044 re #120 - add task to send ping to server at interval 2016-11-21 09:41:50 -05:00
Bill Oley 17527af6b4 re #119 - Create python websocket client 2016-11-16 16:31:50 -05:00
Dave Marion 64f7890f8b re #73 - created Flink job to summarize metrics and re-insert into Timely 2016-11-10 16:03:11 -05:00
Ivan Bella e7c058ef56 closes #116: Simplified the endOfPeriod calculation 2016-11-10 14:11:13 -05:00
Dave Marion 6415d100fc re #118 - send last message at end of subscription with complete flag set to true. Refactor client classes. 2016-11-10 13:25:22 -05:00
Dave Marion 046000c16a closes #118 - don't close connection when metric scanner is done. There might be multiple on one connection, but do inform the Subscription object that the thread is done 2016-11-10 11:25:15 -05:00
Dave Marion d0f6534296 re #118 - close web socket connection on error or when done sending subscription data 2016-11-10 11:05:19 -05:00
Dave Marion 07c04425e1 closes #117 - added endTime to client AddSubscription object 2016-11-09 17:08:28 -05:00
Dave Marion 113b6464f3 closes #116 - aligned the end timestamp to the end of the last downsample period 2016-11-09 15:38:14 -05:00
Dave Marion e2eda4c74a closes #116 - baseline query start to the start of the first downsample window based on the epoch 2016-11-09 10:54:42 -05:00
Dave Marion 68b8d6cd51 closes #115 = added viz tags to metric response on subscriptions 2016-11-08 09:48:52 -05:00
Dave Marion 458028d5df re #111 - remove unused import 2016-11-04 12:05:27 -04:00
Dave Marion 320f291785 closes #113 - fallback to log4j2 2.6.2 2016-11-04 11:27:01 -04:00
Dave Marion 95c2654357 Merge branch 'master' of https://github.com/NationalSecurityAgency/timely 2016-11-03 16:08:57 -04:00
Dave Marion 045964c01d closes #112 - added Java WebSocket client 2016-11-03 14:42:29 -04:00
Ivan Bella 2f8759e32b re #111: Added some useful trace messages 2016-11-03 13:28:28 -04:00
Dave Marion 451f001b9f closes #109 - added endTime to add subscription request 2016-11-03 11:22:03 -04:00
Ivan Bella 044f6576fd close #111: Reimplemented the counter concept for rates. 2016-11-02 17:18:33 -04:00
Dave Marion 520edee16f closes #110 - created client request objects for login and subscription API 2016-11-02 11:09:49 -04:00
Dave Marion 8034a673fc Updated haproxy parsing logic 2016-10-31 12:53:29 -04:00
Dave Marion eb9e874a57 closes #105 - updated most dependencies to latest release 2016-10-27 16:51:20 -04:00
Dave Marion 1658312512 Bumped version for next dev cycle 2016-10-27 13:44:12 -04:00
Dave Marion 2fdfed7554 0.0.3 release 2016-10-27 13:40:22 -04:00
Brian Loss e90340be09 fixes #107 - Fix bad regex in timely Grafana app 2016-10-27 13:21:17 -04:00
Ivan Bella 9770dce1cd re #106: Significant performance enhancement where valid answers are preserved in a separate list avoiding excessive passes through the entire set of captured metrics on each round. 2016-10-26 15:48:56 -04:00
Ivan Bella 8f98199a37 re #101: Removing the first element from the list after computing. Also added some efficiencies in the metrics comparator and the setTopKeyValue method. 2016-10-26 14:52:20 -04:00
Dave Marion 425616d536 Update location of log4j configuration 2016-10-26 13:28:55 -04:00
Dave Marion 158ee4fd55 re #102 - sparse time series optimization 2016-10-26 12:04:25 -04:00
Dave Marion 89e8fd7ebd closes #103 - return rate of zero if no time has elapsed between data points 2016-10-24 11:05:44 -04:00
Dave Marion cb5794491a closes #102 - changes to handle sparse time series. New test. 2016-10-21 16:09:25 -04:00
Dave Marion 8b4f0d5764 closes #99 - re-implemented SlidingWindowFilter and added:
1. Multiple Time Series
2. Ability to handle when a time series drops off
3. Ability to handle when a time series appears
4. New tests
2016-10-20 15:42:52 -04:00
Dave Marion c90b86c4c9 re #91 : remove code added in dd30d54e (#77) because of downsample iterator changes. 2016-10-19 16:47:33 -04:00
Dave Marion f104d02dc6 closes #91 :
1. The DownsampleIterator no longer creates an array of downsamples upon initialization. Instead, it creates downsample buckets as needed.
2. The DownsampleIterator no longer interpolates for missing values.
3. The DownsampleIterator no longer converts counters to rates, this is done with a different iterator. The counter reset value and counter max value are no longer used.
2016-10-14 12:22:03 -04:00
Dave Marion ac85ad1aa7 closes #94 - Fixed rate calculations so that the result is divided by the time difference. Added test for non-constant sample time (added jitter). 2016-10-14 11:53:05 -04:00
Dave Marion 21f3c20a5f closes #93 : pushed common pom things up to the parent pom, removed System.out's in a test, created common module. 2016-10-12 16:07:42 -04:00
klucar b43d877035 final docker fixes, removed unused aggregator from query template 2016-10-10 20:06:22 -04:00
Jim Klucar 8f46ee052c Merge pull request #85 from trucemop/docker
Docker example update
2016-10-10 19:54:07 -04:00
klucar 6cda9c4a60 fixes so templated queries use regex instead of globs 2016-10-10 19:50:05 -04:00
Dave Marion cfc3e491d6 fixes #86 - removed rpm profile from server pom 2016-09-29 13:21:42 -04:00
Dave Marion 23668b294f fixes #84 - calculating rate before downsample iterator using the sliding window iterator 2016-09-29 13:07:41 -04:00
Dave Marion beceb678ea Merge branch 'master' of github.com:NationalSecurityAgency/timely 2016-09-28 14:07:46 -04:00
Dave Marion 4257e28233 Fixup warnings 2016-09-28 14:07:24 -04:00
Brian Loss fb007c170e Ensure server is shut down if there is an error during server.run in order to fix #89. 2016-09-28 14:01:56 -04:00
Dave Marion cabeb2c0d7 re #90 - fix script 2016-09-28 14:00:04 -04:00
Brian Loss e4a2b011a4 Merge branch 'master' of github.com:NationalSecurityAgency/timely 2016-09-28 13:19:13 -04:00
Brian Loss 8f6dfd1644 Update log4j2 configuration to fix #90
moved log4j2.xml to log4j2-spring.xml (recommended by spring boot)
	moved log4j2 config files to conf dir (since it's on the classpath)
	don't specify log4j config file location for spring boot apps (timely server/standalone) since the file is found on the classpath
2016-09-28 13:17:16 -04:00
Dave Marion 33fb3dc857 re #84 - added sliding window iterator which takes a filter. Tests added for moving average and rate calculations 2016-09-28 11:37:15 -04:00
John Highcock 186edeb0f2 Remove extra standalone_test.json 2016-09-26 11:26:39 -04:00
John Highcock a034223376 Install bouncycastle via epel-release 2016-09-25 11:58:51 -04:00
John Highcock 9c75c75aa5 Addressing some of the comments. JAVA_HOME specific version, script quotes, env: prefix for pass. 2016-09-25 09:36:10 -04:00
John Highcock c8646a8d59 Star the timely dashboard 2016-09-24 23:00:18 -04:00
John Highcock b28cb4451b Merge branch 'master' into docker 2016-09-24 21:57:24 -04:00
John Highcock a4b9a1034c Add the grafana bits so that datasource and dashboard are setup. 2016-09-24 21:51:45 -04:00
John Highcock 12e64316eb Can now just run 'docker-compose up' 2016-09-24 19:41:29 -04:00
John Highcock a2389435d4 Working again. 2016-09-24 17:29:17 -04:00
Jim Klucar 6a0455b1cd Merge pull request #82 from klucar/newapi
Timely Client jar and Test speed improvements
2016-09-23 10:19:09 -04:00
Jim Klucar 7abc9e68e4 Standardized on Jackson Json annotations over the XmlElement style
Updated test cases to use compact Json serialization format.
2016-09-22 10:28:34 -04:00
Jim Klucar e45dcb0450 standardized to all Jackson annotations 2016-09-22 09:57:34 -04:00
Jim Klucar a8ce05000e Fixed Metric::equals to ignore ordering of List.
Flattened Json format.
2016-09-22 09:51:57 -04:00
Jim Klucar 747d3e7ad1 removed TODO reminder comment that was fixed 2016-09-19 11:24:05 -04:00
Jim Klucar fcf0ec0b87 removed commented out plugin 2016-09-19 11:22:12 -04:00
Jim Klucar 976c6da07c fixed check to ensure correct number of tags of each type was found 2016-09-19 11:21:44 -04:00
Jim Klucar ed96a0a8e8 made shutdown quiet period configurable. 5 seconds by default 2016-09-19 10:17:48 -04:00
Jim Klucar d5c3bbbcc5 removed old commented out code 2016-09-19 09:22:39 -04:00
John Highcock ec1ac9af73 Remove TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 exception in Dockerfile. 2016-09-16 15:55:45 -04:00
Jim Klucar 2a2d11d01b Made sleep times configurable from the TestConfiguration. 2016-09-16 13:02:24 -04:00
Jim Klucar 14eba0fb93 added exclusion for Server.shutdown. Findbugs doesn't see Collection.forEach as a use and calls the collection of Futures useless 2016-09-16 13:01:57 -04:00
Jim Klucar 418afe8f87 fast server shutdown 2016-09-16 12:31:31 -04:00
Jim Klucar 2b39ec3ab5 Tests now re-use Mini Accumulo Cluster instance 2016-09-16 12:31:31 -04:00
Jim Klucar 2ff895b147 changed core module to client module 2016-09-16 12:31:14 -04:00
Jim Klucar 16a6223c48 Extracted former api classes into a client jar. 2016-09-15 15:40:08 -04:00
Jim Klucar e928ac3746 breaking out models into core module 2016-09-08 14:51:39 -04:00
Dave Marion 8f5d54ebd4 fixes #79 - disable console output from utility class 2016-09-07 10:13:11 -04:00
Dave Marion 123f63972e fixes #78 - changes for Timely to work with Accumulo 1.7 and 1.8 2016-09-06 11:43:42 -04:00
Dave Marion dd30d54ed9 closes #77 - return error when there are too many downsample buckets 2016-09-01 15:47:32 -04:00
Dave Marion d37bf1c824 #16 - per metric ageoff (#76)
* fixes #16, added age off map to configuration to specify ageoff, in days, per metric. "default" accepted. Remove all ageoff iterators on server startup and re-setup with current configuration
2016-08-31 15:48:41 -04:00
Dave Marion 6cd4a8bd67 closes #65: Added support for sending metrics in String and binary form to UDP socket 2016-08-30 15:51:20 -04:00
Dave Marion 1fa71e0c6a fixes #66 - allow metric data to be sent to Timely TCP port in Google Flatbuffers encoded binary form (#74) 2016-08-30 10:06:49 -04:00
Dave Marion c5efeb5be9 closes #69, removed double lexicoder for metric value encoding 2016-08-29 15:07:22 -04:00
Brian Loss 2c8fa5da44 fixes #71: Pass IPs stored in configuration through to tcp, query, and websocket servers. 2016-08-26 14:52:03 -04:00
Dave Marion 9cbc94eb58 turn formatter off so that whitespace changes are not lost 2016-08-26 12:26:07 -04:00
Jim Klucar 4ce4482764 changed whitespace for clarity 2016-08-25 14:29:54 -04:00
Jim Klucar 49a8d970fe minor pom consistency tweaks 2016-08-25 14:18:55 -04:00
brianloss 1be6f24676 Use Spring Configuration (#68)
* Initial pass at converting timely configuration to Spring Boot for type-safe config that is a lot more flexible than standard properties file configuration.

* Change banner color to red.

* Update Configuration class to support fluent API.

* Re-work configuration to group properties in a more sensible manner.

* Use NotBlank everywhere instead of NotEmpty for validations.
2016-08-25 13:19:59 -04:00
Dave Marion 82b94f1a71 fixes #40 - add regex support for lookup requests 2016-08-23 09:26:56 -04:00
Jim Klucar 019c5789ce fixed bug where timely.ssl.trust.store.file property is defined but is empty string 2016-08-05 11:27:43 -04:00
klucar 4336defc14 docker update version 2016-08-05 07:45:56 -04:00
klucar 712a2100bb added instances to metrics 2016-08-05 07:44:57 -04:00
klucar bc46f54604 updated to 0.0.3-SNAPSHOT 2016-08-03 13:54:42 -04:00
Dave Marion 1b713e7874 re #56: fixed some scanner handling, log messages 2016-08-02 10:38:25 -04:00
Dave Marion 3f5dfd2219 fixes #56: Added a Netty handler in the web socket pipeline to get the TSESSIONID cookie value before the web socket upgrade and store it in the channel attribute map. Replaced sessionId property on subscription objects with subscriptionId, which will now allow multiple subscriptions per channel. Modified MetricResponse to contain the subscriptionId in the returned data. Updated tests and example. 2016-08-02 09:29:49 -04:00
Dave Marion ea707fda42 fixes #57, moved plugin/dependency versions to parent pom 2016-08-01 13:02:29 -04:00
klucar b245be476a fixed display name of dashboard 2016-07-28 09:25:24 -04:00
klucar 9619530814 making dashboards available for #59 2016-07-28 09:23:21 -04:00
klucar adf617e59f First cut at #59 2016-07-28 09:20:05 -04:00
Dave Marion 3f49855840 Set version to 0.0.3-SNAPSHOT 2016-07-27 08:23:50 -04:00
232 changed files with 28972 additions and 3805 deletions

No files matched your search

+3
View File
@@ -4,3 +4,6 @@
target/
.idea/
*.iml
logs/
server/pki/
+1
View File
@@ -3,3 +3,4 @@ Eric Newton ([email protected])
Jim Klucar ([email protected])
Charlie Williams ([email protected])
Drew Farris ([email protected])
Brian Loss ([email protected])
+2
View File
@@ -0,0 +1,2 @@
This product includes Google Flatbuffers (https://google.github.io/flatbuffers/)
Copyright 2014 Google Inc. All rights reserved.
+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
+2
View File
@@ -0,0 +1,2 @@
/bin/
/target
+20
View File
@@ -0,0 +1,20 @@
timelyHostname=
timelyTcpPort=
timelyHttpsPort=
timelyWssPort=
doLogin=
#timelyUsername=
#timelyPassword=
keyStoreFile=
keyStoreType=
keyStorePass=
trustStoreFile=
trustStoreType=
trustStorePass=
hostVerificationEnabled=false
bufferSize=10485760
metrics=
startTime=0
endTime=0
interval=1
intervalUnits=HOURS
+336
View File
@@ -0,0 +1,336 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>timely-analytics</artifactId>
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.5</version>
</parent>
<properties>
<flink.version>1.1.4</flink.version>
</properties>
<!--
Execute "mvn clean package -Pbuild-jar"
to build a jar file out of this project!
How to use the Flink Quickstart pom:
a) Adding new dependencies:
You can add dependencies to the list below.
Please check if the maven-shade-plugin below is filtering out your dependency
and remove the exclude from there.
b) Build a jar for running on the cluster:
There are two options for creating a jar from this project
b.1) "mvn clean package" -> this will create a fat jar which contains all
dependencies necessary for running the jar created by this pom in a cluster.
The "maven-shade-plugin" excludes everything that is provided on a running Flink cluster.
b.2) "mvn clean package -Pbuild-jar" -> This will also create a fat-jar, but with much
nicer dependency exclusion handling. This approach is preferred and leads to
much cleaner jar files.
-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java_2.11</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-clients_2.11</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>timely</groupId>
<artifactId>timely-client</artifactId>
<version>${parent.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>timely</groupId>
<artifactId>timely-common</artifactId>
<version>${parent.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<!-- Profile for packaging correct JAR files -->
<id>build-jar</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java_2.11</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-clients_2.11</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- disable the exclusion rules -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes combine.self="override"/>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
<!-- We use the maven-shade plugin to create a fat jar that contains all dependencies
except flink and it's transitive dependencies. The resulting fat-jar can be executed
on a cluster. Change the value of Program-Class if your program entry point changes. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<!-- Run shade goal on package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<!-- This list contains all dependencies of flink-dist
Everything else will be packaged into the fat-jar
-->
<exclude>org.apache.flink:flink-annotations</exclude>
<exclude>org.apache.flink:flink-shaded-hadoop1_2.11</exclude>
<exclude>org.apache.flink:flink-shaded-hadoop2</exclude>
<exclude>org.apache.flink:flink-shaded-curator-recipes</exclude>
<exclude>org.apache.flink:flink-core</exclude>
<exclude>org.apache.flink:flink-java</exclude>
<exclude>org.apache.flink:flink-scala_2.11</exclude>
<exclude>org.apache.flink:flink-runtime_2.11</exclude>
<exclude>org.apache.flink:flink-optimizer_2.11</exclude>
<exclude>org.apache.flink:flink-clients_2.11</exclude>
<exclude>org.apache.flink:flink-avro_2.11</exclude>
<exclude>org.apache.flink:flink-examples-batch_2.11</exclude>
<exclude>org.apache.flink:flink-examples-streaming_2.11</exclude>
<exclude>org.apache.flink:flink-streaming-java_2.11</exclude>
<!-- Also exclude very big transitive dependencies of Flink
WARNING: You have to remove these excludes if your code relies on other
versions of these dependencies.
-->
<exclude>org.scala-lang:scala-library</exclude>
<exclude>org.scala-lang:scala-compiler</exclude>
<exclude>org.scala-lang:scala-reflect</exclude>
<exclude>com.typesafe.akka:akka-actor_*</exclude>
<exclude>com.typesafe.akka:akka-remote_*</exclude>
<exclude>com.typesafe.akka:akka-slf4j_*</exclude>
<exclude>io.netty:netty-all</exclude>
<exclude>io.netty:netty</exclude>
<exclude>commons-fileupload:commons-fileupload</exclude>
<exclude>org.apache.avro:avro</exclude>
<exclude>commons-collections:commons-collections</exclude>
<exclude>org.codehaus.jackson:jackson-core-asl</exclude>
<exclude>org.codehaus.jackson:jackson-mapper-asl</exclude>
<exclude>com.thoughtworks.paranamer:paranamer</exclude>
<exclude>org.xerial.snappy:snappy-java</exclude>
<exclude>org.apache.commons:commons-compress</exclude>
<exclude>org.tukaani:xz</exclude>
<exclude>com.esotericsoftware.kryo:kryo</exclude>
<exclude>com.esotericsoftware.minlog:minlog</exclude>
<exclude>org.objenesis:objenesis</exclude>
<exclude>com.twitter:chill_*</exclude>
<exclude>com.twitter:chill-java</exclude>
<exclude>commons-lang:commons-lang</exclude>
<exclude>junit:junit</exclude>
<exclude>org.apache.commons:commons-lang3</exclude>
<exclude>org.slf4j:slf4j-api</exclude>
<exclude>org.slf4j:slf4j-log4j12</exclude>
<exclude>log4j:log4j</exclude>
<exclude>org.apache.commons:commons-math</exclude>
<exclude>org.apache.sling:org.apache.sling.commons.json</exclude>
<exclude>commons-logging:commons-logging</exclude>
<exclude>commons-codec:commons-codec</exclude>
<exclude>com.fasterxml.jackson.core:jackson-core</exclude>
<exclude>com.fasterxml.jackson.core:jackson-databind</exclude>
<exclude>com.fasterxml.jackson.core:jackson-annotations</exclude>
<exclude>stax:stax-api</exclude>
<exclude>com.typesafe:config</exclude>
<exclude>org.uncommons.maths:uncommons-maths</exclude>
<exclude>com.github.scopt:scopt_*</exclude>
<exclude>commons-io:commons-io</exclude>
<exclude>commons-cli:commons-cli</exclude>
</excludes>
</artifactSet>
<filters>
<filter>
<artifact>org.apache.flink:*</artifact>
<excludes>
<!-- exclude shaded google but include shaded curator -->
<exclude>org/apache/flink/shaded/com/**</exclude>
<exclude>web-docs/**</exclude>
</excludes>
</filter>
<filter>
<!-- Do not copy the signatures in the META-INF folder.
Otherwise, this might cause SecurityExceptions when using the JAR.
-->
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<!-- If you want to use ./bin/flink run <quickstart jar> uncomment the following lines.
This will add a Main-Class entry to the manifest file -->
<!--
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>jar.StreamingJob</mainClass>
</transformer>
</transformers>
-->
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerId>jdt</compilerId>
</configuration>
<dependencies>
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-compiler-jdt</artifactId>
<version>0.21.0</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<versionRange>[2.4,)</versionRange>
<goals>
<goal>single</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore/>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<versionRange>[3.1,)</versionRange>
<goals>
<goal>testCompile</goal>
<goal>compile</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore/>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
@@ -0,0 +1,169 @@
package timely.analytics.flink;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.flink.streaming.util.serialization.SerializationSchema;
import timely.model.Tag;
public class MetricHistogram implements Serializable, SerializationSchema<MetricHistogram> {
private static final long serialVersionUID = 1L;
private static final String SPACE = " ";
private static final String AVG = " sample=avg\n";
private static final String COUNT = " sample=count\n";
private static final String MAX = " sample=max\n";
private static final String MIN = " sample=min\n";
private static final String SUM = " sample=sum\n";
private static final String p50 = " sample=50p\n";
private static final String p75 = " sample=75p\n";
private static final String p90 = " sample=90p\n";
private static final String p99 = " sample=99p\n";
private String metric = null;
private List<Tag> tags = null;
private long timestamp = 0L;
private boolean initialized = false;
private List<Double> values = new ArrayList<>();
public void initialize(String metric, List<Tag> tags) {
this.metric = metric;
this.tags = tags;
initialized = true;
}
public boolean isInitialized() {
return initialized;
}
public String getMetric() {
return metric;
}
public List<Tag> getTags() {
return tags;
}
public long getTimestamp() {
return timestamp;
}
public void update(Double d, long timestamp) {
values.add(d);
this.timestamp = timestamp;
}
public void done() {
Collections.sort(values);
}
public Double avg() {
if (values.size() == 0) {
return 0.0D;
}
return sum() / count();
}
public Double min() {
if (values.size() == 0) {
return 0.0D;
}
return values.get(0);
}
public Double max() {
if (values.size() == 0) {
return 0.0D;
}
return values.get(values.size() - 1);
}
public Double getPercentile(int p) {
if (values.size() == 0) {
return 0.0D;
}
int position = Math.round((p * 1.0f / 100) * values.size());
position = (0 == position) ? 0 : position - 1;
return values.get(position);
}
public Double count() {
return values.size() * 1.0D;
}
public Double sum() {
double sum = 0.0D;
for (Double d : values) {
sum += d;
}
return sum;
}
@Override
public String toString() {
done();
StringBuilder buf = new StringBuilder();
buf.append("metric: ").append(metric);
buf.append(" tags: ").append(tags);
buf.append(" timestamp: ").append(timestamp);
buf.append(" count: ").append(count());
buf.append(" min: ").append(min());
buf.append(" max: ").append(max());
buf.append(" sum: ").append(sum());
buf.append(" 50p: ").append(getPercentile(50));
buf.append(" 75p: ").append(getPercentile(75));
buf.append(" 99p: ").append(getPercentile(99));
return buf.toString();
}
public byte[] serialize(MetricHistogram histo) {
StringBuilder buf = new StringBuilder();
String tags = histo.getTags().stream().map(t -> t.join()).collect(Collectors.joining(" "));
// @formatter:off
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.min())
.append(SPACE).append(tags).append(MIN);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.max())
.append(SPACE).append(tags).append(MAX);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.count())
.append(SPACE).append(tags).append(COUNT);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.sum())
.append(SPACE).append(tags).append(SUM);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.avg())
.append(SPACE).append(tags).append(AVG);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.getPercentile(50))
.append(SPACE).append(tags).append(p50);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.getPercentile(75))
.append(SPACE).append(tags).append(p75);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.getPercentile(90))
.append(SPACE).append(tags).append(p90);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.getPercentile(99))
.append(SPACE).append(tags).append(p99);
// @formatter:off
return buf.toString().getBytes();
}
}
@@ -0,0 +1,20 @@
package timely.analytics.flink;
import org.apache.flink.api.java.functions.KeySelector;
import timely.api.response.MetricResponse;
/**
* Uniquely defines a time series in a Flink stream. A unique time series is the
* metric name and all of its tags, to include visibility if it exists.
*/
public class MetricKeySelector implements KeySelector<MetricResponse, String> {
private static final long serialVersionUID = 1L;
@Override
public String getKey(MetricResponse m) throws Exception {
return m.getMetric() + m.getTags().toString();
}
}
@@ -0,0 +1,55 @@
package timely.analytics.flink;
import java.util.concurrent.ConcurrentSkipListMap;
import org.apache.commons.lang3.mutable.MutableLong;
import org.apache.flink.api.common.accumulators.Accumulator;
/**
* Custom accumulator that retains a sorted map of strings and their counts
*
*/
public class SortedStringAccumulator implements Accumulator<String, ConcurrentSkipListMap<String, MutableLong>> {
private static final long serialVersionUID = 1L;
private ConcurrentSkipListMap<String, MutableLong> values = new ConcurrentSkipListMap<>();
@Override
public void add(String value) {
if (values.containsKey(value)) {
values.get(value).increment();
} else {
values.put(value, new MutableLong(1));
}
}
@Override
public ConcurrentSkipListMap<String, MutableLong> getLocalValue() {
return values;
}
@Override
public void resetLocal() {
values.clear();
}
@Override
public void merge(Accumulator<String, ConcurrentSkipListMap<String, MutableLong>> other) {
other.getLocalValue().forEach((k, v) -> {
if (values.containsKey(k)) {
values.get(k).add(v.longValue());
} else {
values.put(k, v);
}
});
}
@Override
public Accumulator<String, ConcurrentSkipListMap<String, MutableLong>> clone() {
SortedStringAccumulator a = new SortedStringAccumulator();
a.getLocalValue().putAll(this.values);
return a;
}
}
@@ -0,0 +1,218 @@
package timely.analytics.flink;
import java.io.IOException;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import org.apache.flink.api.common.accumulators.LongCounter;
import org.apache.flink.api.common.functions.StoppableFunction;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import org.apache.flink.streaming.api.watermark.Watermark;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.api.response.MetricResponse;
import timely.api.response.MetricResponses;
import timely.client.websocket.ClientHandler;
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
import timely.serialize.JsonSerializer;
public class SubscriptionSource extends RichSourceFunction<MetricResponse> implements Serializable, StoppableFunction {
private static class SubscriptionThreadFactory implements ThreadFactory {
private static final String NAME = "Subscription Source";
private AtomicInteger threadNum = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, NAME + " " + threadNum.getAndIncrement());
}
}
private static final Logger LOG = LoggerFactory.getLogger(SubscriptionSource.class);
private static final long serialVersionUID = 1L;
private transient WebSocketSubscriptionClient client = null;
private long start = 0L;
private long end = 0L;
private final String[] metrics;
private final SummarizationJobParameters jp;
private final long window;
private final AtomicInteger subscriptionsRemaining;
public SubscriptionSource(SummarizationJobParameters jp) {
this.jp = jp;
start = jp.getStartTime();
end = jp.getEndTime();
metrics = jp.getMetrics();
window = jp.getSummarizationInterval().toMilliseconds();
subscriptionsRemaining = new AtomicInteger(metrics.length);
}
@Override
public void open(Configuration parameters) throws Exception {
LOG.info("Opening summarization job.");
super.open(parameters);
client = new WebSocketSubscriptionClient(jp.getTimelyHostname(), jp.getTimelyHttpsPort(),
jp.getTimelyWssPort(), jp.isDoLogin(), jp.getTimelyUsername(), jp.getTimelyPassword(),
jp.getKeyStoreFile(), jp.getKeyStoreType(), jp.getKeyStorePass(), jp.getTrustStoreFile(),
jp.getTrustStoreType(), jp.getTrustStorePass(), jp.isHostVerificationEnabled(), jp.getBufferSize());
}
@Override
public synchronized void close() throws Exception {
super.close();
if (null != client) {
client.close();
}
}
@Override
public void run(SourceContext<MetricResponse> ctx) throws Exception {
LOG.info("Running summarization job");
final SortedStringAccumulator dateTimeAccumulator = new SortedStringAccumulator();
this.getRuntimeContext().addAccumulator("source hourly count", dateTimeAccumulator);
final LongCounter sourceInputs = new LongCounter();
this.getRuntimeContext().addAccumulator("source input counter", sourceInputs);
final LongCounter inputProcessedInMainThread = new LongCounter();
this.getRuntimeContext().addAccumulator("input processed in main thread", inputProcessedInMainThread);
// Use only one thread to ensure that time is still ordered
final ExecutorService svc = Executors.newFixedThreadPool(1, new SubscriptionThreadFactory());
ClientHandler handler = new ClientHandler() {
@Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(new MessageHandler.Whole<String>() {
private final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd-HH");
private long lastWatermarkTime = 0L;
@Override
public void onMessage(final String message) {
LOG.info("Message received on Websocket session {}, length: {}", session.getId(),
message.length());
try {
// Deserialize in this thread
final MetricResponses responses = JsonSerializer.getObjectMapper().readValue(message,
MetricResponses.class);
// Process in the other
final Runnable r = () -> {
responses.getResponses().forEach(response -> {
if (response.isComplete()) {
LOG.info("Received last message.");
ctx.emitWatermark(new Watermark(Long.MAX_VALUE));
subscriptionsRemaining.getAndDecrement();
return;
}
LOG.trace("Received metric: {}", response);
long time = response.getTimestamp();
ctx.collectWithTimestamp(response, time);
dateTimeAccumulator.add(formatter.format(new Date(response.getTimestamp())));
sourceInputs.add(1);
// Emit a watermark every second of event
// time
if (lastWatermarkTime == 0) {
lastWatermarkTime = time;
} else if ((time - lastWatermarkTime) > window) {
lastWatermarkTime = time;
ctx.emitWatermark(new Watermark(time - 1));
}
});
};
try {
svc.execute(r);
} catch (RejectedExecutionException e) {
// Run it in this thread
r.run();
inputProcessedInMainThread.add(1);
}
} catch (IOException e) {
LOG.error("Error deserializing metric response, closing", e);
try {
close();
} catch (Exception e1) {
LOG.error("Error closing client", e1);
}
}
}
});
}
@Override
public void onClose(Session session, CloseReason reason) {
super.onClose(session, reason);
try {
close();
} catch (Exception e1) {
LOG.error("Error closing client", e1);
}
// Signal done sending data
ctx.emitWatermark(new Watermark(Long.MAX_VALUE));
}
@Override
public void onError(Session session, Throwable error) {
super.onError(session, error);
try {
close();
} catch (Exception e1) {
LOG.error("Error closing client", e1);
}
}
};
try {
client.open(handler);
for (String m : metrics) {
LOG.info("Adding subscription for {}", m);
client.addSubscription(m, null, start, end, 5000);
}
while (!client.isClosed() && subscriptionsRemaining.get() > 0) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
LOG.error("Sleep interrupted.");
}
}
} finally {
svc.shutdown();
}
}
@Override
public void cancel() {
LOG.info("Cancelling subscription source.");
try {
close();
} catch (Exception e) {
LOG.error("Error closing web socket client");
}
}
@Override
public void stop() {
LOG.info("Stopping subscription source.");
try {
close();
} catch (Exception e) {
LOG.error("Error closing web socket client");
}
}
}
@@ -0,0 +1,109 @@
package timely.analytics.flink;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.flink.api.common.accumulators.LongCounter;
import org.apache.flink.api.common.functions.FoldFunction;
import org.apache.flink.api.java.utils.ParameterTool;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.sink.SocketClientSink;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.api.response.MetricResponse;
public class SummarizationJob {
private static final Logger LOG = LoggerFactory.getLogger(SummarizationJob.class);
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("Usage: timely.analytics.flink.SummarizationJob <path_to_properties_file>");
System.exit(1);
}
LOG.info("Loading properties from: {}", args[0]);
ParameterTool params = ParameterTool.fromPropertiesFile(args[0]);
final SummarizationJobParameters jp = new SummarizationJobParameters(params);
LOG.info("Properties: {}", jp);
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// @formatter:off
env.getConfig().setGlobalJobParameters(jp);
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
env.addSource(new SubscriptionSource(jp), "Timely Metrics Subscription")
// partition by unique metric
.keyBy(new MetricKeySelector())
.window(TumblingEventTimeWindows.of(jp.getSummarizationInterval()))
.fold(new MetricHistogram(), new FoldFunction<MetricResponse, MetricHistogram>() {
private final Logger LOG = LoggerFactory
.getLogger("timely.analytics.SummarizationJob.FoldFunction@");
private static final long serialVersionUID = 1L;
@Override
public MetricHistogram fold(MetricHistogram histo, MetricResponse metric) throws Exception {
if (!histo.isInitialized()) {
histo.initialize(metric.getMetric(), metric.getTags());
} else {
if (!histo.getMetric().equals(metric.getMetric())) {
throw new RuntimeException("Metric name does not match - partitioning problem");
}
if (!histo.getTags().equals(metric.getTags())) {
throw new RuntimeException("Tags don't not match - partitioning problem");
}
}
LOG.trace("Updating histogram for {} with value {} at {} for metric {}", histo.getMetric()
+ histo.getTags(), metric.getValue(), metric.getTimestamp(), metric.getMetric()
+ metric.getTags());
histo.update(metric.getValue(), metric.getTimestamp());
return histo;
}
})
.name("Metric Windows")
.addSink(
new SocketClientSink<MetricHistogram>(jp.getTimelyHostname(), jp.getTimelyTcpPort(),
new MetricHistogram(), 2, true) {
private final Logger LOG = LoggerFactory
.getLogger("timely.analytics.SummarizationJob.SocketClientSink");
private static final long serialVersionUID = 1L;
private final LongCounter sinkCounter = new LongCounter();
private final SortedStringAccumulator dateTimeAccumulator = new SortedStringAccumulator();
private final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd-HH");
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
this.getRuntimeContext().addAccumulator("sink counter", this.sinkCounter);
this.getRuntimeContext().addAccumulator("sink hourly count", dateTimeAccumulator);
LOG.info("Sink opened");
}
@Override
public void invoke(MetricHistogram histo) throws Exception {
histo.done();
super.invoke(histo);
this.sinkCounter.add(1);
this.dateTimeAccumulator.add(formatter.format(new Date(histo.getTimestamp())));
}
@Override
public void close() throws Exception {
super.close();
LOG.info("Sink closed");
}
}).name("Timely Metric Sink");
// @formatter:on
env.execute("Metric Summarization");
// Looks like there is no way to stop Flink job if underlying web socket
// is closed.
}
}
@@ -0,0 +1,208 @@
package timely.analytics.flink;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.flink.api.common.ExecutionConfig.GlobalJobParameters;
import org.apache.flink.api.java.utils.ParameterTool;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.windowing.time.Time;
public class SummarizationJobParameters extends GlobalJobParameters implements Serializable {
private static final long serialVersionUID = 1L;
private final String timelyHostname;
private final int timelyTcpPort;
private final int timelyHttpsPort;
private final int timelyWssPort;
private final boolean doLogin;
private final String timelyUsername;
private final String timelyPassword;
private final String keyStoreFile;
private final String keyStoreType;
private final String keyStorePass;
private final String trustStoreFile;
private final String trustStoreType;
private final String trustStorePass;
private final boolean hostVerificationEnabled;
private final int bufferSize;
private final String[] metrics;
private final long startTime;
private final long endTime;
private final String interval;
private final String intervalUnits;
public SummarizationJobParameters(ParameterTool params) {
timelyHostname = params.getRequired("timelyHostname");
timelyTcpPort = params.getInt("timelyTcpPort", 4241);
timelyHttpsPort = params.getInt("timelyHttpsPort", 4242);
timelyWssPort = params.getInt("timelyWssPort", 4243);
doLogin = params.getBoolean("doLogin", false);
timelyUsername = params.get("timelyUsername", null);
timelyPassword = params.get("timelyPassword", null);
keyStoreFile = params.getRequired("keyStoreFile");
keyStoreType = params.get("keyStoreType", "JKS");
keyStorePass = params.getRequired("keyStorePass");
trustStoreFile = params.getRequired("trustStoreFile");
trustStoreType = params.get("trustStoreType", "JKS");
trustStorePass = params.getRequired("trustStorePass");
hostVerificationEnabled = params.getBoolean("hostVerificationEnabled", true);
bufferSize = params.getInt("bufferSize", 10485760);
String metricNames = params.getRequired("metrics");
if (null != metricNames) {
metrics = metricNames.split(",");
} else {
metrics = null;
}
startTime = params.getLong("startTime", 0L);
endTime = params.getLong("endTime", 0L);
interval = params.getRequired("interval");
intervalUnits = params.getRequired("intervalUnits");
}
public SummarizationJobParameters(Configuration conf) {
System.out.println("Creating job parameters from configuration: " + conf);
timelyHostname = conf.getString("timelyHostname", null);
timelyTcpPort = conf.getInteger("timelyTcpPort", 4241);
timelyHttpsPort = conf.getInteger("timelyHttpsPort", 4242);
timelyWssPort = conf.getInteger("timelyWssPort", 4243);
doLogin = conf.getBoolean("doLogin", false);
timelyUsername = conf.getString("timelyUsername", null);
timelyPassword = conf.getString("timelyPassword", null);
keyStoreFile = conf.getString("keyStoreFile", null);
keyStoreType = conf.getString("keyStoreType", "JKS");
keyStorePass = conf.getString("keyStorePass", null);
trustStoreFile = conf.getString("trustStoreFile", null);
trustStoreType = conf.getString("trustStoreType", "JKS");
trustStorePass = conf.getString("trustStorePass", null);
hostVerificationEnabled = conf.getBoolean("hostVerificationEnabled", true);
bufferSize = conf.getInteger("bufferSize", 10485760);
String metricNames = conf.getString("metrics", null);
if (null != metricNames) {
metrics = metricNames.split(",");
} else {
metrics = null;
}
startTime = conf.getLong("startTime", 0L);
endTime = conf.getLong("endTime", 0L);
interval = conf.getString("interval", null);
intervalUnits = conf.getString("intervalUnits", null);
}
public Time getSummarizationInterval() {
return Time.of(Long.parseLong(interval), TimeUnit.valueOf(intervalUnits));
}
public String getTimelyHostname() {
return timelyHostname;
}
public int getTimelyTcpPort() {
return timelyTcpPort;
}
public int getTimelyHttpsPort() {
return timelyHttpsPort;
}
public int getTimelyWssPort() {
return timelyWssPort;
}
public boolean isDoLogin() {
return doLogin;
}
public String getTimelyUsername() {
return timelyUsername;
}
public String getTimelyPassword() {
return timelyPassword;
}
public String getKeyStoreFile() {
return keyStoreFile;
}
public String getKeyStoreType() {
return keyStoreType;
}
public String getKeyStorePass() {
return keyStorePass;
}
public String getTrustStoreFile() {
return trustStoreFile;
}
public String getTrustStoreType() {
return trustStoreType;
}
public String getTrustStorePass() {
return trustStorePass;
}
public boolean isHostVerificationEnabled() {
return hostVerificationEnabled;
}
public int getBufferSize() {
return bufferSize;
}
public String[] getMetrics() {
return metrics;
}
public long getStartTime() {
return startTime;
}
public long getEndTime() {
return endTime;
}
public String getInterval() {
return interval;
}
public String getIntervalUnits() {
return intervalUnits;
}
@Override
public Map<String, String> toMap() {
Map<String, String> m = new HashMap<>();
m.put("timelyHostname", this.timelyHostname);
m.put("timelyHttpsPort", Integer.toString(this.timelyHttpsPort));
m.put("timelyWssPort", Integer.toString(this.timelyWssPort));
m.put("doLogin", Boolean.toString(this.doLogin));
m.put("timelyUsername", this.timelyUsername);
m.put("timelyPassword", this.timelyPassword);
m.put("keyStoreFile", this.keyStoreFile);
m.put("keyStoreType", this.keyStoreType);
m.put("keyStorePass", this.keyStorePass);
m.put("trustStoreFile", this.trustStoreFile);
m.put("trustStoreType", this.trustStoreType);
m.put("trustStorePass", this.trustStorePass);
m.put("hostVerificationEnabled", Boolean.toString(this.hostVerificationEnabled));
m.put("bufferSize", Integer.toString(this.bufferSize));
m.put("metrics", String.join(",", this.metrics));
m.put("startTime", Long.toString(this.startTime));
m.put("endTime", Long.toString(this.endTime));
m.put("interval", this.interval);
m.put("intervalUnits", this.intervalUnits);
return m;
}
@Override
public String toString() {
return toMap().toString();
}
}
@@ -0,0 +1,108 @@
package timely.analytics.flink;
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import timely.model.Metric;
import timely.model.Tag;
import timely.model.parse.MetricParser;
public class MetricHistogramTest {
private MetricHistogram m = null;
private long timestamp = System.currentTimeMillis();
@Before
public void createMetric() throws Exception {
m = new MetricHistogram();
for (double d = 1.0D; d <= 100.0; d += 1.0) {
timestamp += 1000;
m.update(d, timestamp);
}
m.toString();
Assert.assertEquals(timestamp, m.getTimestamp());
}
@Test
public void testMin() throws Exception {
Assert.assertEquals(1.0D, m.min(), 0.0D);
}
@Test
public void testMax() throws Exception {
Assert.assertEquals(100.0D, m.max(), 0.0D);
}
@Test
public void testAvg() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
Assert.assertEquals((sum / 100.0D), m.avg(), 0.0D);
}
@Test
public void testCount() throws Exception {
Assert.assertEquals(100.0D, m.count(), 0.0D);
}
@Test
public void test50thPercentile() throws Exception {
Assert.assertEquals(50.0D, m.getPercentile(50), 0.0D);
}
@Test
public void test75thPercentile() throws Exception {
Assert.assertEquals(75.0D, m.getPercentile(75), 0.0D);
}
@Test
public void test90thPercentile() throws Exception {
Assert.assertEquals(90.0D, m.getPercentile(90), 0.0D);
}
@Test
public void test99thPercentile() throws Exception {
Assert.assertEquals(99.0D, m.getPercentile(99), 0.0D);
}
@Test
public void testSerialization() throws Exception {
MetricParser metricParser = new MetricParser();
Tag t1 = new Tag("tag1=value1");
Tag t2 = new Tag("tag2=value2");
Tag avg = new Tag("sample=avg");
Tag min = new Tag("sample=min");
Tag max = new Tag("sample=max");
Tag sum = new Tag("sample=sum");
Tag count = new Tag("sample=count");
Tag p50 = new Tag("sample=50p");
Tag p75 = new Tag("sample=75p");
Tag p90 = new Tag("sample=90p");
Tag p99 = new Tag("sample=99p");
List<Tag> tags = new ArrayList<>();
tags.add(t1);
tags.add(t2);
m.initialize("sys.cpu.user", tags);
byte[] bytes = m.serialize(m);
String puts = new String(bytes);
for (String put : puts.split("\n")) {
Metric metric = metricParser.parse(put);
Assert.assertEquals("sys.cpu.user_summarized", metric.getName());
metric.getTags().forEach(
t -> {
Assert.assertTrue(t.equals(t1) || t.equals(t2) || t.equals(avg) || t.equals(min)
|| t.equals(max) || t.equals(sum) || t.equals(count) || t.equals(p50) || t.equals(p75)
|| t.equals(p90) || t.equals(p99));
});
}
}
}
+1
View File
@@ -0,0 +1 @@
/target/
+142
View File
@@ -0,0 +1,142 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>timely-client</artifactId>
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.5</version>
</parent>
<dependencies>
<dependency>
<groupId>timely</groupId>
<artifactId>timely-common</artifactId>
<version>${parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-client</artifactId>
<version>1.13</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-container-grizzly-client</artifactId>
<version>1.13</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>${version.findbugs-maven}</version>
<configuration>
<effort>Max</effort>
<threshold>Medium</threshold>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${version.jacoco}</version>
<reportSets>
<reportSet>
<id>JaCoCo Unit Test Coverage</id>
<configuration>
<dataFile>${project.build.directory}/coverage/jacoco-ut.exec</dataFile>
</configuration>
<reports>
<report>report</report>
</reports>
</reportSet>
<reportSet>
<id>JaCoCo Integration Test Coverage</id>
<configuration>
<dataFile>${project.build.directory}/coverage/jacoco-it.exec</dataFile>
</configuration>
<reports>
<report>report-integration</report>
</reports>
</reportSet>
</reportSets>
</plugin>
</plugins>
</reporting>
</project>
@@ -0,0 +1,82 @@
package timely.api;
import java.util.Map;
import java.util.Optional;
public class AddSubscription extends SubscriptionRequest {
private String operation = "add";
private String metric = null;
private Optional<Map<String, String>> tags = Optional.empty();
private Optional<Long> startTime = Optional.empty();
private Optional<Long> endTime = Optional.empty();
private Optional<Long> delayTime = Optional.empty();
public String getOperation() {
return operation;
}
public String getMetric() {
return metric;
}
public Optional<Map<String, String>> getTags() {
return tags;
}
public Optional<Long> getStartTime() {
return startTime;
}
public Optional<Long> getDelayTime() {
return delayTime;
}
public void setMetric(String metric) {
this.metric = metric;
}
public void setTags(Optional<Map<String, String>> tags) {
this.tags = tags;
}
public void setStartTime(Optional<Long> startTime) {
this.startTime = startTime;
}
public void setDelayTime(Optional<Long> delayTime) {
this.delayTime = delayTime;
}
public Optional<Long> getEndTime() {
return endTime;
}
public void setEndTime(Optional<Long> endTime) {
this.endTime = endTime;
}
@Override
public int hashCode() {
return (operation + subscriptionId + metric + tags + startTime + endTime + delayTime).hashCode();
}
@Override
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof AddSubscription) {
AddSubscription other = (AddSubscription) obj;
return (this.subscriptionId.equals(other.subscriptionId) && this.metric.equals(other.metric)
&& this.tags.equals(other.tags) && this.startTime.equals(other.startTime)
&& this.endTime.equals(other.endTime) && this.delayTime.equals(other.delayTime));
} else {
return false;
}
}
}
@@ -0,0 +1,45 @@
package timely.api;
public class BasicAuthLogin {
protected String username;
protected String password;
public String getUsername() {
return username;
}
public void setUsername(String user) {
this.username = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public int hashCode() {
return (username + password).hashCode();
}
@Override
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof BasicAuthLogin) {
BasicAuthLogin other = (BasicAuthLogin) obj;
return (this.username.equals(other.username) && this.password.equals(other.password));
} else {
return false;
}
}
}
@@ -0,0 +1,32 @@
package timely.api;
public class CloseSubscription extends SubscriptionRequest {
private String operation = "close";
public String getOperation() {
return operation;
}
@Override
public int hashCode() {
return (operation + subscriptionId).hashCode();
}
@Override
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof CloseSubscription) {
CloseSubscription other = (CloseSubscription) obj;
return (this.subscriptionId.equals(other.subscriptionId));
} else {
return false;
}
}
}
@@ -0,0 +1,32 @@
package timely.api;
public class CreateSubscription extends SubscriptionRequest {
private String operation = "create";
public String getOperation() {
return operation;
}
@Override
public int hashCode() {
return (operation + subscriptionId).hashCode();
}
@Override
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof CreateSubscription) {
CreateSubscription other = (CreateSubscription) obj;
return (this.subscriptionId.equals(other.subscriptionId));
} else {
return false;
}
}
}
@@ -0,0 +1,41 @@
package timely.api;
public class RemoveSubscription extends SubscriptionRequest {
private String operation = "remove";
private String metric = null;
public String getOperation() {
return operation;
}
public String getMetric() {
return metric;
}
public void setMetric(String metric) {
this.metric = metric;
}
@Override
public int hashCode() {
return (operation + subscriptionId + metric).hashCode();
}
@Override
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof RemoveSubscription) {
RemoveSubscription other = (RemoveSubscription) obj;
return (this.subscriptionId.equals(other.subscriptionId) && this.metric.equals(other.metric));
} else {
return false;
}
}
}
@@ -0,0 +1,15 @@
package timely.api;
public abstract class SubscriptionRequest {
protected String subscriptionId = null;
public final String getSubscriptionId() {
return subscriptionId;
}
public final void setSubscriptionId(String subscriptionId) {
this.subscriptionId = subscriptionId;
}
}
@@ -6,7 +6,8 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import timely.api.model.Tag;
import timely.model.Metric;
import timely.model.Tag;
public class MetricResponse {
@@ -14,6 +15,8 @@ public class MetricResponse {
private long timestamp;
private double value;
private List<Tag> tags;
private String subscriptionId;
private boolean complete = false;
public String getMetric() {
return metric;
@@ -31,6 +34,10 @@ public class MetricResponse {
return tags;
}
public boolean isComplete() {
return complete;
}
public void setMetric(String metric) {
this.metric = metric;
}
@@ -47,6 +54,29 @@ public class MetricResponse {
this.tags = tags;
}
public String getSubscriptionId() {
return subscriptionId;
}
public void setSubscriptionId(String subscriptionId) {
this.subscriptionId = subscriptionId;
}
public void setComplete(boolean closed) {
this.complete = closed;
}
public static MetricResponse fromMetric(Metric metric, String subscriptionId) {
MetricResponse response = new MetricResponse();
response.setMetric(metric.getName());
response.setTimestamp(metric.getValue().getTimestamp());
response.setTags(metric.getTags());
response.setValue(metric.getValue().getMeasure());
response.setSubscriptionId(subscriptionId);
response.setComplete(false);
return response;
}
@Override
public int hashCode() {
HashCodeBuilder hash = new HashCodeBuilder();
@@ -54,6 +84,8 @@ public class MetricResponse {
hash.append(this.timestamp);
hash.append(this.value);
hash.append(this.tags);
hash.append(this.subscriptionId);
hash.append(this.complete);
return hash.hashCode();
}
@@ -74,6 +106,8 @@ public class MetricResponse {
equals.append(this.timestamp, other.timestamp);
equals.append(this.value, other.value);
equals.append(this.tags, other.tags);
equals.append(this.subscriptionId, other.subscriptionId);
equals.append(this.complete, other.complete);
return equals.isEquals();
}
@@ -84,6 +118,8 @@ public class MetricResponse {
tsb.append("timestamp", this.timestamp);
tsb.append("value", this.value);
tsb.append("tags", this.tags);
tsb.append("subscriptionId", this.subscriptionId);
tsb.append("complete", this.complete);
return tsb.toString();
}
@@ -0,0 +1,29 @@
package timely.api.response;
import java.util.ArrayList;
import java.util.List;
public class MetricResponses {
private List<MetricResponse> responses = new ArrayList<>();
public synchronized List<MetricResponse> getResponses() {
return this.responses;
}
public synchronized void setResponses(List<MetricResponse> responses) {
this.responses = responses;
}
public synchronized void addResponse(MetricResponse r) {
this.responses.add(r);
}
public int size() {
return this.responses.size();
}
public synchronized void clear() {
this.responses.clear();
}
}
@@ -0,0 +1,55 @@
package timely.client.http;
import javax.net.ssl.SSLContext;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.glassfish.tyrus.client.SslContextConfigurator;
public class HttpClient {
public static SSLContext getSSLContext(String trustStoreFile, String trustStoreType, String trustStorePass,
String keyStoreFile, String keyStoreType, String keyStorePass) {
SslContextConfigurator scc = new SslContextConfigurator();
scc.setTrustStoreFile(trustStoreFile);
scc.setTrustStoreType(trustStoreType);
if (null != trustStorePass) {
scc.setTrustStorePassword(trustStorePass);
}
scc.setKeyStoreFile(keyStoreFile);
scc.setKeyStoreType(keyStoreType);
if (null != keyStorePass) {
scc.setKeyStorePassword(keyStorePass);
}
return scc.createSSLContext();
}
public static CloseableHttpClient get(String trustStoreFile, String trustStoreType, String trustStorePass,
String keyStoreFile, String keyStoreType, String keyStorePass, CookieStore cookieStore,
boolean hostVerificationEnabled) {
SSLContext ssl = getSSLContext(trustStoreFile, trustStoreType, trustStorePass, keyStoreFile, keyStoreType,
keyStorePass);
return get(ssl, cookieStore, hostVerificationEnabled);
}
public static CloseableHttpClient get(SSLContext ssl, CookieStore cookieStore, boolean hostVerificationEnabled) {
RequestConfig defaultRequestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
HttpClientBuilder builder = HttpClients.custom().setSSLContext(ssl).setDefaultCookieStore(cookieStore)
.setDefaultRequestConfig(defaultRequestConfig);
if (hostVerificationEnabled) {
builder.setSSLHostnameVerifier(new DefaultHostnameVerifier());
} else {
builder.setSSLHostnameVerifier(new NoopHostnameVerifier());
}
return builder.build();
}
}
@@ -0,0 +1,106 @@
package timely.client.tcp;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TcpClient implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(TcpClient.class);
private final String host;
private final int port;
private Socket sock = null;
private PrintWriter out = null;
private long connectTime = 0L;
private long backoff = 2000;
public TcpClient(String hostname, int port) {
this.host = hostname;
this.port = port;
}
/**
* Opens a TCP connection to the specified host and port
*
* @throws IOException
* if an error occurs
*/
public void open() throws IOException {
if (connect() != 0) {
throw new IOException();
}
}
/**
* Write a metric to Timely
*
* @param metric
* newline terminated string representation of Timely metric
* @throws IOException
*/
public synchronized void write(String metric) throws IOException {
if (connect() != 0) {
throw new IOException();
}
out.write(metric);
}
public synchronized void flush() {
if (null != out) {
out.flush();
}
}
/**
* Closes the tcp connection to Timely
*
* @throws IOException
* if an error occurs
*/
@Override
public void close() throws IOException {
LOG.info("Shutting down connection to Timely at {}:{}", host, port);
if (null != sock) {
try {
if (null != out) {
out.close();
}
sock.close();
} catch (IOException e) {
LOG.error("Error closing connection to Timely at " + host + ":" + port + ". Error: " + e.getMessage());
} finally {
sock = null;
}
}
}
private synchronized int connect() {
if (null == sock || !sock.isConnected() || out.checkError()) {
if (System.currentTimeMillis() > (connectTime + backoff)) {
try {
connectTime = System.currentTimeMillis();
sock = new Socket(host, port);
out = new PrintWriter(sock.getOutputStream(), false);
backoff = 2000;
LOG.info("Connected to Timely at {}:{}", host, port);
} catch (IOException e) {
LOG.error("Error connecting to Timely at {}:" + host + ":" + port + ". Error: " + e.getMessage());
backoff = backoff * 2;
sock = null;
out = null;
LOG.warn("Will retry connection in {} ms.", backoff);
return -1;
}
} else {
LOG.warn("Not writing to Timely, waiting to reconnect");
return -1;
}
}
return 0;
}
}
@@ -0,0 +1,45 @@
package timely.client.udp;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
public class UdpClient implements AutoCloseable {
private final InetSocketAddress address;
private final DatagramPacket packet;
private DatagramSocket sock;
public UdpClient(String hostname, int port) {
this.address = new InetSocketAddress(hostname, port);
this.packet = new DatagramPacket("".getBytes(UTF_8), 0, 0, address.getAddress(), port);
}
public void open() throws IOException {
if (null == sock) {
this.sock = new DatagramSocket();
}
}
public void write(String metric) throws IOException {
if (null == this.sock) {
throw new IllegalStateException("Must call open first");
}
this.packet.setData(metric.getBytes(UTF_8));
this.sock.send(packet);
}
public void flush() throws IOException {
}
public void close() throws IOException {
if (null != sock) {
sock.close();
sock = null;
}
}
}
@@ -0,0 +1,38 @@
package timely.client.websocket;
import javax.websocket.CloseReason;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class ClientHandler extends Endpoint {
private final static Logger LOG = LoggerFactory.getLogger(ClientHandler.class);
@Override
public void onOpen(Session session, EndpointConfig config) {
LOG.info("Websocket session {} opened.", session.getId());
session.addMessageHandler(new MessageHandler.Whole<String>() {
@Override
public void onMessage(String message) {
LOG.info("Message received on Websocket session {}: {}", session.getId(), message);
}
});
}
@Override
public void onClose(Session session, CloseReason reason) {
LOG.info("Websocket session {} closed.", session.getId());
}
@Override
public void onError(Session session, Throwable error) {
LOG.error("Error occurred on Websocket session" + session.getId(), error);
}
}
@@ -0,0 +1,65 @@
package timely.client.websocket;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.websocket.ClientEndpointConfig;
import javax.websocket.Decoder;
import javax.websocket.Encoder;
import javax.websocket.Extension;
import org.apache.http.cookie.Cookie;
public class TimelyEndpointConfig implements ClientEndpointConfig {
private String sessionCookie = null;
private static final String FORMAT = "%s=%s;";
public TimelyEndpointConfig(Cookie sessionCookie) {
if (null != sessionCookie) {
this.sessionCookie = String.format(FORMAT, sessionCookie.getName(), sessionCookie.getValue());
}
}
@Override
public List<Class<? extends Encoder>> getEncoders() {
return Collections.emptyList();
}
@Override
public List<Class<? extends Decoder>> getDecoders() {
return Collections.emptyList();
}
@Override
public Map<String, Object> getUserProperties() {
return Collections.emptyMap();
}
@Override
public List<String> getPreferredSubprotocols() {
return Collections.emptyList();
}
@Override
public List<Extension> getExtensions() {
return Collections.emptyList();
}
@Override
public Configurator getConfigurator() {
return new Configurator() {
@Override
public void beforeRequest(Map<String, List<String>> headers) {
super.beforeRequest(headers);
if (null != sessionCookie) {
headers.put("Cookie", Collections.singletonList(sessionCookie));
}
}
};
}
}
@@ -0,0 +1,179 @@
package timely.client.websocket;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.websocket.DeploymentException;
import javax.websocket.Session;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.glassfish.tyrus.client.ClientManager;
import org.glassfish.tyrus.client.ClientProperties;
import org.glassfish.tyrus.client.SslEngineConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.api.BasicAuthLogin;
import timely.client.http.HttpClient;
import timely.serialize.JsonSerializer;
import com.google.common.base.Preconditions;
public class WebSocketClient implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(WebSocketClient.class);
private final String timelyHostname;
private final int timelyHttpsPort;
private final int timelyWssPort;
private final boolean doLogin;
private final String timelyUsername;
private final String timelyPassword;
private final boolean hostVerificationEnabled;
private final int bufferSize;
private final SSLContext ssl;
private ClientManager webSocketClient = null;
protected Session session = null;
protected volatile boolean closed = true;
protected WebSocketClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort,
boolean doLogin, String timelyUsername, String timelyPassword, boolean hostVerificationEnabled,
int bufferSize) {
this.ssl = ssl;
this.timelyHostname = timelyHostname;
this.timelyHttpsPort = timelyHttpsPort;
this.timelyWssPort = timelyWssPort;
this.doLogin = doLogin;
this.timelyUsername = timelyUsername;
this.timelyPassword = timelyPassword;
this.hostVerificationEnabled = hostVerificationEnabled;
this.bufferSize = bufferSize;
Preconditions.checkNotNull(timelyHostname, "%s must be supplied", "Timely host name");
Preconditions.checkNotNull(timelyHttpsPort, "%s must be supplied", "Timely HTTPS port");
Preconditions.checkNotNull(timelyWssPort, "%s must be supplied", "Timely WSS port");
if (doLogin
&& ((StringUtils.isEmpty(timelyUsername) && !StringUtils.isEmpty(timelyPassword) || (!StringUtils
.isEmpty(timelyUsername) && StringUtils.isEmpty(timelyPassword))))) {
throw new IllegalArgumentException("Both Timely username and password must be empty or non-empty");
}
}
protected WebSocketClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean doLogin,
String timelyUsername, String timelyPassword, String keyStoreFile, String keyStoreType,
String keyStorePass, String trustStoreFile, String trustStoreType, String trustStorePass,
boolean hostVerificationEnabled, int bufferSize) {
this(HttpClient.getSSLContext(trustStoreFile, trustStoreType, trustStorePass, keyStoreFile, keyStoreType,
keyStorePass), timelyHostname, timelyHttpsPort, timelyWssPort, doLogin, timelyUsername, timelyPassword,
hostVerificationEnabled, bufferSize);
}
public void open(ClientHandler clientEndpoint) throws IOException, DeploymentException, URISyntaxException {
Cookie sessionCookie = null;
if (doLogin) {
BasicCookieStore cookieJar = new BasicCookieStore();
try (CloseableHttpClient client = HttpClient.get(ssl, cookieJar, hostVerificationEnabled)) {
String target = "https://" + timelyHostname + ":" + timelyHttpsPort + "/login";
HttpRequestBase request = null;
if (StringUtils.isEmpty(timelyUsername)) {
// HTTP GET to /login to use certificate based login
request = new HttpGet(target);
LOG.trace("Performing client certificate login");
} else {
// HTTP POST to /login to use username/password
BasicAuthLogin login = new BasicAuthLogin();
login.setUsername(timelyUsername);
login.setPassword(timelyPassword);
String payload = JsonSerializer.getObjectMapper().writeValueAsString(login);
HttpPost post = new HttpPost(target);
post.setEntity(new StringEntity(payload));
request = post;
LOG.trace("Performing BasicAuth login");
}
HttpResponse response = null;
try {
response = client.execute(request);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new HttpResponseException(response.getStatusLine().getStatusCode(), response
.getStatusLine().getReasonPhrase());
}
for (Cookie c : cookieJar.getCookies()) {
if (c.getName().equals("TSESSIONID")) {
sessionCookie = c;
break;
}
}
if (null == sessionCookie) {
throw new IllegalStateException(
"Unable to find TSESSIONID cookie header in Timely login response");
}
} finally {
HttpClientUtils.closeQuietly(response);
}
}
}
SslEngineConfigurator sslEngine = new SslEngineConfigurator(ssl);
sslEngine.setClientMode(true);
sslEngine.setHostVerificationEnabled(hostVerificationEnabled);
webSocketClient = ClientManager.createClient();
webSocketClient.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngine);
webSocketClient.getProperties().put(ClientProperties.INCOMING_BUFFER_SIZE, bufferSize);
String wssPath = "wss://" + timelyHostname + ":" + timelyWssPort + "/websocket";
session = webSocketClient.connectToServer(clientEndpoint, new TimelyEndpointConfig(sessionCookie), new URI(
wssPath));
final ByteBuffer pingData = ByteBuffer.allocate(0);
webSocketClient.getScheduledExecutorService().scheduleAtFixedRate(() -> {
try {
session.getBasicRemote().sendPing(pingData);
} catch (Exception e) {
LOG.error("Error sending ping", e);
}
}, 30, 60, TimeUnit.SECONDS);
closed = false;
}
public synchronized void close() throws IOException {
if (closed) {
return;
}
try {
if (null != webSocketClient) {
webSocketClient.shutdown();
}
} finally {
session = null;
webSocketClient = null;
closed = true;
}
}
public boolean isClosed() {
return closed;
}
}
@@ -0,0 +1,92 @@
package timely.client.websocket.subscription;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.Future;
import javax.net.ssl.SSLContext;
import javax.websocket.CloseReason;
import javax.websocket.DeploymentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.api.AddSubscription;
import timely.api.CloseSubscription;
import timely.api.CreateSubscription;
import timely.api.RemoveSubscription;
import timely.client.websocket.ClientHandler;
import timely.client.websocket.WebSocketClient;
import timely.serialize.JsonSerializer;
public class WebSocketSubscriptionClient extends WebSocketClient {
private static final Logger LOG = LoggerFactory.getLogger(WebSocketSubscriptionClient.class);
private final String subscriptionId;
public WebSocketSubscriptionClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort,
boolean doLogin, String timelyUsername, String timelyPassword, boolean hostVerificationEnabled,
int bufferSize) {
super(ssl, timelyHostname, timelyHttpsPort, timelyWssPort, doLogin, timelyUsername, timelyPassword,
hostVerificationEnabled, bufferSize);
subscriptionId = UUID.randomUUID().toString();
LOG.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
}
public WebSocketSubscriptionClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean doLogin,
String timelyUsername, String timelyPassword, String keyStoreFile, String keyStoreType,
String keyStorePass, String trustStoreFile, String trustStoreType, String trustStorePass,
boolean hostVerificationEnabled, int bufferSize) {
super(timelyHostname, timelyHttpsPort, timelyWssPort, doLogin, timelyUsername, timelyPassword, keyStoreFile,
keyStoreType, keyStorePass, trustStoreFile, trustStoreType, trustStorePass, hostVerificationEnabled,
bufferSize);
subscriptionId = UUID.randomUUID().toString();
LOG.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
}
@Override
public void open(ClientHandler clientEndpoint) throws IOException, DeploymentException, URISyntaxException {
super.open(clientEndpoint);
CreateSubscription create = new CreateSubscription();
create.setSubscriptionId(subscriptionId);
session.getBasicRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(create));
}
@Override
public synchronized void close() throws IOException {
if (null != session) {
CloseSubscription close = new CloseSubscription();
close.setSubscriptionId(subscriptionId);
try {
session.getBasicRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(close));
session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Client called close."));
} catch (Exception e) {
LOG.info("Unable to send close message to server: {}", e.getMessage());
}
}
super.close();
}
public Future<Void> addSubscription(String metric, Map<String, String> tags, long startTime, long endTime,
long delayTime) throws IOException {
AddSubscription add = new AddSubscription();
add.setSubscriptionId(subscriptionId);
add.setMetric(metric);
add.setTags(Optional.ofNullable(tags));
add.setStartTime(Optional.ofNullable(startTime));
add.setEndTime(Optional.ofNullable(endTime));
add.setDelayTime(Optional.ofNullable(delayTime));
return session.getAsyncRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(add));
}
public Future<Void> removeSubscription(String metric) throws Exception {
RemoveSubscription remove = new RemoveSubscription();
remove.setSubscriptionId(subscriptionId);
remove.setMetric(metric);
return session.getAsyncRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(remove));
}
}
@@ -0,0 +1,190 @@
package timely.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import timely.model.parse.TagParser;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
/**
* A Metric consists of a metric name, tags, and a Value
*
* Json has been flattened to reduce overhead. Example:
* {"name":"m1","timestamp":1,"measure":1.0,"tags":[{"k1":"v1"}]}
*
*/
@JsonRootName("metric")
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({ "name" })
public class Metric implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private List<Tag> tags;
private Value value;
public Metric() {
tags = new ArrayList<>();
value = new Value();
}
public Metric(Metric other) {
this();
this.name = other.getName();
this.tags.addAll(other.getTags());
this.value = new Value(other.getValue());
}
public Metric(String name, long timestamp, double measure) {
this();
this.name = name;
this.value.setTimestamp(timestamp);
this.value.setMeasure(measure);
}
public Metric(String name, long timestamp, double measure, List<Tag> tags) {
this(name, timestamp, measure);
this.setTags(tags);
}
public Metric(String name, List<Tag> tags) {
this();
this.name = name;
this.setTags(tags);
}
public static Builder newBuilder() {
return new Builder();
}
@JsonGetter("name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@JsonGetter("tags")
public List<Tag> getTags() {
return tags;
}
public void setTags(List<Tag> tags) {
this.tags.addAll(tags);
}
public void addTag(Tag tag) {
tags.add(new Tag(tag));
}
@JsonUnwrapped
public Value getValue() {
return value;
}
public void setValue(Value value) {
this.value = value;
}
@Override
public String toString() {
Collections.sort(tags);
return "Metric{" + "name='" + name + '\'' + ", tags=" + tags + ", value=" + value + '}';
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Metric metric = (Metric) o;
if (name != null ? !name.equals(metric.name) : metric.name != null)
return false;
if (tags != null) {
if (tags.size() != metric.tags.size()) {
return false;
} else if (!tags.containsAll(metric.tags)) {
return false;
}
}
return value != null ? value.equals(metric.value) : metric.value == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (tags != null ? tags.hashCode() : 0);
result = 31 * result + (value != null ? value.hashCode() : 0);
return result;
}
/**
* Simple Builder for Metric. Note: cannot re-use a builder after build is
* called.
*/
public static class Builder {
Metric metric;
private Builder() {
metric = new Metric();
}
private static TagParser parser = new TagParser();
public Builder tag(Tag tag) {
metric.addTag(tag);
return this;
}
public Builder tags(List<Tag> tags) {
metric.setTags(tags);
return this;
}
public Builder tag(String key, String value) {
metric.addTag(new Tag(key, value));
return this;
}
public Builder tag(String rawTag) {
metric.addTag(parser.parse(rawTag));
return this;
}
public Builder name(String name) {
metric.setName(name);
return this;
}
public Builder value(Value value) {
metric.setValue(value);
return this;
}
public Builder value(long timestamp, double measure) {
metric.setValue(new Value(timestamp, measure));
return this;
}
public Metric build() {
return this.metric;
}
}
}
+111
View File
@@ -0,0 +1,111 @@
package timely.model;
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.Preconditions;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import timely.model.parse.TagParser;
import java.io.Serializable;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Tag consists of key value pair
*/
@JsonRootName("tag")
public class Tag implements Comparable<Tag>, Serializable {
private static final long serialVersionUID = 1L;
private static final TagParser tagParser = new TagParser();
private String key;
private String value;
public Tag() {
}
public Tag(Tag other) {
this.setKey(other.getKey());
this.setValue(other.getValue());
}
public Tag(String tag) {
this(tagParser.parse(tag));
}
public Tag(String key, String value) {
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(value);
this.setKey(key);
this.setValue(value);
}
@JsonAnyGetter
public Map<String, String> get() {
return Stream.of(this).collect(Collectors.toMap(Tag::getKey, Tag::getValue));
}
@JsonAnySetter
public void set(String key, String value) {
this.key = key;
this.value = value;
}
@JsonIgnore
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
@JsonIgnore
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
/**
* Joins key and value into key=value
*
* @return
*/
public String join() {
return tagParser.combine(this);
}
@Override
public String toString() {
return "Tag{" + join() + "}";
}
@Override
public int hashCode() {
return this.toString().hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (null == o || getClass() != o.getClass())
return false;
Tag other = (Tag) o;
return new EqualsBuilder().append(this.key, other.key).append(this.value, other.value).isEquals();
}
@Override
public int compareTo(Tag other) {
return new CompareToBuilder().append(this.key, other.key).append(this.value, other.value).toComparison();
}
}
@@ -0,0 +1,93 @@
package timely.model;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Objects;
import java.io.Serializable;
import java.util.Comparator;
import java.util.concurrent.TimeUnit;
/**
* Value consists of a long timestamp and a double measurement
*/
public class Value implements Comparator<Value>, Serializable {
private static final long serialVersionUID = 1L;
private Long timestamp;
private Double measure;
public Value() {
}
public Value(Value other) {
this.setTimestamp(other.getTimestamp());
this.setMeasure(other.getMeasure());
}
@JsonCreator
public Value(@JsonProperty("timestamp") Long timestamp, @JsonProperty("measure") Double measure) {
this.setTimestamp(timestamp);
this.setMeasure(measure);
}
@JsonProperty("timestamp")
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(final Long timestamp) {
this.setTimestamp(timestamp, TimeUnit.MILLISECONDS);
}
public void setTimestamp(final Long timestamp, TimeUnit timeUnit) {
this.timestamp = timeUnit.toMillis(timestamp);
}
@JsonProperty("measure")
public Double getMeasure() {
return measure;
}
public void setMeasure(final Double measure) {
this.measure = measure;
}
@Override
/**
* Compares timestamps for sorting.
*
* Note: this comparator imposes orderings that are inconsistent with equals
*
*/
public int compare(Value v1, Value v2) {
if (v1.getTimestamp().equals(v2.getTimestamp()))
return 0;
return v1.getTimestamp() > v2.getTimestamp() ? 1 : -1;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (null == o || getClass() != o.getClass())
return false;
if (getTimestamp() != null ? !getTimestamp().equals(((Value) o).getTimestamp())
: ((Value) o).getTimestamp() != null)
return false;
return !(getMeasure() != null ? !getMeasure().equals(((Value) o).getMeasure())
: ((Value) o).getMeasure() != null);
}
@Override
public int hashCode() {
return Objects.hashCode(timestamp, measure);
}
@Override
public String toString() {
return "Value{" + "timestamp=" + timestamp + ", measure=" + measure + "}";
}
}
@@ -0,0 +1,6 @@
package timely.model.parse;
public interface Combiner<T> {
String combine(T o);
}
@@ -0,0 +1,30 @@
package timely.model.parse;
import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import timely.model.Metric;
import java.util.List;
public class MetricParser implements Parser<Metric> {
private static final Splitter spaceSplitter = Splitter.on(" ").omitEmptyStrings().trimResults();
@Override
public Metric parse(String line) {
// put specification
//
// put <metricName> <timestamp> <value> <tagK=tagV> <tagK=tagV> ...
List<String> parts = spaceSplitter.splitToList(line);
Preconditions.checkPositionIndex(3, parts.size());
Metric.Builder builder = Metric.newBuilder();
// index 0 is put
builder.name(parts.get(1)); // metric name
builder.value(Long.parseLong(parts.get(2)), Double.parseDouble(parts.get(3)));
parts.stream().skip(4).forEach(builder::tag);
return builder.build();
}
}
@@ -0,0 +1,7 @@
package timely.model.parse;
@FunctionalInterface
public interface Parser<T> {
T parse(String t);
}
@@ -0,0 +1,53 @@
package timely.model.parse;
import com.google.common.base.Splitter;
import timely.model.Tag;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* Parses tag1=val1,tag2=val2,tag3=val3 into a {@code List} of {@code Tag}
* Combines {@code List} of {@code Tag} into {@code String} of
* tag1=val1,tag2=val2,tag3=val3.
*/
public class TagListParser implements Parser<List<Tag>>, Combiner<Collection<Tag>> {
private static final Splitter commaSplitter = Splitter.on(",").omitEmptyStrings();
private static final TagParser tagParser = new TagParser();
@Override
public List<Tag> parse(String t) {
ArrayList<Tag> tags = new ArrayList<>();
commaSplitter.splitToList(t).forEach(p -> tags.add(tagParser.parse(p)));
return tags;
}
@Override
public String combine(Collection<Tag> tags) {
StringBuilder builder = new StringBuilder();
if (!tags.isEmpty()) {
tags.forEach(p -> builder.append(tagParser.combine(p)).append(','));
builder.setLength(builder.length() - 1);
}
return builder.toString();
}
/**
* An alternative combiner for a map of string to string instead of a list
* of tags
*
* @param tags
* @return string representation
*/
public String combine(Map<String, String> tags) {
StringBuilder builder = new StringBuilder();
if (!tags.isEmpty()) {
tags.forEach((k, v) -> builder.append(tagParser.combine(new Tag(k, v))).append(','));
builder.setLength(builder.length() - 1);
}
return builder.toString();
}
}
@@ -0,0 +1,32 @@
package timely.model.parse;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import timely.model.Tag;
import java.util.List;
/**
* Parses tag1=val1 into a {@code Tag} Combines {@code Tag} into {@code String}
* of tag1=val1
*/
public class TagParser implements Parser<Tag>, Combiner<Tag> {
private static final Splitter equalSplitter = Splitter.on("=").trimResults();
private static final Joiner equalsJoiner = Joiner.on("=");
@Override
public Tag parse(String t) {
List<String> parts = equalSplitter.splitToList(t);
if (parts.size() != 2) {
throw new IllegalArgumentException("Invalid tag format: " + t);
}
return new Tag(parts.get(0), parts.get(1));
}
@Override
public String combine(Tag t) {
return equalsJoiner.join(t.getKey(), t.getValue());
}
}
@@ -0,0 +1,22 @@
package timely.serialize;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
public class JsonSerializer {
private static ObjectMapper mapper = new ObjectMapper();
static {
mapper.registerModule(new Jdk8Module());
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true);
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
mapper.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
}
public static ObjectMapper getObjectMapper() {
return mapper;
}
}
+318
View File
@@ -0,0 +1,318 @@
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.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_period) + " sample average)"
else:
alertTitle += "(y < " + str(-config.alert_percentage) + "% below " + 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 greater than ' + config.min_alert_period
if config.last_alert is not None:
alertTitle = alertTitle + ' in last ' + config.last_alert
title += separator + alertTitle
return title
+128
View File
@@ -0,0 +1,128 @@
import time
from datetime import datetime
from datetime import timedelta
from datetime import tzinfo
from pandas.tslib import Timedelta
import pandas
class TimeDateError(ValueError):
def __init__(self, message, *args):
self.message = message
super(TimeDateError, self).__init__(message, *args)
ZERO = timedelta(0)
# A UTC class.
class UTC(tzinfo):
"""UTC"""
def __str__(self):
return "UTC"
def utcoffset(self, dt):
return ZERO
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return ZERO
utc = UTC()
class TimeDateRange:
beginDt = None
endDt = None
format = "%Y%m%d %H%M%S"
def getBeginMs(self):
if self.beginDt == None:
return None
return int(time.mktime(self.beginDt.timetuple()) * 1000)
def getBeginStr(self):
if self.beginDt == None:
return None
return time.strftime(self.format, self.beginDt.timetuple())
def getEndMs(self):
if self.endDt == None:
return None
return int(time.mktime(self.endDt.timetuple()) * 1000)
def getEndStr(self):
if self.endDt == None:
return None
return time.strftime(self.format, self.endDt.timetuple())
def __init__(self, beginStr, endStr, period, format="%Y%m%d-%H%M%S"):
now = datetime.now(tz=utc)
nowMs = TimeDateRange.unix_time_millis(now)
if beginStr != None and endStr != None and period != None:
raise TimeDateError("You can not provide a begin, end, and period")
elif (beginStr == None and endStr == None and period == None) or (period == None and beginStr == None):
raise TimeDateError("You must provide a time range")
if period == None:
# calculate begin time
beginTuple = time.strptime(beginStr, self.format)
self.beginDt = datetime(*beginTuple[0:6], tzinfo=utc)
# calculate end time
# end is either specified or now
if endStr == None or endStr == 'now':
self.endDt = now
else:
self.endDt = datetime(*time.strptime(endStr, self.format)[0:6], tzinfo=utc)
if self.endDt > now:
self.endDt = now
else:
# period must be specified
td = pandas.to_timedelta(period)
rangeInSec = td.total_seconds()
if beginStr == None:
# calculate begin time from end tme and period
# calculate end time
# end is either specified or now
if endStr == None or endStr == 'now':
self.endDt = now
else:
self.endDt = datetime(*time.strptime(endStr, self.format)[0:6], tzinfo=utc)
if self.endDt > now:
self.endDt = now
# calculate begin time
self.beginDt = self.endDt - timedelta(milliseconds=rangeInSec * 1000)
else:
# calculate end time from begin tme and period
# calculate begin time
self.beginDt = datetime(*time.strptime(beginStr, self.format)[0:6], tzinfo=utc)
# calculate end time
self.endDt = self.beginDt + timedelta(milliseconds=rangeInSec * 1000)
if self.endDt > now:
self.endDt = now
if self.beginDt > now:
raise TimeDateError("begin date/time can not be in the future")
if self.beginDt > self.endDt:
raise TimeDateError("begin date/time can not be past end date/time")
epoch = datetime.utcfromtimestamp(0).replace(tzinfo=utc)
@classmethod
def unix_time_millis(cls, dt):
return (dt - TimeDateRange.epoch).total_seconds() * 1000.0
+72
View File
@@ -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
+201
View File
@@ -0,0 +1,201 @@
import TimelyMetric
from TimeDateRange import TimeDateRange
from TimeDateRange import UTC
from TimelyAnalyticConfiguration import TimelyAnalyticConfiguration
import DataOperations
import pandas
import re
from pandas.tslib import Timestamp
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 find_alerts(timelyMetric, analyticConfig, notebook=False):
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()
now = Timestamp.now()
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.alert_percentage 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_values = addCondition(analyticConfig.orCondition, result_values, currCondition)
any_conditions_values = True
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_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 evaluate the last analyticConfig.last_alert_minutes if set
if analyticConfig.last_alert_minutes is not None:
recentEnoughBegin = now - timedelta(minutes=analyticConfig.last_alert_minutes)
exceptional_values = exceptional_values.ix[recentEnoughBegin:now]
exceptional_average = exceptional_average.ix[recentEnoughBegin:now]
# 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)
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") or (analyticConfig.display.lower() == "alerts" and (anyAverageExceptions or analyticConfig.alert_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', analyticConfig.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,80 @@
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.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.alert_percentage = analyticConfig.get('alert_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.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.alert_percentage = analyticConfig.alert_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
+217
View File
@@ -0,0 +1,217 @@
from TimeDateRange import TimeDateRange
from TimeDateRange import TimeDateError
from TimeDateRange import UTC
from DataOperations import *
import json
import pandas
import getopt
import sys
import random
from WebSocketClient import WebSocketClient
from tornado import ioloop
utc = UTC()
class TimelyWebSocketClient(WebSocketClient):
def __init__(self, hostport, metric, tags, startTime, endTime, connect_timeout=WebSocketClient.DEFAULT_CONNECT_TIMEOUT,
request_timeout=WebSocketClient.DEFAULT_REQUEST_TIMEOUT):
self.metric = metric
self.tags = tags
self.startTime = startTime
self.endTime = endTime
self.subscriptionId = random.randint(1000000000, 9999999999)
WebSocketClient.__init__(self, hostport, connect_timeout, request_timeout)
def _on_message(self, msg):
# implement in subclass
pass
def _on_connection_success(self):
print('Connected.')
create = {
"operation": "create",
"subscriptionId": self.subscriptionId,
}
self.send(create)
self.send(create)
m1 = {
"operation": "add",
"subscriptionId": self.subscriptionId,
"metric": self.metric,
"startTime": self.startTime,
"endTime" : self.endTime
}
if self.tags is not None:
t = self.tags.strip().split(',')
tagDict = {}
for pair in t:
k = pair.split('=')[0].strip()
v = pair.split('=')[1].strip()
tagDict = dict(tagDict.items() + dict({k : v}).items())
m1["tags"] = tagDict
self.send(m1)
def _on_connection_close(self):
print('Connection closed!')
exit()
def _on_connection_error(self, exception):
print('Connection error: %s', exception)
class TimelyMetric(TimelyWebSocketClient):
client = None
endtime = None
def __init__(self, hostport, metric, tags, beginStr, endStr, period, sample):
self.series = pandas.Series()
self.metric = metric
self.tags = tags
self.sample = sample
self.debug = False
self.dataFrame = None
self.data = []
timeDateRange = TimeDateRange(beginStr, endStr, period)
TimelyWebSocketClient.__init__(self, hostport, metric, tags, timeDateRange.getBeginMs(), timeDateRange.getEndMs())
def debugOn(self):
self.debug = True
def debugOff(self):
self.debug = False
def fetch(self):
ioloop.IOLoop().make_current()
self.connect(ioloop.IOLoop.current(instance=False))
ioloop.IOLoop.current(instance=False).start()
return self
def _on_message(self, msg):
global df
global endtime
responsesObj = json.loads(msg)
responses = responsesObj.get("responses")
for obj in responses:
complete = bool(obj.get("complete"))
if complete:
self._on_connection_close()
return
else:
date = int(obj.get("timestamp")/1000)
dt = pandas.datetime.utcfromtimestamp(date)
metricName = str(obj.get("metric"))
metricValue = obj.get("value")
newData = {}
newData["date"] = dt
newData[metricName] = metricValue
tags = obj.get("tags")
for d in tags:
for k,v in d.items():
newData[k] = v
self.data.append(newData)
def _on_connection_close(self):
global client
self.dataFrame = pandas.DataFrame(self.data)
if len(self.dataFrame) > 0:
self.dataFrame['date'] = pandas.DatetimeIndex(self.dataFrame['date'])
self.dataFrame = self.dataFrame.set_index('date')
self.close()
ioloop.IOLoop.current(instance=False).stop()
print("Exiting.")
def getDataFrame(self):
return self.dataFrame;
def setDataFrame(self, dataFrame):
self.dataFrame = dataFrame
def print_debug(self):
if self.debug:
print(self.dataFrame)
def graph(self, groupByColumn=None):
return graph(self.dataFrame, self, sample=self.sample, how=self.how, groupByColumn=groupByColumn)
def main():
period = None
beginStr = None
endStr = None
metric = "timely.metrics.received"
sample = None
how = None
tags = None
groupByColumn = None
try:
argv = sys.argv
options, remainder = getopt.getopt(argv[1:], 'h', ['metric=', 'tags=', 'period=', 'groupByColumn=', 'begin=', 'end=', 'sample=', 'how=', 'hostport='])
except getopt.GetoptError:
print('TimelyMetric.py ---hostport=<host:port> --metric=<metric> --tags=<tag1=val1,tag2=val2> --period=<period>, --groupByColumn=<groupByColumn>, --sample=<sample_period> --how=<mean|min|max>')
sys.exit(2)
for opt, arg in options:
if opt == '-h':
print('TimelyMetric.py --hostport=<host:port> --metric=<metric> --tags=<tag1=val1,tag2=val2> --period=<period>, --groupByColumn=<groupByColumn>, --sample=<sample_period> --how=<mean|min|max>')
sys.exit()
elif opt in ("--metric"):
metric = arg
elif opt in ("--period"):
period = arg
elif opt in ("--begin"):
beginStr = arg
elif opt in ("--end"):
endStr = arg
elif opt in ("--groupByColumn"):
groupByColumn = arg
elif opt in ("--sample"):
sample = arg
elif opt in ("--how"):
how = arg
elif opt in ("--hostport"):
hostport = arg
try:
timelyMetric = TimelyMetric(hostport, metric, tags, beginStr, endStr, period, sample).fetch()
dataFrame = timelyMetric.getDataFrame()
if dataFrame is not None:
dataFrame = resample(dataFrame, metric, sample, how)
dataFrame = pivot(dataFrame, metric, groupByColumn=groupByColumn)
graph(dataFrame, timelyMetric, sample=sample, groupByColumn=groupByColumn, graphConfig={}, notebook=False)
except TimeDateError as e:
print(e.message)
if __name__ == '__main__':
main()
+91
View File
@@ -0,0 +1,91 @@
from tornado import escape
from tornado import gen
from tornado import ioloop
from tornado import websocket
import json
class WebSocketClient():
"""Base for web socket clients.
"""
DEFAULT_CONNECT_TIMEOUT = 60
DEFAULT_REQUEST_TIMEOUT = 60
APPLICATION_JSON = 'application/json'
def __init__(self, hostport, connect_timeout=DEFAULT_CONNECT_TIMEOUT,
request_timeout=DEFAULT_REQUEST_TIMEOUT):
self.connect_timeout = connect_timeout
self.request_timeout = request_timeout
self.url = 'wss://' + hostport + '/websocket'
def connect(self, ioloop=ioloop.IOLoop.current(instance=False)):
"""Connect to the server.
:param str url: server URL.
"""
request = websocket.httpclient.HTTPRequest(self.url, connect_timeout=self.connect_timeout, request_timeout=self.request_timeout, validate_cert=False)
websocket.websocket_connect(request, io_loop=ioloop, callback=self._connect_callback)
def send(self, data):
"""Send message to the server
:param str data: message.
"""
if not self._ws_connection:
raise RuntimeError('Web socket connection is closed.')
self._ws_connection.write_message(escape.utf8(json.dumps(data)))
def close(self):
"""Close connection.
"""
if not self._ws_connection:
raise RuntimeError('Web socket connection is already closed.')
self._ws_connection.close()
self._ws_connection = None
def _connect_callback(self, future):
if future.exception() is None:
self._ws_connection = future.result()
self._on_connection_success()
self._read_messages()
else:
self._on_connection_error(future.exception())
@gen.coroutine
def _read_messages(self):
while True and not self._ws_connection is None:
msg = yield self._ws_connection.read_message()
if msg is None:
self._on_connection_close()
break
self._on_message(msg)
def _on_message(self, msg):
"""This is called when new message is available from the server.
:param str msg: server message.
"""
pass
def _on_connection_success(self):
"""This is called on successful connection ot the server.
"""
pass
def _on_connection_close(self):
"""This is called when server closed the connection.
"""
pass
def _on_connection_error(self, exception):
"""This is called in case if connection to the server could
not established.
"""
pass
+45
View File
@@ -0,0 +1,45 @@
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',
'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,
'alert_percentage' : 25,
'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)
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
<Or>
<Bug pattern="DM_DEFAULT_ENCODING"/>
<Method name="connect" />
<Class name="timely.client.tcp.TcpClient"/>
</Or>
</FindBugsFilter>
@@ -0,0 +1,58 @@
package timely.api;
import org.junit.Assert;
import org.junit.Test;
import timely.serialize.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
public class SerializationTest {
private ObjectMapper mapper = JsonSerializer.getObjectMapper();
@Test
public void testBasicAuth() throws Exception {
BasicAuthLogin login = new BasicAuthLogin();
login.setUsername("test");
login.setPassword("pass");
testSerialization(login);
}
@Test
public void testCreateSubscription() throws Exception {
CreateSubscription create = new CreateSubscription();
create.setSubscriptionId("1234");
testSerialization(create);
}
@Test
public void testCloseSubscription() throws Exception {
CloseSubscription close = new CloseSubscription();
close.setSubscriptionId("1234");
testSerialization(close);
}
@Test
public void testAddSubscription() throws Exception {
AddSubscription add = new AddSubscription();
add.setSubscriptionId("1234");
add.setMetric("sys.cpu.user");
testSerialization(add);
}
@Test
public void testRemoveSubscription() throws Exception {
RemoveSubscription remove = new RemoveSubscription();
remove.setSubscriptionId("1234");
remove.setMetric("sys.cpu.user");
testSerialization(remove);
}
@SuppressWarnings("unchecked")
private <T> void testSerialization(T o) throws Exception {
String ser = mapper.writeValueAsString(o);
T des = mapper.readValue(ser, (Class<T>) o.getClass());
Assert.assertEquals(o, des);
}
}
@@ -0,0 +1,63 @@
package timely.model;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
*
*
*
*/
public class MetricTest {
@Test
public void testEquals() {
Metric m1 = Metric.newBuilder().name("m1").tag("t1", "v1").tag("t2", "v2").value(1, 0.0).build();
Metric m2 = Metric.newBuilder().name("m1").tag("t2", "v2").tag("t1", "v1").value(1, 0.0).build();
assertTrue(m1.equals(m2));
assertTrue(m2.equals(m1));
Metric m3 = Metric.newBuilder().name("m1").tag("t1", "v1").value(1, 0.0).build();
assertFalse(m1.equals(m3));
Metric m4 = Metric.newBuilder().name("m4").tag("t2", "v2").tag("t1", "v1").value(1, 0.0).build();
assertFalse(m1.equals(m4));
Metric m5 = Metric.newBuilder().name("m1").tag("t3", "v3").tag("t2", "v2").tag("t1", "v1").value(1, 0.0)
.build();
assertFalse(m1.equals(m5));
Metric m6 = Metric.newBuilder().name("m1").tag("t2", "v2").tag("t1", "v1").value(2, 0.0).build();
assertFalse(m1.equals(m6));
Metric m7 = Metric.newBuilder().name("m1").tag("t2", "v2").tag("t1", "v1").value(1, 1.0).build();
assertFalse(m1.equals(m7));
}
@Test
public void testJson() throws IOException {
ObjectMapper mapper = new ObjectMapper();
String expectedJson = "{\"name\":\"m1\",\"timestamp\":1,\"measure\":1.0,\"tags\":[{\"k1\":\"v1\"}]}";
Metric m1 = Metric.newBuilder().name("m1").tag("k1", "v1").value(1, 1.0).build();
Metric expectedMetric = mapper.readValue(expectedJson, Metric.class);
assertTrue(m1.equals(expectedMetric));
expectedJson = "{\"name\":\"m1\",\"tags\":[{\"k1\":\"v1\"}],\"timestamp\":5,\"measure\":5.0}";
expectedMetric = mapper.readValue(expectedJson, Metric.class);
assertEquals((long) expectedMetric.getValue().getTimestamp(), 5L);
assertEquals(expectedMetric.getValue().getMeasure(), 5.0D, 0.0);
}
}
@@ -0,0 +1,40 @@
package timely.model;
import org.junit.Assert;
import org.junit.Test;
import timely.model.parse.TagListParser;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class TagListParserTest {
@Test
public void testListParse() {
String value = "tag1=value1,tag2=value2";
List<Tag> tags = new TagListParser().parse(value);
Assert.assertEquals(2, tags.size());
Assert.assertEquals(new Tag("tag1", "value1"), tags.get(0));
Assert.assertEquals(new Tag("tag2", "value2"), tags.get(1));
}
@Test
public void testListCombine() {
List<Tag> tags = new ArrayList<>();
tags.add(new Tag("tag1", "value1"));
tags.add(new Tag("tag2", "value2"));
String combined = new TagListParser().combine(tags);
Assert.assertEquals("tag1=value1,tag2=value2", combined);
}
@Test
public void testListCombineMap() {
Map<String, String> map = new TreeMap<>();
map.put("tag1", "value1");
map.put("tag2", "value2");
String combined = new TagListParser().combine(map);
Assert.assertEquals("tag1=value1,tag2=value2", combined);
}
}
+5 -61
View File
@@ -4,21 +4,17 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.2</version>
<version>0.0.5</version>
</parent>
<artifactId>collectd-nsq-plugin</artifactId>
<dependencies>
<dependency>
<groupId>collectd</groupId>
<artifactId>collectd-api</artifactId>
<version>5.5.1</version>
<scope>system</scope>
<systemPath>${collectd-api-jar}</systemPath>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>timely</groupId>
@@ -39,24 +35,10 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<configuration>
<effort>Max</effort>
<threshold>Medium</threshold>
<xmlOutput>true</xmlOutput>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
<phase>prepare-package</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.2</version>
<configuration>
<artifactSet>
<includes>
@@ -77,49 +59,11 @@
<plugin>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>0.5.2</version>
<configuration>
<configFile>${project.parent.basedir}/eclipse/Eclipse-Formatter.xml</configFile>
<lineEnding>LF</lineEnding>
<overrideConfigCompilerVersion>true</overrideConfigCompilerVersion>
</configuration>
<executions>
<execution>
<goals>
<goal>format</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<versionRange>[0.5.2,)</versionRange>
<goals>
<goal>format</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore/>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
</FindBugsFilter>
+9 -66
View File
@@ -4,21 +4,17 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.2</version>
<version>0.0.5</version>
</parent>
<artifactId>collectd-plugin-parent</artifactId>
<dependencies>
<dependency>
<groupId>collectd</groupId>
<artifactId>collectd-api</artifactId>
<version>5.5.1</version>
<scope>system</scope>
<systemPath>${collectd-api-jar}</systemPath>
</dependency>
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<version>1.0</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -29,7 +25,6 @@
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-easymock-release-full</artifactId>
<version>1.6.4</version>
<classifier>full</classifier>
<scope>test</scope>
</dependency>
@@ -47,75 +42,23 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<configuration>
<effort>Max</effort>
<threshold>Medium</threshold>
<xmlOutput>true</xmlOutput>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
<phase>prepare-package</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<excludedGroups>timely.test.IntegrationTest</excludedGroups>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>0.5.2</version>
<configuration>
<configFile>${project.parent.basedir}/eclipse/Eclipse-Formatter.xml</configFile>
<lineEnding>LF</lineEnding>
<overrideConfigCompilerVersion>true</overrideConfigCompilerVersion>
</configuration>
<executions>
<execution>
<goals>
<goal>format</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<versionRange>[0.5.2,)</versionRange>
<goals>
<goal>format</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore/>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
@@ -17,6 +17,7 @@ public abstract class CollectDPluginParent {
private static final Pattern HADOOP_STATSD_PATTERN = Pattern
.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)");
private static final String INSTANCE = " instance=";
private static final String NAME = " name=";
private static final String SAMPLE = " sample=";
private static final String CODE = " code=";
private static final String PERIOD = ".";
@@ -32,7 +33,7 @@ public abstract class CollectDPluginParent {
private static final Pattern ETHSTAT_PATTERN = Pattern.compile("([\\w-_]+)_queue_([\\w-_]+)_([\\w-_]+)");
private static final String STATSD_PREFIX = "statsd";
private static final String NSQ_PREFIX = STATSD_PREFIX + ".nsq.";
private static final Pattern HAPROXY_PATTERN = Pattern.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)");
private static final Pattern HAPROXY_PATTERN = Pattern.compile("\\[([\\w-_=]+),([\\w-_=]+)\\]");
private final SMARTCodeMapping smart = new SMARTCodeMapping();
@@ -158,13 +159,11 @@ public abstract class CollectDPluginParent {
metric.append("sys.sensors.").append(vl.getType()).append(PERIOD).append(vl.getPluginInstance());
tags.append(INSTANCE).append(instance);
} else if (vl.getPlugin().equals("haproxy")) {
Matcher m = HAPROXY_PATTERN.matcher(vl.getTypeInstance());
metric.append("sys.haproxy.").append(vl.getTypeInstance());
Matcher m = HAPROXY_PATTERN.matcher(vl.getPluginInstance());
if (m.matches()) {
metric.append("sys.haproxy.").append(m.group(3));
tags.append(" proxy=").append(m.group(2));
tags.append(" server=").append(m.group(1));
} else {
metric.append("sys.haproxy.").append(vl.getTypeInstance());
tags.append(" ").append(m.group(1));
tags.append(" ").append(m.group(2));
}
} else if (vl.getPlugin().equals("ipmi")) {
metric.append("sys.ipmi.").append(vl.getType());
@@ -172,17 +171,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 {
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
</FindBugsFilter>
@@ -253,9 +253,10 @@ public class PluginParentTest {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("haproxy");
vl.setPluginInstance("[proxy_name=proxy1,service_name=server1]");
vl.setTime(TIME);
vl.setType("gauge");
vl.setTypeInstance("server1.proxy1.queue_current");
vl.setTypeInstance("queue_current");
vl.setValues(Collections.singletonList((Number) 0.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
@@ -264,7 +265,7 @@ public class PluginParentTest {
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put sys.haproxy.queue_current 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo proxy=proxy1 server=server1 sample=value sampleType=GAUGE\n",
"put sys.haproxy.queue_current 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo proxy_name=proxy1 service_name=server1 sample=value sampleType=GAUGE\n",
result);
}
+9 -68
View File
@@ -4,21 +4,17 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.2</version>
<version>0.0.5</version>
</parent>
<artifactId>collectd-timely-plugin</artifactId>
<dependencies>
<dependency>
<groupId>collectd</groupId>
<artifactId>collectd-api</artifactId>
<version>5.5.1</version>
<scope>system</scope>
<systemPath>${collectd-api-jar}</systemPath>
</dependency>
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<version>1.0</version>
<scope>test</scope>
</dependency>
<dependency>
@@ -34,7 +30,6 @@
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-easymock-release-full</artifactId>
<version>1.6.4</version>
<classifier>full</classifier>
<scope>test</scope>
</dependency>
@@ -57,25 +52,10 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<configuration>
<effort>Max</effort>
<threshold>Medium</threshold>
<xmlOutput>true</xmlOutput>
<excludeFilterFile>src/main/resources/findbugs-excludes.xml</excludeFilterFile>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
<phase>prepare-package</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.2</version>
<configuration>
<artifactSet>
<includes>
@@ -96,58 +76,19 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<excludedGroups>timely.test.IntegrationTest</excludedGroups>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>0.5.2</version>
<configuration>
<configFile>${project.parent.basedir}/eclipse/Eclipse-Formatter.xml</configFile>
<lineEnding>LF</lineEnding>
<overrideConfigCompilerVersion>true</overrideConfigCompilerVersion>
</configuration>
<executions>
<execution>
<goals>
<goal>format</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<versionRange>[0.5.2,)</versionRange>
<goals>
<goal>format</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore/>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
+1
View File
@@ -0,0 +1 @@
/target/
+24
View File
@@ -0,0 +1,24 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.5</version>
</parent>
<artifactId>timely-common</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
+6 -3
View File
@@ -4,14 +4,13 @@
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.2</version>
<version>0.0.5</version>
</parent>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>assemble</id>
@@ -28,6 +27,10 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
</project>
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["../../src/components/auths.js"],"names":[],"mappings":"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","file":"auths.js","sourcesContent":["import _ from 'lodash';\n\nexport class AuthsCtrl {\n\n constructor(backendSrv, $rootScope, $timeout){\n this.$rootScope = $rootScope;\n this.$timeout = $timeout;\n this.backendSrv = backendSrv;\n }\n\n login(datasource){\n this.fetching = {};\n this.fetching.done = false;\n this.fetching.show = true;\n this.fetching.status = 'warning';\n this.fetching.title = 'Fetching auths...';\n\n //this.$rootScope.appEvent('alert-success', ['Authorization Cookie Received', '']);\n //this.$rootScope.appEvent('alert-error', ['Authorization Failed', '']);\n //this.$rootScope.appEvent('alert-warning', ['Fetching Authorizations', '']);\n\n var uri = this._getURI(datasource.jsonData);\n\n if(datasource.jsonData.basicAuths){\n if( this.basicAuthUser && this.basicAuthPassword){\n var authBlob = {username: this.basicAuthUser, password: this.basicAuthPassword};\n this.doPostLogin(uri, authBlob);\n } else {\n this.$rootScope.appEvent('alert-warning', [datasource.name, 'requires User/Password']);\n this.fetching.status = 'warning';\n this.fetching.title = 'User/Password required';\n\n return;\n }\n } else {\n this.doGetLogin(uri);\n }\n\n }\n\n doPostLogin(uri, authBlob){\n this.doXHR('POST', uri, authBlob);\n }\n\n doGetLogin(uri){\n this.doXHR('GET', uri)\n }\n\n doXHR(verb, uri, data){\n if( !data){\n data = \"\";\n }\n var r = new XMLHttpRequest();\n r.open(verb, uri, true);\n r.withCredentials = true;\n r.setRequestHeader('Content-Type', 'application/json');\n r.onreadystatechange = function () {\n this.handleLoginResult(r);\n }.bind(this);\n r.send(JSON.stringify(data));\n }\n\n handleLoginResult(response){\n // wait for readyState to be '4 => done'\n if (response.readyState != 4) return;\n\n this.fetching.done = true;\n\n switch(response.status){\n case 200:\n var cookie = (document.cookie.match(/^(?:.*;)?TSESSIONID=([^;]+)(?:.*)?$/)||[,null])[1]\n console.log(cookie);\n console.log(document.cookie);\n \n this.fetching.status = 'success';\n this.fetching.title = 'Login successful';\n this.$rootScope.appEvent('alert-success', ['Success', '']);\n break;\n default:\n this.fetching.status = 'warning';\n this.fetching.title = response.statusText;\n this.$rootScope.appEvent('alert-warning', [response.status+': '+response.statusText,'']);\n break;\n }\n\n if (r.readyState != 4 || r.status != 200) return;\n alert(\"Success: \" + r.Line truncated
{"version":3,"sources":["../../src/components/auths.js"],"names":["_","AuthsCtrl","backendSrv","$rootScope","$timeout","datasource","fetching","done","show","status","title","uri","_getURI","jsonData","basicAuths","basicAuthUser","basicAuthPassword","authBlob","username","password","doPostLogin","appEvent","name","doGetLogin","doXHR","verb","data","r","XMLHttpRequest","open","withCredentials","setRequestHeader","onreadystatechange","handleLoginResult","bind","send","JSON","stringify","response","readyState","cookie","document","match","console","log","statusText","alert","getResponseHeader","timelyHost","httpsPort"],"mappings":";;;;;;;;;;;;;;;AAAOA,O;;;;;;;;;;;;;;;;;;;;;2BAEMC,S;AAEX,2BAAYC,UAAZ,EAAwBC,UAAxB,EAAoCC,QAApC,EAA6C;AAAA;;AAC3C,eAAKD,UAAL,GAAkBA,UAAlB;AACA,eAAKC,QAAL,GAAgBA,QAAhB;AACA,eAAKF,UAAL,GAAkBA,UAAlB;AACD;;;;gCAEKG,U,EAAW;AACf,iBAAKC,QAAL,GAAgB,EAAhB;AACA,iBAAKA,QAAL,CAAcC,IAAd,GAAqB,KAArB;AACA,iBAAKD,QAAL,CAAcE,IAAd,GAAqB,IAArB;AACA,iBAAKF,QAAL,CAAcG,MAAd,GAAuB,SAAvB;AACA,iBAAKH,QAAL,CAAcI,KAAd,GAAsB,mBAAtB;;AAEA;AACA;AACA;;AAEA,gBAAIC,MAAM,KAAKC,OAAL,CAAaP,WAAWQ,QAAxB,CAAV;;AAEA,gBAAGR,WAAWQ,QAAX,CAAoBC,UAAvB,EAAkC;AAChC,kBAAI,KAAKC,aAAL,IAAsB,KAAKC,iBAA/B,EAAiD;AAC/C,oBAAIC,WAAW,EAACC,UAAU,KAAKH,aAAhB,EAA+BI,UAAU,KAAKH,iBAA9C,EAAf;AACA,qBAAKI,WAAL,CAAiBT,GAAjB,EAAsBM,QAAtB;AACD,eAHD,MAGO;AACL,qBAAKd,UAAL,CAAgBkB,QAAhB,CAAyB,eAAzB,EAA0C,CAAChB,WAAWiB,IAAZ,EAAkB,wBAAlB,CAA1C;AACA,qBAAKhB,QAAL,CAAcG,MAAd,GAAuB,SAAvB;AACA,qBAAKH,QAAL,CAAcI,KAAd,GAAsB,wBAAtB;;AAEA;AACD;AACF,aAXD,MAWO;AACL,mBAAKa,UAAL,CAAgBZ,GAAhB;AACD;AAEF;;;sCAEWA,G,EAAKM,Q,EAAS;AACxB,iBAAKO,KAAL,CAAW,MAAX,EAAmBb,GAAnB,EAAwBM,QAAxB;AACD;;;qCAEUN,G,EAAI;AACb,iBAAKa,KAAL,CAAW,KAAX,EAAkBb,GAAlB;AACD;;;gCAEKc,I,EAAMd,G,EAAKe,I,EAAK;AACpB,gBAAI,CAACA,IAAL,EAAU;AACRA,qBAAO,EAAP;AACD;AACD,gBAAIC,IAAI,IAAIC,cAAJ,EAAR;AACAD,cAAEE,IAAF,CAAOJ,IAAP,EAAad,GAAb,EAAkB,IAAlB;AACAgB,cAAEG,eAAF,GAAoB,IAApB;AACAH,cAAEI,gBAAF,CAAmB,cAAnB,EAAmC,kBAAnC;AACAJ,cAAEK,kBAAF,GAAuB,YAAY;AACjC,mBAAKC,iBAAL,CAAuBN,CAAvB;AACD,aAFsB,CAErBO,IAFqB,CAEhB,IAFgB,CAAvB;AAGAP,cAAEQ,IAAF,CAAOC,KAAKC,SAAL,CAAeX,IAAf,CAAP;AACD;;;4CAEiBY,Q,EAAS;AACzB;AACA,gBAAIA,SAASC,UAAT,IAAuB,CAA3B,EAA8B;;AAE9B,iBAAKjC,QAAL,CAAcC,IAAd,GAAqB,IAArB;;AAEA,oBAAO+B,SAAS7B,MAAhB;AACE,mBAAK,GAAL;AACE,oBAAI+B,SAAS,CAACC,SAASD,MAAT,CAAgBE,KAAhB,CAAsB,qCAAtB,KAA8D,GAAE,IAAF,CAA/D,EAAwE,CAAxE,CAAb;AACAC,wBAAQC,GAAR,CAAYJ,MAAZ;AACAG,wBAAQC,GAAR,CAAYH,SAASD,MAArB;;AAEA,qBAAKlC,QAAL,CAAcG,MAAd,GAAuB,SAAvB;AACA,qBAAKH,QAAL,CAAcI,KAAd,GAAsB,kBAAtB;AACA,qBAAKP,UAAL,CAAgBkB,QAAhB,CAAyB,eAAzB,EAA0C,CAAC,SAAD,EAAY,EAAZ,CAA1C;AACA;AACF;AACE,qBAAKf,QAAL,CAAcG,MAAd,GAAuB,SAAvB;AACA,qBAAKH,QAAL,CAAcI,KAAd,GAAsB4B,SAASO,UAA/B;AACA,qBAAK1C,UAAL,CAAgBkB,QAAhB,CAAyB,eAAzB,EAA0C,CAACiB,SAAS7B,MAAT,GAAgB,IAAhB,GAAqB6B,SAASO,UAA/B,EAA0C,EAA1C,CAA1C;AACA;AAdJ;;AAiBA,gBAAIlB,EAAEY,UAAF,IAAgB,CAAhB,IAAqBZ,EAAElB,MAAF,IAAY,GAArC,EAA0C;AAC1CqC,kBAAM,cAAcnB,EAAEoB,iBAAF,CAAoB,YAApB,CAApB;AACD;;;kCAEOlC,Q,EAAS;AACf,mBAAO,aAAWA,SAASmC,UAApB,GAA+B,GAA/B,GAAmCnC,SAASoC,SAA5C,GAAsD,QAA7D;AACD;;;yCAEa,CAEb","file":"auths.js","sourcesContent":["import _ from 'lodash';\n\nexport class AuthsCtrl {\n\n constructor(backendSrv, $rootScope, $timeout){\n this.$rootScope = $rootScope;\n this.$timeout = $timeout;\n this.backendSrv = backendSrv;\n }\n\n login(datasource){\n this.fetching = {};\n this.fetching.done = false;\n this.fetching.show = true;\n this.fetching.status = 'warning';\n this.fetching.title = 'Fetching auths...';\n\n //this.$rootScope.appEvent('alert-success', ['Authorization Cookie Received', '']);\n //this.$rootScope.appEvent('alert-error', ['Authorization Failed', '']);\n //this.$rootScope.appEvent('alert-warning', ['Fetching Authorizations', '']);\n\n var uri = this._getURI(datasource.jsonData);\n\n if(datasource.jsonData.basicAuths){\n if( this.basicAuthUser && this.basicAuthPassword){\n var authBlob = {username: this.basicAuthUser, password: this.basicAuthPassword};\n this.doPostLogin(uri, authBlob);\n } else {\n this.$rootScope.appEvent('alert-warning', [datasource.name, 'requires User/Password']);\n this.fetching.status = 'warning';\n this.fetching.title = 'User/Password required';\n\n return;\n }\n } else {\n this.doGetLogin(uri);\n }\n\n }\n\n doPostLogin(uri, authBlob){\n this.doXHR('POST', uri, authBlob);\n }\n\n doGetLogin(uri){\n this.doXHR('GET', uri)\n }\n\n doXHR(verb, uri, data){\n if( !data){\n data = \"\";\n }\n var r = new XMLHttpRequest();\n r.open(verb, uri, true);\n r.withCredentials = true;\n r.setRequestHeader('Content-Type', 'application/json');\n r.onreadystatechange = function () {\n this.handleLoginResult(r);\n }.bind(this);\n r.send(JSON.stringify(data));\n }\n\n handleLoginResult(response){\n // wait for readyState to be '4 => done'\n if (response.readyState != 4) return;\n\n this.fetching.done = true;\n\n switcLine truncated
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["../../src/components/authspage.js"],"names":[],"mappings":";;;;;;;;;;;;;;;AACO,O;;AACC,gB,gBAAA,U;AAAY,e,gBAAA,S;;AACZ,e,oCAAA,S;;;;;;;;;;;;;;;;;;;;;+BAEK,a;AAEX,+BAAY,UAAZ,EAAwB,aAAxB,EAAsC;AAAA;;AACpC,eAAK,aAAL,GAAqB,aAArB;AACA,eAAK,WAAL,GAAmB,KAAK,oBAAL,EAAnB;AACA,qBAAW,UAAX,CAAsB,WAAtB,EAAmC,SAAnC;AACD;;;;iDAEqB;AACpB,gBAAI,aAAa,KAAK,aAAL,CAAmB,MAAnB,EAAjB;;AAEA,gBAAI,UAAU,EAAE,GAAF,CAAM,UAAN,EAAkB,UAAS,KAAT,EAAgB,GAAhB,EAAqB,GAArB,EAAyB;AACvD,kBAAI,MAAM,EAAV;AACA,kBAAI,IAAJ,GAAW,EAAX;AACA,kBAAI,IAAJ,CAAS,IAAT,GAAgB,IAAI,GAAJ,EAAS,IAAT,CAAc,IAA9B;AACA,kBAAI,IAAJ,CAAS,EAAT,GAAc,IAAI,GAAJ,EAAS,IAAT,CAAc,EAA5B;AACA,kBAAI,IAAJ,GAAW,GAAX;AACA,kBAAI,QAAJ,GAAe,IAAI,GAAJ,EAAS,QAAxB;AACA,qBAAO,GAAP;AACD,aARa,CAAd;AASA,mBAAO,EAAE,MAAF,CAAS,OAAT,EAAkB,UAAS,CAAT,EAAW;AAClC,qBAAQ,EAAE,IAAF,CAAO,IAAP,KAAgB,YAAhB,IAAgC,EAAE,IAAF,CAAO,EAAP,KAAc,mBAAtD;AACD,aAFM,CAAP;AAGD;;;;;;;;AAGH,oBAAc,WAAd,GAA4B,uBAA5B","file":"authspage.js","sourcesContent":["\nimport _ from 'lodash';\nimport {coreModule, appEvents} from 'app/core/core';\nimport {AuthsCtrl} from 'plugins/timely-app/components/auths';\n\nexport class AuthsPageCtrl {\n\n constructor(backendSrv, datasourceSrv){\n this.datasourceSrv = datasourceSrv;\n this.datasources = this.getTimelyDatasources();\n coreModule.controller('AuthsCtrl', AuthsCtrl);\n }\n\n getTimelyDatasources(){\n var allSources = this.datasourceSrv.getAll();\n\n var sources = _.map(allSources, function(value, key, col){\n var ret = {};\n ret.meta = {};\n ret.meta.type = col[key].meta.type;\n ret.meta.id = col[key].meta.id;\n ret.name = key;\n ret.jsonData = col[key].jsonData;\n return ret;\n });\n return _.filter(sources, function(d){\n return (d.meta.type === 'datasource' && d.meta.id === 'timely-datasource');\n });\n }\n\n}\nAuthsPageCtrl.templateUrl = 'components/auths.html';\n"]}
{"version":3,"sources":["../../src/components/authspage.js"],"names":["_","coreModule","appEvents","AuthsCtrl","AuthsPageCtrl","backendSrv","datasourceSrv","datasources","getTimelyDatasources","controller","allSources","getAll","sources","map","value","key","col","ret","meta","type","id","name","jsonData","filter","d","templateUrl"],"mappings":";;;;;;;;;;;;;;;AACOA,O;;AACCC,gB,gBAAAA,U;AAAYC,e,gBAAAA,S;;AACZC,e,oCAAAA,S;;;;;;;;;;;;;;;;;;;;;+BAEKC,a;AAEX,+BAAYC,UAAZ,EAAwBC,aAAxB,EAAsC;AAAA;;AACpC,eAAKA,aAAL,GAAqBA,aAArB;AACA,eAAKC,WAAL,GAAmB,KAAKC,oBAAL,EAAnB;AACAP,qBAAWQ,UAAX,CAAsB,WAAtB,EAAmCN,SAAnC;AACD;;;;iDAEqB;AACpB,gBAAIO,aAAa,KAAKJ,aAAL,CAAmBK,MAAnB,EAAjB;;AAEA,gBAAIC,UAAUZ,EAAEa,GAAF,CAAMH,UAAN,EAAkB,UAASI,KAAT,EAAgBC,GAAhB,EAAqBC,GAArB,EAAyB;AACvD,kBAAIC,MAAM,EAAV;AACAA,kBAAIC,IAAJ,GAAW,EAAX;AACAD,kBAAIC,IAAJ,CAASC,IAAT,GAAgBH,IAAID,GAAJ,EAASG,IAAT,CAAcC,IAA9B;AACAF,kBAAIC,IAAJ,CAASE,EAAT,GAAcJ,IAAID,GAAJ,EAASG,IAAT,CAAcE,EAA5B;AACAH,kBAAII,IAAJ,GAAWN,GAAX;AACAE,kBAAIK,QAAJ,GAAeN,IAAID,GAAJ,EAASO,QAAxB;AACA,qBAAOL,GAAP;AACD,aARa,CAAd;AASA,mBAAOjB,EAAEuB,MAAF,CAASX,OAAT,EAAkB,UAASY,CAAT,EAAW;AAClC,qBAAQA,EAAEN,IAAF,CAAOC,IAAP,KAAgB,YAAhB,IAAgCK,EAAEN,IAAF,CAAOE,EAAP,KAAc,mBAAtD;AACD,aAFM,CAAP;AAGD;;;;;;;;AAGHhB,oBAAcqB,WAAd,GAA4B,uBAA5B","file":"authspage.js","sourcesContent":["\nimport _ from 'lodash';\nimport {coreModule, appEvents} from 'app/core/core';\nimport {AuthsCtrl} from 'plugins/timely-app/components/auths';\n\nexport class AuthsPageCtrl {\n\n constructor(backendSrv, datasourceSrv){\n this.datasourceSrv = datasourceSrv;\n this.datasources = this.getTimelyDatasources();\n coreModule.controller('AuthsCtrl', AuthsCtrl);\n }\n\n getTimelyDatasources(){\n var allSources = this.datasourceSrv.getAll();\n\n var sources = _.map(allSources, function(value, key, col){\n var ret = {};\n ret.meta = {};\n ret.meta.type = col[key].meta.type;\n ret.meta.id = col[key].meta.id;\n ret.name = key;\n ret.jsonData = col[key].jsonData;\n return ret;\n });\n return _.filter(sources, function(d){\n return (d.meta.type === 'datasource' && d.meta.id === 'timely-datasource');\n });\n }\n\n}\nAuthsPageCtrl.templateUrl = 'components/auths.html';\n"]}
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["../../src/components/config.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;qCACa,mB,GAEX,+BAAc;AAAA;AAEb,O;;;;AAGH,0BAAoB,WAApB,GAAkC,wBAAlC","file":"config.js","sourcesContent":["\nexport class TimelyAppConfigCtrl {\n\n constructor() {\n \n }\n\n}\nTimelyAppConfigCtrl.templateUrl = 'components/config.html';\n"]}
{"version":3,"sources":["../../src/components/config.js"],"names":["TimelyAppConfigCtrl","templateUrl"],"mappings":";;;;;;;;;;;;;;;;qCACaA,mB,GAEX,+BAAc;AAAA;AAEb,O;;;;AAGHA,0BAAoBC,WAApB,GAAkC,wBAAlC","file":"config.js","sourcesContent":["\nexport class TimelyAppConfigCtrl {\n\n constructor() {\n \n }\n\n}\nTimelyAppConfigCtrl.templateUrl = 'components/config.html';\n"]}
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["../../src/components/metrics.js"],"names":[],"mappings":";;;;;;;;;;;;;;;AACO,O;;AACC,mB,wCAAA,a;;;;;;;;;;;;;;;;;;;;;iCAEK,e;AAEX,iCAAY,UAAZ,EAAwB,aAAxB,EAAsC;AAAA;;AACpC,eAAK,aAAL,GAAqB,KAArB;AACA,eAAK,UAAL,GAAkB,UAAlB;AACA,cAAI,MAAM,IAAI,aAAJ,CAAkB,UAAlB,EAA8B,aAA9B,CAAV;AACA,eAAK,WAAL,GAAmB,IAAI,oBAAJ,EAAnB;AACA,cAAI,KAAK,WAAL,CAAiB,MAAjB,GAA0B,CAA9B,EAAgC;AAC9B,iBAAK,MAAL,GAAc,KAAK,WAAL,CAAiB,CAAjB,CAAd;AACA,iBAAK,gBAAL;AACD;AACF;;;;6CAEiB;AAAA;;AAChB,iBAAK,aAAL;AACA,gBAAI,MAAM,KAAK,OAAL,CAAa,KAAK,MAAL,CAAY,QAAzB,CAAV;AACA,iBAAK,UAAL,CAAgB,OAAhB,CACE,EAAE,QAAQ,KAAV;AACE,mBAAK,GADP;AAEE,+BAAiB,IAFnB;AAGE,sBAAQ,EAHV,EADF,EAKE,IALF,CAME,oBAAY;AACV,oBAAK,OAAL,GAAe,MAAK,iBAAL,CAAuB,SAAS,OAAhC,CAAf;AACA,oBAAK,aAAL,GAAqB,IAArB;AACD,aATH;AAUD;;;0CAEc;AACb,iBAAK,OAAL,GAAe,EAAf;AACD;;;4CAEiB,O,EAAQ;AACxB,gBAAI,MAAM,EAAV;AACA,cAAE,IAAF,CAAO,OAAP,EAAgB,UAAS,KAAT,EAAgB,GAAhB,EAAoB;AAClC,kBAAI,SAAS,EAAb;AACA,qBAAO,MAAP,GAAgB,MAAM,MAAtB;AACA,qBAAO,IAAP,GAAc,EAAd;AACA,gBAAE,GAAF,CAAM,MAAM,IAAZ,EAAkB,UAAS,GAAT,EAAc,GAAd,EAAkB;AAC1C;AACA;AACA;AACA;AACQ,oBAAI,OAAO,EAAE,SAAF,CAAY,OAAO,IAAnB,EAAyB,EAAC,QAAQ,IAAI,GAAb,EAAzB,CAAX;AACA,oBAAI,OAAJ;AACA,oBAAI,QAAQ,CAAC,CAAb,EAAgB;AACd,4BAAU,EAAC,MAAM,EAAP,EAAW,QAAQ,EAAnB,EAAV;AACD,iBAFD,MAEO;AACL,4BAAU,OAAO,IAAP,CAAY,IAAZ,CAAV;AACD;AACD,wBAAQ,MAAR,CAAe,IAAf,CAAoB,IAAI,KAAxB;AACA,wBAAQ,MAAR,GAAiB,EAAE,MAAF,CAAS,EAAE,IAAF,CAAO,QAAQ,MAAf,CAAT,CAAjB;AACA,wBAAQ,IAAR,GAAe,IAAI,GAAnB;AACA,oBAAI,OAAO,CAAC,CAAZ,EAAe;AACb,yBAAO,IAAP,CAAY,IAAZ,IAAoB,OAApB;AACD,iBAFD,MAEO;AACL,yBAAO,IAAP,CAAY,IAAZ,CAAiB,OAAjB;AACD;AACF,eApBiB,CAoBhB,IApBgB,CAoBX,MApBW,CAAlB;AAqBA,qBAAO,IAAP,GAAc,EAAE,MAAF,CAAS,OAAO,IAAhB,EAAsB,MAAtB,CAAd;AACA,kBAAI,IAAJ,CAAS,MAAT;AACD,aA3Be,CA2Bd,IA3Bc,CA2BT,GA3BS,CAAhB;;AA6BA,mBAAO,EAAE,MAAF,CAAS,GAAT,EAAc,QAAd,CAAP;AACD;;;kCAEO,Q,EAAS;AACf,mBAAO,aAAW,SAAS,UAApB,GAA+B,GAA/B,GAAmC,SAAS,SAA5C,GAAsD,cAA7D;AACD;;;;;;;;AAGH,sBAAgB,WAAhB,GAA8B,yBAA9B","file":"metrics.js","sourcesContent":["\nimport _ from 'lodash';\nimport {AuthsPageCtrl} from 'plugins/timely-app/components/authspage';\n\nexport class MetricsPageCtrl {\n\n constructor(backendSrv, datasourceSrv){\n this.hasDatasource = false;\n this.backendSrv = backendSrv;\n var apc = new AuthsPageCtrl(backendSrv, datasourceSrv);\n this.datasources = apc.getTimelyDatasources();\n if( this.datasources.length > 0){\n this.source = this.datasources[0];\n this.updateDatasource();\n }\n }\n\n updateDatasource(){\n this._clearMetrics();\n var uri = this._getURI(this.source.jsonData);\n this.backendSrv.request(\n { method: 'GET',\n url: uri,\n withCredentials: true,\n params: \"\" }\n ).then(\n response => {\n this.metrics = this._transformMetrics(response.metrics);\n this.hasDatasource = true;\n });\n }\n\n _clearMetrics(){\n this.metrics = [];\n }\n\n _transformMetrics(metrics){\n var ret = [];\n _.each(metrics, function(value, idx){\n var metric = {};\n metric.metric = value.metric;\n metric.tags = [];\n _.map(value.tags, function(tag, key){\n// result || (result = {});\n// result['name'] = tag.key;\n// result['values'] || (result['values'] = []);\n// result['values'].push(tag.value);\n var gIdx = _.findIndex(metric.tags, {'name': tag.key});\n var grouped;\n if( gIdx == -1 ){\n grouped = {name: '', values: []};\n } else {\n grouped = metric.tags[gIdx];\n }\n grouped.values.push(tag.value);\n grouped.values = _.sortBy(_.uniq(grouped.values))\n grouped.name = tag.key;\n if( gIdx > -1 ){\n metric.tags[gIdx] = grouped;\n } else {\n metric.tags.push(grouped);\n }\n }.bind(metric));\n metric.tags = _.sortBy(metric.tags, 'name')\n ret.push(metric);\n }.bind(ret));\n\n return _.sortBy(ret, 'metric');\n }\n\n _getURI(jsonData){\n return 'https://'+jsonData.timelyHost+':'+jsonData.httpsPort+'/api/metrics'\n }\n\n}\nMetricsPageCtrl.templateUrl = 'components/metrics.html';\n"]}
{"version":3,"sources":["../../src/components/metrics.js"],"names":["_","AuthsPageCtrl","MetricsPageCtrl","backendSrv","datasourceSrv","hasDatasource","apc","datasources","getTimelyDatasources","length","source","updateDatasource","_clearMetrics","uri","_getURI","jsonData","request","method","url","withCredentials","params","then","metrics","_transformMetrics","response","ret","each","value","idx","metric","tags","map","tag","key","gIdx","findIndex","grouped","name","values","push","sortBy","uniq","bind","timelyHost","httpsPort","templateUrl"],"mappings":"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","file":"metrics.js","sourcesContent":["\nimport _ from 'lodash';\nimport {AuthsPageCtrl} from 'plugins/timely-app/components/authspage';\n\nexport class MetricsPageCtrl {\n\n constructor(backendSrv, datasourceSrv){\n this.hasDatasource = false;\n this.backendSrv = backendSrv;\n var apc = new AuthsPageCtrl(backendSrv, datasourceSrv);\n this.datasources = apc.getTimelyDatasources();\n if( this.datasources.length > 0){\n this.source = this.datasources[0];\n this.updateDatasource();\n }\n }\n\n updateDatasource(){\n this._clearMetrics();\n var uri = this._getURI(this.source.jsonData);\n this.backendSrv.request(\n { method: 'GET',\n url: uri,\n withCredentials: true,\n params: \"\" }\n ).then(\n response => {\n this.metrics = this._transformMetrics(response.metrics);\n this.hasDatasource = true;\n });\n }\n\n _clearMetrics(){\n this.metrics = [];\n }\n\n _transformMetrics(metrics){\n var ret = [];\n _.each(metrics, function(value, idx){\n var metric = {};\n metric.metric = value.metric;\n metric.tags = [];\n _.map(value.tags, function(tag, key){\n// result || (result = {});\n// result['name'] = tag.key;\n// result['values'] || (result['values'] = []);\n// result['values'].push(tag.value);\n var gIdx = _.findIndex(metric.tags, {'name': tag.key});\n var grouped;\n if( gIdx == -1 ){\n grouped = {name: '', values: []};\n } else {\n grouped = metric.tags[gIdx];\n }\n grouped.values.push(tag.value);\n grouped.values = _.sortBy(_.uniq(grouped.values))\n grouped.name = tag.key;\n if( gIdx > -1 ){\n metric.tags[gIdx] = grouped;\n } else {\n metric.tags.push(grouped);\n }\n }.bind(metric));\n metric.tags = _.sortBy(metric.tags, 'name')\n ret.push(metric);\n }.bind(ret));\n\n return _.sortBy(ret, 'metric');\n }\n\n _getURI(jsonData){\n return 'https://'+jsonData.timelyHost+':'+jsonData.httpsPort+'/api/metrics'\n }\n\n}\nMetricsPageCtrl.templateUrl = 'components/metrics.html';\n"]}
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["../../src/datasource/config.js"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAO,O;;;sCAGM,oB,GAEX,gCAAc;AAAA;;AACZ,aAAK,OAAL,CAAa,QAAb,GAAwB,KAAK,OAAL,CAAa,QAAb,IAAyB,EAAjD;AACA,aAAK,OAAL,CAAa,MAAb,GAAsB,QAAtB;AACA,aAAK,OAAL,CAAa,SAAb,GAAyB,KAAzB;AACA,aAAK,OAAL,CAAa,eAAb,GAA+B,IAA/B;AACA,aAAK,OAAL,CAAa,WAAb,GAA2B,WAA3B;AACD,O;;;;AAEH,2BAAqB,WAArB,GAAmC,iCAAnC","file":"config.js","sourcesContent":["import _ from 'lodash';\n\n\nexport class DatasourceConfigCtrl {\n\n constructor() {\n this.current.jsonData = this.current.jsonData || {};\n this.current.access = 'direct';\n this.current.basicAuth = false;\n this.current.withCredentials = true;\n this.current.suggestHost = 'localhost';\n }\n}\nDatasourceConfigCtrl.templateUrl = 'datasource/partials/config.html';\n"]}
{"version":3,"sources":["../../src/datasource/config.js"],"names":["_","DatasourceConfigCtrl","current","jsonData","access","basicAuth","withCredentials","suggestHost","templateUrl"],"mappings":";;;;;;;;;;;;;;;AAAOA,O;;;sCAGMC,oB,GAEX,gCAAc;AAAA;;AACZ,aAAKC,OAAL,CAAaC,QAAb,GAAwB,KAAKD,OAAL,CAAaC,QAAb,IAAyB,EAAjD;AACA,aAAKD,OAAL,CAAaE,MAAb,GAAsB,QAAtB;AACA,aAAKF,OAAL,CAAaG,SAAb,GAAyB,KAAzB;AACA,aAAKH,OAAL,CAAaI,eAAb,GAA+B,IAA/B;AACA,aAAKJ,OAAL,CAAaK,WAAb,GAA2B,WAA3B;AACD,O;;;;AAEHN,2BAAqBO,WAArB,GAAmC,iCAAnC","file":"config.js","sourcesContent":["import _ from 'lodash';\n\n\nexport class DatasourceConfigCtrl {\n\n constructor() {\n this.current.jsonData = this.current.jsonData || {};\n this.current.access = 'direct';\n this.current.basicAuth = false;\n this.current.withCredentials = true;\n this.current.suggestHost = 'localhost';\n }\n}\nDatasourceConfigCtrl.templateUrl = 'datasource/partials/config.html';\n"]}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,710 @@
{
"__inputs": [
{
"name": "DS_TIMELY",
"label": "Timely",
"description": "",
"type": "datasource",
"pluginId": "timely-datasource",
"pluginName": "Timely"
}
],
"__requires": [
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "4.4.1"
},
{
"type": "panel",
"id": "graph",
"name": "Graph",
"version": ""
},
{
"type": "panel",
"id": "singlestat",
"name": "Singlestat",
"version": ""
},
{
"type": "datasource",
"id": "timely-datasource",
"name": "Timely",
"version": "1.0.0"
}
],
"annotations": {
"list": []
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"hideControls": false,
"id": null,
"links": [],
"refresh": "1m",
"rows": [
{
"collapse": false,
"height": "150",
"panels": [
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"format": "none",
"gauge": {
"maxValue": 100000,
"minValue": 0,
"show": true,
"thresholdLabels": false,
"thresholdMarkers": false
},
"height": "150",
"hideTimeOverride": true,
"id": 8,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"span": 4,
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"aggregator": "sum",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "timely.metrics.received",
"refId": "A"
}
],
"thresholds": "",
"timeFrom": null,
"timeShift": "1m",
"title": "Metrics Received Last Minute",
"transparent": true,
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"height": "150",
"hideTimeOverride": true,
"id": 9,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"span": 4,
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"aggregator": "count",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "count",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.collectd.cache_size",
"refId": "A",
"tags": {}
}
],
"thresholds": "",
"timeShift": "1m",
"title": "CollectD Instances Reporting",
"transparent": true,
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"height": "150",
"hideTimeOverride": true,
"id": 10,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"span": 4,
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"aggregator": "sum",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "sys.collectd.derive.dropped",
"refId": "A",
"tags": {}
}
],
"thresholds": "",
"timeShift": "1m",
"title": "Metrics Dropped By CollectD",
"transparent": true,
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": false,
"title": "New row",
"titleSize": "h6"
},
{
"collapse": false,
"height": "250px",
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {},
"id": 3,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 3,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "timely.keys.metric.inserted",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Timely Metrics Inserted",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "none",
"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,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {},
"id": 4,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 3,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "avg",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "timely.keys.meta.inserted",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Timely Meta Inserted",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "none",
"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,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {},
"id": 5,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 3,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "timely.metrics.received",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Timely Metrics Received",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "none",
"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,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {},
"id": 7,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 3,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "none",
"alias": "$tag_host",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "sys.collectd.cache_size",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "CollectD Cache Sizes",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"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
}
]
}
],
"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"
},
"timepicker": {
"now": true,
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"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": "${DS_NAME} - Status",
"originalTitle": "${DS_NAME} - Status",
"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": "",
@@ -179,24 +206,30 @@
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu0.user",
"metric": "sys.cpu.user",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"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": "",
@@ -265,24 +295,30 @@
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu0.user",
"metric": "sys.cpu.user",
"refId": "A",
"tags": {
"rack": ".*"
}
}
],
"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": "",
@@ -351,22 +384,28 @@
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu0.user",
"metric": "sys.cpu.user",
"refId": "A",
"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
}
+3 -3
View File
@@ -289,7 +289,7 @@ System.register(['lodash', 'angular', '../../../app/core/utils/datemath'], funct
return key.trim();
});
var key = keysArray[0];
var keysQuery = key + "=*";
var keysQuery = key + "=.*";
if (keysArray.length > 1) {
keysQuery += "," + keysArray.splice(1).join(",");
@@ -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":[],"mappings":"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 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":"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 truncated
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["../../src/datasource/module.js"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAQ,sB,eAAA,gB;;AACA,qB,eAAA,e;;AACA,0B,WAAA,oB;;;sCAEF,0B;;;;AACN,iCAA2B,WAA3B,GAAyC,oCAAzC;;4BAGE,gB;;2BACA,e;;4BACA,oB;;sCACA,0B","file":"module.js","sourcesContent":["import {TimelyDatasource} from './datasource';\nimport {TimelyQueryCtrl} from './query_ctrl';\nimport {DatasourceConfigCtrl} from './config';\n\nclass TimelyAnnotationsQueryCtrl {}\nTimelyAnnotationsQueryCtrl.templateUrl = 'components/annotations.editor.html';\n\nexport {\n TimelyDatasource as Datasource,\n TimelyQueryCtrl as QueryCtrl,\n DatasourceConfigCtrl as ConfigCtrl,\n TimelyAnnotationsQueryCtrl as AnnotationsQueryCtrl\n};\n"]}
{"version":3,"sources":["../../src/datasource/module.js"],"names":["TimelyDatasource","TimelyQueryCtrl","DatasourceConfigCtrl","TimelyAnnotationsQueryCtrl","templateUrl"],"mappings":";;;;;;;;;;;;;;;AAAQA,sB,eAAAA,gB;;AACAC,qB,eAAAA,e;;AACAC,0B,WAAAA,oB;;;sCAEFC,0B;;;;AACNA,iCAA2BC,WAA3B,GAAyC,oCAAzC;;4BAGEJ,gB;;2BACAC,e;;4BACAC,oB;;sCACAC,0B","file":"module.js","sourcesContent":["import {TimelyDatasource} from './datasource';\nimport {TimelyQueryCtrl} from './query_ctrl';\nimport {DatasourceConfigCtrl} from './config';\n\nclass TimelyAnnotationsQueryCtrl {}\nTimelyAnnotationsQueryCtrl.templateUrl = 'components/annotations.editor.html';\n\nexport {\n TimelyDatasource as Datasource,\n TimelyQueryCtrl as QueryCtrl,\n DatasourceConfigCtrl as ConfigCtrl,\n TimelyAnnotationsQueryCtrl as AnnotationsQueryCtrl\n};\n"]}
+5 -1
View File
@@ -8,7 +8,11 @@
"annotations": true,
"includes": [
{"type": "dashboard", "name": "Timely Metrics", "path": "dashboards/standalone_test.json"}
{"type": "dashboard", "name": "Timely Standalone Test", "path": "dashboards/standalone_test.json"},
{"type": "dashboard", "name": "Accumulo Overview", "path": "dashboards/AccumuloOverview.json"},
{"type": "dashboard", "name": "Hadoop Overview", "path": "dashboards/HadoopOverview.json"},
{"type": "dashboard", "name": "System Overview", "path": "dashboards/SystemOverview.json"},
{"type": "dashboard", "name": "Timely Status", "path": "dashboards/TimelyStatus.json"}
],
"info": {
+1 -1
View File
@@ -66,7 +66,7 @@ System.register(['lodash', 'app/plugins/sdk'], function (_export, _context) {
function TimelyQueryCtrl($scope, $injector, uiSegmentSrv) {
_classCallCheck(this, TimelyQueryCtrl);
var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(TimelyQueryCtrl).call(this, $scope, $injector));
var _this = _possibleConstructorReturn(this, (TimelyQueryCtrl.__proto__ || Object.getPrototypeOf(TimelyQueryCtrl)).call(this, $scope, $injector));
_this.errors = _this.validateTarget();
_this.aggregators = ['avg', 'sum', 'min', 'max', 'dev', 'zimsum', 'mimmin', 'mimmax'];
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["../../src/datasource/query_ctrl.js"],"names":[],"mappings":"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","file":"query_ctrl.js","sourcesContent":["import _ from 'lodash';\nimport {QueryCtrl} from 'app/plugins/sdk';\n\nexport class TimelyQueryCtrl extends QueryCtrl {\n\n constructor($scope, $injector, uiSegmentSrv) {\n super($scope, $injector);\n\n this.errors = this.validateTarget();\n this.aggregators = ['avg', 'sum', 'min', 'max', 'dev', 'zimsum', 'mimmin', 'mimmax'];\n Line truncated
{"version":3,"sources":["../../src/datasource/query_ctrl.js"],"names":["_","QueryCtrl","TimelyQueryCtrl","$scope","$injector","uiSegmentSrv","errors","validateTarget","aggregators","fillPolicies","filterTypes","target","aggregator","downsampleAggregator","downsampleFillPolicy","datasource","getAggregators","then","aggs","length","getFilterTypes","suggestMetrics","query","callback","metricFindQuery","getTextValues","suggestTagKeys","metric","suggestTagValues","refresh","metricFindResult","map","value","text","filters","tags","addTagMode","currentTagKey","currentTagValue","targetBlur","key","removeTag","addTag","size","addFilterMode","currentFilterType","currentFilterGroupBy","currentFilter","type","tagk","currentFilterKey","filter","currentFilterValue","groupBy","push","index","splice","fil","removeFilter","addFilter","errs","shouldDownsample","downsampleInterval","kbn","describe_interval","err","message","has","templateUrl"],"mappings":"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 truncated
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["../src/module.js"],"names":[],"mappings":";;;;;;;;AAAQ,yB,qBAAA,mB;;AACA,qB,sBAAA,e;;AACA,mB,wBAAA,a;;;4BAGN,mB;;iCACA,e;;+BACA,a","file":"module.js","sourcesContent":["import {TimelyAppConfigCtrl} from './components/config';\nimport {MetricsPageCtrl} from './components/metrics';\nimport {AuthsPageCtrl} from './components/authspage';\n\nexport {\n TimelyAppConfigCtrl as ConfigCtrl,\n MetricsPageCtrl,\n AuthsPageCtrl\n};\n"]}
{"version":3,"sources":["../src/module.js"],"names":["TimelyAppConfigCtrl","MetricsPageCtrl","AuthsPageCtrl"],"mappings":";;;;;;;;AAAQA,yB,qBAAAA,mB;;AACAC,qB,sBAAAA,e;;AACAC,mB,wBAAAA,a;;;4BAGNF,mB;;iCACAC,e;;+BACAC,a","file":"module.js","sourcesContent":["import {TimelyAppConfigCtrl} from './components/config';\nimport {MetricsPageCtrl} from './components/metrics';\nimport {AuthsPageCtrl} from './components/authspage';\n\nexport {\n TimelyAppConfigCtrl as ConfigCtrl,\n MetricsPageCtrl,\n AuthsPageCtrl\n};\n"]}
+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.2",
"updated": "2016-06-30"
"version": "0.0.5-SNAPSHOT",
"updated": "2017-07-21"
},
"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.2",
"updated": "2016-06-30"
"version": "0.0.5-SNAPSHOT",
"updated": "2017-07-21"
},
"includes": [
@@ -34,7 +34,7 @@
],
"dependencies": {
"grafanaVersion": "3.x.x",
"grafanaVersion": "4.x.x",
"plugins": []
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,710 @@
{
"__inputs": [
{
"name": "DS_TIMELY",
"label": "Timely",
"description": "",
"type": "datasource",
"pluginId": "timely-datasource",
"pluginName": "Timely"
}
],
"__requires": [
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "4.4.1"
},
{
"type": "panel",
"id": "graph",
"name": "Graph",
"version": ""
},
{
"type": "panel",
"id": "singlestat",
"name": "Singlestat",
"version": ""
},
{
"type": "datasource",
"id": "timely-datasource",
"name": "Timely",
"version": "1.0.0"
}
],
"annotations": {
"list": []
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"hideControls": false,
"id": null,
"links": [],
"refresh": "1m",
"rows": [
{
"collapse": false,
"height": "150",
"panels": [
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"format": "none",
"gauge": {
"maxValue": 100000,
"minValue": 0,
"show": true,
"thresholdLabels": false,
"thresholdMarkers": false
},
"height": "150",
"hideTimeOverride": true,
"id": 8,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"span": 4,
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"aggregator": "sum",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "timely.metrics.received",
"refId": "A"
}
],
"thresholds": "",
"timeFrom": null,
"timeShift": "1m",
"title": "Metrics Received Last Minute",
"transparent": true,
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"height": "150",
"hideTimeOverride": true,
"id": 9,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"span": 4,
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"aggregator": "count",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "count",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.collectd.cache_size",
"refId": "A",
"tags": {}
}
],
"thresholds": "",
"timeShift": "1m",
"title": "CollectD Instances Reporting",
"transparent": true,
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
},
{
"cacheTimeout": null,
"colorBackground": false,
"colorValue": false,
"colors": [
"rgba(245, 54, 54, 0.9)",
"rgba(237, 129, 40, 0.89)",
"rgba(50, 172, 45, 0.97)"
],
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"format": "none",
"gauge": {
"maxValue": 100,
"minValue": 0,
"show": false,
"thresholdLabels": false,
"thresholdMarkers": true
},
"height": "150",
"hideTimeOverride": true,
"id": 10,
"interval": null,
"links": [],
"mappingType": 1,
"mappingTypes": [
{
"name": "value to text",
"value": 1
},
{
"name": "range to text",
"value": 2
}
],
"maxDataPoints": 100,
"nullPointMode": "connected",
"nullText": null,
"postfix": "",
"postfixFontSize": "50%",
"prefix": "",
"prefixFontSize": "50%",
"rangeMaps": [
{
"from": "null",
"text": "N/A",
"to": "null"
}
],
"span": 4,
"sparkline": {
"fillColor": "rgba(31, 118, 189, 0.18)",
"full": false,
"lineColor": "rgb(31, 120, 193)",
"show": false
},
"tableColumn": "",
"targets": [
{
"aggregator": "sum",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "sys.collectd.derive.dropped",
"refId": "A",
"tags": {}
}
],
"thresholds": "",
"timeShift": "1m",
"title": "Metrics Dropped By CollectD",
"transparent": true,
"type": "singlestat",
"valueFontSize": "80%",
"valueMaps": [
{
"op": "=",
"text": "N/A",
"value": "null"
}
],
"valueName": "avg"
}
],
"repeat": null,
"repeatIteration": null,
"repeatRowId": null,
"showTitle": false,
"title": "New row",
"titleSize": "h6"
},
{
"collapse": false,
"height": "250px",
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {},
"id": 3,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 3,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "timely.keys.metric.inserted",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Timely Metrics Inserted",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "none",
"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,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {},
"id": 4,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 3,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "avg",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "timely.keys.meta.inserted",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Timely Meta Inserted",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "none",
"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,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {},
"id": 5,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 3,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "timely.metrics.received",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "Timely Metrics Received",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"yaxes": [
{
"format": "none",
"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,
"dashLength": 10,
"dashes": false,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {},
"id": 7,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"span": 3,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "none",
"alias": "$tag_host",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "sys.collectd.cache_size",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"thresholds": [],
"timeFrom": null,
"timeShift": null,
"title": "CollectD Cache Sizes",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"buckets": null,
"mode": "time",
"name": null,
"show": true,
"values": []
},
"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
}
]
}
],
"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"
},
"timepicker": {
"now": true,
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"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": "${DS_NAME} - Status",
"originalTitle": "${DS_NAME} - Status",
"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": "",
@@ -179,24 +206,30 @@
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu0.user",
"metric": "sys.cpu.user",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"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": "",
@@ -265,24 +295,30 @@
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu0.user",
"metric": "sys.cpu.user",
"refId": "A",
"tags": {
"rack": ".*"
}
}
],
"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": "",
@@ -351,22 +384,28 @@
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu0.user",
"metric": "sys.cpu.user",
"refId": "A",
"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
}
@@ -241,7 +241,7 @@ export class TimelyDatasource {
return key.trim();
});
var key = keysArray[0];
var keysQuery = key + "=*";
var keysQuery = key + "=.*";
if (keysArray.length > 1) {
keysQuery += "," + keysArray.splice(1).join(",");
@@ -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));
@@ -8,7 +8,11 @@
"annotations": true,
"includes": [
{"type": "dashboard", "name": "Timely Metrics", "path": "dashboards/standalone_test.json"}
{"type": "dashboard", "name": "Timely Standalone Test", "path": "dashboards/standalone_test.json"},
{"type": "dashboard", "name": "Accumulo Overview", "path": "dashboards/AccumuloOverview.json"},
{"type": "dashboard", "name": "Hadoop Overview", "path": "dashboards/HadoopOverview.json"},
{"type": "dashboard", "name": "System Overview", "path": "dashboards/SystemOverview.json"},
{"type": "dashboard", "name": "Timely Status", "path": "dashboards/TimelyStatus.json"}
],
"info": {
+311 -37
View File
@@ -1,16 +1,33 @@
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.2</version>
<version>0.0.5</version>
<packaging>pom</packaging>
<name>Timely</name>
<description>A secure and scalable time series database based on Apache Accumulo</description>
<licenses>
<license>
<name>Apache License, Version 2.1</name>
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
</license>
</licenses>
<scm>
<connection>scm:git:https://github.com/NationalSecurityAgency/timely.git</connection>
<developerConnection>scm:git:[email protected]:NationalSecurityAgency/timely.git</developerConnection>
<url>https://github.com/NationalSecurityAgency/timely</url>
</scm>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/NationalSecurityAgency/timely/issues</url>
</issueManagement>
<modules>
<module>common</module>
<module>client</module>
<module>server</module>
<module>collectd-timely-plugin</module>
<module>collectd-nsq-plugin</module>
<module>collectd-plugin-parent</module>
<module>grafana</module>
<module>analytics</module>
</modules>
<properties>
<!-- Configure the os-maven-plugin extension to expand the classifier on -->
@@ -18,25 +35,58 @@
<os.detection.classifierWithLikes>fedora</os.detection.classifierWithLikes>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- dependency versions -->
<collectd-api-jar>/usr/share/collectd/java/collectd-api.jar</collectd-api-jar>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<version.accumulo>1.7.0</version.accumulo>
<version.caffeine>2.2.0</version.caffeine>
<version.commons-configuration>1.10</version.commons-configuration>
<version.commons-lang3>3.1</version.commons-lang3>
<version.hadoop>2.6.2</version.hadoop>
<version.jackson>2.6.1</version.jackson>
<version.javassist>3.20.0-GA</version.javassist>
<version.junit>4.11</version.junit>
<version.log4j>2.5</version.log4j>
<version.netty>4.0.38.Final</version.netty>
<version.netty-tcnative>1.1.33.Fork18</version.netty-tcnative>
<version.security>4.0.4.RELEASE</version.security>
<version.slf4j>1.7.12</version.slf4j>
<version.accumulo>1.7.2</version.accumulo>
<version.caffeine>2.3.3</version.caffeine>
<version.collectd>5.5.1</version.collectd>
<version.commons-collections4>4.1</version.commons-collections4>
<version.commons-lang3>3.5</version.commons-lang3>
<version.disruptor>3.3.6</version.disruptor>
<version.fast-classpath-scanner>2.0.5</version.fast-classpath-scanner>
<version.google-flatbuffers>1.4.0</version.google-flatbuffers>
<version.guava>19.0</version.guava>
<version.hadoop>2.7.3</version.hadoop>
<version.httpcomponents>4.5.2</version.httpcomponents>
<version.jackson>2.8.4</version.jackson>
<version.javassist>3.21.0-GA</version.javassist>
<version.jcip-annotations>1.0</version.jcip-annotations>
<version.jsoup>1.9.2</version.jsoup>
<version.junit>4.12</version.junit>
<version.log4j>2.6.2</version.log4j>
<version.netty>4.0.46.Final</version.netty>
<version.netty-tcnative>2.0.1.Final</version.netty-tcnative>
<version.powermock>1.6.4</version.powermock>
<version.slf4j>1.7.21</version.slf4j>
<version.spring-boot>1.4.1.RELEASE</version.spring-boot>
<!-- plugin versions -->
<version.eclipse-lifecycle>1.0.0</version.eclipse-lifecycle>
<version.findbugs-maven>3.0.3</version.findbugs-maven>
<version.formatter>0.5.2</version.formatter>
<version.jacoco>0.7.6.201602180812</version.jacoco>
<version.maven-assembly>2.6</version.maven-assembly>
<version.maven-build-helper>1.12</version.maven-build-helper>
<version.maven-compiler>3.3</version.maven-compiler>
<version.maven-dependency>2.10</version.maven-dependency>
<version.maven-jar>3.0.1</version.maven-jar>
<version.buildnumber-maven>1.4</version.buildnumber-maven>
<version.os-maven>1.5.0.Final</version.os-maven>
<version.maven-pmd>3.6</version.maven-pmd>
<version.maven-rpm>2.1.4</version.maven-rpm>
<version.maven-shade>2.4.2</version.maven-shade>
<version.maven-surefire>2.19.1</version.maven-surefire>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>collectd</groupId>
<artifactId>collectd-api</artifactId>
<version>${version.collectd}</version>
<scope>system</scope>
<systemPath>${collectd-api-jar}</systemPath>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
@@ -62,17 +112,32 @@
<artifactId>caffeine</artifactId>
<version>${version.caffeine}</version>
</dependency>
<dependency>
<groupId>com.google.flatbuffers</groupId>
<artifactId>flatbuffers-java</artifactId>
<version>${version.google-flatbuffers}</version>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>${version.commons-configuration}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${version.guava}</version>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>${version.disruptor}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>io.github.lukehutch</groupId>
<artifactId>fast-classpath-scanner</artifactId>
<version>${version.fast-classpath-scanner}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
@@ -84,6 +149,17 @@
<version>${version.junit}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<version>${version.jcip-annotations}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>${version.commons-collections4}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
@@ -184,6 +260,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${version.httpcomponents}</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
@@ -191,47 +272,155 @@
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${version.security}</version>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${version.jsoup}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${version.security}</version>
</dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-easymock-release-full</artifactId>
<version>${version.powermock}</version>
<classifier>full</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${version.slf4j}</version>
</dependency>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${version.spring-boot}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<version>${version.formatter}</version>
<configuration>
<configFile>${project.parent.basedir}/eclipse/Eclipse-Formatter.xml</configFile>
<lineEnding>LF</lineEnding>
<overrideConfigCompilerVersion>true</overrideConfigCompilerVersion>
</configuration>
<executions>
<execution>
<goals>
<goal>format</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>${version.maven-assembly}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<version>${version.maven-compiler}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${version.maven-dependency}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${version.maven-surefire}</version>
<configuration>
<argLine>${failsafeArgLine} -Djava.library.path=${project.build.directory}/native/META-INF/native/libnetty-tcnative.so -Dzookeeper.sasl.client=false</argLine>
<includes>
<include>**/*.java</include>
</includes>
<groups>timely.test.IntegrationTest</groups>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<version>${version.maven-jar}</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
<manifestEntries>
<Implementation-Build>${buildNumber}</Implementation-Build>
<Implementation-Timestamp>${timestamp}</Implementation-Timestamp>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${version.maven-shade}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${version.maven-surefire}</version>
<configuration>
<argLine>${sureFireArgLine} -Djava.library.path=${project.build.directory}/native/META-INF/native/libnetty-tcnative.so -Dzookeeper.sasl.client=false</argLine>
<excludedGroups>timely.test.IntegrationTest</excludedGroups>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>${version.maven-build-helper}</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>${version.buildnumber-maven}</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<doCheck>false</doCheck>
<doUpdate>false</doUpdate>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.3</version>
<version>${version.findbugs-maven}</version>
<configuration>
<effort>Max</effort>
<threshold>Medium</threshold>
<xmlOutput>true</xmlOutput>
<excludeFilterFile>src/main/resources/findbugs-excludes.xml</excludeFilterFile>
</configuration>
<executions>
<execution>
@@ -242,7 +431,92 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${version.jacoco}</version>
<executions>
<execution>
<id>jacoco-prepare-ut</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<phase>process-test-classes</phase>
<configuration>
<destFile>${project.build.directory}/coverage/jacoco-ut.exec</destFile>
<propertyName>sureFireArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>jacoco-prepare-it</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<phase>pre-integration-test</phase>
<configuration>
<destFile>${project.build.directory}/coverage/jacoco-it.exec</destFile>
<propertyName>failsafeArgLine</propertyName>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>rpm-maven-plugin</artifactId>
<version>${version.maven-rpm}</version>
</plugin>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>${version.eclipse-lifecycle}</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
<versionRange>[0.5.2,)</versionRange>
<goals>
<goal>format</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore/>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<versionRange>[2.10,)</versionRange>
<goals>
<goal>copy-dependencies</goal>
<goal>unpack</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore/>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</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
View File
@@ -0,0 +1 @@
/target/
+12 -5
View File
@@ -3,15 +3,22 @@ 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 && \
mkdir -p /timely/bin
yum -y install java-1.8.0-openjdk-devel maven openssl apr wget epel-release && \
yum -y install bouncycastle && \
yum clean all && \
mkdir -p /timely/bin && \
echo "security.provider.9=org.bouncycastle.jce.provider.BouncyCastleProvider" >> /usr/lib/jvm/java-1.8.0-openjdk/jre/lib/security/java.security && \
ln -sf /usr/share/java/bcprov.jar /usr/lib/jvm/java-1.8.0-openjdk/jre/lib/ext/bcprov.jar
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.91-1.b14.el7_2.x86_64
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk
EXPOSE 9804 54321 54322
ENV TIMELY_VERSION 0.0.2-SNAPSHOT
ENV TIMELY_VERSION 0.0.3-SNAPSHOT
#CMD /timely/bin/timely-standalone.sh
+6
View File
@@ -0,0 +1,6 @@
#!/bin/sh
export SRC_DIR=/timely-server-src
export TIMELY_DIR=/timely
@@ -1,6 +1,11 @@
#!/bin/sh
WORKING="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
. "${WORKING}/deploy-env.sh"
set -e
/timely-server-src/bin/docker/deploy-timely-build.sh
/timely/bin/timely-standalone.sh
"${SRC_DIR}/bin/docker/genCerts.sh"
"${SRC_DIR}/bin/docker/deploy-timely-build.sh"
"${TIMELY_DIR}/bin/timely-standalone.sh"
+6 -2
View File
@@ -1,5 +1,9 @@
#!/bin/sh
#!/bin/bash
WORKING="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
. "${WORKING}/deploy-env.sh"
set -e
tar xzf /timely-server-src/target/timely-server-$TIMELY_VERSION-dist.tar.gz -C /timely --strip-components 1
tar xzf "${SRC_DIR}/target/timely-server-$TIMELY_VERSION-dist.tar.gz" -C "${TIMELY_DIR}" --strip-components 1
+51 -12
View File
@@ -1,19 +1,58 @@
#!/bin/sh
#!/bin/bash
/timely-server-src/bin/docker/deploy-timely-build.sh
WORKING="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
. "${WORKING}/deploy-env.sh"
"${SRC_DIR}/bin/docker/deploy-timely-build.sh"
/timely-server-src/bin/docker/wait-for-it.sh timely:54322 -t 45
"${SRC_DIR}/bin/docker/wait-for-it.sh" timely:54322 -t 45
# create datasource in grafana
curl -X POST -u admin:admin -H "Content-Type: application/json" -d \
'{"name":"Timely","type":"opentsdb","url":"https://timely:54322","access":"proxy","jsonData":{"tsdbVersion":1,"tsdbResolution":1}}' \
http://grafana:3000/api/datasources
# insert the dashboard
curl -X POST -u admin:admin -H "Content-Type: application/json" \
-d @/timely-server-src/bin/docker/standalone_test.json \
http://grafana:3000/api/dashboards/db
# enable app
curl -k -H "Content-Type: application/json" -d \
'{
"enabled":true,
"pinned":true
}' \
https://admin:admin@grafana:3000/api/plugins/timely-app/settings
/timely/bin/insert-test-data.sh
# create data source
curl -k -H "Content-Type: application/json" -d \
'{
"name":"Timely",
"type":"timely-datasource",
"Access":"direct",
"jsonData":
{
"timelyHost":"localhost",
"httpsPort":"54322",
"wsPort":"54323",
"basicAuths":true
}
}' \
https://admin:admin@grafana:3000/api/datasources
# import the dashboard
curl -k -H "Content-Type: application/json" -d \
'{
"pluginId":"timely-datasource",
"path":"dashboards/standalone_test.json",
"overwrite":false,
"inputs":[{
"name":"*",
"type":"datasource",
"pluginId":"timely-datasource",
"value":"Timely"
}]
}' \
https://admin:admin@grafana:3000/api/dashboards/import
# star the dashboard
curl -k -X POST https://admin:admin@grafana:3000/api/user/stars/dashboard/1
"${TIMELY_DIR}/bin/insert-test-data.sh"
+56
View File
@@ -0,0 +1,56 @@
#!/bin/bash
WORKING="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
. "${WORKING}/deploy-env.sh"
PASSPREFIX=pass:
KEYPASS=password
export PASSWORD=$PASSPREFIX$KEYPASS
if [ ! -d "${SRC_DIR}/pki" ]; then
mkdir "${SRC_DIR}/pki"
pushd "${SRC_DIR}/pki"
#Create a private key
openssl genrsa -aes256 -out CA.key -passout env:PASSWORD 4096
#Create a certificate request using the private key
openssl req -x509 -new -key CA.key -sha256 -nodes -days 365 -out CA.pem -passin env:PASSWORD -subj '/C=US/ST=Confusion/L=Here/O=Timely/OU=Server/CN=localhost/emailAddress=noreply@localhost/subjectAltName=DNS.1=127.0.0.1'
#Create your SSL material for Grafana
#Create the private key for the Grafana server
openssl genrsa -out grafana.key -passout env:PASSWORD 4096
#Generate a certificate signing request (CSR) with our Grafana private key
openssl req -new -key grafana.key -sha256 -nodes -out grafana.csr -subj '/C=US/ST=Confusion/L=Here/O=Timely/OU=Server/CN=localhost/emailAddress=noreply@localhost/subjectAltName=DNS.1=127.0.0.1'
#Use the CSR and the CA to create a certificate for the server (a reply to the CSR)
openssl x509 -req -in grafana.csr -CA CA.pem -CAkey CA.key -CAcreateserial -out grafana.crt -days 365 -passin env:PASSWORD
#Create your SSL material for Timely
#Create the private key for the Timely server
openssl genrsa -out timely.key 4096
#Generate a certificate signing request (CSR) with our Timely private key
openssl req -new -key timely.key -sha256 -nodes -subj '/C=US/ST=Confusion/L=Here/O=Timely/OU=Server/CN=localhost/emailAddress=noreply@localhost/subjectAltName=DNS.1=127.0.0.1' > timely.csr
#Use the CSR and the CA to create a certificate for the server (a reply to the CSR)
openssl x509 -req -in timely.csr -CA CA.pem -CAkey CA.key -CAcreateserial -out timely.crt -days 365 -passin env:PASSWORD
#Convert the private key to pkcs#8 format
openssl pkcs8 -topk8 -inform PEM -outform PEM -in timely.key -out timely-pkcs8.key -passout env:PASSWORD
popd
fi
+2 -2
View File
@@ -55,8 +55,8 @@ http_port = 3000
;enable_gzip = false
# https certs & key file
cert_file = /etc/grafana/pki/timely-cert.pem
cert_key = /etc/grafana/pki/timely-key.pem
cert_file = /timely-server-src/pki/grafana.crt
cert_key = /timely-server-src/pki/grafana.key
#################################### Database ####################################
[database]
-429
View File
@@ -1,429 +0,0 @@
{"dashboard":
{
"id": null,
"title": "StandaloneTest",
"originalTitle": "StandaloneTest",
"tags": [],
"style": "dark",
"timezone": "browser",
"editable": true,
"hideControls": false,
"sharedCrosshair": false,
"rows": [
{
"collapse": false,
"editable": true,
"height": "250px",
"panels": [
{
"aliasColors": {},
"bars": false,
"datasource": "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)",
"thresholdLine": false
},
"id": 1,
"legend": {
"alignAsTable": true,
"avg": false,
"current": true,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": true,
"values": true
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 12,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"disableDownsampling": false,
"downsampleAggregator": "avg",
"downsampleFillPolicy": "none",
"downsampleInterval": "",
"errors": {},
"isCounter": false,
"metric": "timely.metrics.received",
"refId": "A",
"shouldComputeRate": false
},
{
"aggregator": "sum",
"disableDownsampling": false,
"downsampleAggregator": "avg",
"downsampleFillPolicy": "none",
"downsampleInterval": "",
"errors": {},
"metric": "timely.keys.meta.inserted",
"refId": "B"
},
{
"aggregator": "sum",
"disableDownsampling": false,
"downsampleAggregator": "avg",
"downsampleFillPolicy": "none",
"downsampleInterval": "",
"errors": {},
"metric": "timely.keys.metric.inserted",
"refId": "C"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Timely Status",
"tooltip": {
"msResolution": true,
"shared": false,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"yaxes": [
{
"format": "short",
"label": "Keys",
"logBase": 1,
"max": null,
"min": null,
"show": true
},
{
"format": "short",
"logBase": 1,
"max": null,
"min": null,
"show": false
}
]
}
],
"title": "Row"
},
{
"collapse": false,
"editable": true,
"height": "250px",
"panels": [
{
"aliasColors": {},
"bars": false,
"datasource": "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)"
},
"id": 2,
"isNew": true,
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 12,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "max",
"alias": "$tag_host",
"currentTagKey": "",
"currentTagValue": "",
"disableDownsampling": false,
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu0.user",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"timeFrom": null,
"timeShift": null,
"title": "CPU User by Host",
"tooltip": {
"msResolution": false,
"shared": true,
"value_type": "cumulative"
},
"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": "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)"
},
"id": 3,
"isNew": true,
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 12,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "max",
"alias": "$tag_rack",
"currentTagKey": "",
"currentTagValue": "",
"disableDownsampling": false,
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu0.user",
"refId": "A",
"tags": {
"rack": ".*"
}
}
],
"timeFrom": null,
"timeShift": null,
"title": "CPU User by Rack",
"tooltip": {
"msResolution": false,
"shared": true,
"value_type": "cumulative"
},
"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": "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)"
},
"id": 4,
"isNew": true,
"legend": {
"alignAsTable": true,
"avg": false,
"current": false,
"max": false,
"min": false,
"rightSide": true,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 12,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "max",
"alias": "",
"currentTagKey": "",
"currentTagValue": "",
"disableDownsampling": false,
"downsampleAggregator": "max",
"downsampleFillPolicy": "none",
"downsampleInterval": "1s",
"metric": "sys.cpu0.user",
"refId": "A",
"tags": {}
}
],
"timeFrom": null,
"timeShift": null,
"title": "Cumulative CPU",
"tooltip": {
"msResolution": false,
"shared": true,
"value_type": "cumulative"
},
"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
}
]
}
],
"title": "New row"
}
],
"time": {
"from": "now-15m",
"to": "now"
},
"timepicker": {
"now": true,
"refresh_intervals": [
"5s",
"10s",
"30s",
"1m",
"5m",
"15m",
"30m",
"1h",
"2h",
"1d"
],
"time_options": [
"5m",
"15m",
"1h",
"6h",
"12h",
"24h",
"2d",
"7d",
"30d"
]
},
"templating": {
"list": []
},
"annotations": {
"list": []
},
"refresh": "5s",
"schemaVersion": 12,
"version": 1,
"links": []
}
}
+5 -4
View File
@@ -9,12 +9,13 @@ fi
THIS_DIR="${THIS_SCRIPT%/*}"
BASE_DIR=${THIS_DIR}/..
CONF_DIR="${BASE_DIR}/conf"
CONF_FILE="${CONF_DIR}/timely.properties"
LIB_DIR="${BASE_DIR}/lib"
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*"
JVM_ARGS="-Xmx256m -Xms128m -Dlog4j.configurationFile=${THIS_DIR}/log4j2.xml"
JVM_ARGS="-Xmx256m -Xms128m"
JVM_ARGS="${JVM_ARGS} -Dlogging.config=${CONF_DIR}/log4j2-error-console.xml"
JVM_ARGS="${JVM_ARGS} -Dlog4j.configurationFile=${CONF_DIR}/log4j2-error-console.xml"
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.util.GetMetricTableSplitPoints "${CONF_FILE}""
$JAVA_HOME/bin/java ${JVM_ARGS} timely.util.GetMetricTableSplitPoints "${CONF_FILE}"
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.util.GetMetricTableSplitPoints --spring.config.name=timely"
$JAVA_HOME/bin/java ${JVM_ARGS} timely.util.GetMetricTableSplitPoints --spring.config.name=timely
Loaded 100 of 232 files, more files were not shown because too many files have changed in this diff. Show more