Compare commits

..
148 Commits
Author SHA1 Message Date
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
Dave Marion 053d15c559 Set version in pom to 0.0.2 for tag 2016-07-27 08:22:15 -04:00
Dave Marion b3a479636b Add ASL badge to README 2016-07-26 14:33:21 -04:00
Dave Marion 8539986faf re #55, serve up favicon.ico if it exists 2016-07-26 13:57:41 -04:00
Drew Farris cbdf28c510 This >really< fixes #54 to work around nulls at deserialization time 2016-07-26 13:24:21 -04:00
klucar 670cc7769d Transparent favicon 2016-07-26 12:20:23 -04:00
klucar 22a9be3ba2 Generated favicon.ico 2016-07-26 12:17:13 -04:00
Dave Marion 2836b03366 Removed README, it's already in the docs 2016-07-26 08:56:36 -04:00
Dave Marion 64bde2189e fixes #54, protect against NPE 2016-07-26 08:49:17 -04:00
Dave Marion 4d41c8e19a fix formatting 2016-07-25 13:31:24 -04:00
Dave Marion 08a095e349 Fix mistake in README 2016-07-25 13:30:50 -04:00
Dave Marion fc0f2b8356 Remove READMEs and associated Screenshots, they are now in the slate & gh-pages branches 2016-07-25 13:29:54 -04:00
Dave Marion e9c0f63478 re #50, return -1 when not connected and use fqdn as hostname when no period in fqdn 2016-07-25 11:04:13 -04:00
Dave Marion 9c01d00686 Log errors that occur in the pipeline 2016-07-25 10:42:52 -04:00
Klucar dd8d379292 Fixes #53 2016-07-22 13:48:28 -04:00
Klucar 1acd5ce5cb updated Browser Test text to Browser Cert Check 2016-07-22 13:21:40 -04:00
Klucar aa3ac901b6 grafana timely logo update 2016-07-22 13:19:12 -04:00
Klucar 2c6270f23e retrieved websocket host from browser window 2016-07-22 09:56:32 -04:00
Dave Marion f6728b4e8d Add logo to README 2016-07-21 16:03:17 -04:00
klucar fb0590d778 Merge of Grafana app branch 2016-07-21 15:42:35 -04:00
Dave Marion f94ec78c66 closes #43, release reference to ByteBuf created in TcpDecoder. 2016-07-21 11:38:48 -04:00
Dave Marion 3fddbb4c6f closes #41, added rules for snmp plugin 2016-07-21 08:49:15 -04:00
Dave Marion e841ac90b8 removed unused imports 2016-07-18 12:48:49 -04:00
Dave Marion 203a97d7db Don't log known error condition 2016-07-15 13:27:06 -04:00
Dave Marion 4d19538c77 fixes #36, separate the request operations from the protocols. 2016-07-15 11:51:59 -04:00
Dave Marion e83356cb74 closes #45, add path to cookie 2016-07-15 09:26:59 -04:00
Dave Marion 5f1beb6045 closes #42 - remove grafana redirect 2016-07-12 17:50:40 -04:00
Dave Marion 12ee77386b closes #37 - update Netty to 4.0.38.Final 2016-07-06 08:26:07 -04:00
Dave Marion accbb2af9a closes #27, added web socket support to provide ability to create/add/remove subscriptions to receive metric data 2016-07-05 14:35:08 -04:00
Dave Marion 041cee1a80 closes #35, redirect http to https, which returns a 404 and a Strict-Transport-Security header 2016-07-05 09:52:32 -04:00
Dave Marion f8efdbf240 closes #34 - clean up warnings. Only allow file server to access /webapp 2016-06-30 14:34:24 -04:00
Jim Klucar ca4155be6f fixed test dashboard id 2016-06-30 11:07:32 -04:00
klucar b3c7b143e0 changed queries to regular expressions 2016-06-30 07:41:12 -04:00
Dave Marion 42d31efff8 Merge pull request #32 from NationalSecurityAgency/docker
re #31 Changes for using Docker
2016-06-29 12:27:48 -04:00
Dave Marion 56e90ef693 re #30, add test for processing all values of the first tag found in meta table when no tags in the query. Fix regex tests. 2016-06-29 11:34:21 -04:00
klucar 6345efa996 changed localhost to 127.0.0.1 to match original scripts 2016-06-28 22:04:30 -04:00
klucar 701f841cfe fixed .so vs .jnilib netty tcnative extraction. fixed overriding timely host and port in launch scripts 2016-06-28 22:01:01 -04:00
Jim Klucar 4b6de88e25 Update README.docker 2016-06-28 09:48:07 -04:00
Jim Klucar de9b0df49e Update README.docker 2016-06-28 09:46:28 -04:00
klucar b8418e4e19 created 3-container example system using docker-compose 2016-06-28 07:20:59 -04:00
Dave Marion d5cec191e2 closes #28, note that the binary is not fully portable 2016-06-27 19:33:10 -04:00
Dave Marion 13feefde31 closes #1 - added utility to generate split points for the metric table from the meta table 2016-06-24 08:43:11 -04:00
Dave Marion 86c9d8835d closes #26: removed unused code in downsample iterator thus commons-lang3 is no longer required in the tserver classpath. Re-ordered tags based on the counts from the meta cache 2016-06-23 16:06:11 -04:00
Dave Marion b8da5152e0 closes #17 - regex support for tag values 2016-06-23 13:55:27 -04:00
Dave Marion e73564c578 closes #24, added note to README about tag order in queries 2016-06-22 16:18:59 -04:00
Dave Marion f42696ddfc Added static file server for #22 2016-06-22 16:09:46 -04:00
Dave Marion 7e3a85050d Bump version to 0.0.2-SNAPSHOT 2016-06-22 14:33:26 -04:00
Dave Marion b022c5539e Change version to 0.0.1 for tag 2016-06-22 14:22:29 -04:00
Dave Marion e4bdea4ee9 fixes #23, return html or json depending on the Accept header precedence 2016-06-22 13:49:35 -04:00
Jim Klucar 60325e1821 Update README.md
fixed typo
2016-06-21 15:06:41 -04:00
Dave Marion 69ca6a8691 Fix formatting in quick setup guide 2016-06-21 13:20:48 -04:00
Dave Marion b18126ccd1 Remove unnecessary todo markers 2016-06-21 13:17:11 -04:00
Dave Marion 8d41f6305d Update the guide 2016-06-20 11:32:18 -04:00
Dave Marion ad223941e2 Removed unused code 2016-06-20 10:01:43 -04:00
Dave Marion 99b3635e76 Update formatting 2016-06-17 14:54:46 -04:00
Dave Marion f912458faa Fixed #8, added security to Timely 2016-06-06 09:20:40 -04:00
Dave Marion 097cbf485b Fix metric name and tag set for IPMI plugin 2016-06-02 13:37:30 -04:00
Dave Marion f85f77814a closes #15 2016-06-01 16:08:41 -04:00
Dave Marion e7d38a07ff Fix minor build issues, apply defaults for MetaCache in Configuration 2016-05-11 21:26:33 -04:00
Dave Marion 66a64241d9 closes #13: Added exception handler at end of pipeline to return HTTP 500 or response code within a TimelyException 2016-05-10 10:51:57 -04:00
Dave Marion c78a27bc71 Fix integration test 2016-04-27 10:25:58 -04:00
Dave Marion b6cdadaaee re #7: change default downsample from 1s to 60s 2016-04-26 14:40:21 -04:00
Dave Marion a6b88f18ab fixes #6, allows for StatsD metrics in other formats 2016-04-26 12:35:36 -04:00
Dave Marion b101208828 fixes #4, handle ethstat metrics a little better 2016-04-26 10:50:02 -04:00
Dave Marion 368a33b545 Added contributors file 2016-04-22 15:06:05 -04:00
Dave Marion 7850c49054 Fix table format 2016-04-22 14:58:23 -04:00
Dave Marion d97dd7971e Added ASL 2.0, updated README, exclude older transitive slf4j dependency, formatted poms 2016-04-22 14:27:43 -04:00
Dave Marion 6f61ffcf33 Add JaCoCo for code coverage, update README 2016-04-22 14:06:00 -04:00
Dave Marion d6c9dc1a27 Supply a name to the iterator to allow multiple instances of it 2016-04-22 13:56:57 -04:00
Dave Marion 2dbd0b61b7 Fix ArrayIndexOutOfBounds error 2016-04-22 13:56:21 -04:00
Dave Marion c7e1567e5a Bump Accumulo and Log4j version, update README 2016-04-22 13:55:31 -04:00
Dave Marion e661cbebc1 Update README 2016-04-22 13:42:33 -04:00
Dave Marion 4e4f1911af Add findbugs to build, fix bugs 2016-04-22 13:41:27 -04:00
Dave Marion 45975462bd Modify DataStore so that each thread gets its own BatchWriter 2016-04-22 13:37:47 -04:00
Dave Marion 9851638c32 Initial commit 2016-04-21 12:11:06 -04:00
371 changed files with 41432 additions and 17612 deletions

No files matched your search

-9
View File
@@ -1,9 +0,0 @@
If this is a question or feature request, make sure to:
- [ ] The title starts with `Question:` or `Feature:`.
If this is an bug report, not a question, make sure to:
- [ ] I'm not running Windows (which is unsupported), or if I am, I can confirm this issue appears on another platform, or Vagrant.
- [ ] This issue appears in the latest `dev` branch.
- [ ] I've included my browser and Ruby version in this issue.
-5
View File
@@ -1,5 +0,0 @@
Make sure you've checked off all these things before submitting:
- [ ] This pull request isn't for a company's fork, it's intended for the upstream Slate shared by everybody.
- [ ] This pull request is submitted to the `dev` branch.
- [ ] If it makes frontend changes, this pull request has been tested in the latest version of Firefox, Chrome, IE, and Safari.
+7 -23
View File
@@ -1,25 +1,9 @@
*.gem
*.rbc
.bundle
.config
coverage
InstalledFiles
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
*.DS_STORE
build/
.cache
.vagrant
.sass-cache
# YARD artifacts
.yardoc
_yardoc
doc/
.classpath
.project
.settings/
target/
.idea/
*.iml
logs/
server/pki/
-10
View File
@@ -1,10 +0,0 @@
sudo: false
language: ruby
rvm:
- 2.0.0
- 2.1.0
cache: bundler
script: bundle exec middleman build
-75
View File
@@ -1,75 +0,0 @@
# Changelog
## Version 1.3.3
*June 11, 2016*
Documentation and example changes.
## Version 1.3.2
*February 3, 2016*
A small bugfix for slightly incorrect background colors on code samples in some cases.
## Version 1.3.1
*January 31, 2016*
A small bugfix for incorrect whitespace in code blocks.
## Version 1.3
*January 27, 2016*
We've upgraded Middleman and a number of other dependencies, which should fix quite a few bugs.
Instead of `rake build` and `rake deploy`, you should now run `bundle exec middleman build --clean` to build your server, and `./deploy.sh` to deploy it to Github Pages.
## Version 1.2
*June 20, 2015*
**Fixes:**
- Remove crash on invalid languages
- Update Tocify to scroll to the highlighted header in the Table of Contents
- Fix variable leak and update search algorithms
- Update Python examples to be valid Python
- Update gems
- More misc. bugfixes of Javascript errors
- Add Dockerfile
- Remove unused gems
- Optimize images, fonts, and generated asset files
- Add chinese font support
- Remove RedCarpet header ID patch
- Update language tabs to not disturb existing query strings
## Version 1.1
*July 27, 2014*
**Fixes:**
- Finally, a fix for the redcarpet upgrade bug
## Version 1.0
*July 2, 2014*
[View Issues](https://github.com/tripit/slate/issues?milestone=1&state=closed)
**Features:**
- Responsive designs for phones and tablets
- Started tagging versions
**Fixes:**
- Fixed 'unrecognized expression' error
- Fixed #undefined hash bug
- Fixed bug where the current language tab would be unselected
- Fixed bug where tocify wouldn't highlight the current section while searching
- Fixed bug where ids of header tags would have special characters that caused problems
- Updated layout so that pages with disabled search wouldn't load search.js
- Cleaned up Javascript
+6
View File
@@ -0,0 +1,6 @@
Dave Marion ([email protected])
Eric Newton ([email protected])
Jim Klucar ([email protected])
Charlie Williams ([email protected])
Drew Farris ([email protected])
Brian Loss ([email protected])
-10
View File
@@ -1,10 +0,0 @@
source 'https://rubygems.org'
# Middleman
gem 'middleman', '~>4.0.0'
gem 'middleman-gh-pages', '~> 0.0.3'
gem 'middleman-syntax', '~> 2.1.0'
gem 'middleman-autoprefixer', '~> 2.7.0'
gem "middleman-sprockets", "~> 4.0.0.rc"
gem 'rouge', '~> 1.10.1'
gem 'redcarpet', '~> 3.3.2'
-134
View File
@@ -1,134 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (4.2.5.1)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
addressable (2.4.0)
autoprefixer-rails (6.3.1)
execjs
json
backports (3.6.7)
capybara (2.5.0)
mime-types (>= 1.16)
nokogiri (>= 1.3.3)
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.10.0)
compass-import-once (1.0.5)
sass (>= 3.2, < 3.5)
concurrent-ruby (0.9.2)
contracts (0.12.0)
erubis (2.7.0)
execjs (2.6.0)
fastimage (1.8.1)
addressable (~> 2.3, >= 2.3.5)
ffi (1.9.10)
haml (4.0.7)
tilt
hamster (2.0.0)
concurrent-ruby (~> 0.8)
hashie (3.4.3)
i18n (0.7.0)
json (1.8.3)
kramdown (1.9.0)
listen (3.0.5)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
middleman (4.0.0)
coffee-script (~> 2.2)
compass-import-once (= 1.0.5)
haml (>= 4.0.5)
kramdown (~> 1.2)
middleman-cli (= 4.0.0)
middleman-core (= 4.0.0)
sass (>= 3.4.0, < 4.0)
middleman-autoprefixer (2.7.0)
autoprefixer-rails (>= 6.3.1, < 7.0.0)
middleman-core (>= 3.3.3)
middleman-cli (4.0.0)
thor (>= 0.17.0, < 2.0)
middleman-core (4.0.0)
activesupport (~> 4.2)
addressable (~> 2.4.0)
backports (~> 3.6)
bundler (~> 1.1)
capybara (~> 2.5.0)
contracts (~> 0.12.0)
erubis
execjs (~> 2.0)
fastimage (~> 1.8)
hamster (~> 2.0)
hashie (~> 3.4)
i18n (~> 0.7.0)
listen (~> 3.0)
padrino-helpers (~> 0.13.0)
rack (>= 1.4.5, < 2.0)
sass (>= 3.4)
tilt (~> 1.4.1)
uglifier (~> 2.6)
middleman-gh-pages (0.0.3)
rake (> 0.9.3)
middleman-sprockets (4.0.0.rc.1)
middleman-core (>= 4.0.0.rc.1)
sprockets (~> 3.0)
middleman-syntax (2.1.0)
middleman-core (>= 3.2)
rouge (~> 1.0)
mime-types (3.0)
mime-types-data (~> 3.2015)
mime-types-data (3.2015.1120)
mini_portile2 (2.0.0)
minitest (5.8.4)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
padrino-helpers (0.13.1)
i18n (~> 0.6, >= 0.6.7)
padrino-support (= 0.13.1)
tilt (~> 1.4.1)
padrino-support (0.13.1)
activesupport (>= 3.1)
rack (1.6.4)
rack-test (0.6.3)
rack (>= 1.0)
rake (10.4.2)
rb-fsevent (0.9.7)
rb-inotify (0.9.5)
ffi (>= 0.5.0)
redcarpet (3.3.4)
rouge (1.10.1)
sass (3.4.21)
sprockets (3.4.1)
rack (> 1, < 3)
thor (0.19.1)
thread_safe (0.3.5)
tilt (1.4.1)
tzinfo (1.2.2)
thread_safe (~> 0.1)
uglifier (2.7.2)
execjs (>= 0.3.0)
json (>= 1.8.0)
xpath (2.0.0)
nokogiri (~> 1.3)
PLATFORMS
ruby
DEPENDENCIES
middleman (~> 4.0.0)
middleman-autoprefixer (~> 2.7.0)
middleman-gh-pages (~> 0.0.3)
middleman-sprockets (~> 4.0.0.rc)
middleman-syntax (~> 2.1.0)
redcarpet (~> 3.3.2)
rouge (~> 1.10.1)
BUNDLED WITH
1.10.6
+200 -10
View File
@@ -1,13 +1,203 @@
Copyright 2008-2013 Concur Technologies, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain
a copy of the License at
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
http://www.apache.org/licenses/LICENSE-2.0
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
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.
+2
View File
@@ -0,0 +1,2 @@
This product includes Google Flatbuffers (https://google.github.io/flatbuffers/)
Copyright 2014 Google Inc. All rights reserved.
+5 -103
View File
@@ -1,106 +1,8 @@
<p align="center">
<img src="https://raw.githubusercontent.com/lord/img/master/logo-slate.png" alt="Slate: API Documentation Generator" width="226">
<br>
<a href="https://travis-ci.org/lord/slate"><img src="https://travis-ci.org/lord/slate.svg?branch=master" alt="Build Status"></a>
</p>
![Timely](timely-readme-logo.png)
<p align="center">Slate helps you create beautiful, intelligent, responsive API documentation.</p>
[![Apache License][li]][ll]
<p align="center"><img src="https://dl.dropboxusercontent.com/u/95847291/github%20images/slate/slate_screenshot_new.png" width=700 alt="Screenshot of Example Documentation created with Slate"></p>
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/).
<p align="center"><em>The example above was created with Slate. Check it out at <a href="https://lord.github.io/slate">lord.github.io/slate</a>.</em></p>
Features
------------
* **Clean, intuitive design** — With Slate, the description of your API is on the left side of your documentation, and all the code examples are on the right side. Inspired by [Stripe's](https://stripe.com/docs/api) and [Paypal's](https://developer.paypal.com/webapps/developer/docs/api/) API docs. Slate is responsive, so it looks great on tablets, phones, and even in print.
* **Everything on a single page** — Gone are the days when your users had to search through a million pages to find what they wanted. Slate puts the entire documentation on a single page. We haven't sacrificed linkability, though. As you scroll, your browser's hash will update to the nearest header, so linking to a particular point in the documentation is still natural and easy.
* **Slate is just Markdown** — When you write docs with Slate, you're just writing Markdown, which makes it simple to edit and understand. Everything is written in Markdown — even the code samples are just Markdown code blocks.
* **Write code samples in multiple languages** — If your API has bindings in multiple programming languages, you can easily put in tabs to switch between them. In your document, you'll distinguish different languages by specifying the language name at the top of each code block, just like with Github Flavored Markdown.
* **Out-of-the-box syntax highlighting** for [almost 100 languages](http://rouge.jneen.net/), no configuration required.
* **Automatic, smoothly scrolling table of contents** on the far left of the page. As you scroll, it displays your current position in the document. It's fast, too. We're using Slate at TripIt to build documentation for our new API, where our table of contents has over 180 entries. We've made sure that the performance remains excellent, even for larger documents.
* **Let your users update your documentation for you** — By default, your Slate-generated documentation is hosted in a public Github repository. Not only does this mean you get free hosting for your docs with Github Pages, but it also makes it simple for other developers to make pull requests to your docs if they find typos or other problems. Of course, if you don't want to use GitHub, you're also welcome to host your docs elsewhere.
Getting started with Slate is super easy! Simply fork this repository and follow the instructions below. Or, if you'd like to check out what Slate is capable of, take a look at the [sample docs](http://lord.github.io/slate).
Getting Started with Slate
------------------------------
### Prerequisites
You're going to need:
- **Linux or OS X** — Windows may work, but is unsupported.
- **Ruby, version 2.0 or newer**
- **Bundler** — If Ruby is already installed, but the `bundle` command doesn't work, just run `gem install bundler` in a terminal.
### Getting Set Up
1. Fork this repository on Github.
2. Clone *your forked repository* (not our original one) to your hard drive with `git clone https://github.com/YOURUSERNAME/slate.git`
3. `cd slate`
4. Initialize and start Slate. You can either do this locally, or with Vagrant:
```shell
# either run this to run locally
bundle install
bundle exec middleman server
# OR run this to run with vagrant
vagrant up
```
You can now see the docs at http://localhost:4567. Whoa! That was fast!
Now that Slate is all set up your machine, you'll probably want to learn more about [editing Slate markdown](https://github.com/lord/slate/wiki/Markdown-Syntax), or [how to publish your docs](https://github.com/lord/slate/wiki/Deploying-Slate).
If you'd prefer to use Docker, instructions are available [in the wiki](https://github.com/lord/slate/wiki/Docker).
Companies Using Slate
---------------------------------
* [NASA](https://api.nasa.gov)
* [IBM Cloudant](https://docs.cloudant.com/api.html)
* [Travis-CI](https://docs.travis-ci.com/api/)
* [Mozilla](http://mozilla.github.io/localForage/)
* [Appium](http://appium.io/slate/en/master)
* [Dwolla](https://docs.dwolla.com/)
* [Clearbit](https://clearbit.com/docs)
* [Coinbase](https://developers.coinbase.com/api)
* [Parrot Drones](http://developer.parrot.com/docs/bebop/)
* [Fidor Bank](http://docs.fidor.de/)
You can view more in [the list on the wiki](https://github.com/lord/slate/wiki/Slate-in-the-Wild).
Need Help? Found a bug?
--------------------
[Submit an issue](https://github.com/lord/slate/issues) to the Slate Github if you need any help. And, of course, feel free to submit pull requests with bug fixes or changes.
Contributors
--------------------
Slate was built by [Robert Lord](https://lord.io) while interning at [TripIt](https://www.tripit.com/).
Thanks to the following people who have submitted major pull requests:
- [@chrissrogers](https://github.com/chrissrogers)
- [@bootstraponline](https://github.com/bootstraponline)
- [@realityking](https://github.com/realityking)
- [@cvkef](https://github.com/cvkef)
Also, thanks to [Sauce Labs](http://saucelabs.com) for helping sponsor the project.
Special Thanks
--------------------
- [Middleman](https://github.com/middleman/middleman)
- [jquery.tocify.js](https://github.com/gfranko/jquery.tocify.js)
- [middleman-syntax](https://github.com/middleman/middleman-syntax)
- [middleman-gh-pages](https://github.com/edgecase/middleman-gh-pages)
- [Font Awesome](http://fortawesome.github.io/Font-Awesome/)
[li]: http://img.shields.io/badge/license-ASL-blue.svg
[ll]: https://www.apache.org/licenses/LICENSE-2.0
Vendored
-39
View File
@@ -1,39 +0,0 @@
Vagrant.configure(2) do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.network :forwarded_port, guest: 4567, host: 4567
config.vm.provision "bootstrap",
type: "shell",
inline: <<-SHELL
sudo apt-get update
sudo apt-get install -yq ruby2.0 ruby2.0-dev pkg-config build-essential nodejs git libxml2-dev libxslt-dev
sudo apt-get autoremove -yq
gem2.0 install --no-ri --no-rdoc bundler
SHELL
# add the local user git config to the vm
config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig"
config.vm.provision "install",
type: "shell",
privileged: false,
inline: <<-SHELL
echo "=============================================="
echo "Installing app dependencies"
cd /vagrant
bundle config build.nokogiri --use-system-libraries
bundle install
SHELL
config.vm.provision "run",
type: "shell",
privileged: false,
run: "always",
inline: <<-SHELL
echo "=============================================="
echo "Starting up middleman at http://localhost:4567"
echo "If it does not come up, check the ~/middleman.log file for any error messages"
cd /vagrant
bundle exec middleman server --force-polling -l 1 &> ~/middleman.log &
SHELL
end
+1
View File
@@ -0,0 +1 @@
/target/
+120
View File
@@ -0,0 +1,120 @@
<?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.3</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.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.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>
</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,182 @@
package timely.model;
import com.fasterxml.jackson.annotation.*;
import timely.model.parse.TagParser;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 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 {
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.Joiner;
import com.google.common.base.Preconditions;
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 Joiner equalJoiner = Joiner.on("=");
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 equalJoiner.join(key, value);
}
@Override
public String toString() {
return "Tag{" + equalJoiner.join(this.getKey(), this.getValue()) + "}";
}
@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;
return this.toString().equals(o.toString());
}
@Override
public int compareTo(Tag other) {
return this.toString().compareTo(other.toString());
}
}
@@ -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,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,23 @@
package timely.model.parse;
import com.google.common.base.Splitter;
import timely.model.Tag;
import java.util.ArrayList;
import java.util.List;
/**
* Parses tag1=val1,tag2=val2,tag3=val3 into a {@code List} of {@code Tag}
*/
public class TagListParser implements Parser<List<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;
}
}
@@ -0,0 +1,20 @@
package timely.model.parse;
import com.google.common.base.Splitter;
import timely.model.Tag;
import java.util.List;
public class TagParser implements Parser<Tag> {
private static final Splitter equalSplitter = Splitter.on("=").trimResults();
@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));
}
}
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
</FindBugsFilter>
@@ -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);
}
}
+65
View File
@@ -0,0 +1,65 @@
<?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>
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.3</version>
</parent>
<artifactId>collectd-nsq-plugin</artifactId>
<dependencies>
<dependency>
<groupId>collectd</groupId>
<artifactId>collectd-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>timely</groupId>
<artifactId>collectd-plugin-parent</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<artifactSet>
<includes>
</includes>
</artifactSet>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<id>shade</id>
<goals>
<goal>shade</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,149 @@
package timely.collectd.plugin;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Random;
import org.apache.http.HttpStatus;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.collectd.api.Collectd;
import org.collectd.api.CollectdConfigInterface;
import org.collectd.api.CollectdShutdownInterface;
import org.collectd.api.CollectdWriteInterface;
import org.collectd.api.OConfigItem;
import org.collectd.api.ValueList;
/**
*
* CollectD plugin that writes metrics collected by the StatsD plugin to NSQ.
* NSQ can be configured to write statsd metrics to CollectD. If you do this,
* set the statsd prefix in NSQ to 'nsq'.
*
*/
public class WriteNSQPlugin extends CollectDPluginParent implements CollectdConfigInterface, CollectdShutdownInterface,
CollectdWriteInterface {
private String host = null;
private int port = 0;
private String topic = "metrics#ephemeral";
private String endpoint = null;
private ByteArrayOutputStream baos = null;
private DataOutputStream out = null;
private CloseableHttpClient client = HttpClients.createDefault();
public WriteNSQPlugin() {
Collectd.registerConfig(WriteNSQPlugin.class.getName(), this);
Collectd.registerShutdown(WriteNSQPlugin.class.getName(), this);
Collectd.registerWrite(WriteNSQPlugin.class.getName(), this);
}
public synchronized int write(ValueList vl) {
baos = new ByteArrayOutputStream();
out = new DataOutputStream(baos);
super.process(vl);
try {
out.flush();
HttpPost post = new HttpPost(endpoint);
EntityBuilder request = EntityBuilder.create();
request.setBinary(baos.toByteArray());
post.setEntity(request.build());
CloseableHttpResponse response = client.execute(post);
try {
int code = response.getStatusLine().getStatusCode();
String msg = response.getStatusLine().getReasonPhrase();
// Consume the entire response so the connection will be reused
EntityUtils.consume(response.getEntity());
if (code != HttpStatus.SC_OK) {
Collectd.logInfo("Code: " + code + ", msg: " + msg);
}
} finally {
response.close();
}
} catch (IOException e) {
Collectd.logError("Error sending metrics to NSQ: " + e.getMessage());
} finally {
if (null != out) {
try {
out.close();
out = null;
} catch (IOException e) {
}
}
}
return 0;
}
@Override
public synchronized void write(String metric) {
try {
out.writeBytes(metric);
} catch (IOException e) {
Collectd.logError("Error writing metric: " + e.getMessage());
try {
out.close(); // Should cause IOException in write.
} catch (IOException e1) {
}
}
}
public void flush() {
}
public synchronized int shutdown() {
Collectd.logInfo("Shutting down connection to NSQ at " + host + ":" + port);
try {
client.close();
} catch (IOException e) {
Collectd.logError("Error closing HttpClient: " + e.getMessage());
}
return 0;
}
public synchronized int config(OConfigItem config) {
super.config(config);
for (OConfigItem child : config.getChildren()) {
switch (child.getKey()) {
case "host":
case "hostname":
case "Host":
case "HostName":
String hostString = child.getValues().get(0).getString();
String[] hosts = hostString.split(",");
if (hosts.length == 1) {
host = hosts[0];
} else {
host = hosts[new Random().nextInt(hosts.length)];
}
break;
case "Port":
case "port":
port = Integer.parseInt(child.getValues().get(0).getString());
break;
case "topic":
case "Topic":
topic = child.getValues().get(0).getString();
break;
default:
}
}
this.endpoint = "http://" + host + ":" + port + "/mpub?topic=" + topic;
if (null != host) {
return 0;
}
if (host == null) {
Collectd.logError("NSQ host must be configured");
}
if (port == 0) {
Collectd.logError("NSQ port must be configured");
}
return -1;
}
}
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
</FindBugsFilter>
+60
View File
@@ -0,0 +1,60 @@
<?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>
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.3</version>
</parent>
<artifactId>collectd-plugin-parent</artifactId>
<dependencies>
<dependency>
<groupId>collectd</groupId>
<artifactId>collectd-api</artifactId>
</dependency>
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-easymock-release-full</artifactId>
<classifier>full</classifier>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-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>
</plugins>
</build>
</project>
@@ -0,0 +1,251 @@
package timely.collectd.plugin;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.collectd.api.Collectd;
import org.collectd.api.DataSource;
import org.collectd.api.OConfigItem;
import org.collectd.api.ValueList;
public abstract class CollectDPluginParent {
private static final String PUT = "put {0} {1} {2}{3}\n";
private static final Pattern HADOOP_STATSD_PATTERN = Pattern
.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)");
private static final String INSTANCE = " instance=";
private static final String SAMPLE = " sample=";
private static final String CODE = " code=";
private static final String PERIOD = ".";
private static final String SAMPLE_TYPE = " sampleType=";
private static final String COUNTER = "COUNTER";
private static final String GAUGE = "GAUGE";
private static final String DERIVE = "DERIVE";
private static final String ABSOLUTE = "ABSOLUTE";
private static final Pattern NSQ_PATTERN1 = Pattern.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)");
private static final Pattern NSQ_PATTERN2 = Pattern.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)");
private static final Pattern NSQ_PATTERN3 = Pattern
.compile("([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_]+)\\.([\\w-_#]+)\\.([\\w-_]+)");
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 final SMARTCodeMapping smart = new SMARTCodeMapping();
protected Set<String> addlTags = new HashSet<>();
public int config(OConfigItem config) {
for (OConfigItem child : config.getChildren()) {
switch (child.getKey()) {
case "Tags":
case "tags":
String[] additionalTags = child.getValues().get(0).getString().split(",");
for (String t : additionalTags) {
addlTags.add(" " + t.trim());
}
default:
}
}
return 0;
}
public abstract void write(String metric);
public void process(ValueList vl) {
debugValueList(vl);
StringBuilder metric = new StringBuilder();
Long timestamp = vl.getTime();
StringBuilder tags = new StringBuilder();
String host = vl.getHost();
int idx = host.indexOf(PERIOD);
if (-1 != idx) {
tags.append(" host=").append(host.substring(0, idx));
} else {
tags.append(" host=").append(host);
}
int nIdx = host.indexOf('n');
if (-1 != nIdx) {
tags.append(" rack=").append(host.substring(0, nIdx));
}
for (String tag : addlTags) {
tags.append(tag);
}
if (vl.getPlugin().equals(STATSD_PREFIX)) {
Matcher m = HADOOP_STATSD_PATTERN.matcher(vl.getTypeInstance());
Matcher n1 = NSQ_PATTERN1.matcher(vl.getTypeInstance());
Matcher n2 = NSQ_PATTERN2.matcher(vl.getTypeInstance());
Matcher n3 = NSQ_PATTERN3.matcher(vl.getTypeInstance());
String instance = null;
if (m.matches() && !vl.getTypeInstance().startsWith("nsq")) {
// Here we are processing the statsd metrics coming from the
// Hadoop Metrics2 StatsDSink without the host name.
// The format of metric is:
// serviceName.contextName.recordName.metricName. The recordName
// is typically duplicative and is dropped here. The serviceName
// is used as the instance.
metric.append(STATSD_PREFIX).append(PERIOD).append(m.group(2)).append(PERIOD).append(m.group(4));
instance = m.group(1);
} else if (n1.matches() && vl.getTypeInstance().startsWith("nsq")) {
metric.append(NSQ_PREFIX).append(n1.group(2)).append(PERIOD).append(n1.group(3));
} else if (n2.matches() && vl.getTypeInstance().startsWith("nsq")) {
metric.append(NSQ_PREFIX).append(n2.group(2)).append(PERIOD).append(n2.group(4));
instance = n2.group(3);
} else if (n3.matches() && vl.getTypeInstance().startsWith("nsq")) {
metric.append(NSQ_PREFIX).append(n3.group(4)).append(PERIOD).append(n3.group(6));
instance = n3.group(5);
} else {
// Handle StatsD metrics of unknown formats. If there is a
// period in the metric name, use everything up to that as
// the instance.
int period = vl.getTypeInstance().indexOf('.');
if (-1 == period) {
metric.append(STATSD_PREFIX).append(PERIOD).append(vl.getTypeInstance());
} else {
instance = vl.getTypeInstance().substring(0, period);
metric.append(STATSD_PREFIX).append(PERIOD).append(vl.getTypeInstance().substring(period + 1));
}
}
timestamp = vl.getTime();
if (null != instance) {
tags.append(INSTANCE).append(instance);
}
} else if (vl.getPlugin().equals("ethstat")) {
metric.append("sys.ethstat.");
if (vl.getTypeInstance().contains("queue")) {
Matcher m = ETHSTAT_PATTERN.matcher(vl.getTypeInstance());
if (m.matches()) {
metric.append(m.group(1)).append("_").append(m.group(3));
tags.append(" queue=").append(m.group(2));
} else {
metric.append(vl.getTypeInstance());
}
} else {
metric.append(vl.getTypeInstance());
}
tags.append(INSTANCE).append(vl.getPluginInstance());
} else if (vl.getPlugin().equals("hddtemp")) {
metric.append("sys.hddtemp.").append(vl.getType());
tags.append(INSTANCE).append(vl.getTypeInstance());
} else if (vl.getPlugin().equals("smart")) {
int code = -1;
String name = null;
if (vl.getTypeInstance().startsWith("attribute-")) {
int hyphen = vl.getTypeInstance().indexOf('-');
code = Integer.parseInt(vl.getTypeInstance().substring(hyphen + 1));
name = smart.get(code);
}
if (code == -1) {
if (notEmpty(vl.getTypeInstance())) {
metric.append("sys.smart.").append(vl.getTypeInstance());
} else {
metric.append("sys.smart.").append(vl.getType());
}
} else {
metric.append("sys.smart.").append(name);
tags.append(CODE).append(code);
}
tags.append(INSTANCE).append(vl.getPluginInstance());
} else if (vl.getPlugin().equals("sensors")) {
String instance = "";
if (vl.getTypeInstance().startsWith("temp")) {
instance = vl.getTypeInstance().substring(4);
}
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());
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());
}
} else if (vl.getPlugin().equals("ipmi")) {
metric.append("sys.ipmi.").append(vl.getType());
tags.append(INSTANCE).append(vl.getTypeInstance().replaceAll(" ", "_"));
} else if (vl.getPlugin().equals("snmp")) {
metric.append("sys.snmp.").append(vl.getType());
tags.append(INSTANCE).append(vl.getTypeInstance().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());
} 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());
} else if (notEmpty(vl.getType()) && notEmpty(vl.getPlugin())) {
metric.append("sys.").append(vl.getPlugin()).append(PERIOD).append(vl.getType());
} else {
Collectd.logWarning("Unhandled metric: " + vl.toString());
return;
}
final String metricName = metric.toString().replaceAll(" ", "_");
for (int i = 0; i < vl.getValues().size(); i++) {
StringBuilder tagsWithSample = new StringBuilder(tags.toString());
String sampleName = vl.getDataSet().getDataSources().get(i).getName();
int type = vl.getDataSet().getDataSources().get(i).getType();
String sampleType = convertType(type);
if (null != sampleName) {
tagsWithSample.append(SAMPLE).append(sampleName);
}
if (null != sampleType) {
tagsWithSample.append(SAMPLE_TYPE).append(sampleType);
}
Double value = vl.getValues().get(i).doubleValue();
String datapoint = MessageFormat.format(PUT, metricName, timestamp.toString(), value.toString(),
tagsWithSample.toString());
Collectd.logDebug("Writing: " + datapoint);
write(datapoint);
}
}
private void debugValueList(ValueList vl) {
Collectd.logDebug("Input: " + vl.toString());
Collectd.logDebug("Plugin: " + vl.getPlugin());
Collectd.logDebug("PluginInstance: " + vl.getPluginInstance());
Collectd.logDebug("Type: " + vl.getType());
Collectd.logDebug("TypeInstance: " + vl.getTypeInstance());
for (int i = 0; i < vl.getValues().size(); i++) {
Number value = vl.getValues().get(i);
DataSource ds = vl.getDataSet().getDataSources().get(i);
Collectd.logDebug(convertType(ds.getType()) + " " + ds.getName() + " = " + value);
}
}
private String convertType(int type) {
String result = null;
switch (type) {
case 0:
result = COUNTER;
break;
case 1:
result = GAUGE;
break;
case 2:
result = DERIVE;
break;
case 3:
result = ABSOLUTE;
break;
default:
result = GAUGE;
break;
}
return result;
}
private boolean notEmpty(String arg) {
return (null != arg) && !(arg.equals(""));
}
}
@@ -0,0 +1,169 @@
package timely.collectd.plugin;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class SMARTCodeMapping extends HashMap<Integer, String> {
private static final long serialVersionUID = 1L;
private static final Map<Integer, String> smart;
static {
Map<Integer, String> map = new HashMap<>();
/**
* mapping from https://en.wikipedia.org/wiki/S.M.A.R.T.
*/
map.put(1, "Read_Error_Rate");
map.put(2, "Throughput_Performance");
map.put(3, "Spin_Up_Time");
map.put(4, "Start_Stop_Count");
map.put(5, "Reallocated_Sectors_Count");
map.put(6, "Read_Channel_Margin");
map.put(7, "Seek_Error_Rate");
map.put(8, "Seek_Time_Performance");
map.put(9, "Power_On_Hours");
map.put(10, "Spin_Retry_Count");
map.put(11, "Calibration_Retry_Count");
map.put(12, "Power_Cycle_Count");
map.put(13, "Soft_Read_Error_Rate");
map.put(22, "Current_Helium_Level");
map.put(170, "Available_Reserved_Space");
map.put(171, "SSD_Program_Fail_Count");
map.put(172, "SSD_Erase_Fail_Count");
map.put(173, "SSD_Wear_Leveling_Count");
map.put(174, "Unexpected_power_loss_count");
map.put(175, "Power_Loss_Protection_Failure");
map.put(176, "Erase_Fail_Count");
map.put(177, "Wear_Range_Delta");
map.put(179, "Used_Reserved_Block_Count_Total");
map.put(180, "Unused_Reserved_Block_Count_Total");
map.put(181, "Program_Fail_Count_Total");
map.put(182, "Erase_Fail_Count");
map.put(183, "SATA_Downshift_Error_Count");
map.put(184, "End_to_End_error");
map.put(185, "Head_Stability");
map.put(186, "Induced_Op_Vibration_Detection");
map.put(187, "Reported_Uncorrectable_Errors");
map.put(188, "Command_Timeout");
map.put(189, "High_Fly_Writes");
map.put(190, "Airflow_Temperature_Celsius");
map.put(190, "Temperature_Difference_from_100");
map.put(191, "G_sense_Error_Rate");
map.put(192, "Unsafe_Shutdown_Count");
map.put(193, "Load_Unload_Cycle_Count");
map.put(194, "Temperature_Celsius");
map.put(195, "Hardware_ECC_Recovered");
map.put(196, "Reallocation_Event_Count");
map.put(197, "Current_Pending_Sector_Count");
map.put(198, "Uncorrectable_Sector_Count");
map.put(199, "UltraDMA_CRC_Error_Count");
// map.put(200,"Multi_Zone_Error_Rate_[41]");
map.put(200, "Write_Error_Rate");
map.put(201, "Soft_Read_Error_Rate");
map.put(202, "Data_Address_Mark_errors");
map.put(203, "Run_Out_Cancel");
map.put(204, "Soft_ECC_Correction");
map.put(205, "Thermal_Asperity_Rate");
map.put(206, "Flying_Height");
map.put(207, "Spin_High_Current");
map.put(208, "Spin_Buzz");
map.put(209, "Offline_Seek_Performance");
map.put(210, "Vibration_During_Write");
map.put(211, "Vibration_During_Write");
map.put(212, "Shock_During_Write");
map.put(220, "Disk_Shift");
map.put(221, "G_Sense_Error_Rate");
map.put(222, "Loaded_Hours");
map.put(223, "Load_Unload_Retry_Count");
map.put(224, "Load_Friction");
map.put(225, "Load_Unload_Cycle_Count");
map.put(226, "Load_In_time");
map.put(227, "Torque_Amplification_Count");
map.put(228, "Power_Off_Retract_Cycle");
// map.put(230,"GMR_Head_Amplitude");
map.put(230, "Drive_Life_Protection_Status");
map.put(231, "Temperature");
// map.put(231,"SSD_Life_Left");
map.put(232, "Endurance_Remaining");
// map.put(232,"Available_Reserved_Space");
map.put(233, "Power_On_Hours");
// map.put(233,"Media_Wearout_Indicator");
map.put(234, "Average_erase_count");
map.put(235, "Good_Block_Count");
map.put(240, "Head_Flying_Hours");
// map.put(240,"Transfer_Error_Rate_(Fujitsu)");
map.put(241, "Total_LBAs_Written");
map.put(242, "Total_LBAs_Read");
map.put(243, "Total_LBAs_Written_Expanded");
map.put(244, "Total_LBAs_Read_Expanded");
map.put(249, "NAND_Writes_1GiB");
map.put(250, "Read_Error_Retry_Rate");
map.put(251, "Minimum_Spares_Remaining");
map.put(252, "Newly_Added_Bad_Flash_Block");
map.put(254, "Free_Fall_Protection");
smart = Collections.unmodifiableMap(map);
}
protected SMARTCodeMapping() {
}
public int size() {
return smart.size();
}
public boolean isEmpty() {
return smart.isEmpty();
}
public boolean containsKey(Object key) {
return smart.containsKey(key);
}
public boolean containsValue(Object value) {
return smart.containsValue(value);
}
public String get(Object key) {
return smart.get(key);
}
public String put(Integer key, String value) {
return smart.put(key, value);
}
public String remove(Object key) {
return smart.remove(key);
}
public void putAll(Map<? extends Integer, ? extends String> m) {
smart.putAll(m);
}
public void clear() {
smart.clear();
}
public Set<Integer> keySet() {
return smart.keySet();
}
public Collection<String> values() {
return smart.values();
}
public Set<java.util.Map.Entry<Integer, String>> entrySet() {
return smart.entrySet();
}
public boolean equals(Object o) {
return smart.equals(o);
}
public int hashCode() {
return smart.hashCode();
}
}
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
</FindBugsFilter>
@@ -0,0 +1,336 @@
package timely.collectd.plugin;
import static org.junit.Assert.*;
import java.util.Collections;
import net.jcip.annotations.NotThreadSafe;
import org.collectd.api.Collectd;
import org.collectd.api.DataSet;
import org.collectd.api.DataSource;
import org.collectd.api.ValueList;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Collectd.class })
@NotThreadSafe
public class PluginParentTest {
public class TestPlugin extends CollectDPluginParent {
public TestPlugin() {
super.addlTags.add(" addl1=foo");
}
@Override
public void write(String metric) {
result = metric;
}
}
private static final String HOST = "r01n01.test";
private static final Long TIME = 1456156976840L;
public String result = null;
@Before
public void setup() throws Exception {
PowerMock.suppress(PowerMock.everythingDeclaredIn(Collectd.class));
}
@Test
public void testStatsDHadoopFormat() throws Exception {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("statsd");
vl.setTime(TIME);
vl.setType("derive");
vl.setTypeInstance("DataNode.dfs.datanode.BlocksRead");
vl.setValues(Collections.singletonList((Number) 1.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put statsd.dfs.BlocksRead 1456156976840 1.0 host=r01n01 rack=r01 addl1=foo instance=DataNode sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testStatsDUnknownFormat() throws Exception {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("statsd");
vl.setTime(TIME);
vl.setType("derive");
vl.setTypeInstance("baz");
vl.setValues(Collections.singletonList((Number) 1.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals("put statsd.baz 1456156976840 1.0 host=r01n01 rack=r01 addl1=foo sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testStatsDUnknownFormat2() throws Exception {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("statsd");
vl.setTime(TIME);
vl.setType("derive");
vl.setTypeInstance("bar.baz");
vl.setValues(Collections.singletonList((Number) 1.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put statsd.baz 1456156976840 1.0 host=r01n01 rack=r01 addl1=foo instance=bar sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testHddTemp() throws Exception {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("hddtemp");
vl.setTime(TIME);
vl.setType("temperature");
vl.setTypeInstance("sda");
vl.setValues(Collections.singletonList((Number) 35.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put sys.hddtemp.temperature 1456156976840 35.0 host=r01n01 rack=r01 addl1=foo instance=sda sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testSmart1() throws Exception {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("smart");
vl.setPluginInstance("sda");
vl.setTime(TIME);
vl.setType("smart_badsectors");
vl.setValues(Collections.singletonList((Number) 0.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put sys.smart.smart_badsectors 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo instance=sda sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testSmart2() throws Exception {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("smart");
vl.setPluginInstance("sda");
vl.setTime(TIME);
vl.setType("smart_attribute");
vl.setTypeInstance("raw-read-error-rate");
vl.setValues(Collections.singletonList((Number) 0.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put sys.smart.raw-read-error-rate 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo instance=sda sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testSmartCode() throws Exception {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("smart");
vl.setPluginInstance("sda");
vl.setTime(TIME);
vl.setType("smart_attribute");
vl.setTypeInstance("attribute-242");
vl.setValues(Collections.singletonList((Number) 0.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put sys.smart.Total_LBAs_Read 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo code=242 instance=sda sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testSnmp() throws Exception {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("snmp");
// vl.setPluginInstance("sda");
vl.setTime(TIME);
vl.setType("if_octets");
vl.setTypeInstance("Ethernet1");
vl.setValues(Collections.singletonList((Number) 0.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put sys.snmp.if_octets 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo instance=Ethernet1 sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testSensors() {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("sensors");
vl.setPluginInstance("coretemp-isa-0000");
vl.setTime(TIME);
vl.setType("temperature");
vl.setTypeInstance("temp1");
vl.setValues(Collections.singletonList((Number) 35.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put sys.sensors.temperature.coretemp-isa-0000 1456156976840 35.0 host=r01n01 rack=r01 addl1=foo instance=1 sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testHAProxy1() {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("haproxy");
vl.setTime(TIME);
vl.setType("gauge");
vl.setTypeInstance("run_queue");
vl.setValues(Collections.singletonList((Number) 0.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put sys.haproxy.run_queue 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testHAProxy2() {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("haproxy");
vl.setTime(TIME);
vl.setType("gauge");
vl.setTypeInstance("server1.proxy1.queue_current");
vl.setValues(Collections.singletonList((Number) 0.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put sys.haproxy.queue_current 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo proxy=proxy1 server=server1 sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testEthStatNoQueue() {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("ethstat");
vl.setPluginInstance("eth0");
vl.setTime(TIME);
vl.setType("derive");
vl.setTypeInstance("tx_comp_queue_full");
vl.setValues(Collections.singletonList((Number) 6.0D));
DataSet ds = new DataSet("DERIVE");
ds.addDataSource(new DataSource("value", 1, 6.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put sys.ethstat.tx_comp_queue_full 1456156976840 6.0 host=r01n01 rack=r01 addl1=foo instance=eth0 sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testEthStatWithQueue() {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("ethstat");
vl.setPluginInstance("eth0");
vl.setTime(TIME);
vl.setType("derive");
vl.setTypeInstance("rx_queue_1_bytes");
vl.setValues(Collections.singletonList((Number) 6.0D));
DataSet ds = new DataSet("DERIVE");
ds.addDataSource(new DataSource("value", 1, 6.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put sys.ethstat.rx_bytes 1456156976840 6.0 host=r01n01 rack=r01 addl1=foo queue=1 instance=eth0 sample=value sampleType=GAUGE\n",
result);
}
@Test
public void testIpmi() {
ValueList vl = new ValueList();
vl.setHost(HOST);
vl.setPlugin("ipmi");
vl.setTime(TIME);
vl.setType("temperature");
vl.setTypeInstance("LAN NIC Temp system_board (3.2)");
vl.setValues(Collections.singletonList((Number) 6.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 6.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl);
assertEquals(
"put sys.ipmi.temperature 1456156976840 6.0 host=r01n01 rack=r01 addl1=foo instance=LAN_NIC_Temp_system_board_(3.2) sample=value sampleType=GAUGE\n",
result);
}
}
+90
View File
@@ -0,0 +1,90 @@
<?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>
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.3</version>
</parent>
<artifactId>collectd-timely-plugin</artifactId>
<dependencies>
<dependency>
<groupId>collectd</groupId>
<artifactId>collectd-api</artifactId>
</dependency>
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-easymock-release-full</artifactId>
<classifier>full</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>timely</groupId>
<artifactId>collectd-plugin-parent</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<configuration>
<artifactSet>
<includes>
</includes>
</artifactSet>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<id>shade</id>
<goals>
<goal>shade</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-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>
</plugins>
</build>
</project>
@@ -0,0 +1,129 @@
package timely.collectd.plugin;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import org.collectd.api.Collectd;
import org.collectd.api.CollectdConfigInterface;
import org.collectd.api.CollectdShutdownInterface;
import org.collectd.api.CollectdWriteInterface;
import org.collectd.api.OConfigItem;
import org.collectd.api.ValueList;
/**
*
* CollectD plugin that writes metrics collected by the StatsD plugin to Timely.
*
*/
public class WriteTimelyPlugin extends CollectDPluginParent implements CollectdConfigInterface,
CollectdShutdownInterface, CollectdWriteInterface {
private String host = null;
private int port = 0;
private Socket sock = null;
private PrintWriter out = null;
private long connectTime = 0L;
private long backoff = 2000;
public WriteTimelyPlugin() {
Collectd.registerConfig(WriteTimelyPlugin.class.getName(), this);
Collectd.registerShutdown(WriteTimelyPlugin.class.getName(), this);
Collectd.registerWrite(WriteTimelyPlugin.class.getName(), this);
}
private synchronized int connect() {
if (null == sock || !sock.isConnected() || out.checkError()) {
if (System.currentTimeMillis() > (connectTime + backoff)) {
try {
connectTime = System.currentTimeMillis();
sock = new Socket(host, port);
out = new PrintWriter(sock.getOutputStream(), false);
backoff = 2000;
Collectd.logInfo("Connected to Timely at " + host + ":" + port);
} catch (IOException e) {
Collectd.logError("Error connecting to Timely at " + host + ":" + port + ". Error: "
+ e.getMessage());
backoff = backoff * 2;
sock = null;
out = null;
Collectd.logWarning("Will retry connection in " + backoff + " ms.");
return -1;
}
} else {
Collectd.logWarning("Not writing to Timely, waiting to reconnect");
return -1;
}
}
return 0;
}
public synchronized int write(ValueList vl) {
int c = connect();
if (c != 0) {
return c;
}
super.process(vl);
return 0;
}
@Override
public synchronized void write(String metric) {
out.write(metric);
}
public synchronized void flush() {
if (null != out) {
out.flush();
}
}
public synchronized int shutdown() {
Collectd.logInfo("Shutting down connection to Timely at " + host + ":" + port);
if (null != sock) {
try {
if (null != out) {
out.close();
}
sock.close();
} catch (IOException e) {
Collectd.logError("Error closing connection to Timely at " + host + ":" + port + ". Error: "
+ e.getMessage());
return -1;
}
}
return 0;
}
public synchronized int config(OConfigItem config) {
super.config(config);
for (OConfigItem child : config.getChildren()) {
switch (child.getKey()) {
case "host":
case "hostname":
case "Host":
case "HostName":
host = child.getValues().get(0).getString();
break;
case "Port":
case "port":
port = Integer.parseInt(child.getValues().get(0).getString());
break;
default:
}
}
if (null != host) {
return 0;
}
if (host == null) {
Collectd.logError("Timely host must be configured");
}
if (port == 0) {
Collectd.logError("Timely port must be configured");
}
return -1;
}
}
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
<Or>
<Bug pattern="DM_DEFAULT_ENCODING"/>
<Method name="connect" />
<Class name="timely.collectd.plugin.WriteTimelyPlugin"/>
</Or>
</FindBugsFilter>
@@ -0,0 +1,202 @@
package timely.collectd.plugin;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import net.jcip.annotations.NotThreadSafe;
import org.collectd.api.Collectd;
import org.collectd.api.DataSet;
import org.collectd.api.DataSource;
import org.collectd.api.OConfigItem;
import org.collectd.api.ValueList;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Collectd.class })
@NotThreadSafe
public class WriteTimelyPluginTest {
private WriteTimelyPlugin plugin = null;
private FakeServer server = null;
@Before
public void setup() throws Exception {
PowerMock.suppress(PowerMock.everythingDeclaredIn(Collectd.class));
server = new FakeServer();
}
private ValueList createMetric() {
ValueList val = new ValueList();
val.setHost("r001n01.localdomain");
val.setTime(System.currentTimeMillis());
val.setPlugin("hddtemp");
val.setPluginInstance(null);
val.setType("temperature");
val.setTypeInstance("sda");
val.setValues(Collections.singletonList((Number) new Double(2.0)));
DataSet ds = new DataSet("test");
ds.addDataSource(new DataSource("test", DataSource.TYPE_COUNTER, 0, 100));
val.setDataSet(ds);
return val;
}
private void setupPlugin() throws Exception {
OConfigItem host = new OConfigItem("Host");
host.addValue(server.getHost());
OConfigItem port = new OConfigItem("Port");
port.addValue(Integer.toString(server.getPort()));
OConfigItem config = new OConfigItem("");
config.addChild(host);
config.addChild(port);
plugin = new WriteTimelyPlugin();
Assert.assertEquals(0, plugin.config(config));
// Seed with one metric to create the connection
Assert.assertEquals(0, plugin.write(createMetric()));
plugin.flush();
Thread.sleep(100);
Assert.assertTrue(server.messageReceived());
}
@Test
public void testWrite() throws Exception {
Thread t = new Thread(server);
t.start();
setupPlugin();
while (!server.ready()) {
Thread.sleep(1000);
}
Assert.assertEquals(0, plugin.write(createMetric()));
plugin.flush();
Thread.sleep(100);
Assert.assertTrue(server.messageReceived());
plugin.shutdown();
server.shutdown();
t.join();
}
@Test
public void testWriteAfterServerRestart() throws Exception {
Thread t = new Thread(server);
t.start();
setupPlugin();
while (!server.ready()) {
Thread.sleep(1000);
}
Assert.assertEquals(0, plugin.write(createMetric()));
plugin.flush();
Thread.sleep(100);
Assert.assertTrue(server.messageReceived());
server.shutdown();
t.join();
Thread.sleep(2000);
server.create();
Thread t2 = new Thread(server);
t2.start();
while (!server.ready()) {
Thread.sleep(1000);
// Keep sending metrics to plugin to force reconnect
int result = plugin.write(createMetric());
System.out.println("Wrote to client, result: " + result);
Assert.assertEquals(0, result);
plugin.flush();
}
Assert.assertEquals(0, plugin.write(createMetric()));
plugin.flush();
Thread.sleep(1000);
Assert.assertTrue(server.messageReceived());
plugin.shutdown();
server.shutdown();
t2.join();
}
private static class FakeServer implements Runnable {
private ServerSocket server = null;
private BufferedReader reader = null;
private String host = null;
private int port = 0;
private Socket s = null;
private boolean received = false;
public FakeServer() throws Exception {
create();
}
public void create() throws Exception {
server = new ServerSocket(port);
server.setReceiveBufferSize(8192);
host = server.getInetAddress().getHostAddress();
port = server.getLocalPort();
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public void shutdown() throws Exception {
System.out.println("Closing server.");
s.close();
s = null;
reader.close();
reader = null;
server.close();
server = null;
}
public boolean ready() throws Exception {
return (s != null && s.isConnected());
}
public boolean messageReceived() {
try {
return Boolean.valueOf(this.received);
} finally {
this.received = false;
}
}
@Override
public void run() {
try {
s = server.accept();
System.out.println("Client connected.");
reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
while (server != null && !server.isClosed() && s != null && s.isConnected()) {
String line;
try {
line = reader.readLine();
} catch (Exception e) {
// Might have been closed
System.out.println("Closed by Exception: " + e.getMessage());
return;
}
if (null != line) {
this.received = true;
}
System.out.println(line);
}
} catch (IOException e) {
Assert.fail(e.getMessage());
}
System.out.println("Exiting run method.");
}
}
}
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="CONSOLE" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="TRACE">
<AppenderRef ref="CONSOLE"/>
</Root>
</Loggers>
</Configuration>
+16
View File
@@ -0,0 +1,16 @@
<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.3</version>
</parent>
<artifactId>timely-common</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,4 @@
package timely.test;
public interface IntegrationTest {
}
-44
View File
@@ -1,44 +0,0 @@
# Markdown
set :markdown_engine, :redcarpet
set :markdown,
fenced_code_blocks: true,
smartypants: true,
disable_indented_code_blocks: true,
prettify: true,
tables: true,
with_toc_data: true,
no_intra_emphasis: true
# Assets
set :css_dir, 'stylesheets'
set :js_dir, 'javascripts'
set :images_dir, 'images'
set :fonts_dir, 'fonts'
# Activate the syntax highlighter
activate :syntax
activate :autoprefixer do |config|
config.browsers = ['last 2 version', 'Firefox ESR']
config.cascade = false
config.inline = true
end
# Github pages require relative links
activate :relative_assets
set :relative_links, true
# Build Configuration
configure :build do
# If you're having trouble with Middleman hanging, commenting
# out the following two lines has been known to help
activate :minify_css
activate :minify_javascript
# activate :relative_assets
# activate :asset_hash
# activate :gzip
end
# Deploy Configuration
# If you want Middleman to listen on a different port, you can set that below
set :port, 4567
-222
View File
@@ -1,222 +0,0 @@
#!/usr/bin/env bash
set -o errexit #abort if any command fails
me=$(basename "$0")
help_message="\
Usage: $me [-c FILE] [<options>]
Deploy generated files to a git branch.
Options:
-h, --help Show this help information.
-v, --verbose Increase verbosity. Useful for debugging.
-e, --allow-empty Allow deployment of an empty directory.
-m, --message MESSAGE Specify the message used when committing on the
deploy branch.
-n, --no-hash Don't append the source commit's hash to the deploy
commit's message.
-c, --config-file PATH Override default & environment variables' values
with those in set in the file at 'PATH'. Must be the
first option specified.
Variables:
GIT_DEPLOY_DIR Folder path containing the files to deploy.
GIT_DEPLOY_BRANCH Commit deployable files to this branch.
GIT_DEPLOY_REPO Push the deploy branch to this repository.
These variables have default values defined in the script. The defaults can be
overridden by environment variables. Any environment variables are overridden
by values set in a '.env' file (if it exists), and in turn by those set in a
file specified by the '--config-file' option."
bundle exec middleman build --clean
parse_args() {
# Set args from a local environment file.
if [ -e ".env" ]; then
source .env
fi
# Set args from file specified on the command-line.
if [[ $1 = "-c" || $1 = "--config-file" ]]; then
source "$2"
shift 2
fi
# Parse arg flags
# If something is exposed as an environment variable, set/overwrite it
# here. Otherwise, set/overwrite the internal variable instead.
while : ; do
if [[ $1 = "-h" || $1 = "--help" ]]; then
echo "$help_message"
return 0
elif [[ $1 = "-v" || $1 = "--verbose" ]]; then
verbose=true
shift
elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then
allow_empty=true
shift
elif [[ ( $1 = "-m" || $1 = "--message" ) && -n $2 ]]; then
commit_message=$2
shift 2
elif [[ $1 = "-n" || $1 = "--no-hash" ]]; then
GIT_DEPLOY_APPEND_HASH=false
shift
else
break
fi
done
# Set internal option vars from the environment and arg flags. All internal
# vars should be declared here, with sane defaults if applicable.
# Source directory & target branch.
deploy_directory=build
deploy_branch=gh-pages
#if no user identity is already set in the current git environment, use this:
default_username=${GIT_DEPLOY_USERNAME:-deploy.sh}
default_email=${GIT_DEPLOY_EMAIL:-}
#repository to deploy to. must be readable and writable.
repo=origin
#append commit hash to the end of message by default
append_hash=${GIT_DEPLOY_APPEND_HASH:-true}
}
main() {
parse_args "$@"
enable_expanded_output
if ! git diff --exit-code --quiet --cached; then
echo Aborting due to uncommitted changes in the index >&2
return 1
fi
commit_title=`git log -n 1 --format="%s" HEAD`
commit_hash=` git log -n 1 --format="%H" HEAD`
#default commit message uses last title if a custom one is not supplied
if [[ -z $commit_message ]]; then
commit_message="publish: $commit_title"
fi
#append hash to commit message unless no hash flag was found
if [ $append_hash = true ]; then
commit_message="$commit_message"$'\n\n'"generated from commit $commit_hash"
fi
previous_branch=`git rev-parse --abbrev-ref HEAD`
if [ ! -d "$deploy_directory" ]; then
echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2
return 1
fi
# must use short form of flag in ls for compatibility with OS X and BSD
if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then
echo "Deploy directory '$deploy_directory' is empty. Aborting. If you're sure you want to deploy an empty tree, use the --allow-empty / -e flag." >&2
return 1
fi
if git ls-remote --exit-code $repo "refs/heads/$deploy_branch" ; then
# deploy_branch exists in $repo; make sure we have the latest version
disable_expanded_output
git fetch --force $repo $deploy_branch:$deploy_branch
enable_expanded_output
fi
# check if deploy_branch exists locally
if git show-ref --verify --quiet "refs/heads/$deploy_branch"
then incremental_deploy
else initial_deploy
fi
restore_head
}
initial_deploy() {
git --work-tree "$deploy_directory" checkout --orphan $deploy_branch
git --work-tree "$deploy_directory" add --all
commit+push
}
incremental_deploy() {
#make deploy_branch the current branch
git symbolic-ref HEAD refs/heads/$deploy_branch
#put the previously committed contents of deploy_branch into the index
git --work-tree "$deploy_directory" reset --mixed --quiet
git --work-tree "$deploy_directory" add --all
set +o errexit
diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD --)$?
set -o errexit
case $diff in
0) echo No changes to files in $deploy_directory. Skipping commit.;;
1) commit+push;;
*)
echo git diff exited with code $diff. Aborting. Staying on branch $deploy_branch so you can debug. To switch back to master, use: git symbolic-ref HEAD refs/heads/master && git reset --mixed >&2
return $diff
;;
esac
}
commit+push() {
set_user_id
git --work-tree "$deploy_directory" commit -m "$commit_message"
disable_expanded_output
#--quiet is important here to avoid outputting the repo URL, which may contain a secret token
git push --quiet $repo $deploy_branch
enable_expanded_output
}
#echo expanded commands as they are executed (for debugging)
enable_expanded_output() {
if [ $verbose ]; then
set -o xtrace
set +o verbose
fi
}
#this is used to avoid outputting the repo URL, which may contain a secret token
disable_expanded_output() {
if [ $verbose ]; then
set +o xtrace
set -o verbose
fi
}
set_user_id() {
if [[ -z `git config user.name` ]]; then
git config user.name "$default_username"
fi
if [[ -z `git config user.email` ]]; then
git config user.email "$default_email"
fi
}
restore_head() {
if [[ $previous_branch = "HEAD" ]]; then
#we weren't on any branch before, so just set HEAD back to the commit it was on
git update-ref --no-deref HEAD $commit_hash $deploy_branch
else
git symbolic-ref HEAD refs/heads/$previous_branch
fi
git reset --mixed
}
filter() {
sed -e "s|$repo|\$repo|g"
}
sanitize() {
"$@" 2> >(filter 1>&2) | filter
}
[[ $1 = --source-only ]] || main "$@"
+295
View File
@@ -0,0 +1,295 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="12">
<profile kind="CodeFormatterProfile" name="Timely" version="12">
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.compiler.source" value="1.8"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.compiler.problem.assertIdentifier" value="error"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.compiler.problem.enumIdentifier" value="error"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.compiler.compliance" value="1.8"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode" value="enabled"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_binary_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.compiler.codegen.targetPlatform" value="1.8"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
</profile>
</profiles>
-148
View File
@@ -1,148 +0,0 @@
{
"IcoMoonType": "selection",
"icons": [
{
"icon": {
"paths": [
"M438.857 73.143q119.429 0 220.286 58.857t159.714 159.714 58.857 220.286-58.857 220.286-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857zM512 785.714v-108.571q0-8-5.143-13.429t-12.571-5.429h-109.714q-7.429 0-13.143 5.714t-5.714 13.143v108.571q0 7.429 5.714 13.143t13.143 5.714h109.714q7.429 0 12.571-5.429t5.143-13.429zM510.857 589.143l10.286-354.857q0-6.857-5.714-10.286-5.714-4.571-13.714-4.571h-125.714q-8 0-13.714 4.571-5.714 3.429-5.714 10.286l9.714 354.857q0 5.714 5.714 10t13.714 4.286h105.714q8 0 13.429-4.286t6-10z"
],
"attrs": [],
"isMulticolor": false,
"tags": [
"exclamation-circle"
],
"defaultCode": 61546,
"grid": 14
},
"attrs": [],
"properties": {
"id": 100,
"order": 4,
"prevSize": 28,
"code": 58880,
"name": "exclamation-sign",
"ligatures": ""
},
"setIdx": 0,
"iconIdx": 0
},
{
"icon": {
"paths": [
"M585.143 786.286v-91.429q0-8-5.143-13.143t-13.143-5.143h-54.857v-292.571q0-8-5.143-13.143t-13.143-5.143h-182.857q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h54.857v182.857h-54.857q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h256q8 0 13.143-5.143t5.143-13.143zM512 274.286v-91.429q0-8-5.143-13.143t-13.143-5.143h-109.714q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h109.714q8 0 13.143-5.143t5.143-13.143zM877.714 512q0 119.429-58.857 220.286t-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857 220.286 58.857 159.714 159.714 58.857 220.286z"
],
"attrs": [],
"isMulticolor": false,
"tags": [
"info-circle"
],
"defaultCode": 61530,
"grid": 14
},
"attrs": [],
"properties": {
"id": 85,
"order": 3,
"name": "info-sign",
"prevSize": 28,
"code": 58882
},
"setIdx": 0,
"iconIdx": 2
},
{
"icon": {
"paths": [
"M733.714 419.429q0-16-10.286-26.286l-52-51.429q-10.857-10.857-25.714-10.857t-25.714 10.857l-233.143 232.571-129.143-129.143q-10.857-10.857-25.714-10.857t-25.714 10.857l-52 51.429q-10.286 10.286-10.286 26.286 0 15.429 10.286 25.714l206.857 206.857q10.857 10.857 25.714 10.857 15.429 0 26.286-10.857l310.286-310.286q10.286-10.286 10.286-25.714zM877.714 512q0 119.429-58.857 220.286t-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857 220.286 58.857 159.714 159.714 58.857 220.286z"
],
"attrs": [],
"isMulticolor": false,
"tags": [
"check-circle"
],
"defaultCode": 61528,
"grid": 14
},
"attrs": [],
"properties": {
"id": 83,
"order": 9,
"prevSize": 28,
"code": 58886,
"name": "ok-sign"
},
"setIdx": 0,
"iconIdx": 6
},
{
"icon": {
"paths": [
"M658.286 475.429q0-105.714-75.143-180.857t-180.857-75.143-180.857 75.143-75.143 180.857 75.143 180.857 180.857 75.143 180.857-75.143 75.143-180.857zM950.857 950.857q0 29.714-21.714 51.429t-51.429 21.714q-30.857 0-51.429-21.714l-196-195.429q-102.286 70.857-228 70.857-81.714 0-156.286-31.714t-128.571-85.714-85.714-128.571-31.714-156.286 31.714-156.286 85.714-128.571 128.571-85.714 156.286-31.714 156.286 31.714 128.571 85.714 85.714 128.571 31.714 156.286q0 125.714-70.857 228l196 196q21.143 21.143 21.143 51.429z"
],
"width": 951,
"attrs": [],
"isMulticolor": false,
"tags": [
"search"
],
"defaultCode": 61442,
"grid": 14
},
"attrs": [],
"properties": {
"id": 2,
"order": 1,
"prevSize": 28,
"code": 58887,
"name": "icon-search"
},
"setIdx": 0,
"iconIdx": 7
}
],
"height": 1024,
"metadata": {
"name": "slate",
"license": "SIL OFL 1.1"
},
"preferences": {
"showGlyphs": true,
"showQuickUse": true,
"showQuickUse2": true,
"showSVGs": true,
"fontPref": {
"prefix": "icon-",
"metadata": {
"fontFamily": "slate",
"majorVersion": 1,
"minorVersion": 0,
"description": "Based on FontAwesome",
"license": "SIL OFL 1.1"
},
"metrics": {
"emSize": 1024,
"baseline": 6.25,
"whitespace": 50
},
"resetPoint": 58880,
"showSelector": false,
"selector": "class",
"classSelector": ".icon",
"showMetrics": false,
"showMetadata": true,
"showVersion": true,
"ie7": false
},
"imagePref": {
"prefix": "icon-",
"png": true,
"useClassSelector": true,
"color": 4473924,
"bgColor": 16777215
},
"historySize": 100,
"showCodes": true,
"gridSize": 16,
"showLiga": false
}
}
+15
View File
@@ -0,0 +1,15 @@
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>dist</id>
<formats>
<format>tar.gz</format>
</formats>
<fileSets>
<fileSet>
<directory>timely-app</directory>
<outputDirectory>timely-app</outputDirectory>
</fileSet>
</fileSets>
<includeBaseDirectory>false</includeBaseDirectory>
</assembly>
+32
View File
@@ -0,0 +1,32 @@
<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-app</artifactId>
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.3</version>
</parent>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemble</id>
<goals>
<goal>single</goal>
</goals>
<phase>package</phase>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
<tarLongFileMode>posix</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
+2
View File
@@ -0,0 +1,2 @@
node_modules/
+65
View File
@@ -0,0 +1,65 @@
module.exports = function(grunt) {
require('load-grunt-tasks')(grunt);
grunt.loadNpmTasks('grunt-execute');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.initConfig({
clean: ["dist"],
copy: {
src_to_dist: {
cwd: 'src',
expand: true,
src: ['**/*', '!**/*.js', '!**/*.scss'],
dest: 'dist'
},
img_to_dist: {
cwd: 'src',
expand: true,
src: ['img/*'],
dest: 'dist/src/'
},
pluginDef: {
expand: true,
src: ['plugin.json', 'README.md'],
dest: 'dist',
}
},
watch: {
rebuild_all: {
files: ['src/**/*', 'plugin.json', 'README.md'],
tasks: ['default'],
options: {spawn: false}
},
},
babel: {
options: {
sourceMap: true,
presets: ["es2015"],
plugins: ['transform-es2015-modules-systemjs', "transform-es2015-for-of"],
},
dist: {
files: [{
cwd: 'src',
expand: true,
src: ['**/*.js'],
dest: 'dist',
ext:'.js'
}]
},
}
});
grunt.registerTask('default',
['clean',
'copy:src_to_dist',
'copy:pluginDef',
'copy:img_to_dist',
'babel'
]);
};
+3
View File
@@ -0,0 +1,3 @@
# Timely
Timely: a scalable, distributed, **secure** time series database.
+3
View File
@@ -0,0 +1,3 @@
# Timely
Timely: a scalable, distributed, **secure** time series database.
@@ -0,0 +1,10 @@
<div class="gf-form-group">
<div class="gf-form">
<span class="gf-form-label width-13">OpenTSDB metrics query</span>
<input type="text" class="gf-form-input" ng-model='ctrl.annotation.target' placeholder="events.eventname"></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-13">Show Global Annotations?</span>
<editor-checkbox text="" model="ctrl.annotation.isGlobal"></editor-checkbox>
</div>
</div>
+52
View File
@@ -0,0 +1,52 @@
<div class="page-header">
<h1>Timely Login</h1>
</div>
<div ng-if="ctrl.datasources.length === 0">
<h4>No Timely datasources are defined.</h4>
<i><a href="datasources/new">Create one</a></i>
</div>
<div ng-repeat="source in ctrl.datasources" ng-init="d=source" ng-controller="AuthsCtrl as actrl">
<div class="gf-box">
<div class="gf-box-header p-x-1 p-y-1">
<h3 class="">{{d.name}}
<span class="pull-right">
<h6><i>https://{{d.jsonData.timelyHost}}:{{d.jsonData.httpsPort}}/login</i></h6>
</span>
</h3>
</div>
<div class="gf-box-body">
<div ng-if="d.jsonData.basicAuths" class="p-b-1">
<div class="gf-form">
<span class="gf-form-label width-7">
User
</span>
<input id="timlely-user" class="gf-form-input max-width-21" type="text" ng-model='actrl.basicAuthUser' placeholder="user" required></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-7">
Password
</span>
<input id="timely-password" class="gf-form-input max-width-21" type="password" ng-model='actrl.basicAuthPassword' placeholder="password" required></input>
</div>
</div>
<div ng-if="actrl.fetching" class="gf-row">
<div class="alert-{{actrl.fetching.status}} alert">
<div class="alert-title">{{actrl.fetching.title}}</div>
</div>
</div>
<div class="gf-form-button-row center-block">
<button type="submit" class="btn btn-success" ng-click="actrl.login(d)">
Login
</button>
</div>
</div>
</div>
</div>
+146
View File
@@ -0,0 +1,146 @@
'use strict';
System.register(['lodash'], function (_export, _context) {
"use strict";
var _, _createClass, AuthsCtrl;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
return {
setters: [function (_lodash) {
_ = _lodash.default;
}],
execute: function () {
_createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
_export('AuthsCtrl', AuthsCtrl = function () {
function AuthsCtrl(backendSrv, $rootScope, $timeout) {
_classCallCheck(this, AuthsCtrl);
this.$rootScope = $rootScope;
this.$timeout = $timeout;
this.backendSrv = backendSrv;
}
_createClass(AuthsCtrl, [{
key: 'login',
value: function login(datasource) {
this.fetching = {};
this.fetching.done = false;
this.fetching.show = true;
this.fetching.status = 'warning';
this.fetching.title = 'Fetching auths...';
//this.$rootScope.appEvent('alert-success', ['Authorization Cookie Received', '']);
//this.$rootScope.appEvent('alert-error', ['Authorization Failed', '']);
//this.$rootScope.appEvent('alert-warning', ['Fetching Authorizations', '']);
var uri = this._getURI(datasource.jsonData);
if (datasource.jsonData.basicAuths) {
if (this.basicAuthUser && this.basicAuthPassword) {
var authBlob = { username: this.basicAuthUser, password: this.basicAuthPassword };
this.doPostLogin(uri, authBlob);
} else {
this.$rootScope.appEvent('alert-warning', [datasource.name, 'requires User/Password']);
this.fetching.status = 'warning';
this.fetching.title = 'User/Password required';
return;
}
} else {
this.doGetLogin(uri);
}
}
}, {
key: 'doPostLogin',
value: function doPostLogin(uri, authBlob) {
this.doXHR('POST', uri, authBlob);
}
}, {
key: 'doGetLogin',
value: function doGetLogin(uri) {
this.doXHR('GET', uri);
}
}, {
key: 'doXHR',
value: function doXHR(verb, uri, data) {
if (!data) {
data = "";
}
var r = new XMLHttpRequest();
r.open(verb, uri, true);
r.withCredentials = true;
r.setRequestHeader('Content-Type', 'application/json');
r.onreadystatechange = function () {
this.handleLoginResult(r);
}.bind(this);
r.send(JSON.stringify(data));
}
}, {
key: 'handleLoginResult',
value: function handleLoginResult(response) {
// wait for readyState to be '4 => done'
if (response.readyState != 4) return;
this.fetching.done = true;
switch (response.status) {
case 200:
var cookie = (document.cookie.match(/^(?:.*;)?TSESSIONID=([^;]+)(?:.*)?$/) || [, null])[1];
console.log(cookie);
console.log(document.cookie);
this.fetching.status = 'success';
this.fetching.title = 'Login successful';
this.$rootScope.appEvent('alert-success', ['Success', '']);
break;
default:
this.fetching.status = 'warning';
this.fetching.title = response.statusText;
this.$rootScope.appEvent('alert-warning', [response.status + ': ' + response.statusText, '']);
break;
}
if (r.readyState != 4 || r.status != 200) return;
alert("Success: " + r.getResponseHeader('Set-Cookie'));
}
}, {
key: '_getURI',
value: function _getURI(jsonData) {
return 'https://' + jsonData.timelyHost + ':' + jsonData.httpsPort + '/login';
}
}, {
key: '_showResults',
value: function _showResults() {}
}]);
return AuthsCtrl;
}());
_export('AuthsCtrl', AuthsCtrl);
}
};
});
//# sourceMappingURL=auths.js.map
+1
View File
@@ -0,0 +1 @@
{"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":"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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 switcLine truncated
+80
View File
@@ -0,0 +1,80 @@
'use strict';
System.register(['lodash', 'app/core/core', 'plugins/timely-app/components/auths'], function (_export, _context) {
"use strict";
var _, coreModule, appEvents, AuthsCtrl, _createClass, AuthsPageCtrl;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
return {
setters: [function (_lodash) {
_ = _lodash.default;
}, function (_appCoreCore) {
coreModule = _appCoreCore.coreModule;
appEvents = _appCoreCore.appEvents;
}, function (_pluginsTimelyAppComponentsAuths) {
AuthsCtrl = _pluginsTimelyAppComponentsAuths.AuthsCtrl;
}],
execute: function () {
_createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
_export('AuthsPageCtrl', AuthsPageCtrl = function () {
function AuthsPageCtrl(backendSrv, datasourceSrv) {
_classCallCheck(this, AuthsPageCtrl);
this.datasourceSrv = datasourceSrv;
this.datasources = this.getTimelyDatasources();
coreModule.controller('AuthsCtrl', AuthsCtrl);
}
_createClass(AuthsPageCtrl, [{
key: 'getTimelyDatasources',
value: function getTimelyDatasources() {
var allSources = this.datasourceSrv.getAll();
var sources = _.map(allSources, function (value, key, col) {
var ret = {};
ret.meta = {};
ret.meta.type = col[key].meta.type;
ret.meta.id = col[key].meta.id;
ret.name = key;
ret.jsonData = col[key].jsonData;
return ret;
});
return _.filter(sources, function (d) {
return d.meta.type === 'datasource' && d.meta.id === 'timely-datasource';
});
}
}]);
return AuthsPageCtrl;
}());
_export('AuthsPageCtrl', AuthsPageCtrl);
AuthsPageCtrl.templateUrl = 'components/auths.html';
}
};
});
//# sourceMappingURL=authspage.js.map
+1
View File
@@ -0,0 +1 @@
{"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"]}
+10
View File
@@ -0,0 +1,10 @@
<h3 class="page-heading">Timely App Configuration</h3>
<div class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form">
<span class="gf-form-label">Currently, all configuration is done in the Timely datasource.</span>
</div>
</div>
</div>
+27
View File
@@ -0,0 +1,27 @@
'use strict';
System.register([], function (_export, _context) {
"use strict";
var TimelyAppConfigCtrl;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
return {
setters: [],
execute: function () {
_export('TimelyAppConfigCtrl', TimelyAppConfigCtrl = function TimelyAppConfigCtrl() {
_classCallCheck(this, TimelyAppConfigCtrl);
});
_export('TimelyAppConfigCtrl', TimelyAppConfigCtrl);
TimelyAppConfigCtrl.templateUrl = 'components/config.html';
}
};
});
//# sourceMappingURL=config.js.map
+1
View File
@@ -0,0 +1 @@
{"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"]}
+53
View File
@@ -0,0 +1,53 @@
<div class="page-header">
<h1>Metrics Browser</h1>
</div>
<div ng-hide="ctrl.hasDatasource" >
<h4>No Timely datasources are defined.</h4>
<i><a href="datasources/new">Create one</a></i>
</div>
<div class="gf-box" ng-show="ctrl.hasDatasource">
<div class="gf-box-header">
<div class="gf-form-inline">
<div class="gf-form max-width-30">
<span class="gf-label width-7 p-y-1 p-x-1">Datasource</span>
<div class="gf-form-select-wrapper gf-form-select-wrapper--has-help-icon max-width-24">
<select class="gf-form-input"
ng-model="ctrl.source"
ng-options="d.name for d in ctrl.datasources"
ng-change=ctrl.updateDatasource()></select>
<info-popover mode="right-absolute">
Select a Datasource<br>
</info-popover>
</div>
</div>
</div>
</div>
<div class="gf-box-body">
<div class="grafana-options-table">
<div class="gf-form width-20 pull-right">
<input type="text" class="gf-form-input" placeholder="filter" ng-model="searchText">
</input>
</div>
<table>
<tr>
<th>Metric</th>
<th>Tags</th>
</tr>
<tr ng-repeat="metric in ctrl.metrics | filter:searchText">
<td>{{metric.metric}}</td>
<td class="p-x-1" ng-repeat="tag in metric.tags">
{{tag.name}} = {{tag.values}}
</td>
</tr>
</table>
</div>
</div>
</div>
+124
View File
@@ -0,0 +1,124 @@
'use strict';
System.register(['lodash', 'plugins/timely-app/components/authspage'], function (_export, _context) {
"use strict";
var _, AuthsPageCtrl, _createClass, MetricsPageCtrl;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
return {
setters: [function (_lodash) {
_ = _lodash.default;
}, function (_pluginsTimelyAppComponentsAuthspage) {
AuthsPageCtrl = _pluginsTimelyAppComponentsAuthspage.AuthsPageCtrl;
}],
execute: function () {
_createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
_export('MetricsPageCtrl', MetricsPageCtrl = function () {
function MetricsPageCtrl(backendSrv, datasourceSrv) {
_classCallCheck(this, MetricsPageCtrl);
this.hasDatasource = false;
this.backendSrv = backendSrv;
var apc = new AuthsPageCtrl(backendSrv, datasourceSrv);
this.datasources = apc.getTimelyDatasources();
if (this.datasources.length > 0) {
this.source = this.datasources[0];
this.updateDatasource();
}
}
_createClass(MetricsPageCtrl, [{
key: 'updateDatasource',
value: function updateDatasource() {
var _this = this;
this._clearMetrics();
var uri = this._getURI(this.source.jsonData);
this.backendSrv.request({ method: 'GET',
url: uri,
withCredentials: true,
params: "" }).then(function (response) {
_this.metrics = _this._transformMetrics(response.metrics);
_this.hasDatasource = true;
});
}
}, {
key: '_clearMetrics',
value: function _clearMetrics() {
this.metrics = [];
}
}, {
key: '_transformMetrics',
value: function _transformMetrics(metrics) {
var ret = [];
_.each(metrics, function (value, idx) {
var metric = {};
metric.metric = value.metric;
metric.tags = [];
_.map(value.tags, function (tag, key) {
// result || (result = {});
// result['name'] = tag.key;
// result['values'] || (result['values'] = []);
// result['values'].push(tag.value);
var gIdx = _.findIndex(metric.tags, { 'name': tag.key });
var grouped;
if (gIdx == -1) {
grouped = { name: '', values: [] };
} else {
grouped = metric.tags[gIdx];
}
grouped.values.push(tag.value);
grouped.values = _.sortBy(_.uniq(grouped.values));
grouped.name = tag.key;
if (gIdx > -1) {
metric.tags[gIdx] = grouped;
} else {
metric.tags.push(grouped);
}
}.bind(metric));
metric.tags = _.sortBy(metric.tags, 'name');
ret.push(metric);
}.bind(ret));
return _.sortBy(ret, 'metric');
}
}, {
key: '_getURI',
value: function _getURI(jsonData) {
return 'https://' + jsonData.timelyHost + ':' + jsonData.httpsPort + '/api/metrics';
}
}]);
return MetricsPageCtrl;
}());
_export('MetricsPageCtrl', MetricsPageCtrl);
MetricsPageCtrl.templateUrl = 'components/metrics.html';
}
};
});
//# sourceMappingURL=metrics.js.map
+1
View File
@@ -0,0 +1 @@
{"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":";;;;;;;;;;;;;;;AACOA,O;;AACCC,mB,wCAAAA,a;;;;;;;;;;;;;;;;;;;;;iCAEKC,e;AAEX,iCAAYC,UAAZ,EAAwBC,aAAxB,EAAsC;AAAA;;AACpC,eAAKC,aAAL,GAAqB,KAArB;AACA,eAAKF,UAAL,GAAkBA,UAAlB;AACA,cAAIG,MAAM,IAAIL,aAAJ,CAAkBE,UAAlB,EAA8BC,aAA9B,CAAV;AACA,eAAKG,WAAL,GAAmBD,IAAIE,oBAAJ,EAAnB;AACA,cAAI,KAAKD,WAAL,CAAiBE,MAAjB,GAA0B,CAA9B,EAAgC;AAC9B,iBAAKC,MAAL,GAAc,KAAKH,WAAL,CAAiB,CAAjB,CAAd;AACA,iBAAKI,gBAAL;AACD;AACF;;;;6CAEiB;AAAA;;AAChB,iBAAKC,aAAL;AACA,gBAAIC,MAAM,KAAKC,OAAL,CAAa,KAAKJ,MAAL,CAAYK,QAAzB,CAAV;AACA,iBAAKZ,UAAL,CAAgBa,OAAhB,CACE,EAAEC,QAAQ,KAAV;AACEC,mBAAKL,GADP;AAEEM,+BAAiB,IAFnB;AAGEC,sBAAQ,EAHV,EADF,EAKEC,IALF,CAME,oBAAY;AACV,oBAAKC,OAAL,GAAe,MAAKC,iBAAL,CAAuBC,SAASF,OAAhC,CAAf;AACA,oBAAKjB,aAAL,GAAqB,IAArB;AACD,aATH;AAUD;;;0CAEc;AACb,iBAAKiB,OAAL,GAAe,EAAf;AACD;;;4CAEiBA,O,EAAQ;AACxB,gBAAIG,MAAM,EAAV;AACAzB,cAAE0B,IAAF,CAAOJ,OAAP,EAAgB,UAASK,KAAT,EAAgBC,GAAhB,EAAoB;AAClC,kBAAIC,SAAS,EAAb;AACAA,qBAAOA,MAAP,GAAgBF,MAAME,MAAtB;AACAA,qBAAOC,IAAP,GAAc,EAAd;AACA9B,gBAAE+B,GAAF,CAAMJ,MAAMG,IAAZ,EAAkB,UAASE,GAAT,EAAcC,GAAd,EAAkB;AAC1C;AACA;AACA;AACA;AACQ,oBAAIC,OAAOlC,EAAEmC,SAAF,CAAYN,OAAOC,IAAnB,EAAyB,EAAC,QAAQE,IAAIC,GAAb,EAAzB,CAAX;AACA,oBAAIG,OAAJ;AACA,oBAAIF,QAAQ,CAAC,CAAb,EAAgB;AACdE,4BAAU,EAACC,MAAM,EAAP,EAAWC,QAAQ,EAAnB,EAAV;AACD,iBAFD,MAEO;AACLF,4BAAUP,OAAOC,IAAP,CAAYI,IAAZ,CAAV;AACD;AACDE,wBAAQE,MAAR,CAAeC,IAAf,CAAoBP,IAAIL,KAAxB;AACAS,wBAAQE,MAAR,GAAiBtC,EAAEwC,MAAF,CAASxC,EAAEyC,IAAF,CAAOL,QAAQE,MAAf,CAAT,CAAjB;AACAF,wBAAQC,IAAR,GAAeL,IAAIC,GAAnB;AACA,oBAAIC,OAAO,CAAC,CAAZ,EAAe;AACbL,yBAAOC,IAAP,CAAYI,IAAZ,IAAoBE,OAApB;AACD,iBAFD,MAEO;AACLP,yBAAOC,IAAP,CAAYS,IAAZ,CAAiBH,OAAjB;AACD;AACF,eApBiB,CAoBhBM,IApBgB,CAoBXb,MApBW,CAAlB;AAqBAA,qBAAOC,IAAP,GAAc9B,EAAEwC,MAAF,CAASX,OAAOC,IAAhB,EAAsB,MAAtB,CAAd;AACAL,kBAAIc,IAAJ,CAASV,MAAT;AACD,aA3Be,CA2Bda,IA3Bc,CA2BTjB,GA3BS,CAAhB;;AA6BA,mBAAOzB,EAAEwC,MAAF,CAASf,GAAT,EAAc,QAAd,CAAP;AACD;;;kCAEOV,Q,EAAS;AACf,mBAAO,aAAWA,SAAS4B,UAApB,GAA+B,GAA/B,GAAmC5B,SAAS6B,SAA5C,GAAsD,cAA7D;AACD;;;;;;;;AAGH1C,sBAAgB2C,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"]}
+257
View File
@@ -0,0 +1,257 @@
<query-editor-row query-ctrl="ctrl" can-collapse="false">
<div class="gf-form-inline">
<div class="gf-form max-width-25">
<label class="gf-form-label query-keyword width-8">
Metric
<label class="gf-form-label" bs-tooltip="ctrl.errors.metric" style="color: rgb(229, 189, 28)" ng-show="ctrl.errors.metric">
<i class="fa fa-warning"></i>
</label>
</label>
<input type="text" class="gf-form-input" ng-model="ctrl.target.metric"
spellcheck='false' bs-typeahead="ctrl.suggestMetrics" placeholder="metric name" data-min-length=0 data-items=100
ng-blur="ctrl.targetBlur()">
</input>
</div>
<div class="gf-form">
<label class="gf-form-label query-keyword">
Aggregator
<a bs-tooltip="ctrl.errors.aggregator" style="color: rgb(229, 189, 28)" ng-show="ctrl.errors.aggregator">
<i class="fa fa-warning"></i>
</a>
</label>
<div class="gf-form-select-wrapper max-width-15">
<select ng-model="ctrl.target.aggregator" class="gf-form-input"
ng-options="agg for agg in ctrl.aggregators"
ng-change="ctrl.targetBlur()">
</select>
</div>
</div>
<div class="gf-form max-width-20">
<label class="gf-form-label query-keyword width-6">
Alias:
<info-popover mode="right-normal">
Use patterns like $tag_tagname to replace part of the alias for a tag value
</info-popover>
</label>
<input type="text" class="gf-form-input"
ng-model="ctrl.target.alias"
spellcheck='false'
placeholder="series alias"
data-min-length=0 data-items=100
ng-blur="ctrl.targetBlur()"></input>
</div>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form max-width-25">
<label class="gf-form-label query-keyword width-8">Down sample</label>
<input type="text" class="gf-form-input"
ng-model="ctrl.target.downsampleInterval"
ng-model-onblur
ng-change="ctrl.targetBlur()"
placeholder="interval"></input>
<info-popover mode="right-absolute">
blank for auto, or for example <code>1m</code>
</info-popover>
</div>
<div class="gf-form">
<label class="gf-form-label query-keyword">Aggregator</label>
<div class="gf-form-select-wrapper">
<select ng-model="ctrl.target.downsampleAggregator" class="gf-form-input"
ng-options="agg for agg in ctrl.aggregators"
ng-change="ctrl.targetBlur()">
</select>
</div>
</div>
<div class="gf-form" ng-if="ctrl.tsdbVersion >= 2">
<label class="gf-form-label query-keyword width-6">Fill</label>
<div class="gf-form-select-wrapper">
<select ng-model="ctrl.target.downsampleFillPolicy" class="gf-form-input"
ng-options="agg for agg in ctrl.fillPolicies"
ng-change="ctrl.targetBlur()">
</select>
</div>
</div>
<gf-form-switch class="gf-form"
label="Disable downsampling"
label-class="query-keyword"
checked="ctrl.target.disableDownsampling"
on-change="ctrl.targetBlur()">
</gf-form-switch>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div>
</div>
<div class="gf-form-inline" ng-if="ctrl.tsdbVersion >= 2">
<div class="gf-form">
<label class="gf-form-label query-keyword width-8">
Filters
<info-popover mode="right-normal">
Filters does not work with tags, either of the two will work but not both.
</info-popover>
</label>
<div ng-repeat="fil in ctrl.target.filters track by $index" class="gf-form-label">
{{fil.tagk}}&nbsp;=&nbsp;{{fil.type}}&#40;{{fil.filter}}&#41;&nbsp;&#44&nbsp;groupBy&nbsp;=&nbsp;{{fil.groupBy}}
<a ng-click="ctrl.editFilter(fil, $index)">
<i class="fa fa-pencil"></i>
</a>
<a ng-click="ctrl.removeFilter($index)">
<i class="fa fa-remove"></i>
</a>
</div>
<label class="gf-form-label query-keyword" ng-hide="ctrl.addFilterMode">
<a ng-click="ctrl.addFilter()">
<i class="fa fa-plus"></i>
</a>
</label>
</div>
<div class="gf-form-inline" ng-show="ctrl.addFilterMode">
<div class="gf-form">
<input type="text" class="gf-form-input" spellcheck='false'
bs-typeahead="ctrl.suggestTagKeys" data-min-length=0 data-items=100
ng-model="ctrl.target.currentFilterKey" placeholder="key">
</input>
</div>
<div class="gf-form">
<label class="gf-form-label query-keyword">Type</label>
<div class="gf-form-select-wrapper">
<select ng-model="ctrl.target.currentFilterType" class="gf-form-input" ng-options="filType for filType in ctrl.filterTypes">
</select>
</div>
</div>
<div class="gf-form">
<input type="text" class="gf-form-input" spellcheck='false' bs-typeahead="ctrl.suggestTagValues" data-min-length=0 data-items=100 ng-model="ctrl.target.currentFilterValue" placeholder="filter">
</input>
</div>
<gf-form-switch class="gf-form"
label="Group by"
label-class="query-keyword"
checked="ctrl.target.currentFilterGroupBy"
on-change="ctrl.targetBlur()">
</gf-form-switch>
<div class="gf-form" ng-show="ctrl.addFilterMode">
<label class="gf-form-label" ng-show="ctrl.errors.filters">
<a bs-tooltip="ctrl.errors.filters" style="color: rgb(229, 189, 28)" >
<i class="fa fa-warning"></i>
</a>
</label>
<label class="gf-form-label">
<a ng-click="ctrl.addFilter()" ng-hide="ctrl.errors.filters">add filter</a>
<a ng-click="ctrl.closeAddFilterMode()">
<i class="fa fa-remove"></i>
</a>
</label>
</div>
</div>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label query-keyword width-8">
Tags
<info-popover mode="right-normal" ng-if="ctrl.tsdbVersion >= 2">
Please use filters, tags are deprecated in opentsdb 2.2
</info-popover>
</label>
</div>
<div class="gf-form" ng-repeat="(key, value) in ctrl.target.tags track by $index" class="gf-form">
<label class="gf-form-label">
{{key}}&nbsp;=&nbsp;{{value}}
<a ng-click="ctrl.editTag(key, value)">
<i class="fa fa-pencil"></i>
</a>
<a ng-click="ctrl.removeTag(key)">
<i class="fa fa-remove"></i>
</a>
</label>
</div>
<div class="gf-form" ng-hide="ctrl.addTagMode">
<label class="gf-form-label query-keyword">
<a ng-click="ctrl.addTag()"><i class="fa fa-plus"></i></a>
</label>
</div>
<div class="gf-form" ng-show="ctrl.addTagMode">
<input type="text"
class="gf-form-input" spellcheck='false'
bs-typeahead="ctrl.suggestTagKeys" data-min-length=0 data-items=100
ng-model="ctrl.target.currentTagKey" placeholder="key">
</input>
<input type="text" class="gf-form-input"
spellcheck='false' bs-typeahead="ctrl.suggestTagValues"
data-min-length=0 data-items=100 ng-model="ctrl.target.currentTagValue" placeholder="value">
</input>
<label class="gf-form-label" ng-show="ctrl.errors.tags">
<a bs-tooltip="ctrl.errors.tags" style="color: rgb(229, 189, 28)" >
<i class="fa fa-warning"></i>
</a>
</label>
<label class="gf-form-label" >
<a ng-click="ctrl.addTag()" ng-hide="ctrl.errors.tags">add tag</a>
<a ng-click="ctrl.closeAddTagMode()"><i class="fa fa-remove"></i></a>
</label>
</div>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div>
</div>
<div class="gf-form-inline">
<gf-form-switch class="gf-form" label="Rate" label-class="width-8 query-keyword" checked="ctrl.target.shouldComputeRate" on-change="ctrl.targetBlur()">
</gf-form-switch>
<gf-form-switch ng-hide="!ctrl.target.shouldComputeRate"
class="gf-form" label="Counter" label-class="query-keyword" checked="ctrl.target.isCounter" on-change="ctrl.targetBlur()">
</gf-form-switch>
<div class="gf-form" ng-hide="!ctrl.target.isCounter || !ctrl.target.shouldComputeRate">
<label class="gf-form-label query-keyword">Counter Max</label>
<input type="text" class="gf-form-input"
ng-disabled="!ctrl.target.shouldComputeRate"
ng-model="ctrl.target.counterMax" spellcheck='false'
placeholder="max value" ng-model-onblur
ng-blur="ctrl.targetBlur()">
</input>
<label class="gf-form-label query-keyword">Reset Value</label>
<input type="text" class="tight-form-input input-small"
ng-disabled="!ctrl.target.shouldComputeRate"
ng-model="ctrl.target.counterResetValue" spellcheck='false'
placeholder="reset value" ng-model-onblur
ng-blur="ctrl.targetBlur()">
</input>
</div>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div>
</div>
</query-editor-row>
View File
Whitespace-only changes.
View File
Whitespace-only changes.
+3
View File
@@ -0,0 +1,3 @@
.timely-app-heading {
text-align: center;
}
+35
View File
@@ -0,0 +1,35 @@
'use strict';
System.register(['lodash'], function (_export, _context) {
"use strict";
var _, DatasourceConfigCtrl;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
return {
setters: [function (_lodash) {
_ = _lodash.default;
}],
execute: function () {
_export('DatasourceConfigCtrl', DatasourceConfigCtrl = function DatasourceConfigCtrl() {
_classCallCheck(this, DatasourceConfigCtrl);
this.current.jsonData = this.current.jsonData || {};
this.current.access = 'direct';
this.current.basicAuth = false;
this.current.withCredentials = true;
this.current.suggestHost = 'localhost';
});
_export('DatasourceConfigCtrl', DatasourceConfigCtrl);
DatasourceConfigCtrl.templateUrl = 'datasource/partials/config.html';
}
};
});
//# sourceMappingURL=config.js.map
+1
View File
@@ -0,0 +1 @@
{"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,786 @@
{
"__inputs": [
{
"name": "DS_TIMELY",
"label": "Timely",
"description": "",
"type": "datasource",
"pluginId": "timely-datasource",
"pluginName": "Timely"
}
],
"__requires": [
{
"type": "panel",
"id": "singlestat",
"name": "Singlestat",
"version": ""
},
{
"type": "panel",
"id": "graph",
"name": "Graph",
"version": ""
},
{
"type": "grafana",
"id": "grafana",
"name": "Grafana",
"version": "3.1.0"
},
{
"type": "datasource",
"id": "timely-datasource",
"name": "Timely",
"version": "1.0.0"
}
],
"id": null,
"title": "Timely Status",
"tags": [],
"style": "dark",
"timezone": "browser",
"editable": true,
"hideControls": false,
"sharedCrosshair": false,
"rows": [
{
"collapse": false,
"editable": true,
"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,
"isNew": true,
"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
},
"targets": [
{
"aggregator": "count",
"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,
"isNew": true,
"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
},
"targets": [
{
"aggregator": "count",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "count",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "sys.collectd.queue_length",
"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,
"isNew": true,
"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
},
"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"
}
],
"title": "New row"
},
{
"collapse": false,
"editable": true,
"height": "250px",
"panels": [
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 3,
"isNew": true,
"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": [],
"span": 4,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "timely.keys.metric.inserted",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"timeFrom": null,
"timeShift": null,
"title": "Timely Metrics Inserted",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"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,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 4,
"isNew": true,
"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": [],
"span": 4,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "avg",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "timely.keys.meta.inserted",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"timeFrom": null,
"timeShift": null,
"title": "Timely Meta Inserted",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"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,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 5,
"isNew": true,
"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": [],
"span": 4,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "timely.metrics.received",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"timeFrom": null,
"timeShift": null,
"title": "Timely Metrics Received",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"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
}
]
}
],
"title": "New row"
},
{
"collapse": false,
"editable": true,
"height": "250px",
"panels": [
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 7,
"isNew": true,
"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": [],
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"alias": "$tag_host",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "sys.collectd.cache_size",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"timeFrom": null,
"timeShift": null,
"title": "CollectD Cache Sizes",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"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": "${DS_TIMELY}",
"editable": true,
"error": false,
"fill": 0,
"grid": {
"threshold1": null,
"threshold1Color": "rgba(216, 200, 27, 0.27)",
"threshold2": null,
"threshold2Color": "rgba(234, 112, 112, 0.22)"
},
"id": 11,
"isNew": true,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 2,
"links": [],
"nullPointMode": "connected",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"span": 6,
"stack": false,
"steppedLine": false,
"targets": [
{
"aggregator": "sum",
"alias": "$tag_host",
"currentTagKey": "",
"currentTagValue": "",
"downsampleAggregator": "sum",
"downsampleFillPolicy": "none",
"downsampleInterval": "1m",
"metric": "sys.collectd.queue_length",
"refId": "A",
"tags": {
"host": ".*"
}
}
],
"timeFrom": null,
"timeShift": null,
"title": "CollectD Queue Length",
"tooltip": {
"msResolution": true,
"shared": true,
"sort": 0,
"value_type": "cumulative"
},
"type": "graph",
"xaxis": {
"show": true
},
"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-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"
]
},
"templating": {
"list": []
},
"annotations": {
"list": []
},
"refresh": "1m",
"schemaVersion": 12,
"version": 8,
"links": [],
"gnetId": null
}
@@ -0,0 +1,434 @@
{
"__inputs": [
{
"name": "DS_NAME",
"type": "datasource",
"pluginId": "timely-datasource"
}
],
"id": null,
"title": "Timely Standalone Demo",
"originalTitle": "Timely Standalone Demo",
"tags": ["imported"],
"style": "dark",
"timezone": "browser",
"editable": true,
"hideControls": false,
"sharedCrosshair": false,
"rows": [
{
"collapse": false,
"editable": true,
"height": "250px",
"panels": [
{
"aliasColors": {},
"bars": false,
"datasource": "${DS_NAME}",
"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": "${DS_NAME}",
"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.cpu.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": "${DS_NAME}",
"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.cpu.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": "${DS_NAME}",
"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.cpu.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": []
}
+533
View File
@@ -0,0 +1,533 @@
'use strict';
System.register(['lodash', 'angular', '../../../app/core/utils/datemath'], function (_export, _context) {
"use strict";
var _, angular, dateMath, _createClass, TimelyDatasource;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
return {
setters: [function (_lodash) {
_ = _lodash.default;
}, function (_angular) {
angular = _angular.default;
}, function (_appCoreUtilsDatemath) {
dateMath = _appCoreUtilsDatemath;
}],
execute: function () {
_createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
_export('TimelyDatasource', TimelyDatasource = function () {
// arguments injected by angular
function TimelyDatasource(instanceSettings, $q, backendSrv, templateSrv, contextSrv) {
_classCallCheck(this, TimelyDatasource);
this.type = instanceSettings.type;
this.name = instanceSettings.name;
this.jsonData = instanceSettings.jsonData || {};
this.httpsPort = instanceSettings.jsonData.httpsPort;
this.timelyHost = instanceSettings.jsonData.timelyHost;
this.wsPort = instanceSettings.jsonData.wsPort;
if (!instanceSettings.jsonData.basicAuths) {
instanceSettings.jsonData.basicAuths = false;
}
this.url = this._makeHttpsUrl();
this.withCredentials = true;
this.basicAuth = false;
this.supportMetrics = true;
this.tagKeys = {};
this.$q = $q;
this.backendSrv = backendSrv;
this.templateSrv = templateSrv;
this.contextSrv = contextSrv;
this.aggregatorsPromise = null;
this.filterTypesPromise = null;
}
// REQUIRED INTERFACE
_createClass(TimelyDatasource, [{
key: 'query',
value: function query(options) {
var start = this.convertToTSDBTime(options.rangeRaw.from, false);
var end = this.convertToTSDBTime(options.rangeRaw.to, true);
var qs = [];
_.each(options.targets, function (target) {
if (!target.metric) {
return;
}
qs.push(this.convertTargetToQuery(target, options));
}.bind(this));
var queries = _.compact(qs);
// No valid targets, return the empty result to save a round trip.
if (_.isEmpty(queries)) {
var d = this.$q.defer();
d.resolve({ data: [] });
return d.promise;
}
var groupByTags = {};
_.each(queries, function (query) {
if (query.filters && query.filters.length > 0) {
_.each(query.filters, function (val) {
groupByTags[val.tagk] = true;
});
} else {
_.each(query.tags, function (val, key) {
groupByTags[key] = true;
});
}
});
return this.performTimeSeriesQuery(queries, start, end).then(function (response) {
var metricToTargetMapping = this.mapMetricsToTargets(response.data, options);
var result = _.map(response.data, function (metricData, index) {
index = metricToTargetMapping[index];
if (index === -1) {
index = 0;
}
this._saveTagKeys(metricData);
return this.transformMetricData(metricData, groupByTags, options.targets[index], options);
}.bind(this));
return { data: result };
}.bind(this));
}
}, {
key: 'testDatasource',
value: function testDatasource() {
return this.backendSrv.datasourceRequest({
url: this.url + '/version',
method: 'GET'
}).then(function (response) {
if (response.status === 200) {
return { status: "success", message: "Data source is working", title: "Success" };
}
});
}
}, {
key: 'annotationQuery',
value: function annotationQuery(options) {
var start = convertToTSDBTime(options.rangeRaw.from, false);
var end = convertToTSDBTime(options.rangeRaw.to, true);
var qs = [];
var eventList = [];
qs.push({ aggregator: "sum", metric: options.annotation.target });
var queries = _.compact(qs);
return this.performTimeSeriesQuery(queries, start, end).then(function (results) {
if (results.data[0]) {
var annotationObject = results.data[0].annotations;
if (options.annotation.isGlobal) {
annotationObject = results.data[0].globalAnnotations;
}
if (annotationObject) {
_.each(annotationObject, function (annotation) {
var event = {
title: annotation.description,
time: Math.floor(annotation.startTime) * 1000,
text: annotation.notes,
annotation: options.annotation
};
eventList.push(event);
});
}
}
return eventList;
}.bind(this));
}
}, {
key: 'metricFindQuery',
value: function metricFindQuery(query) {
if (!query) {
return this.$q.when([]);
}
var interpolated;
try {
interpolated = this.templateSrv.replace(query);
} catch (err) {
return this.$q.reject(err);
}
var responseTransform = function responseTransform(result) {
return _.map(result, function (value) {
return { text: value };
});
};
var metrics_regex = /metrics\((.*)\)/;
var tag_names_regex = /tag_names\((.*)\)/;
var tag_values_regex = /tag_values\((.*?),\s?(.*)\)/;
var tag_names_suggest_regex = /suggest_tagk\((.*)\)/;
var tag_values_suggest_regex = /suggest_tagv\((.*)\)/;
var metrics_query = interpolated.match(metrics_regex);
if (metrics_query) {
return this._performSuggestQuery(metrics_query[1], 'metrics').then(responseTransform);
}
var tag_names_query = interpolated.match(tag_names_regex);
if (tag_names_query) {
return this._performMetricKeyLookup(tag_names_query[1]).then(responseTransform);
}
var tag_values_query = interpolated.match(tag_values_regex);
if (tag_values_query) {
return this._performMetricKeyValueLookup(tag_values_query[1], tag_values_query[2]).then(responseTransform);
}
var tag_names_suggest_query = interpolated.match(tag_names_suggest_regex);
if (tag_names_suggest_query) {
return this._performSuggestQuery(tag_names_suggest_query[1], 'tagk').then(responseTransform);
}
var tag_values_suggest_query = interpolated.match(tag_values_suggest_regex);
if (tag_values_suggest_query) {
return this._performSuggestQuery(tag_values_suggest_query[1], 'tagv').then(responseTransform);
}
return this.$q.when([]);
}
}, {
key: 'performTimeSeriesQuery',
value: function performTimeSeriesQuery(queries, start, end) {
var msResolution = true;
var reqBody = {
start: start,
queries: queries,
msResolution: msResolution,
globalAnnotations: true,
showQuery: true
};
// Relative queries (e.g. last hour) don't include an end time
if (end) {
reqBody.end = end;
}
var options = {
method: 'POST',
url: this.url + '/api/query',
data: reqBody
};
this._addCredentialOptions(options);
// In case the backend is 3rd-party hosted and does not suport OPTIONS, urlencoded requests
// go as POST rather than OPTIONS+POST
options.headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
return this.backendSrv.datasourceRequest(options);
}
}, {
key: '_saveTagKeys',
value: function _saveTagKeys(metricData) {
var tagKeys = Object.keys(metricData.tags);
_.each(metricData.aggregateTags, function (tag) {
tagKeys.push(tag);
});
this.tagKeys[metricData.metric] = tagKeys;
}
}, {
key: 'suggestTagKeys',
value: function suggestTagKeys(metric) {
return this.$q.when(this.tagKeys[metric] || []);
}
}, {
key: '_performSuggestQuery',
value: function _performSuggestQuery(query, type) {
return this._get('/api/suggest', { type: type, q: query, max: 1000 }).then(function (result) {
return result.data;
});
}
}, {
key: '_performMetricKeyValueLookup',
value: function _performMetricKeyValueLookup(metric, keys) {
if (!metric || !keys) {
return $q.when([]);
}
var keysArray = keys.split(",").map(function (key) {
return key.trim();
});
var key = keysArray[0];
var keysQuery = key + "=.*";
if (keysArray.length > 1) {
keysQuery += "," + keysArray.splice(1).join(",");
}
var m = metric + "{" + keysQuery + "}";
return this._get('/api/search/lookup', { m: m, limit: 3000 }).then(function (result) {
result = result.data.results;
var tagvs = [];
_.each(result, function (r) {
if (tagvs.indexOf(r.tags[key]) === -1) {
tagvs.push(r.tags[key]);
}
});
return tagvs;
});
}
}, {
key: '_performMetricKeyLookup',
value: function _performMetricKeyLookup(metric) {
if (!metric) {
return this.$q.when([]);
}
return this._get('/api/search/lookup', { m: metric, limit: 1000 }).then(function (result) {
result = result.data.results;
var tagks = [];
_.each(result, function (r) {
_.each(r.tags, function (tagv, tagk) {
if (tagks.indexOf(tagk) === -1) {
tagks.push(tagk);
}
});
});
return tagks;
});
}
}, {
key: '_get',
value: function _get(relativeUrl, params) {
var options = {
method: 'GET',
url: this.url + relativeUrl,
params: params
};
this._addCredentialOptions(options);
return this.backendSrv.datasourceRequest(options);
}
}, {
key: '_addCredentialOptions',
value: function _addCredentialOptions(options) {
if (this.basicAuth || this.withCredentials) {
options.withCredentials = true;
}
if (this.basicAuth) {
options.headers = { "Authorization": this.basicAuth };
}
}
}, {
key: 'getAggregators',
value: function getAggregators() {
if (this.aggregatorsPromise) {
return this.aggregatorsPromise;
}
this.aggregatorsPromise = this._get('/api/aggregators').then(function (result) {
if (result.data && _.isArray(result.data)) {
return result.data.sort();
}
return [];
});
return this.aggregatorsPromise;
}
}, {
key: 'getFilterTypes',
value: function getFilterTypes() {
if (this.filterTypesPromise) {
return this.filterTypesPromise;
}
// filters are for a newer opentsdb api version than Timely originally copied.
this.filterTypesPromise = this._get('/api/aggregators').then(function (result) {
return [];
});
return this.filterTypesPromise;
}
}, {
key: 'transformMetricData',
value: function transformMetricData(md, groupByTags, target, options) {
var metricLabel = this.createMetricLabel(md, target, groupByTags, options);
var dps = [];
// TSDB returns datapoints has a hash of ts => value.
// Can't use _.pairs(invert()) because it stringifies keys/values
_.each(md.dps, function (v, k) {
dps.push([v, k * 1]);
});
return { target: metricLabel, datapoints: dps };
}
}, {
key: 'createMetricLabel',
value: function createMetricLabel(md, target, groupByTags, options) {
if (target.alias) {
var scopedVars = _.clone(options.scopedVars || {});
_.each(md.tags, function (value, key) {
scopedVars['tag_' + key] = { value: value };
});
return this.templateSrv.replace(target.alias, scopedVars);
}
var label = md.metric;
var tagData = [];
if (!_.isEmpty(md.tags)) {
_.each(_.pairs(md.tags), function (tag) {
if (_.has(groupByTags, tag[0])) {
tagData.push(tag[0] + "=" + tag[1]);
}
});
}
if (!_.isEmpty(tagData)) {
label += "{" + tagData.join(", ") + "}";
}
return label;
}
}, {
key: 'convertTargetToQuery',
value: function convertTargetToQuery(target, options) {
if (!target.metric || target.hide) {
return null;
}
var query = {
metric: this.templateSrv.replace(target.metric, options.scopedVars),
aggregator: "avg"
};
if (target.aggregator) {
query.aggregator = this.templateSrv.replace(target.aggregator);
}
if (target.shouldComputeRate) {
query.rate = true;
query.rateOptions = {
counter: !!target.isCounter
};
if (target.counterMax && target.counterMax.length) {
query.rateOptions.counterMax = parseInt(target.counterMax);
}
if (target.counterResetValue && target.counterResetValue.length) {
query.rateOptions.resetValue = parseInt(target.counterResetValue);
}
}
if (!target.disableDownsampling) {
var interval = this.templateSrv.replace(target.downsampleInterval || options.interval);
if (interval.match(/\.[0-9]+s/)) {
interval = parseFloat(interval) * 1000 + "ms";
}
query.downsample = interval + "-" + target.downsampleAggregator;
if (target.downsampleFillPolicy && target.downsampleFillPolicy !== "none") {
query.downsample += "-" + target.downsampleFillPolicy;
}
}
if (target.filters && target.filters.length > 0) {
query.filters = angular.copy(target.filters);
if (query.filters) {
for (var filter_key in query.filters) {
query.filters[filter_key].filter = this.templateSrv.replace(query.filters[filter_key].filter, options.scopedVars, 'pipe');
}
}
} else {
query.tags = angular.copy(target.tags);
if (query.tags) {
for (var tag_key in query.tags) {
query.tags[tag_key] = this.templateSrv.replace(query.tags[tag_key], options.scopedVars, 'pipe');
}
}
}
return query;
}
}, {
key: 'mapMetricsToTargets',
value: function mapMetricsToTargets(metrics, options) {
var interpolatedTagValue;
return _.map(metrics, function (metricData) {
return _.findIndex(options.targets, function (target) {
if (target.filters && target.filters.length > 0) {
return target.metric === metricData.metric;
} else {
return target.metric === metricData.metric && _.all(target.tags, function (tagV, tagK) {
interpolatedTagValue = this.templateSrv.replace(tagV, options.scopedVars, 'pipe');
return metricData.tags[tagK] === interpolatedTagValue || interpolatedTagValue === "*";
}.bind(this));
}
}.bind(this));
}.bind(this));
}
}, {
key: 'convertToTSDBTime',
value: function convertToTSDBTime(date, roundUp) {
if (date === 'now') {
return null;
}
date = dateMath.parse(date, roundUp);
return date.valueOf();
}
}, {
key: '_makeHttpsUrl',
value: function _makeHttpsUrl() {
return 'https://' + this.timelyHost + ':' + this.httpsPort;
}
}, {
key: '_makeWsUrl',
value: function _makeWsUrl() {
return 'ws://' + this.timelyHost + ':' + this.wsPort;
}
}]);
return TimelyDatasource;
}());
_export('TimelyDatasource', TimelyDatasource);
}
};
});
//# sourceMappingURL=datasource.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/datasource/datasource.js"],"names":["_","angular","dateMath","TimelyDatasource","instanceSettings","$q","backendSrv","templateSrv","contextSrv","type","name","jsonData","httpsPort","timelyHost","wsPort","basicAuths","url","_makeHttpsUrl","withCredentials","basicAuth","supportMetrics","tagKeys","aggregatorsPromise","filterTypesPromise","options","start","convertToTSDBTime","rangeRaw","from","end","to","qs","each","targets","target","metric","push","convertTargetToQuery","bind","queries","compact","isEmpty","d","defer","resolve","data","promise","groupByTags","query","filters","length","val","tagk","tags","key","performTimeSeriesQuery","then","response","metricToTargetMapping","mapMetricsToTargets","result","map","metricData","index","_saveTagKeys","transformMetricData","datasourceRequest","method","status","message","title","eventList","aggregator","annotation","results","annotationObject","annotations","isGlobal","globalAnnotations","event","description","time","Math","floor","startTime","text","notes","when","interpolated","replace","err","reject","responseTransform","value","metrics_regex","tag_names_regex","tag_values_regex","tag_names_suggest_regex","tag_values_suggest_regex","metrics_query","match","_performSuggestQuery","tag_names_query","_performMetricKeyLookup","tag_values_query","_performMetricKeyValueLookup","tag_names_suggest_query","tag_values_suggest_query","msResolution","reqBody","showQuery","_addCredentialOptions","headers","Object","keys","aggregateTags","tag","_get","q","max","keysArray","split","trim","keysQuery","splice","join","m","limit","tagvs","r","indexOf","tagks","tagv","relativeUrl","params","isArray","sort","md","metricLabel","createMetricLabel","dps","v","k","datapoints","alias","scopedVars","clone","label","tagData","pairs","has","hide","shouldComputeRate","rate","rateOptions","counter","isCounter","counterMax","parseInt","counterResetValue","resetValue","disableDownsampling","interval","downsampleInterval","parseFloat","downsample","downsampleAggregator","downsampleFillPolicy","copy","filter_key","filter","tag_key","metrics","interpolatedTagValue","findIndex","all","tagV","tagK","date","roundUp","parse","valueOf"],"mappings":"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 truncated
+39
View File
@@ -0,0 +1,39 @@
'use strict';
System.register(['./datasource', './query_ctrl', './config'], function (_export, _context) {
"use strict";
var TimelyDatasource, TimelyQueryCtrl, DatasourceConfigCtrl, TimelyAnnotationsQueryCtrl;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
return {
setters: [function (_datasource) {
TimelyDatasource = _datasource.TimelyDatasource;
}, function (_query_ctrl) {
TimelyQueryCtrl = _query_ctrl.TimelyQueryCtrl;
}, function (_config) {
DatasourceConfigCtrl = _config.DatasourceConfigCtrl;
}],
execute: function () {
_export('AnnotationsQueryCtrl', TimelyAnnotationsQueryCtrl = function TimelyAnnotationsQueryCtrl() {
_classCallCheck(this, TimelyAnnotationsQueryCtrl);
});
TimelyAnnotationsQueryCtrl.templateUrl = 'components/annotations.editor.html';
_export('Datasource', TimelyDatasource);
_export('QueryCtrl', TimelyQueryCtrl);
_export('ConfigCtrl', DatasourceConfigCtrl);
_export('AnnotationsQueryCtrl', TimelyAnnotationsQueryCtrl);
}
};
});
//# sourceMappingURL=module.js.map
+1
View File
@@ -0,0 +1 @@
{"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"]}
+66
View File
@@ -0,0 +1,66 @@
<div class="gf-form-group">
<div class="gf-form-group">
<h3 class="page-heading">Server Settings</h3>
<div class="gf-form-inline">
<div class="gf-form max-width-30">
<span class="gf-form-label width-7">Hostname</span>
<input class="gf-form-input" type="text"
ng-model="ctrl.current.jsonData.timelyHost" placeholder="{{ctrl.current.jsonData.suggestHost}}"
min-length="0"
ng-pattern="/(\w+:{0,1}\w*@)?(\S+)?$/" required></input>
<info-popover mode="right-absolute">
<p>Hostname of timely server</p>
</info-popover>
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form max-width-30">
<span class="gf-form-label width-7">HTTPS Port</span>
<input class="gf-form-input" type="text"
ng-model="ctrl.current.jsonData.httpsPort"
min-length="0"
ng-pattern="/[0-9]+/" required></input>
<info-popover mode="right-absolute">
<p>Port number for Timely HTTPS access</p>
</info-popover>
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form max-width-30">
<span class="gf-form-label width-7">WS Port</span>
<input class="gf-form-input" type="text"
ng-model="ctrl.current.jsonData.wsPort"
min-length="0"
ng-pattern="/[0-9]+/"></input>
<info-popover mode="right-absolute">
<p>Port number for Timely WebSocket access</p>
</info-popover>
</div>
</div>
<gf-form-switch class="gf-form "
label="Basic Auths"
checked="ctrl.current.jsonData.basicAuths" switch-class="max-width-6">
</gf-form-switch>
</div>
<div class="gf-form-group">
<div class="gf-form">
<span class="gf-form-label">
<a ng-href="https://{{ctrl.current.jsonData.timelyHost}}:{{ctrl.current.jsonData.httpsPort}}/version" target="_blank">
Browser Cert Check
</a>
<info-popover mode="right">
<p>Opens a new browser to test https access, allows you to accept a cert, etc.</p>
</info-popover>
</span>
</div>
</div>
</div>
+28
View File
@@ -0,0 +1,28 @@
{
"type": "datasource",
"name": "Timely",
"id": "timely-datasource",
"metrics": true,
"defaultMatchFormat": "pipe",
"annotations": true,
"includes": [
{"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": {
"author": {
"name": "National Security Agency",
"url": "http://github.com/NationalSecurityAgency/timely"
},
"logos": {
"small": "../timely-app/img/brand_small.png",
"large": "../timely-app/img/brand_large.png"
}
}
}
+277
View File
@@ -0,0 +1,277 @@
'use strict';
System.register(['lodash', 'app/plugins/sdk'], function (_export, _context) {
"use strict";
var _, QueryCtrl, _createClass, TimelyQueryCtrl;
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
return {
setters: [function (_lodash) {
_ = _lodash.default;
}, function (_appPluginsSdk) {
QueryCtrl = _appPluginsSdk.QueryCtrl;
}],
execute: function () {
_createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
_export('TimelyQueryCtrl', TimelyQueryCtrl = function (_QueryCtrl) {
_inherits(TimelyQueryCtrl, _QueryCtrl);
function TimelyQueryCtrl($scope, $injector, uiSegmentSrv) {
_classCallCheck(this, TimelyQueryCtrl);
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'];
_this.fillPolicies = ['none', 'nan', 'null', 'zero'];
_this.filterTypes = ['wildcard', 'iliteral_or', 'not_iliteral_or', 'not_literal_or', 'iwildcard', 'literal_or', 'regexp'];
if (!_this.target.aggregator) {
_this.target.aggregator = 'sum';
}
if (!_this.target.downsampleAggregator) {
_this.target.downsampleAggregator = 'avg';
}
if (!_this.target.downsampleFillPolicy) {
_this.target.downsampleFillPolicy = 'none';
}
_this.datasource.getAggregators().then(function (aggs) {
if (aggs.length !== 0) {
_this.aggregators = aggs;
}
});
_this.datasource.getFilterTypes().then(function (filterTypes) {
if (filterTypes.length !== 0) {
_this.filterTypes = filterTypes;
}
});
// needs to be defined here as it is called from typeahead
_this.suggestMetrics = function (query, callback) {
_this.datasource.metricFindQuery('metrics(' + query + ')').then(_this.getTextValues).then(callback);
};
_this.suggestTagKeys = function (query, callback) {
_this.datasource.suggestTagKeys(_this.target.metric).then(callback);
};
_this.suggestTagValues = function (query, callback) {
_this.datasource.metricFindQuery('suggest_tagv(' + query + ')').then(_this.getTextValues).then(callback);
};
return _this;
}
_createClass(TimelyQueryCtrl, [{
key: 'targetBlur',
value: function targetBlur() {
this.errors = this.validateTarget();
this.refresh();
}
}, {
key: 'getTextValues',
value: function getTextValues(metricFindResult) {
return _.map(metricFindResult, function (value) {
return value.text;
});
}
}, {
key: 'addTag',
value: function addTag() {
if (this.target.filters && this.target.filters.length > 0) {
this.errors.tags = "Please remove filters to use tags, tags and filters are mutually exclusive.";
}
if (!this.addTagMode) {
this.addTagMode = true;
return;
}
if (!this.target.tags) {
this.target.tags = {};
}
this.errors = this.validateTarget();
if (!this.errors.tags) {
this.target.tags[this.target.currentTagKey] = this.target.currentTagValue;
this.target.currentTagKey = '';
this.target.currentTagValue = '';
this.targetBlur();
}
this.addTagMode = false;
}
}, {
key: 'removeTag',
value: function removeTag(key) {
delete this.target.tags[key];
this.targetBlur();
}
}, {
key: 'editTag',
value: function editTag(key, value) {
this.removeTag(key);
this.target.currentTagKey = key;
this.target.currentTagValue = value;
this.addTag();
}
}, {
key: 'closeAddTagMode',
value: function closeAddTagMode() {
this.addTagMode = false;
return;
}
}, {
key: 'addFilter',
value: function addFilter() {
if (this.target.tags && _.size(this.target.tags) > 0) {
this.errors.filters = "Please remove tags to use filters, tags and filters are mutually exclusive.";
}
if (!this.addFilterMode) {
this.addFilterMode = true;
return;
}
if (!this.target.filters) {
this.target.filters = [];
}
if (!this.target.currentFilterType) {
this.target.currentFilterType = 'iliteral_or';
}
if (!this.target.currentFilterGroupBy) {
this.target.currentFilterGroupBy = false;
}
this.errors = this.validateTarget();
if (!this.errors.filters) {
var currentFilter = {
type: this.target.currentFilterType,
tagk: this.target.currentFilterKey,
filter: this.target.currentFilterValue,
groupBy: this.target.currentFilterGroupBy
};
this.target.filters.push(currentFilter);
this.target.currentFilterType = 'literal_or';
this.target.currentFilterKey = '';
this.target.currentFilterValue = '';
this.target.currentFilterGroupBy = false;
this.targetBlur();
}
this.addFilterMode = false;
}
}, {
key: 'removeFilter',
value: function removeFilter(index) {
this.target.filters.splice(index, 1);
this.targetBlur();
}
}, {
key: 'editFilter',
value: function editFilter(fil, index) {
this.removeFilter(index);
this.target.currentFilterKey = fil.tagk;
this.target.currentFilterValue = fil.filter;
this.target.currentFilterType = fil.type;
this.target.currentFilterGroupBy = fil.groupBy;
this.addFilter();
}
}, {
key: 'closeAddFilterMode',
value: function closeAddFilterMode() {
this.addFilterMode = false;
return;
}
}, {
key: 'validateTarget',
value: function validateTarget() {
var errs = {};
if (this.target.shouldDownsample) {
try {
if (this.target.downsampleInterval) {
kbn.describe_interval(this.target.downsampleInterval);
} else {
errs.downsampleInterval = "You must supply a downsample interval (e.g. '1m' or '1h').";
}
} catch (err) {
errs.downsampleInterval = err.message;
}
}
if (this.target.tags && _.has(this.target.tags, this.target.currentTagKey)) {
errs.tags = "Duplicate tag key '" + this.target.currentTagKey + "'.";
}
return errs;
}
}]);
return TimelyQueryCtrl;
}(QueryCtrl));
_export('TimelyQueryCtrl', TimelyQueryCtrl);
TimelyQueryCtrl.templateUrl = 'components/query.editor.html';
}
};
});
//# sourceMappingURL=query_ctrl.js.map
+1
View File
@@ -0,0 +1 @@
{"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
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

+24
View File
@@ -0,0 +1,24 @@
'use strict';
System.register(['./components/config', './components/metrics', './components/authspage'], function (_export, _context) {
"use strict";
var TimelyAppConfigCtrl, MetricsPageCtrl, AuthsPageCtrl;
return {
setters: [function (_componentsConfig) {
TimelyAppConfigCtrl = _componentsConfig.TimelyAppConfigCtrl;
}, function (_componentsMetrics) {
MetricsPageCtrl = _componentsMetrics.MetricsPageCtrl;
}, function (_componentsAuthspage) {
AuthsPageCtrl = _componentsAuthspage.AuthsPageCtrl;
}],
execute: function () {
_export('ConfigCtrl', TimelyAppConfigCtrl);
_export('MetricsPageCtrl', MetricsPageCtrl);
_export('AuthsPageCtrl', AuthsPageCtrl);
}
};
});
//# sourceMappingURL=module.js.map
+1
View File
@@ -0,0 +1 @@
{"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"]}
+41
View File
@@ -0,0 +1,41 @@
{
"type": "app",
"name": "Timely",
"id": "timely-app",
"css": {
"dark": "css/dark.css",
"light": "css/light.css"
},
"info": {
"description": "Timely App",
"author": {
"name": "National Security Agency",
"url": "http://github.com/NationalSecurityAgency"
},
"keywords": ["timely app datasource"],
"logos": {
"small": "img/brand_small.png",
"large": "img/brand_large.png"
},
"links": [
{"name": "Project site", "url": "https://github.com/NationalSecurityAgency/timely"},
{"name": "License & Terms", "url": "https://raw.githubusercontent.com/NationalSecurityAgency/timely/master/LICENSE"}
],
"version": "0.0.3",
"updated": "2016-06-30"
},
"includes": [
{"type": "datasource", "name": "Timely"},
{ "type": "page", "name": "Login", "component": "AuthsPageCtrl", "role": "Viewer", "addToNav": true},
{ "type": "page", "name": "Metrics", "component": "MetricsPageCtrl", "role": "Viewer", "addToNav": true}
],
"dependencies": {
"grafanaVersion": "3.x.x",
"plugins": []
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

+41
View File
@@ -0,0 +1,41 @@
{
"name": "timely-app",
"private": true,
"version": "0.0.2",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/NationalSecurityAgency/timely.git"
},
"author": "",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/NationalSecurityAgency/timely/issues"
},
"devDependencies": {
"babel": "~6.5.1",
"babel-plugin-transform-es2015-for-of": "^6.8.0",
"grunt": "~0.4.5",
"grunt-babel": "~6.0.0",
"grunt-contrib-clean": "~0.6.0",
"grunt-contrib-copy": "~0.8.2",
"grunt-contrib-uglify": "~0.11.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-execute": "~0.2.2",
"grunt-mocha-test": "~0.12.7",
"grunt-systemjs-builder": "^0.2.5",
"load-grunt-tasks": "~3.2.0"
},
"dependencies": {
"ag-grid": "^5.0.2",
"babel-plugin-transform-es2015-modules-systemjs": "^6.5.0",
"babel-preset-es2015": "^6.5.0",
"dynatable": "alfajango/jquery-dynatable#v0.3.1",
"lodash": "~4.0.0"
},
"homepage": "https://github.com/NationalSecurityAgency/timely"
}
+41
View File
@@ -0,0 +1,41 @@
{
"type": "app",
"name": "Timely",
"id": "timely-app",
"css": {
"dark": "css/dark.css",
"light": "css/light.css"
},
"info": {
"description": "Timely App",
"author": {
"name": "National Security Agency",
"url": "http://github.com/NationalSecurityAgency"
},
"keywords": ["timely app datasource"],
"logos": {
"small": "img/brand_small.png",
"large": "img/brand_large.png"
},
"links": [
{"name": "Project site", "url": "https://github.com/NationalSecurityAgency/timely"},
{"name": "License & Terms", "url": "https://raw.githubusercontent.com/NationalSecurityAgency/timely/master/LICENSE"}
],
"version": "0.0.3",
"updated": "2016-06-30"
},
"includes": [
{"type": "datasource", "name": "Timely"},
{ "type": "page", "name": "Login", "component": "AuthsPageCtrl", "role": "Viewer", "addToNav": true},
{ "type": "page", "name": "Metrics", "component": "MetricsPageCtrl", "role": "Viewer", "addToNav": true}
],
"dependencies": {
"grafanaVersion": "3.x.x",
"plugins": []
}
}
@@ -0,0 +1,10 @@
<div class="gf-form-group">
<div class="gf-form">
<span class="gf-form-label width-13">OpenTSDB metrics query</span>
<input type="text" class="gf-form-input" ng-model='ctrl.annotation.target' placeholder="events.eventname"></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-13">Show Global Annotations?</span>
<editor-checkbox text="" model="ctrl.annotation.isGlobal"></editor-checkbox>
</div>
</div>
@@ -0,0 +1,52 @@
<div class="page-header">
<h1>Timely Login</h1>
</div>
<div ng-if="ctrl.datasources.length === 0">
<h4>No Timely datasources are defined.</h4>
<i><a href="datasources/new">Create one</a></i>
</div>
<div ng-repeat="source in ctrl.datasources" ng-init="d=source" ng-controller="AuthsCtrl as actrl">
<div class="gf-box">
<div class="gf-box-header p-x-1 p-y-1">
<h3 class="">{{d.name}}
<span class="pull-right">
<h6><i>https://{{d.jsonData.timelyHost}}:{{d.jsonData.httpsPort}}/login</i></h6>
</span>
</h3>
</div>
<div class="gf-box-body">
<div ng-if="d.jsonData.basicAuths" class="p-b-1">
<div class="gf-form">
<span class="gf-form-label width-7">
User
</span>
<input id="timlely-user" class="gf-form-input max-width-21" type="text" ng-model='actrl.basicAuthUser' placeholder="user" required></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-7">
Password
</span>
<input id="timely-password" class="gf-form-input max-width-21" type="password" ng-model='actrl.basicAuthPassword' placeholder="password" required></input>
</div>
</div>
<div ng-if="actrl.fetching" class="gf-row">
<div class="alert-{{actrl.fetching.status}} alert">
<div class="alert-title">{{actrl.fetching.title}}</div>
</div>
</div>
<div class="gf-form-button-row center-block">
<button type="submit" class="btn btn-success" ng-click="actrl.login(d)">
Login
</button>
</div>
</div>
</div>
</div>
@@ -0,0 +1,97 @@
import _ from 'lodash';
export class AuthsCtrl {
constructor(backendSrv, $rootScope, $timeout){
this.$rootScope = $rootScope;
this.$timeout = $timeout;
this.backendSrv = backendSrv;
}
login(datasource){
this.fetching = {};
this.fetching.done = false;
this.fetching.show = true;
this.fetching.status = 'warning';
this.fetching.title = 'Fetching auths...';
//this.$rootScope.appEvent('alert-success', ['Authorization Cookie Received', '']);
//this.$rootScope.appEvent('alert-error', ['Authorization Failed', '']);
//this.$rootScope.appEvent('alert-warning', ['Fetching Authorizations', '']);
var uri = this._getURI(datasource.jsonData);
if(datasource.jsonData.basicAuths){
if( this.basicAuthUser && this.basicAuthPassword){
var authBlob = {username: this.basicAuthUser, password: this.basicAuthPassword};
this.doPostLogin(uri, authBlob);
} else {
this.$rootScope.appEvent('alert-warning', [datasource.name, 'requires User/Password']);
this.fetching.status = 'warning';
this.fetching.title = 'User/Password required';
return;
}
} else {
this.doGetLogin(uri);
}
}
doPostLogin(uri, authBlob){
this.doXHR('POST', uri, authBlob);
}
doGetLogin(uri){
this.doXHR('GET', uri)
}
doXHR(verb, uri, data){
if( !data){
data = "";
}
var r = new XMLHttpRequest();
r.open(verb, uri, true);
r.withCredentials = true;
r.setRequestHeader('Content-Type', 'application/json');
r.onreadystatechange = function () {
this.handleLoginResult(r);
}.bind(this);
r.send(JSON.stringify(data));
}
handleLoginResult(response){
// wait for readyState to be '4 => done'
if (response.readyState != 4) return;
this.fetching.done = true;
switch(response.status){
case 200:
var cookie = (document.cookie.match(/^(?:.*;)?TSESSIONID=([^;]+)(?:.*)?$/)||[,null])[1]
console.log(cookie);
console.log(document.cookie);
this.fetching.status = 'success';
this.fetching.title = 'Login successful';
this.$rootScope.appEvent('alert-success', ['Success', '']);
break;
default:
this.fetching.status = 'warning';
this.fetching.title = response.statusText;
this.$rootScope.appEvent('alert-warning', [response.status+': '+response.statusText,'']);
break;
}
if (r.readyState != 4 || r.status != 200) return;
alert("Success: " + r.getResponseHeader('Set-Cookie'));
}
_getURI(jsonData){
return 'https://'+jsonData.timelyHost+':'+jsonData.httpsPort+'/login'
}
_showResults(){
}
}
@@ -0,0 +1,32 @@
import _ from 'lodash';
import {coreModule, appEvents} from 'app/core/core';
import {AuthsCtrl} from 'plugins/timely-app/components/auths';
export class AuthsPageCtrl {
constructor(backendSrv, datasourceSrv){
this.datasourceSrv = datasourceSrv;
this.datasources = this.getTimelyDatasources();
coreModule.controller('AuthsCtrl', AuthsCtrl);
}
getTimelyDatasources(){
var allSources = this.datasourceSrv.getAll();
var sources = _.map(allSources, function(value, key, col){
var ret = {};
ret.meta = {};
ret.meta.type = col[key].meta.type;
ret.meta.id = col[key].meta.id;
ret.name = key;
ret.jsonData = col[key].jsonData;
return ret;
});
return _.filter(sources, function(d){
return (d.meta.type === 'datasource' && d.meta.id === 'timely-datasource');
});
}
}
AuthsPageCtrl.templateUrl = 'components/auths.html';
@@ -0,0 +1,10 @@
<h3 class="page-heading">Timely App Configuration</h3>
<div class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form">
<span class="gf-form-label">Currently, all configuration is done in the Timely datasource.</span>
</div>
</div>
</div>
@@ -0,0 +1,9 @@
export class TimelyAppConfigCtrl {
constructor() {
}
}
TimelyAppConfigCtrl.templateUrl = 'components/config.html';
@@ -0,0 +1,53 @@
<div class="page-header">
<h1>Metrics Browser</h1>
</div>
<div ng-hide="ctrl.hasDatasource" >
<h4>No Timely datasources are defined.</h4>
<i><a href="datasources/new">Create one</a></i>
</div>
<div class="gf-box" ng-show="ctrl.hasDatasource">
<div class="gf-box-header">
<div class="gf-form-inline">
<div class="gf-form max-width-30">
<span class="gf-label width-7 p-y-1 p-x-1">Datasource</span>
<div class="gf-form-select-wrapper gf-form-select-wrapper--has-help-icon max-width-24">
<select class="gf-form-input"
ng-model="ctrl.source"
ng-options="d.name for d in ctrl.datasources"
ng-change=ctrl.updateDatasource()></select>
<info-popover mode="right-absolute">
Select a Datasource<br>
</info-popover>
</div>
</div>
</div>
</div>
<div class="gf-box-body">
<div class="grafana-options-table">
<div class="gf-form width-20 pull-right">
<input type="text" class="gf-form-input" placeholder="filter" ng-model="searchText">
</input>
</div>
<table>
<tr>
<th>Metric</th>
<th>Tags</th>
</tr>
<tr ng-repeat="metric in ctrl.metrics | filter:searchText">
<td>{{metric.metric}}</td>
<td class="p-x-1" ng-repeat="tag in metric.tags">
{{tag.name}} = {{tag.values}}
</td>
</tr>
</table>
</div>
</div>
</div>
@@ -0,0 +1,76 @@
import _ from 'lodash';
import {AuthsPageCtrl} from 'plugins/timely-app/components/authspage';
export class MetricsPageCtrl {
constructor(backendSrv, datasourceSrv){
this.hasDatasource = false;
this.backendSrv = backendSrv;
var apc = new AuthsPageCtrl(backendSrv, datasourceSrv);
this.datasources = apc.getTimelyDatasources();
if( this.datasources.length > 0){
this.source = this.datasources[0];
this.updateDatasource();
}
}
updateDatasource(){
this._clearMetrics();
var uri = this._getURI(this.source.jsonData);
this.backendSrv.request(
{ method: 'GET',
url: uri,
withCredentials: true,
params: "" }
).then(
response => {
this.metrics = this._transformMetrics(response.metrics);
this.hasDatasource = true;
});
}
_clearMetrics(){
this.metrics = [];
}
_transformMetrics(metrics){
var ret = [];
_.each(metrics, function(value, idx){
var metric = {};
metric.metric = value.metric;
metric.tags = [];
_.map(value.tags, function(tag, key){
// result || (result = {});
// result['name'] = tag.key;
// result['values'] || (result['values'] = []);
// result['values'].push(tag.value);
var gIdx = _.findIndex(metric.tags, {'name': tag.key});
var grouped;
if( gIdx == -1 ){
grouped = {name: '', values: []};
} else {
grouped = metric.tags[gIdx];
}
grouped.values.push(tag.value);
grouped.values = _.sortBy(_.uniq(grouped.values))
grouped.name = tag.key;
if( gIdx > -1 ){
metric.tags[gIdx] = grouped;
} else {
metric.tags.push(grouped);
}
}.bind(metric));
metric.tags = _.sortBy(metric.tags, 'name')
ret.push(metric);
}.bind(ret));
return _.sortBy(ret, 'metric');
}
_getURI(jsonData){
return 'https://'+jsonData.timelyHost+':'+jsonData.httpsPort+'/api/metrics'
}
}
MetricsPageCtrl.templateUrl = 'components/metrics.html';
Loaded 100 of 371 files, more files were not shown because too many files have changed in this diff. Show more