Compare commits

..
451 Commits
Author SHA1 Message Date
Dave Marion c5da744883 Minor edits 2016-10-26 16:40:54 -04:00
Dave Marion ebc35e5c63 Updating documentiaton for 0.0.3 release 2016-10-24 15:46:33 -04:00
Dave Marion 3e49716525 for #75 - Update documentation to UDP protocol, commons collections4 on the tservers, release notes 2016-09-29 15:41:30 -04:00
Brian Loss b47668f277 Update documentation to reflect the change to Spring Boot configuration (re #75) 2016-09-29 10:23:01 -04:00
Jim Klucar eb45592f90 updated grunt info 2016-08-05 11:13:20 -04:00
Dave Marion 7ad726a551 re #56, update docs for changes to web socket API 2016-08-02 10:47:57 -04:00
klucar 87a3b43b13 fixed some links, added some words 2016-07-26 13:54:34 -04:00
klucar b13bd4c65d interleaved operation and responses 2016-07-26 13:34:54 -04:00
klucar 5a5c539688 interleaved operation and responses 2016-07-26 13:31:35 -04:00
Dave Marion 465223cdb6 Updated docs 2016-07-25 12:46:14 -04:00
Dave Marion 99e4e93603 Still need the commons-lang3 jar on the Accumulo Tablet Servers 2016-07-25 11:24:17 -04:00
Dave Marion 193c9f2c5b More doc changes, added collectd and examples 2016-07-22 14:48:04 -04:00
Klucar 8490e9cbc6 updated grafana build instructions 2016-07-22 13:01:58 -04:00
Klucar aa08e5df03 updated logo 2016-07-22 13:01:42 -04:00
Klucar 053017ba39 instructions to compile grafana app 2016-07-22 11:42:41 -04:00
Dave Marion 6f188b3473 Modified some CSS items 2016-07-21 15:22:02 -04:00
Dave Marion b27b3c3e52 Add Grafana docs 2016-07-21 14:26:17 -04:00
Dave Marion b2330262bd more doc changes 2016-07-20 14:26:16 -04:00
Dave Marion 0702fa3d47 wip 2016-07-19 15:57:48 -04:00
Dave Marion 813d8e5d28 Trying to get rid of the README 2016-07-19 11:42:48 -04:00
Dave Marion e63f41a20c wip 2016-07-15 07:38:42 -04:00
Dave Marion 9d7ca484e3 wip 2016-07-14 12:14:53 -04:00
Dave Marion bb787fc8ca wip 2016-07-14 09:09:35 -04:00
Robert Lord 6dd96e1c15 Bump CHANGELOG 2016-06-11 09:51:34 -05:00
Robert Lord a68507a00e Remove CONTRIBUTING 2016-06-11 09:50:23 -05:00
Robert Lord 8d3eb0a433 Update readme 2016-06-11 09:49:56 -05:00
Robert Lord e9384ed058 Add issue template 2016-06-10 22:05:39 -05:00
Robert Lord 31e021a01f Add PR template 2016-06-10 21:58:16 -05:00
Robert Lord ad752cd538 Update rouge languages link in README 2016-06-10 17:23:21 -05:00
Robert Lord ed6578ca73 Merge pull request #511 from Jameskmonger/patch-1
Add JavaScript examples
2016-05-24 09:33:49 -05:00
Robert Lord 1e54d1dd41 Merge pull request #464 from BaButtons/patch-1
Address #463
2016-05-24 00:09:57 -05:00
James Monger cec5d662ad Add JavaScript examples 2016-04-21 11:38:08 +01:00
Robert Lord f380e4c203 Note the need for an upgraded Ruby 2016-03-08 16:23:19 -06:00
Robert Lord 19d651a65a Add link to wiki 2016-03-01 20:46:01 -06:00
Robert Lord 13b113d1a5 Merge branch 'master' into dev 2016-03-01 20:44:01 -06:00
Robert Lord 979aaa91d5 Fixes #440, version 1.3.2 2016-03-01 20:43:54 -06:00
BaButtons b84d76cd83 Add deploy configuration with a port set option
Addressing tripit/slate#463
2016-02-25 15:23:17 -05:00
Robert Lord 6a8c406f56 Merge pull request #454 from pra85/patch-2
Minor English Tweak
2016-02-11 16:42:51 -06:00
Prayag Verma 30c270c029 Minor English Tweak
Replace `a` with `an`
2016-02-10 23:47:10 +05:30
Robert Lord 28066ed281 Fixes #440, version 1.3.2 2016-02-03 16:19:16 -06:00
Robert Lord 6e37ca292f Add changelog for 1.3.1 2016-01-31 12:42:35 -06:00
Robert Lord db48d22661 Fix broken word break styles 2016-01-31 12:41:11 -06:00
Tariq Islam 365a0b58ea Merge pull request #435 from tripit/dev
Thanks @lord and everyone contributing! Slate v1.3 ftw!
2016-01-29 16:16:13 -08:00
Robert Lord d4bd994f03 Add version notes 2016-01-27 17:07:02 -06:00
Robert Lord 1c5bd80d4b Add travis script 2016-01-27 16:50:19 -06:00
Robert Lord d6a7b5ff97 Small readme improvement 2016-01-27 16:48:16 -06:00
Robert Lord ac9cb0aef9 Remove Rake 2016-01-27 16:41:30 -06:00
Robert Lord d88d714d90 Make deploy script executable 2016-01-27 16:36:01 -06:00
Robert Lord ffa2829fe5 Add deploy script 2016-01-27 16:35:39 -06:00
Robert Lord b5c6495662 Fix travis bugs 2016-01-27 16:30:19 -06:00
Robert Lord 471c19a7c0 Remove docker 2016-01-27 15:53:28 -06:00
Robert Lord 1d108d0f40 Update Vagrant to work properly 2016-01-27 15:50:34 -06:00
Robert Lord 7f1d6da6dc Remove last inline script 2016-01-27 02:00:01 -06:00
Robert Lord a4b9208af0 Move jquery to be local 2016-01-27 01:37:16 -06:00
Robert Lord 9f83bbd158 Add comment about middleman hanging to config.rb 2016-01-27 01:18:58 -06:00
Robert Lord 5c87f10383 Fix non-wrapping code in firefox 2016-01-27 00:53:24 -06:00
Robert Lord ccd158df4f Add code block warning 2016-01-27 00:45:32 -06:00
Robert Lord 20d94974fa Add parrot link 2016-01-26 18:41:22 -06:00
Eric Caron 4f5443ce06 It should have be it. It wasn't it. It was its. 2016-01-26 15:54:36 -06:00
Eric Caron 79bb28c2f8 README copy-editing changes Applying the copy-editing changes noticed by Ira Brooker (@IOB1979) to the current master branch 2016-01-26 15:54:36 -06:00
Robert Lord 8cba352315 Add lang-specific class 2016-01-26 15:39:37 -06:00
Robert Lord 884cda666a Update readme 2016-01-26 13:10:36 -06:00
Robert Lord c0dddf7560 Improve contribution guidelines 2016-01-26 13:03:37 -06:00
Robert Lord 44cf741f01 Add new logo 2016-01-26 12:55:22 -06:00
Robert Lord 63e3e30bc5 Update readme styling again 2016-01-26 12:53:06 -06:00
Robert Lord b6084cfd0a Update readme styling 2016-01-26 12:52:42 -06:00
Robert Lord 02428eb687 Ignore .sass-cache 2016-01-26 12:52:33 -06:00
Robert Lord 7f88aafcba Upgrade to middleman 4 2016-01-26 12:52:03 -06:00
Robert Lord f4dea9008d Merge branch 'master' into dev 2016-01-26 12:07:22 -06:00
Robert Lord e1026d921c Merge pull request #428 from tinybike/master
Added Augur API to examples
2016-01-17 17:35:19 -06:00
Jack Peterson 35690907be Added Augur API to examples 2016-01-17 14:34:19 -08:00
Robert Lord 3ad0542fc7 Merge pull request #420 from netbe/fix-doc-docker
Update Boot2docker information for OSX
2016-01-08 23:46:11 -06:00
François Benaiteau 65c3dbd544 Update Boot2docker information for OSX 2016-01-08 12:31:33 +01:00
Robert Lord bc8ac808b4 Merge pull request #419 from blackxored/better-docker-support
Better docker support
2016-01-02 14:29:48 -06:00
Adrian Perez 75f61557a2 fix(docker): new middleman requires JS runtime 2016-01-02 01:51:06 +01:00
Adrian Perez f90e6b076d feat(docker): improve docker support
This improves Docker support in the following ways:

* Base image off `ruby:onbuild` to avoid unnecessary custom steps and ease
derived images.
* Adds `.dockerignore` to avoid sending large files to build.
* Adds a `docker-compose.yml` so users can simply type `docker-compose up`
to get it running.
* Explicity sets the volume definition in the `Dockerfile`.
* Volume is automatically mount by `docker-compose` (the `source` directory
relative to the project's dir).
* Workaround watcher failing to pick directory changes probably because of
vboxsf and the `listen` gem failing to register filesystem changes.
* Updates documentation.
2016-01-02 00:51:00 +01:00
Robert Lord 47cca3d8e7 Merge pull request #411 from zachpanz88/patch-1
Change cat name
2015-12-20 14:03:15 +08:00
Zach Panzarino 837a7e7873 Change cat name
After recent events it is probably better to use a different name for the cat.
2015-12-18 22:51:49 -05:00
Robert Lord b871b44b72 Merge pull request #399 from ReadmeCritic/patch-1
Update README URLs based on HTTP redirects
2015-12-08 18:55:30 -08:00
ReadmeCritic 97a4c89d0c Update README URLs based on HTTP redirects 2015-12-08 12:22:18 -08:00
Robert Lord 8e14f805dc Merge pull request #387 from jaredtking/invoiced
Added Invoiced to list of examples on README
2015-11-18 12:45:31 -06:00
Jared King 82717e043d Added Invoiced to list of examples on README 2015-11-18 11:10:10 -06:00
Robert Lord 018a6939db Merge pull request #385 from agonzalezro/docker-fix
Use base ruby image in Dockerfile & fix watcher
2015-11-17 15:17:50 -06:00
Álex González 2618c77db0 Use base ruby image in Dockerfile & fix watcher
It seems that the watcher will not work without the
--force-polling option.
2015-11-17 13:53:34 +01:00
Robert Lord c9d8d34e79 Merge pull request #384 from evantahler/master
add actionhero docs
2015-11-16 14:35:40 -06:00
Evan Tahler 40443b32fd Update README.md
add actionhero docs
2015-11-16 10:53:18 -08:00
Robert Lord 1151d00926 Merge pull request #380 from detain/master
Added Links to InterServer Slate Implementation
2015-11-13 18:13:28 -06:00
Joe Huss c76359868a Added Links to InterServer Slate Implementation
URL: https://my.interserver.net/apidoc/

Our implementation includes some minor customizations which others mind fight useful including icons for the Language tabs at the top right.

Side Note: The document contents including sample scripts , input/output parameter+descriptions, etc are generated entirely from a script i wrote that parses my SOAP API WSDL file, PHP Source (parsing phpdoc comments), and MySQL Table defintions (parsing field comments) to generate and populate all the neccesary info. At some point (faster if i have any requests for it ) ill make those scripts publicly available after i clean up the source a bit and make it more portable.
2015-11-12 01:01:14 -05:00
Robert Lord 964c25a36b Merge pull request #371 from djpowers/fix-broken-examples
Fix broken examples
2015-11-05 16:58:26 -06:00
Dave Powers 1e86f824af Fix link to BlockCypher (does not work over HTTPS) 2015-11-05 09:41:24 -05:00
Dave Powers 01fd02005a Fix link to IBM Cloudant (page has moved) 2015-11-05 09:39:07 -05:00
Dave Powers fb4c2a9ceb Remove link to ChaiOne Gameplan (broken link) 2015-11-04 14:15:23 -05:00
Robert Lord ecdce169bc Merge pull request #365 from mflaxman/patch-1
Add blockcypher to examples
2015-10-22 16:18:37 -05:00
Michael Flaxman f0a8dec91c Add blockcypher to examples 2015-10-22 12:35:29 -04:00
Robert Lord e9cfc6bf3c Merge pull request #354 from rexposadas/fix-docker-error
upgraded to wily to remove error from version trusty
2015-10-11 20:25:45 -05:00
Rex Posadas 150ff8a800 upgraded to later ubuntu wily to remove error from version trusty 2015-10-11 14:57:44 -05:00
Robert Lord 727ac193ab Merge pull request #350 from sproutbox/dev
Basic Vagrant support. Close #348
2015-10-08 22:00:48 -05:00
Marc Guyer 3c1c9c49d5 Add local git config to guest vm 2015-10-08 14:09:27 +00:00
Marc Guyer 4a3fdfaea2 Update Vagrantfile
More memory needed for `rake publish`
2015-10-06 17:21:17 -04:00
Marc Guyer ce2f2ae8de Update Vagrantfile
Need git for `rake publish`
2015-10-06 17:12:55 -04:00
Marc Guyer 4136f7b0f7 Formatting fixes for README 2015-10-06 16:48:51 -04:00
Marc Guyer dc45e382ce Merge remote-tracking branch 'upstream/dev' into dev 2015-10-06 16:43:01 -04:00
Marc Guyer 57aa27c0eb Basic support for Vagrant 2015-10-06 16:41:22 -04:00
Robert Lord 236ca52c93 Merge branch 'master' into dev 2015-10-06 12:19:59 -05:00
Robert Lord 787eb795b6 Merge pull request #344 from realityking/hostingDe
Add hosting.de API docs to the list
2015-09-30 14:38:46 -05:00
Rouven Weßling e0cdc7339e Add hosting.de API docs to the list 2015-09-30 17:56:34 +02:00
Robert Lord fd27069a2d Merge pull request #339 from axsemantics/master
make middleman pick up changes when run in docker
2015-09-28 12:32:44 -05:00
Andreas Madsack fcea9014d2 mount volume for live changes to Dockerfile 2015-09-28 17:03:48 +02:00
Robert Lord 9e42fbb04c Merge pull request #335 from brettporter/patch-1
Add SafetyCulture API to the list
2015-09-23 00:16:18 -05:00
Brett Porter 1c508a738f Add SafetyCulture API to the list 2015-09-23 15:09:13 +10:00
Robert Lord 7078f7f6e8 Merge pull request #331 from pomier/fix-dockerfile
Fix Dockerfile by installing nodejs
2015-08-27 19:57:34 -04:00
Romain Pomier 92d732f8a4 Install nodejs in Dockerfile to replace therubyracer 2015-08-27 11:09:28 +02:00
Robert Lord c90eab79f9 Merge pull request #327 from victorquinn/master
Add SocialRadar to the list of docs sites using Slate
2015-08-13 17:15:06 -04:00
Victor Quinn 977f2568d7 Fix path to iOS docs 2015-08-13 16:44:05 -04:00
Victor Quinn ed9e958df7 Add SocialRadar to the list of docs sites using Slate 2015-08-13 15:54:18 -04:00
Robert Lord 22ffeba825 Merge pull request #324 from gabrielf/patch-2
Use HTTPS for github urls.
2015-08-08 09:48:37 -07:00
Gabriel Falkenberg 5d27eaf9cf Use HTTPS for github urls. 2015-08-08 17:23:29 +02:00
Robert Lord 07c5ccefc0 Merge pull request #319 from dlackty/update-gems
Update gems
2015-08-06 07:26:01 -07:00
Richard Lee 47e18611f2 Update other dependencies 2015-08-06 18:40:17 +08:00
Richard Lee 83d655b55e Update rouge and middleman-autoprefixer 2015-08-06 16:58:57 +08:00
Robert Lord d4e94080d4 Merge pull request #318 from dlackty/remove-therubyracer-dev
Remove therubyracer in favor of system JS runtimes
2015-08-05 11:16:19 -07:00
Richard Lee befb8d6fac Remove therubyracer 2015-08-05 23:31:44 +08:00
Robert Lord b0e0192374 Merge pull request #316 from daudich/f/supporkit-doc-example
adding supporkit docs as an example
2015-08-05 08:25:12 -07:00
Dhiren Audich 87a2950ade adding supporkit docs as an example of the slate docs 2015-08-05 11:04:29 -04:00
Robert Lord eb1c0db712 Merge pull request #313 from pbechu/patch-1
Add Aircall.io to README
2015-08-04 09:50:02 -07:00
Pierre-Baptiste Béchu 5e605079eb Add Aircall.io to README 2015-08-04 02:42:21 -07:00
Robert Lord ebc8810d65 Merge pull request #309 from sibrus/dev
Improved the appearance of code blocks when printing.
2015-07-29 14:35:00 -07:00
Ivan Matyunin 5cfcbc7f7b Improved the appearance of code blocks when printing. 2015-07-29 16:50:28 -04:00
Tariq Islam adeb496a88 Merge pull request #292 from tripit/dev
Slate 1.2.1
@lord my fault, I seemed to have totally missed the emails sent!
2015-07-27 12:33:43 -07:00
Robert Lord b9d45b2185 Merge pull request #303 from rezanachmad/patch-1
Add OAuth.io to README
2015-07-16 09:18:37 -07:00
Rezan Achmad 0c37f0dfc4 Add OAuth.io to README 2015-07-16 15:09:59 +08:00
Robert Lord ad3b2769fe Update tocify to recache headers on image load, fixes #293 2015-07-06 18:54:45 -07:00
Robert Lord 2e22c87c1b Merge pull request #290 from niftylettuce/patch-1
Added new in the wild link I made
2015-07-02 07:55:16 -07:00
niftylettuce 7639ce60bc Update README.md 2015-07-02 03:04:14 -04:00
Robert Lord ae3d50277e Update RedCarpet gem 2015-06-28 12:44:12 -07:00
Robert Lord dcc563b406 Merge pull request #288 from johnf/patch-1
Fix Changelog date
2015-06-28 12:34:24 -07:00
John Ferlito f3591651f1 Fix Changelog date
Version 1.2 was released in 2015 not 2014
2015-06-27 16:33:07 +10:00
Tariq Islam 7f873ca9e0 Merge pull request #281 from tripit/dev
Slate v1.2
holy moly that's a lot of changes! 👍
2015-06-22 04:29:59 -07:00
Robert Lord 415dcf2c90 Add changes to log from v1.2 2015-06-20 01:54:06 -04:00
Robert Lord fd5cba00f0 Fix small bug with new language tabs 2015-06-20 01:53:20 -04:00
Robert Lord d14fd0f70e Update language tabs to not disturb existing query strings, fixes #57 2015-06-20 01:49:25 -04:00
Robert Lord bb24528f85 Update gems 2015-06-20 01:04:02 -04:00
Robert Lord 872550d0b7 Update h3 fonts to work better for chinese, fixes #214 2015-06-20 00:48:56 -04:00
Robert Lord a15a6ba1b1 Merge pull request #189 from realityking/fonts
Improvements for the icon font
2015-06-20 00:17:27 -04:00
Robert Lord be57777a3d Add chinese fonts, thanks to @JayMiao 2015-06-20 00:05:46 -04:00
Robert Lord 1fe3ce6396 Update lord.io link to https 2015-06-19 23:33:54 -04:00
Robert Lord 203bc79211 Merge pull request #276 from rezanachmad/master
Update README.md with link to Fidor Bank
2015-06-16 10:36:10 -04:00
Rezan Achmad 685b1554e9 Update README.md with link to Fidor Bank 2015-06-16 14:47:17 +07:00
Robert Lord 1eac62fd59 Merge pull request #273 from akilb/patch-1
Update README with link to viagogo API docs
2015-06-10 15:00:10 -07:00
Akil Burgess 48c514abc7 Update README with link to viagogo API docs 2015-06-10 22:48:22 +01:00
Robert Lord 8ab0ed7b24 Merge pull request #265 from realityking/unusedjs
Remove some unused JS.
2015-06-02 20:32:20 -05:00
Rouven Weßling a38011b4a5 Remove some unused JS. 2015-06-02 23:02:41 +02:00
Robert Lord 1f4e6b915d Merge pull request #264 from realityking/fix
Fix minor SCSS issues introduced in #262.
2015-06-01 17:15:11 -05:00
Rouven Weßling 402f931fc9 Fix minor SCSS issues introduced in ab816e432a. 2015-06-01 23:27:03 +02:00
Robert Lord 6d6c3e6070 Merge pull request #263 from realityking/js
Don't generate unnecessary JS files.
2015-05-31 19:54:38 -05:00
Robert Lord 2e8be87224 Merge pull request #262 from realityking/autoprefixer
Use Autoprefixer for vendor prefixes
2015-05-31 19:53:49 -05:00
Rouven Weßling b7e65975b0 Add WOFF2 version of the icon font 2015-06-01 00:38:54 +02:00
Rouven Weßling d27f5c4b7d Remove unused icons from the font 2015-06-01 00:38:54 +02:00
Rouven Weßling 384ffac2fd Don't generate unnecessary JS files.
Also exclude jquery.highlight from the nosearch version, as it's not needed there.
2015-06-01 00:29:57 +02:00
Rouven Weßling ab816e432a Use Autoprefixer for vendor prefixes 2015-06-01 00:11:21 +02:00
Robert Lord 99ee16e359 Merge pull request #261 from realityking/rouge
Update rouge to version 1.9.0
2015-05-31 16:14:17 -05:00
Rouven Weßling 3a53a3c029 Update rouge to version 1.9.0 2015-05-31 20:20:58 +02:00
Robert Lord 67263d8db4 Merge pull request #259 from kohenkatz/patch-1
Consistency fixes
2015-05-28 22:07:56 -05:00
MK 06c1641ad1 Consistency fixes
as discussed on commit 84b7705fd1
2015-05-28 18:41:56 -04:00
Robert Lord 234d1e197d Merge pull request #251 from Maks3w/feature/travis-cache
Feature/travis cache
2015-05-19 19:07:59 -05:00
Robert Lord 22e8e480e5 Merge pull request #253 from Maks3w/feature/rake-clobber
Add "rake clobber" for to remove generated files
2015-05-19 19:07:29 -05:00
Robert Lord 22fc8af88c Merge pull request #252 from Maks3w/hotfix/secure-rubygems
Hotfix/secure rubygems
2015-05-19 15:37:39 -05:00
Maks3w bdebff8250 Add "rake clobber" for to remove generated files 2015-05-18 16:33:31 +02:00
Maks3w d0e46a3894 [Travis-CI] Enable bundler cache 2015-05-18 10:26:22 +02:00
Maks3w d7769c653d [Travis-CI] Specify language to test is ruby 2015-05-18 10:25:21 +02:00
Maks3w 094c38223e [Travis-CI] Use docker build infraestructure 2015-05-18 10:25:17 +02:00
Maks3w fddf304087 Use HTTPS for fetch gems 2015-05-18 09:58:08 +02:00
Tariq Islam 452876af0d Merge pull request #239 from tripit/update
Bugfixes merged.
2015-05-01 00:24:21 -07:00
Robert Lord 16dca4d000 Update gems 2015-04-30 16:01:45 -05:00
Robert Lord f989143692 Fix styling bug in example index 2015-04-30 16:01:45 -05:00
Nik Samokhvalov 4fe37604b7 Update README.md 2015-04-30 16:01:44 -05:00
Rouven Weßling 5da237e7fe Don't use a selector to get the heading text for search results.
Prevents bugs with special CSS characters.

Closes #201.
2015-04-30 16:01:44 -05:00
German Attanasio Ruiz 23eb3f433e Update README.md
Adding IBM Cloudant to the example list
2015-04-30 16:01:44 -05:00
Chrisovalantis Kefalidis fd684122dd Specify version for therubyracer gem to 0.12.1 2015-04-30 16:01:19 -05:00
Chrisovalantis Kefalidis 6ea72a13fa Update rake gem to version 10.4.2 2015-04-30 16:01:19 -05:00
Chrisovalantis Kefalidis a91ac15fab Update redcarpet gem to version 3.2.2 2015-04-30 16:01:19 -05:00
Chrisovalantis Kefalidis e14878ff56 Specify version for middleman-syntax gem to 2.0.0 2015-04-30 16:01:19 -05:00
Chrisovalantis Kefalidis 8276ba8ff4 Specify version for middleman-gh-pages gem to 0.0.3 2015-04-30 16:01:19 -05:00
Chrisovalantis Kefalidis ec2415e319 Update middleman gem to version 3.3.10 2015-04-30 16:01:18 -05:00
Chrisovalantis Kefalidis f5b34ba69a Remove middleman-livereload gem 2015-04-30 16:01:18 -05:00
Chrisovalantis Kefalidis c39c82c917 Remove ruby18_source_location gem 2015-04-30 16:01:18 -05:00
Chrisovalantis Kefalidis e3f36f9057 Remove wdm gem 2015-04-30 16:01:18 -05:00
Chrisovalantis Kefalidis a7596ff0a5 Cleanup Gemfile 2015-04-30 16:01:18 -05:00
Chrisovalantis Kefalidis a9d8b9b3b1 Cleanup config.rb 2015-04-30 16:01:18 -05:00
Rouven Weßling c8e7c646dc Optimize images
Saves 26,9% on logo png and a whopping 96,6% on navbar.png
2015-04-30 16:01:18 -05:00
Rouven Weßling 0dac148f95 Update Middleman to version 3.3.9 2015-04-30 16:01:18 -05:00
Rouven Weßling f2ebab9325 Rename SCSS files, so no unnecessary stylesheets are generated. 2015-04-30 16:01:18 -05:00
Rouven Weßling 1d13e198d0 Update normalize.css to version 3.0.2 2015-04-30 16:01:18 -05:00
Rouven Weßling b550f04dae Update jQuery UI to version 1.11.3 2015-04-30 16:01:18 -05:00
Rouven Weßling b1e0ff5d94 Update lunr.js to version 0.5.7 2015-04-30 16:01:17 -05:00
Rouven Weßling 3a236aa81e Update jQuery to version 2.1.3 2015-04-30 16:01:17 -05:00
Rouven Weßling a60fd38cda Use strict mode for JavaScript 2015-04-30 16:01:17 -05:00
Rouven Weßling 6062141cce Update Rouge to Version 1.8 2015-04-30 16:01:17 -05:00
Matthias Kadenbach 506095a1ed Add git to allow rake build 2015-04-30 16:01:17 -05:00
Robert Lord 7452f6b172 Merge pull request #237 from FloorLamp/patch-1
Fix typo
2015-04-30 15:31:56 -05:00
Norton Wang 321a994cdc Fix typo 2015-04-29 18:14:36 -04:00
Robert Lord d82f9707b3 Merge pull request #232 from kpavlov/patch-1
added api example: developers.cardpay.com
2015-04-23 14:21:56 -05:00
Konstantin Pavlov 923add84f6 added api example: developers.cardpay.com 2015-04-23 21:33:40 +03:00
Robert Lord 58bcd3922d Merge pull request #231 from davidstanley01/patch-1
Update of Readme
2015-04-21 21:35:37 -05:00
David Stanley 0bb523732e Update of Readme
Just saw that freaking NASA is using this for docs!
2015-04-21 15:57:48 -07:00
Robert Lord e644e3a5d3 Merge pull request #227 from jordanwalsh23/master
added whispir.io to the list of reference sites
2015-04-21 14:46:41 -05:00
Jordan Walsh 8e0396d7d3 added whispir.io to the list of reference sites 2015-04-21 19:06:15 +10:00
Robert Lord ebfe330a2b Merge pull request #222 from intelliot/patch-1
Add Coinbase to list of examples
2015-04-15 13:28:37 -05:00
Elliot Lee f5dcc4efb8 Add Coinbase to list of examples 2015-04-14 20:24:31 -07:00
Robert Lord 2011c772a1 Merge pull request #216 from switchpayments/master
Added Switch Payments to list of examples.
2015-04-08 19:57:01 -05:00
André Tavares fd2f54b3de Added Switch Payments to list of examples. 2015-04-08 15:17:00 +01:00
Robert Lord 384f8d7b19 Merge pull request #202 from xunzhang/master
"Examples of Slate in the Wild" update in README.md
2015-03-17 13:12:49 -05:00
xunzhang 97f87c9c4a Examples of Slate in the Wild update in README.md 2015-03-17 12:27:07 +08:00
Robert Lord 13b4487a2b Merge pull request #200 from styloa/patch-1
added Crafty Clicks API to Slate in the Wild list
2015-03-12 13:29:58 -05:00
Adam Stylo e619c48a94 added Crafty Clicks API to Slate in the Wild list 2015-03-12 15:55:09 +00:00
Robert Lord b744ba51bb Add @realityking to contributors list 2015-02-24 12:21:37 -06:00
Robert Lord 44a0dafe03 Merge pull request #184 from imaginator/patch-1
Added another "use in the wild"
2015-02-24 12:19:34 -06:00
Simon Tennant dfa162fed5 Take 2 2015-02-24 15:37:39 +01:00
Robert Lord fd1937a3f7 Merge pull request #185 from mehulkar/patch-2
Easy setup with Docker
2015-02-23 16:12:38 -06:00
Mehul Kar 10179a6613 Easy setup with Docker 2015-02-23 11:05:57 -08:00
Simon Tennant 8eada057da Update README.md 2015-02-19 17:23:38 +01:00
Simon Tennant 872c00a894 Update README.md 2015-02-19 16:05:18 +01:00
Tariq Islam bb5c721450 Merge pull request #165 from tripit/dev
Update master, all done, thanks @lord
2015-01-28 05:44:25 -08:00
Robert Lord 7c110ede15 Remove redcarpet header fix, just use vanilla redcarpet IDs 2015-01-23 20:54:24 -06:00
Robert Lord eb5235ff8c Remove outline from lang selector links, add focus style 2015-01-23 20:39:40 -06:00
Robert Lord 5ad521614d Readd parent() selection for code samples 2015-01-23 20:27:55 -06:00
Tariq Islam 73d2997a24 Merge pull request #159 from tripit/dev
Update master. Thanks @lord
2015-01-20 09:51:28 -08:00
Robert Lord 5e89f01652 Merge pull request #157 from swarzech/dev
fixed the rouge gem to fixed an issue with the language tabs
2015-01-15 12:40:54 -06:00
Robert Lord 757cf8ef79 Add note about Windows to Readme 2015-01-15 12:39:39 -06:00
Stefanie Nickerson ddf0346f04 fixed the rouge gem to fixed an issue with the language tabs 2015-01-15 06:42:31 -05:00
Robert Lord 115d04f19e Merge pull request #154 from Codestar/patch-1
Update README.md
2015-01-11 22:26:21 -06:00
Codestar f3eaecc7a9 Update README.md 2015-01-11 15:09:07 +02:00
Robert Lord 04944c9e8f Merge pull request #151 from zdenekdrahos/patch-1
Add RozpisyZapasu to list of examples
2015-01-05 14:52:49 -06:00
zdenekdrahos 868ea757f1 Add RozpisyZapasu to list of examples 2014-12-27 11:47:30 +01:00
Robert Lord be28b785a1 Fix scrollIntoView undefined bug when there is no hash, fixes #114
Thanks to @kevin-buttercoin for this fix!
2014-12-04 15:42:01 -08:00
Robert Lord 902ddd7fdc Update gems again 2014-12-04 15:39:17 -08:00
Tariq Islam c665bb4e8f Merge pull request #143 from tripit/dev
Fix some bugs, clean up, and readme changes.

Thanks @lord!
2014-12-04 12:40:45 -08:00
Robert Lord 14a9aac0fc Clarify auto-update info in readme 2014-11-13 21:28:00 -06:00
Robert Lord c74bf7b50e Merge pull request #131 from dmyers/text-shadow
Changed text shadows to use mixin
2014-11-13 14:53:35 -06:00
Derek Myers 2828342821 Changed text shadows to use mixin 2014-11-12 14:14:20 -06:00
Robert Lord 482f0b9979 Update language tabs to recalc toc heights on change 2014-11-05 20:56:48 -06:00
Tariq Islam 058429a9fd Merge pull request #124 from tripit/dev
Update gems and new markup styling issue.

All done, thanks Robert!
2014-11-04 22:31:35 -08:00
Robert Lord 77cdc3fc66 Update gems and new markup styling issue 2014-11-02 13:42:41 -06:00
Robert Lord 5e649aa91a Merge pull request #120 from Dwolla/add-dwolla-to-examples
add Dwolla to list of examples
2014-10-24 13:48:04 -05:00
Gordon Zheng a01287460a add Dwolla to list of examples 2014-10-24 00:39:21 -04:00
Robert Lord 3530073f2e Merge pull request #116 from xmo-odoo/patch-1
Fix Python examples
2014-10-14 13:47:00 -05:00
xmo-odoo 39dc7095f7 Fix Python examples 2014-10-14 12:00:40 +02:00
Tariq Islam 28b58aed86 Merge pull request #115 from tripit/dev
Small Docs Updates
2014-10-09 23:59:45 -07:00
Robert Lord ae07d2f6d2 Update contribution guidelines 2014-10-10 00:51:33 -05:00
Joel Richards ef4da2a0c0 Remove orchestrate.io from examples 2014-10-10 00:51:33 -05:00
fermayo f00be01caf added Dockerfile 2014-10-10 00:51:03 -05:00
Robert Lord ed5fa1b75c Merge pull request #113 from kevin-buttercoin/master
fixed XSS vuln in searchbox
2014-10-09 19:05:30 -05:00
Kevin Adams b1256f4800 changed to use jQuery text method 2014-10-09 14:59:06 -07:00
Kevin Adams b40b3b47ed fixed XSS vuln in searchbox 2014-10-08 16:38:46 -07:00
Robert Lord 9c7ea33305 Merge pull request #110 from sobstel/master
Add another example of slate (golazon).
2014-10-05 14:31:43 -05:00
Przemek Sobstel ff7f3c6708 Add another example of slate (golazon). 2014-10-05 12:08:22 +02:00
Tariq Islam bd6865585c Merge pull request #104 from klysium/patch-1
Update README.md

Thanks for the update, and using Slate!
2014-08-21 11:32:35 -07:00
Kennedy c59addd90e Update README.md
added mozilla's recroom
2014-08-21 13:56:35 -04:00
Tariq Islam 1f438aaea6 Merge pull request #103 from tripit/dev
Slate 1.1
2014-08-13 09:08:41 -07:00
Robert Lord 8e7b03b64e Upgrade redcarpet, fix header patch, fixes #92 2014-07-27 23:21:24 -07:00
Robert Lord 82a99d5537 Increase line height for new font, add quotes around fonts 2014-07-17 09:41:10 -07:00
Robert Lord 3c36233e6b Merge pull request #95 from samdozor/dev
Changing the code font-family to prefer Menlo/Consolas over Monaco
2014-07-17 09:37:42 -07:00
Sam Dozor 54e4408d8c Changing the code-font font-family to prefer Menlo and Consolas over Monaco, and adding more back-up fonts. 2014-07-16 16:53:38 -04:00
Robert Lord 965156d54b Merge pull request #94 from moizjv/updateappium
Adding appium docs to examples
2014-07-14 22:34:58 -07:00
Moiz Virani f1d92f01dd Adding appium docs to examples 2014-07-14 14:33:06 -07:00
Robert Lord 052036b0c2 Fix incorrect header nesting in redcarpet patch
Spotted by @moizjv, thanks!
2014-07-09 22:41:31 -07:00
Tariq Islam c5381c62af Merge pull request #90 from tripit/dev
Version 1.0
2014-07-08 12:56:19 -07:00
Robert Lord 60d1dbd37d Update search results to scroll, remove initial dummy text 2014-07-03 00:11:02 -07:00
Robert Lord 512b57d799 Update CHANGELOG.md 2014-07-03 00:05:23 -07:00
Robert Lord 395502b152 Add changelog 2014-07-03 00:01:48 -07:00
Robert Lord 18cd104883 Add better search results in a sliding search results area 2014-07-02 23:43:25 -07:00
Robert Lord 51e537aca2 Simplify embossed tocify styles, in preperation for search 2014-07-02 23:38:17 -07:00
Robert Lord 1b1427c3ee Add placeholder to search box 2014-07-02 22:46:14 -07:00
Robert Lord 324da17ba3 Fix bugs with toc not highlighting, begin search overhaul 2014-07-02 22:34:58 -07:00
Robert Lord 719061a638 Update headers to never have problematic characters in ids, fixes #64, hopefully 2014-06-24 22:34:25 -07:00
Robert Lord e8a491c9ea Fix unrecognized .highlight. bug #84 2014-06-24 01:03:39 -07:00
Robert Lord 0f89c96ba0 Remove extra 'also' from README 2014-06-23 23:16:58 -07:00
Robert Lord d552a1b5cb More readme changes 2014-06-23 23:15:31 -07:00
Robert Lord 1bb564f84a Shuffle readme, add link to myself 2014-06-23 23:14:37 -07:00
Robert Lord f868ff0bcf Revert to old versions of gems, until codeblock-messing up reason is identified 2014-06-22 03:14:38 -07:00
Robert Lord d1fdd685a6 Fix default language selection bug 2014-06-22 03:10:26 -07:00
Robert Lord 0f93ffcc2b More js cleanup for #80 2014-06-22 02:41:16 -07:00
Robert Lord bdbd7a38a8 Update app javascript to pass jslint, fixes #80 2014-06-22 02:37:01 -07:00
Robert Lord b147e6a2d7 Update toc javascript to hopefully be more performant 2014-06-22 02:33:55 -07:00
Robert Lord 200a871f85 Update gems 2014-06-22 02:02:14 -07:00
Tariq Islam 0a8c73adab Merge pull request #78 from tripit/dev
Fix scrolling bugs, history bugs, and add search minimum score to display
2014-06-22 00:16:07 -07:00
Robert Lord c1359e81a7 Add note to readme about Travis-ci and Mozilla 2014-06-16 12:09:08 -07:00
Robert Lord 3e4f52dfc9 Add note to readme about sauce labs 2014-06-15 22:34:25 -07:00
Robert Lord f4f2a1abfa Re-rotate nav button image 2014-06-14 19:43:37 -07:00
Robert Lord b5419b1e9c Add background to nav button 2014-06-14 19:41:08 -07:00
Robert Lord 3a91faa8e6 Fix bug with messed up margin on some code samples on phones 2014-06-14 19:19:48 -07:00
Robert Lord 062e35a3b3 Update readme with responsive notes 2014-06-14 18:55:32 -07:00
Robert Lord 00a93ec76e Add new screenshot to README 2014-06-12 16:04:52 -07:00
Robert Lord 65496915b8 Hide mobile lang selector and search on print 2014-06-12 16:02:41 -07:00
Robert Lord 3125ad8f72 Add extra margin to nav touch targets on mobile 2014-06-12 01:48:53 -07:00
Robert Lord 1e144aaa66 Update nav button to go to very edge of screen 2014-06-12 01:39:37 -07:00
Robert Lord 1478579c59 Add language tabs to navbar on phone 2014-06-12 01:32:25 -07:00
Robert Lord d77f1e7b9f Increase size of nav button touch target area 2014-06-12 00:51:50 -07:00
Robert Lord e559ad1097 Add first draft of single column design for phones 2014-06-12 00:32:50 -07:00
Robert Lord c2c35cfa25 Add retracting sidebar for tablets 2014-06-12 00:01:52 -07:00
Robert Lord ec9a688846 Fix bad h1 top border commit 2014-06-11 23:09:04 -07:00
Robert Lord 4d4f6efeb8 Fix #75, don't set page hash to undefined 2014-06-11 22:10:31 -07:00
Robert Lord 5a69760f54 Remove top border from first h1 of page 2014-06-11 22:04:08 -07:00
Robert Lord 0aff03f8da Fixes #77, update sites without search
Sites without search now do not include search.js or lunr.js,
making the javascript for those pages much faster to load.
2014-06-11 21:58:33 -07:00
Robert Lord b363be873b Update language tabs to properly stay in section, and fix history navigation bug 2014-06-11 21:49:37 -07:00
Robert Lord 7dead4c392 Update selected tab to not darken on mousedown 2014-06-11 21:21:28 -07:00
Robert Lord d71ae97f7a Remove excess whitespace, add extra equal sign to lang.js 2014-06-11 21:15:26 -07:00
Robert Lord cfa9f48dd0 Merge pull request #68 from bootstraponline/lang_default
Lang default
2014-05-18 23:08:13 -07:00
bootstraponline 1e341563fb Fix language on load 2014-05-18 12:29:03 -04:00
Robert Lord 34c6c69d61 Merge pull request #67 from stetzer/master
Add Emerging Threats API docs link to the readme
2014-05-15 21:39:20 -04:00
Mark Stetzer a35e1341b6 Adding link to Emerging Threats API docs 2014-05-15 16:14:02 -04:00
Robert Lord 078c42a082 Merge pull request #63 from chrissrogers/dev
Fixes a variable leak and simplifies low score filtration
2014-05-09 12:29:49 -04:00
Christopher Rogers e0cee862d9 Fixes a variable leak and simplifies low score filtration
Signed-off-by: Christopher Rogers <[email protected]>
2014-05-07 19:39:16 -07:00
Robert Lord e5cf1f2589 Merge pull request #56 from bootstraponline/scroll_to_closest_header
Scroll to closest header
2014-05-05 12:16:45 -04:00
Robert Lord 6bf197da74 Merge pull request #53 from bootstraponline/dont_crash_on_invalid_language
Don't crash on invalid language
2014-05-05 11:51:40 -04:00
Tariq Islam 0eb4caa425 Merge pull request #49 from tripit/dev
Search, bug fixes, new features, and more
2014-05-03 17:22:36 -07:00
bootstraponline 2f617a2160 Scroll to closest header 2014-04-27 21:50:33 -04:00
Robert Lord 938a056fcc Merge pull request #51 from bootstraponline/search
Reposition headers based on score
2014-04-27 19:15:17 -04:00
bootstraponline f9c4195f23 Don't crash on invalid language 2014-04-27 16:32:11 -04:00
bootstraponline 2384d9af3f Reposition headers based on score
Enforce min score
2014-04-26 10:23:57 -04:00
Robert Lord adcf6c7099 Update Travis badge to SVG in README 2014-04-22 13:50:12 -04:00
Robert Lord 126ea199cc Add contributors section to README 2014-04-22 11:18:44 -04:00
Robert Lord edd22fde15 Update rake 2014-04-22 11:07:52 -04:00
Robert Lord 84b3e5e3d6 Add search frontmatter key to specify visibility of search 2014-04-21 12:18:44 -04:00
Robert Lord 0316c0c5e9 Add aside print styling, fixes #4 2014-04-21 12:10:36 -04:00
Robert Lord 259bf0f560 Remove from screen.scss that was causing errors 2014-04-21 12:05:07 -04:00
Robert Lord 6d73ffb052 Remove leftover console.logs from tocify edits 2014-04-21 11:56:00 -04:00
Robert Lord 75869a561f Prevent reload page on language change, fixes #36
- Uses onpopstate to handle users pressing back buttons
- Switches the query string and changes the language
  without reloading.
- Thanks to @bootstraponline for some of the code in this commit.
2014-04-21 11:31:32 -04:00
Robert Lord 215d773fcf Merge pull request #46 from bootstraponline/flash_fix
Fix flash on page load
2014-04-21 11:02:18 -04:00
bootstraponline 03b28598cc Fix flash as suggested by @lord 2014-04-19 22:01:56 -04:00
Robert Lord df2d2ec5e9 Add note about browsers to contributing.md 2014-04-19 21:36:15 -04:00
Robert Lord 0feb513407 Adjust search info appearance, fix Firefox bug 2014-04-19 21:36:00 -04:00
Robert Lord 7386fd2e21 Fix bug with section padding and long code blocks 2014-04-19 18:04:23 -04:00
Robert Lord fc0c995cb6 Add h4,h5,h6 as suggested by @bootstraponline, fix section padding 2014-04-19 17:58:42 -04:00
Robert Lord 06680512a8 Update gems 2014-04-19 17:18:21 -04:00
Robert Lord e3e72aec83 Add contributing.md 2014-04-17 13:46:29 -04:00
Robert Lord 26eef2f000 Merge pull request #35 from tmp-/fix_flash_on_load
Prevent flash on first load
2014-04-17 12:08:32 -04:00
Robert Lord 9bbb62877e Merge branch 'lunr' of https://github.com/chrissrogers/slate into dev 2014-04-17 11:27:03 -04:00
bootstraponline cabfe33e58 Prevent flash on first load 2014-04-16 20:37:57 -04:00
Christopher Rogers a4e1fb3c24 Adds js handler for setting search info box width equal to content width
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-16 15:05:05 -07:00
Christopher Rogers 0ebbae94fe Cleans up some css
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-16 14:11:43 -07:00
Christopher Rogers 440c799c4c Removes lunr stemmer from search index pipeline
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-16 14:03:58 -07:00
Tariq Islam 3de499063c Merge pull request #31 from tripit/dev
Update gems
2014-04-15 23:11:47 -07:00
Christopher Rogers 3c4e0d0bae Switches jQuery to load through Google CDN
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-15 13:44:56 -05:00
Christopher Rogers 0a0e84b8e8 Standardizes search styles
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-15 13:40:45 -05:00
Christopher Rogers 477146e5bf Removes .ruby-version
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-15 11:02:32 -05:00
Robert Lord 4e37eeb524 Update gems 2014-04-14 12:34:06 -04:00
Christopher Rogers 4d568401a3 Improves no results notice and removes highlight and notice on search field blur
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-11 20:36:03 -07:00
Christopher Rogers 535a3b0486 Adds 'no results found' message to search
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-11 18:01:55 -07:00
Christopher Rogers 5892700b5c Fixes toc alignment on search and adds highlight library
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-11 10:27:15 -07:00
Christopher Rogers 59ee05c606 Updates search field markup and style
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-10 17:47:01 -07:00
Christopher Rogers f2d1387971 Adds search icon
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-10 17:46:39 -07:00
Christopher Rogers 02e48810ba Adds .ruby-version
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-10 17:05:42 -07:00
Tariq Islam 0ddd142279 Merge pull request #28 from tripit/dev
Update gems
2014-04-10 02:42:19 -07:00
Christopher Rogers e669a0d4ac Adds rudimentary search support
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-09 18:12:55 -07:00
Christopher Rogers d1b98be182 Cleans up layout
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-09 18:12:05 -07:00
Christopher Rogers b171d3c48a Organizes javascript into libraries and application code
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-09 14:54:23 -07:00
Christopher Rogers adf94ffbf6 Simplifies layout language selection and js init logic
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-09 14:45:41 -07:00
Christopher Rogers 68807cd485 Fixes some leakage in the language selector
Signed-off-by: Christopher Rogers <[email protected]>
2014-04-09 14:14:24 -07:00
Robert Lord ebbd2d89b4 Update gems 2014-04-07 12:03:45 -04:00
Tariq Islam 53db9d4a64 Merge pull request #26 from tripit/dev
Update gems and add new site to README
2014-04-01 10:03:13 -07:00
Robert Lord 32e0470613 Update gems 2014-04-01 11:17:05 -04:00
Robert Lord ca23e5ccdc Add PricePlow to README 2014-04-01 11:13:54 -04:00
Tariq Islam 0c41f3c213 Merge pull request #23 from tripit/dev
Bug fixes, a new link in the README, and a new partials feature
2014-03-31 01:02:42 -07:00
Robert Lord c091fae675 Update gems 2014-03-30 22:53:27 -04:00
Robert Lord e307f1dbbb Update jQuery to work over SSL, resolves #18 2014-03-30 22:46:48 -04:00
Robert Lord c364a2329b Add link in README to Build a Quine tutorial 2014-03-30 22:44:30 -04:00
Robert Lord 88fcba6798 Add explanation of partials to _errors.md 2014-03-30 22:42:54 -04:00
Marcio Lima b90436e48e Add ability to split content in include files. 2014-03-28 12:29:31 -03:00
Tariq Islam dc7a7dce41 Merge pull request #16 from tripit/dev
Update gems and add execjs and therubyracer
2014-03-25 11:38:04 -07:00
Robert Lord 6e7c428315 Add execjs and rubyracer to Gemfile, should resolve #12 2014-03-21 21:13:49 -04:00
Robert Lord fa0115eb57 Add .cache to gitignore 2014-03-21 21:07:19 -04:00
Robert Lord 8eb3ce6237 Update gems 2014-03-21 21:06:36 -04:00
Tariq Islam bb83688fc7 Merge pull request #10 from lord/master
Update gems, switch redcarpet to gem reference now that 3.1 is released
2014-02-18 12:55:34 -08:00
Robert Lord 5b3dd91fff Update gems, switch redcarpet to gem reference now that 3.1 is released 2014-02-18 15:39:33 -05:00
Tariq Islam 3c5231fbd0 Merge pull request #8 from lord/master
Update gems - merged from Robert.
2014-02-14 12:13:19 -08:00
Robert Lord 8ea97c7f77 Update gems 2014-02-07 20:06:23 -05:00
Robert Lord 5bc89ce207 Update middleman-syntax and rouge, should fix #6 2014-01-13 15:24:17 -08:00
Robert Lord b7a4296978 Add ChaiOne to Slate examples in readme 2014-01-11 09:13:38 -08:00
Robert Lord 3321fd1616 Update README.md 2014-01-10 22:10:07 -08:00
Robert Lord 7defe86bf6 Update gems 2014-01-10 12:27:39 -08:00
Robert Lord 35598a4e16 Add styling for horizontal rules 2013-12-31 16:34:19 -08:00
Robert Lord d84692b7b9 Delete syntax.md
All of its contents are now hosted in the wiki.
2013-12-20 15:37:48 -08:00
Robert Lord 1c9d74a75b Update README.md, remove FAQ, add link to wiki 2013-12-20 15:26:52 -08:00
Robert Lord d744b8a22f Add styling for definition lists 2013-12-20 10:44:14 -08:00
Robert Lord 730ee46de9 Update middleman gem 2013-12-19 16:45:06 -08:00
Robert Lord a406646361 Update gems 2013-12-04 11:42:22 -08:00
Robert Lord c1502d0476 Add asides instructions to syntax.md 2013-11-18 11:39:47 -08:00
Robert Lord 446f9341b9 Update Gemfile.lock 2013-11-18 11:10:08 -08:00
Robert Lord 6d7ba45f2c Remove unused github-linguist dependency 2013-11-18 11:00:50 -08:00
Robert Lord 24729b9308 Update Travis icon to only check master branch 2013-11-18 10:45:01 -08:00
Robert Lord bc9b1263be Fix Travis README icon 2013-11-18 10:39:18 -08:00
Robert Lord 9331e3b9db Add travis config, add travis icon to README 2013-11-18 10:31:36 -08:00
Robert Lord 27e0db7d14 Set default task to build 2013-11-18 09:31:28 -08:00
Robert Lord 42cb37cc9e Add rake to Gemfile 2013-11-18 09:31:07 -08:00
Robert Lord 5b306d8134 Merge pull request #2 from tripit/dev
Update github-linguist, middleman, add Gemnasium status badge
2013-11-18 09:08:24 -08:00
Robert Lord b39deb560f Update github-linguist, middleman, add Gemnasium status badge 2013-11-18 09:00:12 -08:00
Robert Lord 198484ef2b Add hack to prevent tocify from animating on page load 2013-10-31 13:44:02 -07:00
Robert Lord d3ab3cc4b7 Add asides for nice-looking notes and warnings
You can now use <aside> with the classes

- warning
- success
- notice

to add little colored notes to your API docs! Examples are in
source/index.md.

Also, note that if you have a custom variables.scss, you'll have
to add

+$aside-notice-bg: #8fbcd4;
+$aside-warning-bg: #c97a7e;
+$aside-success-bg: #6ac174;

to it.
2013-10-31 12:26:07 -07:00
Robert Lord ca40fed573 Add note to README about variables.scss 2013-10-31 11:41:25 -07:00
Robert Lord bdd05b3c0c Fix bug where weird white block could appear at bottom of page.
This bug occured if the final code sample extended beyond the
explanation at the bottom of the page.

To fix it, I simply made the background color of body a soft
blue.
2013-10-31 10:56:54 -07:00
Robert Lord 7c6594c595 Update README with more info about logo size 2013-10-31 10:54:54 -07:00
Robert Lord c404bc02df Add default language selecting with localStorage
Now, Slate will use localStorage to track the last selected
language, so if the user visits again with no language in the URL,
they will be redirected to the last language they used.

This update also fixes a bug with how the layout inserts the
language names into the javascript. Previously, they would be,
(for some inane reason) arrays within arrays. It is now just
an array. Whoever wrote that previous code was clearly a fool.
2013-10-29 10:40:07 -07:00
Robert Lord 5acbe01c3d Fix capitalization error in README 2013-10-25 11:41:13 -07:00
Robert Lord e2b70aff42 Change print stylesheet, fix slight bug with naming
Also changed README wording slightly.
2013-10-25 11:39:53 -07:00
Robert Lord 834119ecd8 Add print stylesheet 2013-10-25 11:33:19 -07:00
Robert Lord 26d47b06a0 Fix bug where syntax.css would fail to compile, causing errors 2013-10-21 15:17:35 -07:00
Robert Lord dc33dfe0a7 Add table of contents footer links feature
Now you can add links to the bottom of your table of contents!
Documentation has also been changed to reflect this new
feature.

Please note that if you have a custom variables.scss, you'll have
to merge in this line:

    $nav-footer-border-color: #666;
2013-10-21 14:09:38 -07:00
Robert Lord 81b9110cad Add Github hosting feature to README 2013-10-20 21:14:19 -07:00
Robert Lord 052ac6db37 Update README, made it much more simple and clear
* Reworded a bunch of sections
* Added "features" section with bullets for the various features
  of Slate
* Added screenshot of Slate
2013-10-16 13:26:42 -07:00
Robert Lord f10e324f5f Fix incorrect instructions in syntax help file 2013-10-16 13:01:47 -07:00
Robert Lord 6a22d7c11d Update SCSS, fix bug where code annotations had wrong font. 2013-10-16 12:45:00 -07:00
Robert Lord 35a5d35512 Hide TripIt docs link from README, since they're not ready yet. 2013-10-14 15:35:26 -07:00
Robert Lord 04c0abbcfa Refactor SCSS for better organization, readability, and customizability. 2013-10-11 15:55:46 -07:00
Robert Lord e5658f498a Update copyright year 2013-10-11 11:55:42 -07:00
Robert Lord 2e9e2b65f8 Add special thanks to readme 2013-10-11 11:30:08 -07:00
Robert Lord 91ff8a738a Add copyright information to source files 2013-10-11 11:28:04 -07:00
Robert Lord 20f303f3d1 Remove unused commented-out settings from config.rb 2013-10-11 10:59:06 -07:00
Robert Lord a250c6dbc2 Add :no_intra_emphasis to redcarpet settings 2013-10-10 10:16:32 -07:00
Robert Lord 489fb16b94 Update README.md and default index.md
Seriously upgraded the README documentation.
ALso, added a tiny fix to the Kittn example in index.md.
2013-10-09 15:18:14 -07:00
Robert Lord d72f08d936 Update README.md
Changed a tiny wording thing.
2013-10-08 09:37:51 -07:00
Robert Lord e7a0552edc Update README.md
Fixed some more formatting problems, and reworded a few sections.
2013-10-07 14:47:09 -07:00
Robert Lord 916412b51b Update syntax.md
Fixed another problem where the table example would show up as an actual table instead of a markdown example.
2013-10-07 12:49:12 -07:00
Robert Lord 6155c542a3 Update syntax.md
Fixed a tiny problem
2013-10-07 12:48:15 -07:00
Robert Lord 8aa611f77a Adjust styling of border below h1 tag to be more consistent 2013-10-07 12:30:32 -07:00
Robert Lord 84b7705fd1 Add Kittn example file 2013-10-07 12:29:37 -07:00
Robert Lord 2d75b7a04d Add syntax documentation 2013-10-07 12:29:19 -07:00
Robert Lord dac9cff8fc Update README.md
Added some more helpful information.
2013-10-07 12:28:33 -07:00
Robert Lord b15573155e Added sample code to index.md 2013-10-03 18:02:49 -07:00
Robert Lord e641bd7d4a Add generic logo, remove TripIt logos. 2013-10-03 18:02:18 -07:00
Robert Lord d562c8f71e Neeeevermind Apache License 2013-10-03 17:57:35 -07:00
Robert Lord 0a78bb259f Add MIT License 2013-10-03 17:30:50 -07:00
Robert Lord a4e05ed506 Update README.md
Just made some edits, added the Slate name, and fixed the code rendering issue.
2013-10-03 17:24:37 -07:00
Robert Lord 82b8ca4616 A new README 2013-10-03 16:54:40 -07:00
Robert Lord 63429f1e9a Added relative links that are needed for hosting a page in a non-root directory. 2013-10-03 14:58:18 -07:00
Robert Lord 1030376e37 More style fixes and changes 2013-10-01 13:32:30 -07:00
Robert Lord f7e6117e85 Various style updates and bugfixes 2013-09-27 13:42:57 -07:00
Robert Lord 38ad55851a Change language declaration
Now, if no languages are specified, the language selection bar simply doesn't appear.

It has also been renamed from "languages" to "language_tabs".

Additionally, now language names default to the markdown name. They can still be overridden by the languagename:Display Name syntax.
2013-09-27 13:37:36 -07:00
Robert Lord 7ae21ae972 Fix padding bug with blockquotes in the right area. 2013-09-25 10:15:59 -07:00
Robert Lord fd80b240bd Make every other table row have a different color 2013-09-24 14:54:42 -07:00
Robert Lord 28f442e529 Add automatic hash generation with redcarpet dev, and change tocify scrollHistory to be compatible with the ids 2013-09-24 12:25:12 -07:00
Robert Lord 7ba798c51d Overflow fixes and toc horizontal scrollbar fix 2013-09-24 10:35:33 -07:00
Robert Lord 5cc9188e3c Fix tocify to reset cache on browser window resize 2013-09-24 09:47:40 -07:00
Robert Lord 9e84ebf28c Add margin to bottom of tables 2013-09-24 09:39:19 -07:00
Robert Lord 541998da39 Change code buttons to refresh the page with the language name after the ? in the url
This commit has two benefits:

- Now, copying the URL will actually copy the current language as well. You don't need to think to add a language

- If a language moves objects on the page down, the tocify header location cache will not be invalid, since it is generated on page load. Therefore, if code moves some elements down, since the page is reloaded, the cache will also be regenerated, to reflect the real locations of the headers.
2013-09-23 12:06:39 -07:00
Robert Lord bc79a655e5 More changes 2013-09-23 10:38:13 -07:00
Robert Lord 6c077ba873 Add stylesheets, javascript, and html for documentation generation 2013-09-17 15:44:08 -07:00
Robert Lord 7edf6c803d Add build/ directory to .gitignore 2013-09-13 15:32:37 -07:00
Robert Lord a1e673e599 Initial commit, with default middleman code 2013-09-13 15:24:31 -07:00
Robert Lord f656a9aa6d Add .DS_STORE to .gitignore 2013-09-13 15:19:33 -07:00
Robert Lord 9a707a0172 Initial commit 2013-09-13 15:15:24 -07:00
425 changed files with 17612 additions and 48558 deletions

No files matched your search

+9
View File
@@ -0,0 +1,9 @@
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
@@ -0,0 +1,5 @@
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.
+23 -8
View File
@@ -1,10 +1,25 @@
.classpath
.project
.settings/
target/
*.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/
.idea/
*.iml
logs/
server/pki/
client/src/main/python/setup.py
+10
View File
@@ -0,0 +1,10 @@
sudo: false
language: ruby
rvm:
- 2.0.0
- 2.1.0
cache: bundler
script: bundle exec middleman build
+75
View File
@@ -0,0 +1,75 @@
# 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
@@ -1,6 +0,0 @@
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
@@ -0,0 +1,10 @@
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
@@ -0,0 +1,134 @@
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
+10 -200
View File
@@ -1,203 +1,13 @@
Copyright 2008-2013 Concur Technologies, Inc.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
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
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.
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.
-2
View File
@@ -1,2 +0,0 @@
This product includes Google Flatbuffers (https://google.github.io/flatbuffers/)
Copyright 2014 Google Inc. All rights reserved.
+103 -5
View File
@@ -1,8 +1,106 @@
![Timely](timely-readme-logo.png)
<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>
[![Apache License][li]][ll]
<p align="center">Slate helps you create beautiful, intelligent, responsive API documentation.</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"><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>
[li]: http://img.shields.io/badge/license-ASL-blue.svg
[ll]: https://www.apache.org/licenses/LICENSE-2.0
<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/)
Vendored
+39
View File
@@ -0,0 +1,39 @@
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
-2
View File
@@ -1,2 +0,0 @@
/bin/
/target
-20
View File
@@ -1,20 +0,0 @@
timelyHostname=
timelyTcpPort=
timelyHttpsPort=
timelyWssPort=
doLogin=
#timelyUsername=
#timelyPassword=
keyStoreFile=
keyStoreType=
keyStorePass=
trustStoreFile=
trustStoreType=
trustStorePass=
hostVerificationEnabled=false
bufferSize=10485760
metrics=
startTime=0
endTime=0
interval=1
intervalUnits=HOURS
-336
View File
@@ -1,336 +0,0 @@
<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>timely-analytics</artifactId>
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.7-SNAPSHOT</version>
</parent>
<properties>
<flink.version>1.1.4</flink.version>
</properties>
<!--
Execute "mvn clean package -Pbuild-jar"
to build a jar file out of this project!
How to use the Flink Quickstart pom:
a) Adding new dependencies:
You can add dependencies to the list below.
Please check if the maven-shade-plugin below is filtering out your dependency
and remove the exclude from there.
b) Build a jar for running on the cluster:
There are two options for creating a jar from this project
b.1) "mvn clean package" -> this will create a fat jar which contains all
dependencies necessary for running the jar created by this pom in a cluster.
The "maven-shade-plugin" excludes everything that is provided on a running Flink cluster.
b.2) "mvn clean package -Pbuild-jar" -> This will also create a fat-jar, but with much
nicer dependency exclusion handling. This approach is preferred and leads to
much cleaner jar files.
-->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java_2.11</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-clients_2.11</artifactId>
<version>${flink.version}</version>
</dependency>
<dependency>
<groupId>timely</groupId>
<artifactId>timely-client</artifactId>
<version>${parent.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>timely</groupId>
<artifactId>timely-common</artifactId>
<version>${parent.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<!-- Profile for packaging correct JAR files -->
<id>build-jar</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java_2.11</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-clients_2.11</artifactId>
<version>${flink.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- disable the exclusion rules -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes combine.self="override"/>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
<!-- We use the maven-shade plugin to create a fat jar that contains all dependencies
except flink and it's transitive dependencies. The resulting fat-jar can be executed
on a cluster. Change the value of Program-Class if your program entry point changes. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<!-- Run shade goal on package phase -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<!-- This list contains all dependencies of flink-dist
Everything else will be packaged into the fat-jar
-->
<exclude>org.apache.flink:flink-annotations</exclude>
<exclude>org.apache.flink:flink-shaded-hadoop1_2.11</exclude>
<exclude>org.apache.flink:flink-shaded-hadoop2</exclude>
<exclude>org.apache.flink:flink-shaded-curator-recipes</exclude>
<exclude>org.apache.flink:flink-core</exclude>
<exclude>org.apache.flink:flink-java</exclude>
<exclude>org.apache.flink:flink-scala_2.11</exclude>
<exclude>org.apache.flink:flink-runtime_2.11</exclude>
<exclude>org.apache.flink:flink-optimizer_2.11</exclude>
<exclude>org.apache.flink:flink-clients_2.11</exclude>
<exclude>org.apache.flink:flink-avro_2.11</exclude>
<exclude>org.apache.flink:flink-examples-batch_2.11</exclude>
<exclude>org.apache.flink:flink-examples-streaming_2.11</exclude>
<exclude>org.apache.flink:flink-streaming-java_2.11</exclude>
<!-- Also exclude very big transitive dependencies of Flink
WARNING: You have to remove these excludes if your code relies on other
versions of these dependencies.
-->
<exclude>org.scala-lang:scala-library</exclude>
<exclude>org.scala-lang:scala-compiler</exclude>
<exclude>org.scala-lang:scala-reflect</exclude>
<exclude>com.typesafe.akka:akka-actor_*</exclude>
<exclude>com.typesafe.akka:akka-remote_*</exclude>
<exclude>com.typesafe.akka:akka-slf4j_*</exclude>
<exclude>io.netty:netty-all</exclude>
<exclude>io.netty:netty</exclude>
<exclude>commons-fileupload:commons-fileupload</exclude>
<exclude>org.apache.avro:avro</exclude>
<exclude>commons-collections:commons-collections</exclude>
<exclude>org.codehaus.jackson:jackson-core-asl</exclude>
<exclude>org.codehaus.jackson:jackson-mapper-asl</exclude>
<exclude>com.thoughtworks.paranamer:paranamer</exclude>
<exclude>org.xerial.snappy:snappy-java</exclude>
<exclude>org.apache.commons:commons-compress</exclude>
<exclude>org.tukaani:xz</exclude>
<exclude>com.esotericsoftware.kryo:kryo</exclude>
<exclude>com.esotericsoftware.minlog:minlog</exclude>
<exclude>org.objenesis:objenesis</exclude>
<exclude>com.twitter:chill_*</exclude>
<exclude>com.twitter:chill-java</exclude>
<exclude>commons-lang:commons-lang</exclude>
<exclude>junit:junit</exclude>
<exclude>org.apache.commons:commons-lang3</exclude>
<exclude>org.slf4j:slf4j-api</exclude>
<exclude>org.slf4j:slf4j-log4j12</exclude>
<exclude>log4j:log4j</exclude>
<exclude>org.apache.commons:commons-math</exclude>
<exclude>org.apache.sling:org.apache.sling.commons.json</exclude>
<exclude>commons-logging:commons-logging</exclude>
<exclude>commons-codec:commons-codec</exclude>
<exclude>com.fasterxml.jackson.core:jackson-core</exclude>
<exclude>com.fasterxml.jackson.core:jackson-databind</exclude>
<exclude>com.fasterxml.jackson.core:jackson-annotations</exclude>
<exclude>stax:stax-api</exclude>
<exclude>com.typesafe:config</exclude>
<exclude>org.uncommons.maths:uncommons-maths</exclude>
<exclude>com.github.scopt:scopt_*</exclude>
<exclude>commons-io:commons-io</exclude>
<exclude>commons-cli:commons-cli</exclude>
</excludes>
</artifactSet>
<filters>
<filter>
<artifact>org.apache.flink:*</artifact>
<excludes>
<!-- exclude shaded google but include shaded curator -->
<exclude>org/apache/flink/shaded/com/**</exclude>
<exclude>web-docs/**</exclude>
</excludes>
</filter>
<filter>
<!-- Do not copy the signatures in the META-INF folder.
Otherwise, this might cause SecurityExceptions when using the JAR.
-->
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<!-- If you want to use ./bin/flink run <quickstart jar> uncomment the following lines.
This will add a Main-Class entry to the manifest file -->
<!--
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>jar.StreamingJob</mainClass>
</transformer>
</transformers>
-->
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerId>jdt</compilerId>
</configuration>
<dependencies>
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-compiler-jdt</artifactId>
<version>0.21.0</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<versionRange>[2.4,)</versionRange>
<goals>
<goal>single</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore/>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<versionRange>[3.1,)</versionRange>
<goals>
<goal>testCompile</goal>
<goal>compile</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore/>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
@@ -1,169 +0,0 @@
package timely.analytics.flink;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.flink.streaming.util.serialization.SerializationSchema;
import timely.model.Tag;
public class MetricHistogram implements Serializable, SerializationSchema<MetricHistogram> {
private static final long serialVersionUID = 1L;
private static final String SPACE = " ";
private static final String AVG = " sample=avg\n";
private static final String COUNT = " sample=count\n";
private static final String MAX = " sample=max\n";
private static final String MIN = " sample=min\n";
private static final String SUM = " sample=sum\n";
private static final String p50 = " sample=50p\n";
private static final String p75 = " sample=75p\n";
private static final String p90 = " sample=90p\n";
private static final String p99 = " sample=99p\n";
private String metric = null;
private List<Tag> tags = null;
private long timestamp = 0L;
private boolean initialized = false;
private List<Double> values = new ArrayList<>();
public void initialize(String metric, List<Tag> tags) {
this.metric = metric;
this.tags = tags;
initialized = true;
}
public boolean isInitialized() {
return initialized;
}
public String getMetric() {
return metric;
}
public List<Tag> getTags() {
return tags;
}
public long getTimestamp() {
return timestamp;
}
public void update(Double d, long timestamp) {
values.add(d);
this.timestamp = timestamp;
}
public void done() {
Collections.sort(values);
}
public Double avg() {
if (values.size() == 0) {
return 0.0D;
}
return sum() / count();
}
public Double min() {
if (values.size() == 0) {
return 0.0D;
}
return values.get(0);
}
public Double max() {
if (values.size() == 0) {
return 0.0D;
}
return values.get(values.size() - 1);
}
public Double getPercentile(int p) {
if (values.size() == 0) {
return 0.0D;
}
int position = Math.round((p * 1.0f / 100) * values.size());
position = (0 == position) ? 0 : position - 1;
return values.get(position);
}
public Double count() {
return values.size() * 1.0D;
}
public Double sum() {
double sum = 0.0D;
for (Double d : values) {
sum += d;
}
return sum;
}
@Override
public String toString() {
done();
StringBuilder buf = new StringBuilder();
buf.append("metric: ").append(metric);
buf.append(" tags: ").append(tags);
buf.append(" timestamp: ").append(timestamp);
buf.append(" count: ").append(count());
buf.append(" min: ").append(min());
buf.append(" max: ").append(max());
buf.append(" sum: ").append(sum());
buf.append(" 50p: ").append(getPercentile(50));
buf.append(" 75p: ").append(getPercentile(75));
buf.append(" 99p: ").append(getPercentile(99));
return buf.toString();
}
public byte[] serialize(MetricHistogram histo) {
StringBuilder buf = new StringBuilder();
String tags = histo.getTags().stream().map(t -> t.join()).collect(Collectors.joining(" "));
// @formatter:off
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.min())
.append(SPACE).append(tags).append(MIN);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.max())
.append(SPACE).append(tags).append(MAX);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.count())
.append(SPACE).append(tags).append(COUNT);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.sum())
.append(SPACE).append(tags).append(SUM);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.avg())
.append(SPACE).append(tags).append(AVG);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.getPercentile(50))
.append(SPACE).append(tags).append(p50);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.getPercentile(75))
.append(SPACE).append(tags).append(p75);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.getPercentile(90))
.append(SPACE).append(tags).append(p90);
buf.append("put ").append(histo.getMetric() + "_summarized")
.append(SPACE).append(histo.getTimestamp())
.append(SPACE).append(histo.getPercentile(99))
.append(SPACE).append(tags).append(p99);
// @formatter:off
return buf.toString().getBytes();
}
}
@@ -1,20 +0,0 @@
package timely.analytics.flink;
import org.apache.flink.api.java.functions.KeySelector;
import timely.api.response.MetricResponse;
/**
* Uniquely defines a time series in a Flink stream. A unique time series is the
* metric name and all of its tags, to include visibility if it exists.
*/
public class MetricKeySelector implements KeySelector<MetricResponse, String> {
private static final long serialVersionUID = 1L;
@Override
public String getKey(MetricResponse m) throws Exception {
return m.getMetric() + m.getTags().toString();
}
}
@@ -1,55 +0,0 @@
package timely.analytics.flink;
import java.util.concurrent.ConcurrentSkipListMap;
import org.apache.commons.lang3.mutable.MutableLong;
import org.apache.flink.api.common.accumulators.Accumulator;
/**
* Custom accumulator that retains a sorted map of strings and their counts
*
*/
public class SortedStringAccumulator implements Accumulator<String, ConcurrentSkipListMap<String, MutableLong>> {
private static final long serialVersionUID = 1L;
private ConcurrentSkipListMap<String, MutableLong> values = new ConcurrentSkipListMap<>();
@Override
public void add(String value) {
if (values.containsKey(value)) {
values.get(value).increment();
} else {
values.put(value, new MutableLong(1));
}
}
@Override
public ConcurrentSkipListMap<String, MutableLong> getLocalValue() {
return values;
}
@Override
public void resetLocal() {
values.clear();
}
@Override
public void merge(Accumulator<String, ConcurrentSkipListMap<String, MutableLong>> other) {
other.getLocalValue().forEach((k, v) -> {
if (values.containsKey(k)) {
values.get(k).add(v.longValue());
} else {
values.put(k, v);
}
});
}
@Override
public Accumulator<String, ConcurrentSkipListMap<String, MutableLong>> clone() {
SortedStringAccumulator a = new SortedStringAccumulator();
a.getLocalValue().putAll(this.values);
return a;
}
}
@@ -1,218 +0,0 @@
package timely.analytics.flink;
import java.io.IOException;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import org.apache.flink.api.common.accumulators.LongCounter;
import org.apache.flink.api.common.functions.StoppableFunction;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
import org.apache.flink.streaming.api.watermark.Watermark;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.api.response.MetricResponse;
import timely.api.response.MetricResponses;
import timely.client.websocket.ClientHandler;
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
import timely.serialize.JsonSerializer;
public class SubscriptionSource extends RichSourceFunction<MetricResponse> implements Serializable, StoppableFunction {
private static class SubscriptionThreadFactory implements ThreadFactory {
private static final String NAME = "Subscription Source";
private AtomicInteger threadNum = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, NAME + " " + threadNum.getAndIncrement());
}
}
private static final Logger LOG = LoggerFactory.getLogger(SubscriptionSource.class);
private static final long serialVersionUID = 1L;
private transient WebSocketSubscriptionClient client = null;
private long start = 0L;
private long end = 0L;
private final String[] metrics;
private final SummarizationJobParameters jp;
private final long window;
private final AtomicInteger subscriptionsRemaining;
public SubscriptionSource(SummarizationJobParameters jp) {
this.jp = jp;
start = jp.getStartTime();
end = jp.getEndTime();
metrics = jp.getMetrics();
window = jp.getSummarizationInterval().toMilliseconds();
subscriptionsRemaining = new AtomicInteger(metrics.length);
}
@Override
public void open(Configuration parameters) throws Exception {
LOG.info("Opening summarization job.");
super.open(parameters);
client = new WebSocketSubscriptionClient(jp.getTimelyHostname(), jp.getTimelyHttpsPort(),
jp.getTimelyWssPort(), jp.isDoLogin(), jp.getTimelyUsername(), jp.getTimelyPassword(),
jp.getKeyStoreFile(), jp.getKeyStoreType(), jp.getKeyStorePass(), jp.getTrustStoreFile(),
jp.getTrustStoreType(), jp.getTrustStorePass(), jp.isHostVerificationEnabled(), jp.getBufferSize());
}
@Override
public synchronized void close() throws Exception {
super.close();
if (null != client) {
client.close();
}
}
@Override
public void run(SourceContext<MetricResponse> ctx) throws Exception {
LOG.info("Running summarization job");
final SortedStringAccumulator dateTimeAccumulator = new SortedStringAccumulator();
this.getRuntimeContext().addAccumulator("source hourly count", dateTimeAccumulator);
final LongCounter sourceInputs = new LongCounter();
this.getRuntimeContext().addAccumulator("source input counter", sourceInputs);
final LongCounter inputProcessedInMainThread = new LongCounter();
this.getRuntimeContext().addAccumulator("input processed in main thread", inputProcessedInMainThread);
// Use only one thread to ensure that time is still ordered
final ExecutorService svc = Executors.newFixedThreadPool(1, new SubscriptionThreadFactory());
ClientHandler handler = new ClientHandler() {
@Override
public void onOpen(Session session, EndpointConfig config) {
session.addMessageHandler(new MessageHandler.Whole<String>() {
private final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd-HH");
private long lastWatermarkTime = 0L;
@Override
public void onMessage(final String message) {
LOG.info("Message received on Websocket session {}, length: {}", session.getId(),
message.length());
try {
// Deserialize in this thread
final MetricResponses responses = JsonSerializer.getObjectMapper().readValue(message,
MetricResponses.class);
// Process in the other
final Runnable r = () -> {
responses.getResponses().forEach(response -> {
if (response.isComplete()) {
LOG.info("Received last message.");
ctx.emitWatermark(new Watermark(Long.MAX_VALUE));
subscriptionsRemaining.getAndDecrement();
return;
}
LOG.trace("Received metric: {}", response);
long time = response.getTimestamp();
ctx.collectWithTimestamp(response, time);
dateTimeAccumulator.add(formatter.format(new Date(response.getTimestamp())));
sourceInputs.add(1);
// Emit a watermark every second of event
// time
if (lastWatermarkTime == 0) {
lastWatermarkTime = time;
} else if ((time - lastWatermarkTime) > window) {
lastWatermarkTime = time;
ctx.emitWatermark(new Watermark(time - 1));
}
});
};
try {
svc.execute(r);
} catch (RejectedExecutionException e) {
// Run it in this thread
r.run();
inputProcessedInMainThread.add(1);
}
} catch (IOException e) {
LOG.error("Error deserializing metric response, closing", e);
try {
close();
} catch (Exception e1) {
LOG.error("Error closing client", e1);
}
}
}
});
}
@Override
public void onClose(Session session, CloseReason reason) {
super.onClose(session, reason);
try {
close();
} catch (Exception e1) {
LOG.error("Error closing client", e1);
}
// Signal done sending data
ctx.emitWatermark(new Watermark(Long.MAX_VALUE));
}
@Override
public void onError(Session session, Throwable error) {
super.onError(session, error);
try {
close();
} catch (Exception e1) {
LOG.error("Error closing client", e1);
}
}
};
try {
client.open(handler);
for (String m : metrics) {
LOG.info("Adding subscription for {}", m);
client.addSubscription(m, null, start, end, 5000);
}
while (!client.isClosed() && subscriptionsRemaining.get() > 0) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
LOG.error("Sleep interrupted.");
}
}
} finally {
svc.shutdown();
}
}
@Override
public void cancel() {
LOG.info("Cancelling subscription source.");
try {
close();
} catch (Exception e) {
LOG.error("Error closing web socket client");
}
}
@Override
public void stop() {
LOG.info("Stopping subscription source.");
try {
close();
} catch (Exception e) {
LOG.error("Error closing web socket client");
}
}
}
@@ -1,109 +0,0 @@
package timely.analytics.flink;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.flink.api.common.accumulators.LongCounter;
import org.apache.flink.api.common.functions.FoldFunction;
import org.apache.flink.api.java.utils.ParameterTool;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.sink.SocketClientSink;
import org.apache.flink.streaming.api.windowing.assigners.TumblingEventTimeWindows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.api.response.MetricResponse;
public class SummarizationJob {
private static final Logger LOG = LoggerFactory.getLogger(SummarizationJob.class);
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("Usage: timely.analytics.flink.SummarizationJob <path_to_properties_file>");
System.exit(1);
}
LOG.info("Loading properties from: {}", args[0]);
ParameterTool params = ParameterTool.fromPropertiesFile(args[0]);
final SummarizationJobParameters jp = new SummarizationJobParameters(params);
LOG.info("Properties: {}", jp);
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// @formatter:off
env.getConfig().setGlobalJobParameters(jp);
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
env.addSource(new SubscriptionSource(jp), "Timely Metrics Subscription")
// partition by unique metric
.keyBy(new MetricKeySelector())
.window(TumblingEventTimeWindows.of(jp.getSummarizationInterval()))
.fold(new MetricHistogram(), new FoldFunction<MetricResponse, MetricHistogram>() {
private final Logger LOG = LoggerFactory
.getLogger("timely.analytics.SummarizationJob.FoldFunction@");
private static final long serialVersionUID = 1L;
@Override
public MetricHistogram fold(MetricHistogram histo, MetricResponse metric) throws Exception {
if (!histo.isInitialized()) {
histo.initialize(metric.getMetric(), metric.getTags());
} else {
if (!histo.getMetric().equals(metric.getMetric())) {
throw new RuntimeException("Metric name does not match - partitioning problem");
}
if (!histo.getTags().equals(metric.getTags())) {
throw new RuntimeException("Tags don't not match - partitioning problem");
}
}
LOG.trace("Updating histogram for {} with value {} at {} for metric {}", histo.getMetric()
+ histo.getTags(), metric.getValue(), metric.getTimestamp(), metric.getMetric()
+ metric.getTags());
histo.update(metric.getValue(), metric.getTimestamp());
return histo;
}
})
.name("Metric Windows")
.addSink(
new SocketClientSink<MetricHistogram>(jp.getTimelyHostname(), jp.getTimelyTcpPort(),
new MetricHistogram(), 2, true) {
private final Logger LOG = LoggerFactory
.getLogger("timely.analytics.SummarizationJob.SocketClientSink");
private static final long serialVersionUID = 1L;
private final LongCounter sinkCounter = new LongCounter();
private final SortedStringAccumulator dateTimeAccumulator = new SortedStringAccumulator();
private final SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd-HH");
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
this.getRuntimeContext().addAccumulator("sink counter", this.sinkCounter);
this.getRuntimeContext().addAccumulator("sink hourly count", dateTimeAccumulator);
LOG.info("Sink opened");
}
@Override
public void invoke(MetricHistogram histo) throws Exception {
histo.done();
super.invoke(histo);
this.sinkCounter.add(1);
this.dateTimeAccumulator.add(formatter.format(new Date(histo.getTimestamp())));
}
@Override
public void close() throws Exception {
super.close();
LOG.info("Sink closed");
}
}).name("Timely Metric Sink");
// @formatter:on
env.execute("Metric Summarization");
// Looks like there is no way to stop Flink job if underlying web socket
// is closed.
}
}
@@ -1,208 +0,0 @@
package timely.analytics.flink;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.flink.api.common.ExecutionConfig.GlobalJobParameters;
import org.apache.flink.api.java.utils.ParameterTool;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.windowing.time.Time;
public class SummarizationJobParameters extends GlobalJobParameters implements Serializable {
private static final long serialVersionUID = 1L;
private final String timelyHostname;
private final int timelyTcpPort;
private final int timelyHttpsPort;
private final int timelyWssPort;
private final boolean doLogin;
private final String timelyUsername;
private final String timelyPassword;
private final String keyStoreFile;
private final String keyStoreType;
private final String keyStorePass;
private final String trustStoreFile;
private final String trustStoreType;
private final String trustStorePass;
private final boolean hostVerificationEnabled;
private final int bufferSize;
private final String[] metrics;
private final long startTime;
private final long endTime;
private final String interval;
private final String intervalUnits;
public SummarizationJobParameters(ParameterTool params) {
timelyHostname = params.getRequired("timelyHostname");
timelyTcpPort = params.getInt("timelyTcpPort", 4241);
timelyHttpsPort = params.getInt("timelyHttpsPort", 4242);
timelyWssPort = params.getInt("timelyWssPort", 4243);
doLogin = params.getBoolean("doLogin", false);
timelyUsername = params.get("timelyUsername", null);
timelyPassword = params.get("timelyPassword", null);
keyStoreFile = params.getRequired("keyStoreFile");
keyStoreType = params.get("keyStoreType", "JKS");
keyStorePass = params.getRequired("keyStorePass");
trustStoreFile = params.getRequired("trustStoreFile");
trustStoreType = params.get("trustStoreType", "JKS");
trustStorePass = params.getRequired("trustStorePass");
hostVerificationEnabled = params.getBoolean("hostVerificationEnabled", true);
bufferSize = params.getInt("bufferSize", 10485760);
String metricNames = params.getRequired("metrics");
if (null != metricNames) {
metrics = metricNames.split(",");
} else {
metrics = null;
}
startTime = params.getLong("startTime", 0L);
endTime = params.getLong("endTime", 0L);
interval = params.getRequired("interval");
intervalUnits = params.getRequired("intervalUnits");
}
public SummarizationJobParameters(Configuration conf) {
System.out.println("Creating job parameters from configuration: " + conf);
timelyHostname = conf.getString("timelyHostname", null);
timelyTcpPort = conf.getInteger("timelyTcpPort", 4241);
timelyHttpsPort = conf.getInteger("timelyHttpsPort", 4242);
timelyWssPort = conf.getInteger("timelyWssPort", 4243);
doLogin = conf.getBoolean("doLogin", false);
timelyUsername = conf.getString("timelyUsername", null);
timelyPassword = conf.getString("timelyPassword", null);
keyStoreFile = conf.getString("keyStoreFile", null);
keyStoreType = conf.getString("keyStoreType", "JKS");
keyStorePass = conf.getString("keyStorePass", null);
trustStoreFile = conf.getString("trustStoreFile", null);
trustStoreType = conf.getString("trustStoreType", "JKS");
trustStorePass = conf.getString("trustStorePass", null);
hostVerificationEnabled = conf.getBoolean("hostVerificationEnabled", true);
bufferSize = conf.getInteger("bufferSize", 10485760);
String metricNames = conf.getString("metrics", null);
if (null != metricNames) {
metrics = metricNames.split(",");
} else {
metrics = null;
}
startTime = conf.getLong("startTime", 0L);
endTime = conf.getLong("endTime", 0L);
interval = conf.getString("interval", null);
intervalUnits = conf.getString("intervalUnits", null);
}
public Time getSummarizationInterval() {
return Time.of(Long.parseLong(interval), TimeUnit.valueOf(intervalUnits));
}
public String getTimelyHostname() {
return timelyHostname;
}
public int getTimelyTcpPort() {
return timelyTcpPort;
}
public int getTimelyHttpsPort() {
return timelyHttpsPort;
}
public int getTimelyWssPort() {
return timelyWssPort;
}
public boolean isDoLogin() {
return doLogin;
}
public String getTimelyUsername() {
return timelyUsername;
}
public String getTimelyPassword() {
return timelyPassword;
}
public String getKeyStoreFile() {
return keyStoreFile;
}
public String getKeyStoreType() {
return keyStoreType;
}
public String getKeyStorePass() {
return keyStorePass;
}
public String getTrustStoreFile() {
return trustStoreFile;
}
public String getTrustStoreType() {
return trustStoreType;
}
public String getTrustStorePass() {
return trustStorePass;
}
public boolean isHostVerificationEnabled() {
return hostVerificationEnabled;
}
public int getBufferSize() {
return bufferSize;
}
public String[] getMetrics() {
return metrics;
}
public long getStartTime() {
return startTime;
}
public long getEndTime() {
return endTime;
}
public String getInterval() {
return interval;
}
public String getIntervalUnits() {
return intervalUnits;
}
@Override
public Map<String, String> toMap() {
Map<String, String> m = new HashMap<>();
m.put("timelyHostname", this.timelyHostname);
m.put("timelyHttpsPort", Integer.toString(this.timelyHttpsPort));
m.put("timelyWssPort", Integer.toString(this.timelyWssPort));
m.put("doLogin", Boolean.toString(this.doLogin));
m.put("timelyUsername", this.timelyUsername);
m.put("timelyPassword", this.timelyPassword);
m.put("keyStoreFile", this.keyStoreFile);
m.put("keyStoreType", this.keyStoreType);
m.put("keyStorePass", this.keyStorePass);
m.put("trustStoreFile", this.trustStoreFile);
m.put("trustStoreType", this.trustStoreType);
m.put("trustStorePass", this.trustStorePass);
m.put("hostVerificationEnabled", Boolean.toString(this.hostVerificationEnabled));
m.put("bufferSize", Integer.toString(this.bufferSize));
m.put("metrics", String.join(",", this.metrics));
m.put("startTime", Long.toString(this.startTime));
m.put("endTime", Long.toString(this.endTime));
m.put("interval", this.interval);
m.put("intervalUnits", this.intervalUnits);
return m;
}
@Override
public String toString() {
return toMap().toString();
}
}
@@ -1,108 +0,0 @@
package timely.analytics.flink;
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import timely.model.Metric;
import timely.model.Tag;
import timely.model.parse.MetricParser;
public class MetricHistogramTest {
private MetricHistogram m = null;
private long timestamp = System.currentTimeMillis();
@Before
public void createMetric() throws Exception {
m = new MetricHistogram();
for (double d = 1.0D; d <= 100.0; d += 1.0) {
timestamp += 1000;
m.update(d, timestamp);
}
m.toString();
Assert.assertEquals(timestamp, m.getTimestamp());
}
@Test
public void testMin() throws Exception {
Assert.assertEquals(1.0D, m.min(), 0.0D);
}
@Test
public void testMax() throws Exception {
Assert.assertEquals(100.0D, m.max(), 0.0D);
}
@Test
public void testAvg() throws Exception {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
Assert.assertEquals((sum / 100.0D), m.avg(), 0.0D);
}
@Test
public void testCount() throws Exception {
Assert.assertEquals(100.0D, m.count(), 0.0D);
}
@Test
public void test50thPercentile() throws Exception {
Assert.assertEquals(50.0D, m.getPercentile(50), 0.0D);
}
@Test
public void test75thPercentile() throws Exception {
Assert.assertEquals(75.0D, m.getPercentile(75), 0.0D);
}
@Test
public void test90thPercentile() throws Exception {
Assert.assertEquals(90.0D, m.getPercentile(90), 0.0D);
}
@Test
public void test99thPercentile() throws Exception {
Assert.assertEquals(99.0D, m.getPercentile(99), 0.0D);
}
@Test
public void testSerialization() throws Exception {
MetricParser metricParser = new MetricParser();
Tag t1 = new Tag("tag1=value1");
Tag t2 = new Tag("tag2=value2");
Tag avg = new Tag("sample=avg");
Tag min = new Tag("sample=min");
Tag max = new Tag("sample=max");
Tag sum = new Tag("sample=sum");
Tag count = new Tag("sample=count");
Tag p50 = new Tag("sample=50p");
Tag p75 = new Tag("sample=75p");
Tag p90 = new Tag("sample=90p");
Tag p99 = new Tag("sample=99p");
List<Tag> tags = new ArrayList<>();
tags.add(t1);
tags.add(t2);
m.initialize("sys.cpu.user", tags);
byte[] bytes = m.serialize(m);
String puts = new String(bytes);
for (String put : puts.split("\n")) {
Metric metric = metricParser.parse(put);
Assert.assertEquals("sys.cpu.user_summarized", metric.getName());
metric.getTags().forEach(
t -> {
Assert.assertTrue(t.equals(t1) || t.equals(t2) || t.equals(avg) || t.equals(min)
|| t.equals(max) || t.equals(sum) || t.equals(count) || t.equals(p50) || t.equals(p75)
|| t.equals(p90) || t.equals(p99));
});
}
}
}
-1
View File
@@ -1 +0,0 @@
/target/
-202
View File
@@ -1,202 +0,0 @@
<?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.7-SNAPSHOT</version>
</parent>
<properties>
<!-- PEP 440 compliant version gets supstituted into src/main/python/template/setup.py -->
<python.client.version>0.0.7.dev0</python.client.version>
</properties>
<dependencies>
<dependency>
<groupId>timely</groupId>
<artifactId>timely-common</artifactId>
<version>${parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-client</artifactId>
<version>1.13</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-container-grizzly-client</artifactId>
<version>1.13</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>net.revelc.code</groupId>
<artifactId>formatter-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>filter-setup</id>
<goals>
<goal>copy-resources</goal>
</goals>
<phase>process-resources</phase>
<configuration>
<outputDirectory>${project.basedir}/src/main/python</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}/src/main/python/template</directory>
<includes>
<include>setup.py</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<!--
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>python-dist</id>
<goals>
<goal>exec</goal>
</goals>
<phase>package</phase>
<configuration>
<executable>python</executable>
<workingDirectory>${project.basedir}/src/main/python</workingDirectory>
<commandlineArgs>setup.py sdist - -dist-dir ${project.build.directory}</commandlineArgs>
</configuration>
</execution>
<execution>
<id>python-clean</id>
<goals>
<goal>exec</goal>
</goals>
<phase>package</phase>
<configuration>
<executable>rm</executable>
<workingDirectory>${project.basedir}/src/main/python</workingDirectory>
<commandlineArgs>-rf timely.egg-info setup.py</commandlineArgs>
</configuration>
</execution>
</executions>
</plugin>
-->
</plugins>
</build>
<reporting>
<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>
@@ -1,82 +0,0 @@
package timely.api;
import java.util.Map;
import java.util.Optional;
public class AddSubscription extends SubscriptionRequest {
private String operation = "add";
private String metric = null;
private Optional<Map<String, String>> tags = Optional.empty();
private Optional<Long> startTime = Optional.empty();
private Optional<Long> endTime = Optional.empty();
private Optional<Long> delayTime = Optional.empty();
public String getOperation() {
return operation;
}
public String getMetric() {
return metric;
}
public Optional<Map<String, String>> getTags() {
return tags;
}
public Optional<Long> getStartTime() {
return startTime;
}
public Optional<Long> getDelayTime() {
return delayTime;
}
public void setMetric(String metric) {
this.metric = metric;
}
public void setTags(Optional<Map<String, String>> tags) {
this.tags = tags;
}
public void setStartTime(Optional<Long> startTime) {
this.startTime = startTime;
}
public void setDelayTime(Optional<Long> delayTime) {
this.delayTime = delayTime;
}
public Optional<Long> getEndTime() {
return endTime;
}
public void setEndTime(Optional<Long> endTime) {
this.endTime = endTime;
}
@Override
public int hashCode() {
return (operation + subscriptionId + metric + tags + startTime + endTime + delayTime).hashCode();
}
@Override
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof AddSubscription) {
AddSubscription other = (AddSubscription) obj;
return (this.subscriptionId.equals(other.subscriptionId) && this.metric.equals(other.metric)
&& this.tags.equals(other.tags) && this.startTime.equals(other.startTime)
&& this.endTime.equals(other.endTime) && this.delayTime.equals(other.delayTime));
} else {
return false;
}
}
}
@@ -1,45 +0,0 @@
package timely.api;
public class BasicAuthLogin {
protected String username;
protected String password;
public String getUsername() {
return username;
}
public void setUsername(String user) {
this.username = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public int hashCode() {
return (username + password).hashCode();
}
@Override
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof BasicAuthLogin) {
BasicAuthLogin other = (BasicAuthLogin) obj;
return (this.username.equals(other.username) && this.password.equals(other.password));
} else {
return false;
}
}
}
@@ -1,32 +0,0 @@
package timely.api;
public class CloseSubscription extends SubscriptionRequest {
private String operation = "close";
public String getOperation() {
return operation;
}
@Override
public int hashCode() {
return (operation + subscriptionId).hashCode();
}
@Override
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof CloseSubscription) {
CloseSubscription other = (CloseSubscription) obj;
return (this.subscriptionId.equals(other.subscriptionId));
} else {
return false;
}
}
}
@@ -1,32 +0,0 @@
package timely.api;
public class CreateSubscription extends SubscriptionRequest {
private String operation = "create";
public String getOperation() {
return operation;
}
@Override
public int hashCode() {
return (operation + subscriptionId).hashCode();
}
@Override
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof CreateSubscription) {
CreateSubscription other = (CreateSubscription) obj;
return (this.subscriptionId.equals(other.subscriptionId));
} else {
return false;
}
}
}
@@ -1,41 +0,0 @@
package timely.api;
public class RemoveSubscription extends SubscriptionRequest {
private String operation = "remove";
private String metric = null;
public String getOperation() {
return operation;
}
public String getMetric() {
return metric;
}
public void setMetric(String metric) {
this.metric = metric;
}
@Override
public int hashCode() {
return (operation + subscriptionId + metric).hashCode();
}
@Override
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (obj == this) {
return true;
}
if (obj instanceof RemoveSubscription) {
RemoveSubscription other = (RemoveSubscription) obj;
return (this.subscriptionId.equals(other.subscriptionId) && this.metric.equals(other.metric));
} else {
return false;
}
}
}
@@ -1,15 +0,0 @@
package timely.api;
public abstract class SubscriptionRequest {
protected String subscriptionId = null;
public final String getSubscriptionId() {
return subscriptionId;
}
public final void setSubscriptionId(String subscriptionId) {
this.subscriptionId = subscriptionId;
}
}
@@ -1,126 +0,0 @@
package timely.api.response;
import java.util.List;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import timely.model.Metric;
import timely.model.Tag;
public class MetricResponse {
private String metric;
private long timestamp;
private double value;
private List<Tag> tags;
private String subscriptionId;
private boolean complete = false;
public String getMetric() {
return metric;
}
public long getTimestamp() {
return timestamp;
}
public double getValue() {
return value;
}
public List<Tag> getTags() {
return tags;
}
public boolean isComplete() {
return complete;
}
public void setMetric(String metric) {
this.metric = metric;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
public void setValue(double value) {
this.value = value;
}
public void setTags(List<Tag> tags) {
this.tags = tags;
}
public String getSubscriptionId() {
return subscriptionId;
}
public void setSubscriptionId(String subscriptionId) {
this.subscriptionId = subscriptionId;
}
public void setComplete(boolean closed) {
this.complete = closed;
}
public static MetricResponse fromMetric(Metric metric, String subscriptionId) {
MetricResponse response = new MetricResponse();
response.setMetric(metric.getName());
response.setTimestamp(metric.getValue().getTimestamp());
response.setTags(metric.getTags());
response.setValue(metric.getValue().getMeasure());
response.setSubscriptionId(subscriptionId);
response.setComplete(false);
return response;
}
@Override
public int hashCode() {
HashCodeBuilder hash = new HashCodeBuilder();
hash.append(this.metric);
hash.append(this.timestamp);
hash.append(this.value);
hash.append(this.tags);
hash.append(this.subscriptionId);
hash.append(this.complete);
return hash.hashCode();
}
@Override
public boolean equals(Object obj) {
if (null == obj) {
return false;
}
if (this == obj) {
return true;
}
if (!(obj instanceof MetricResponse)) {
return false;
}
MetricResponse other = (MetricResponse) obj;
EqualsBuilder equals = new EqualsBuilder();
equals.append(this.metric, other.metric);
equals.append(this.timestamp, other.timestamp);
equals.append(this.value, other.value);
equals.append(this.tags, other.tags);
equals.append(this.subscriptionId, other.subscriptionId);
equals.append(this.complete, other.complete);
return equals.isEquals();
}
@Override
public String toString() {
ToStringBuilder tsb = new ToStringBuilder(this);
tsb.append("metric", this.metric);
tsb.append("timestamp", this.timestamp);
tsb.append("value", this.value);
tsb.append("tags", this.tags);
tsb.append("subscriptionId", this.subscriptionId);
tsb.append("complete", this.complete);
return tsb.toString();
}
}
@@ -1,29 +0,0 @@
package timely.api.response;
import java.util.ArrayList;
import java.util.List;
public class MetricResponses {
private List<MetricResponse> responses = new ArrayList<>();
public synchronized List<MetricResponse> getResponses() {
return this.responses;
}
public synchronized void setResponses(List<MetricResponse> responses) {
this.responses = responses;
}
public synchronized void addResponse(MetricResponse r) {
this.responses.add(r);
}
public int size() {
return this.responses.size();
}
public synchronized void clear() {
this.responses.clear();
}
}
@@ -1,55 +0,0 @@
package timely.client.http;
import javax.net.ssl.SSLContext;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.glassfish.tyrus.client.SslContextConfigurator;
public class HttpClient {
public static SSLContext getSSLContext(String trustStoreFile, String trustStoreType, String trustStorePass,
String keyStoreFile, String keyStoreType, String keyStorePass) {
SslContextConfigurator scc = new SslContextConfigurator();
scc.setTrustStoreFile(trustStoreFile);
scc.setTrustStoreType(trustStoreType);
if (null != trustStorePass) {
scc.setTrustStorePassword(trustStorePass);
}
scc.setKeyStoreFile(keyStoreFile);
scc.setKeyStoreType(keyStoreType);
if (null != keyStorePass) {
scc.setKeyStorePassword(keyStorePass);
}
return scc.createSSLContext();
}
public static CloseableHttpClient get(String trustStoreFile, String trustStoreType, String trustStorePass,
String keyStoreFile, String keyStoreType, String keyStorePass, CookieStore cookieStore,
boolean hostVerificationEnabled) {
SSLContext ssl = getSSLContext(trustStoreFile, trustStoreType, trustStorePass, keyStoreFile, keyStoreType,
keyStorePass);
return get(ssl, cookieStore, hostVerificationEnabled);
}
public static CloseableHttpClient get(SSLContext ssl, CookieStore cookieStore, boolean hostVerificationEnabled) {
RequestConfig defaultRequestConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();
HttpClientBuilder builder = HttpClients.custom().setSSLContext(ssl).setDefaultCookieStore(cookieStore)
.setDefaultRequestConfig(defaultRequestConfig);
if (hostVerificationEnabled) {
builder.setSSLHostnameVerifier(new DefaultHostnameVerifier());
} else {
builder.setSSLHostnameVerifier(new NoopHostnameVerifier());
}
return builder.build();
}
}
@@ -1,106 +0,0 @@
package timely.client.tcp;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TcpClient implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(TcpClient.class);
private final String host;
private final int port;
private Socket sock = null;
private PrintWriter out = null;
private long connectTime = 0L;
private long backoff = 2000;
public TcpClient(String hostname, int port) {
this.host = hostname;
this.port = port;
}
/**
* Opens a TCP connection to the specified host and port
*
* @throws IOException
* if an error occurs
*/
public void open() throws IOException {
if (connect() != 0) {
throw new IOException();
}
}
/**
* Write a metric to Timely
*
* @param metric
* newline terminated string representation of Timely metric
* @throws IOException
*/
public synchronized void write(String metric) throws IOException {
if (connect() != 0) {
throw new IOException();
}
out.write(metric);
}
public synchronized void flush() {
if (null != out) {
out.flush();
}
}
/**
* Closes the tcp connection to Timely
*
* @throws IOException
* if an error occurs
*/
@Override
public void close() throws IOException {
LOG.info("Shutting down connection to Timely at {}:{}", host, port);
if (null != sock) {
try {
if (null != out) {
out.close();
}
sock.close();
} catch (IOException e) {
LOG.error("Error closing connection to Timely at " + host + ":" + port + ". Error: " + e.getMessage());
} finally {
sock = null;
}
}
}
private synchronized int connect() {
if (null == sock || !sock.isConnected() || out.checkError()) {
if (System.currentTimeMillis() > (connectTime + backoff)) {
try {
connectTime = System.currentTimeMillis();
sock = new Socket(host, port);
out = new PrintWriter(sock.getOutputStream(), false);
backoff = 2000;
LOG.info("Connected to Timely at {}:{}", host, port);
} catch (IOException e) {
LOG.error("Error connecting to Timely at {}:" + host + ":" + port + ". Error: " + e.getMessage());
backoff = backoff * 2;
sock = null;
out = null;
LOG.warn("Will retry connection in {} ms.", backoff);
return -1;
}
} else {
LOG.warn("Not writing to Timely, waiting to reconnect");
return -1;
}
}
return 0;
}
}
@@ -1,45 +0,0 @@
package timely.client.udp;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
public class UdpClient implements AutoCloseable {
private final InetSocketAddress address;
private final DatagramPacket packet;
private DatagramSocket sock;
public UdpClient(String hostname, int port) {
this.address = new InetSocketAddress(hostname, port);
this.packet = new DatagramPacket("".getBytes(UTF_8), 0, 0, address.getAddress(), port);
}
public void open() throws IOException {
if (null == sock) {
this.sock = new DatagramSocket();
}
}
public void write(String metric) throws IOException {
if (null == this.sock) {
throw new IllegalStateException("Must call open first");
}
this.packet.setData(metric.getBytes(UTF_8));
this.sock.send(packet);
}
public void flush() throws IOException {
}
public void close() throws IOException {
if (null != sock) {
sock.close();
sock = null;
}
}
}
@@ -1,38 +0,0 @@
package timely.client.websocket;
import javax.websocket.CloseReason;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class ClientHandler extends Endpoint {
private final static Logger LOG = LoggerFactory.getLogger(ClientHandler.class);
@Override
public void onOpen(Session session, EndpointConfig config) {
LOG.info("Websocket session {} opened.", session.getId());
session.addMessageHandler(new MessageHandler.Whole<String>() {
@Override
public void onMessage(String message) {
LOG.info("Message received on Websocket session {}: {}", session.getId(), message);
}
});
}
@Override
public void onClose(Session session, CloseReason reason) {
LOG.info("Websocket session {} closed.", session.getId());
}
@Override
public void onError(Session session, Throwable error) {
LOG.error("Error occurred on Websocket session" + session.getId(), error);
}
}
@@ -1,65 +0,0 @@
package timely.client.websocket;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.websocket.ClientEndpointConfig;
import javax.websocket.Decoder;
import javax.websocket.Encoder;
import javax.websocket.Extension;
import org.apache.http.cookie.Cookie;
public class TimelyEndpointConfig implements ClientEndpointConfig {
private String sessionCookie = null;
private static final String FORMAT = "%s=%s;";
public TimelyEndpointConfig(Cookie sessionCookie) {
if (null != sessionCookie) {
this.sessionCookie = String.format(FORMAT, sessionCookie.getName(), sessionCookie.getValue());
}
}
@Override
public List<Class<? extends Encoder>> getEncoders() {
return Collections.emptyList();
}
@Override
public List<Class<? extends Decoder>> getDecoders() {
return Collections.emptyList();
}
@Override
public Map<String, Object> getUserProperties() {
return Collections.emptyMap();
}
@Override
public List<String> getPreferredSubprotocols() {
return Collections.emptyList();
}
@Override
public List<Extension> getExtensions() {
return Collections.emptyList();
}
@Override
public Configurator getConfigurator() {
return new Configurator() {
@Override
public void beforeRequest(Map<String, List<String>> headers) {
super.beforeRequest(headers);
if (null != sessionCookie) {
headers.put("Cookie", Collections.singletonList(sessionCookie));
}
}
};
}
}
@@ -1,179 +0,0 @@
package timely.client.websocket;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLContext;
import javax.websocket.DeploymentException;
import javax.websocket.Session;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.HttpClientUtils;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.glassfish.tyrus.client.ClientManager;
import org.glassfish.tyrus.client.ClientProperties;
import org.glassfish.tyrus.client.SslEngineConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.api.BasicAuthLogin;
import timely.client.http.HttpClient;
import timely.serialize.JsonSerializer;
import com.google.common.base.Preconditions;
public class WebSocketClient implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(WebSocketClient.class);
private final String timelyHostname;
private final int timelyHttpsPort;
private final int timelyWssPort;
private final boolean doLogin;
private final String timelyUsername;
private final String timelyPassword;
private final boolean hostVerificationEnabled;
private final int bufferSize;
private final SSLContext ssl;
private ClientManager webSocketClient = null;
protected Session session = null;
protected volatile boolean closed = true;
protected WebSocketClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort,
boolean doLogin, String timelyUsername, String timelyPassword, boolean hostVerificationEnabled,
int bufferSize) {
this.ssl = ssl;
this.timelyHostname = timelyHostname;
this.timelyHttpsPort = timelyHttpsPort;
this.timelyWssPort = timelyWssPort;
this.doLogin = doLogin;
this.timelyUsername = timelyUsername;
this.timelyPassword = timelyPassword;
this.hostVerificationEnabled = hostVerificationEnabled;
this.bufferSize = bufferSize;
Preconditions.checkNotNull(timelyHostname, "%s must be supplied", "Timely host name");
Preconditions.checkNotNull(timelyHttpsPort, "%s must be supplied", "Timely HTTPS port");
Preconditions.checkNotNull(timelyWssPort, "%s must be supplied", "Timely WSS port");
if (doLogin
&& ((StringUtils.isEmpty(timelyUsername) && !StringUtils.isEmpty(timelyPassword) || (!StringUtils
.isEmpty(timelyUsername) && StringUtils.isEmpty(timelyPassword))))) {
throw new IllegalArgumentException("Both Timely username and password must be empty or non-empty");
}
}
protected WebSocketClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean doLogin,
String timelyUsername, String timelyPassword, String keyStoreFile, String keyStoreType,
String keyStorePass, String trustStoreFile, String trustStoreType, String trustStorePass,
boolean hostVerificationEnabled, int bufferSize) {
this(HttpClient.getSSLContext(trustStoreFile, trustStoreType, trustStorePass, keyStoreFile, keyStoreType,
keyStorePass), timelyHostname, timelyHttpsPort, timelyWssPort, doLogin, timelyUsername, timelyPassword,
hostVerificationEnabled, bufferSize);
}
public void open(ClientHandler clientEndpoint) throws IOException, DeploymentException, URISyntaxException {
Cookie sessionCookie = null;
if (doLogin) {
BasicCookieStore cookieJar = new BasicCookieStore();
try (CloseableHttpClient client = HttpClient.get(ssl, cookieJar, hostVerificationEnabled)) {
String target = "https://" + timelyHostname + ":" + timelyHttpsPort + "/login";
HttpRequestBase request = null;
if (StringUtils.isEmpty(timelyUsername)) {
// HTTP GET to /login to use certificate based login
request = new HttpGet(target);
LOG.trace("Performing client certificate login");
} else {
// HTTP POST to /login to use username/password
BasicAuthLogin login = new BasicAuthLogin();
login.setUsername(timelyUsername);
login.setPassword(timelyPassword);
String payload = JsonSerializer.getObjectMapper().writeValueAsString(login);
HttpPost post = new HttpPost(target);
post.setEntity(new StringEntity(payload));
request = post;
LOG.trace("Performing BasicAuth login");
}
HttpResponse response = null;
try {
response = client.execute(request);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
throw new HttpResponseException(response.getStatusLine().getStatusCode(), response
.getStatusLine().getReasonPhrase());
}
for (Cookie c : cookieJar.getCookies()) {
if (c.getName().equals("TSESSIONID")) {
sessionCookie = c;
break;
}
}
if (null == sessionCookie) {
throw new IllegalStateException(
"Unable to find TSESSIONID cookie header in Timely login response");
}
} finally {
HttpClientUtils.closeQuietly(response);
}
}
}
SslEngineConfigurator sslEngine = new SslEngineConfigurator(ssl);
sslEngine.setClientMode(true);
sslEngine.setHostVerificationEnabled(hostVerificationEnabled);
webSocketClient = ClientManager.createClient();
webSocketClient.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngine);
webSocketClient.getProperties().put(ClientProperties.INCOMING_BUFFER_SIZE, bufferSize);
String wssPath = "wss://" + timelyHostname + ":" + timelyWssPort + "/websocket";
session = webSocketClient.connectToServer(clientEndpoint, new TimelyEndpointConfig(sessionCookie), new URI(
wssPath));
final ByteBuffer pingData = ByteBuffer.allocate(0);
webSocketClient.getScheduledExecutorService().scheduleAtFixedRate(() -> {
try {
session.getBasicRemote().sendPing(pingData);
} catch (Exception e) {
LOG.error("Error sending ping", e);
}
}, 30, 60, TimeUnit.SECONDS);
closed = false;
}
public synchronized void close() throws IOException {
if (closed) {
return;
}
try {
if (null != webSocketClient) {
webSocketClient.shutdown();
}
} finally {
session = null;
webSocketClient = null;
closed = true;
}
}
public boolean isClosed() {
return closed;
}
}
@@ -1,92 +0,0 @@
package timely.client.websocket.subscription;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.Future;
import javax.net.ssl.SSLContext;
import javax.websocket.CloseReason;
import javax.websocket.DeploymentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import timely.api.AddSubscription;
import timely.api.CloseSubscription;
import timely.api.CreateSubscription;
import timely.api.RemoveSubscription;
import timely.client.websocket.ClientHandler;
import timely.client.websocket.WebSocketClient;
import timely.serialize.JsonSerializer;
public class WebSocketSubscriptionClient extends WebSocketClient {
private static final Logger LOG = LoggerFactory.getLogger(WebSocketSubscriptionClient.class);
private final String subscriptionId;
public WebSocketSubscriptionClient(SSLContext ssl, String timelyHostname, int timelyHttpsPort, int timelyWssPort,
boolean doLogin, String timelyUsername, String timelyPassword, boolean hostVerificationEnabled,
int bufferSize) {
super(ssl, timelyHostname, timelyHttpsPort, timelyWssPort, doLogin, timelyUsername, timelyPassword,
hostVerificationEnabled, bufferSize);
subscriptionId = UUID.randomUUID().toString();
LOG.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
}
public WebSocketSubscriptionClient(String timelyHostname, int timelyHttpsPort, int timelyWssPort, boolean doLogin,
String timelyUsername, String timelyPassword, String keyStoreFile, String keyStoreType,
String keyStorePass, String trustStoreFile, String trustStoreType, String trustStorePass,
boolean hostVerificationEnabled, int bufferSize) {
super(timelyHostname, timelyHttpsPort, timelyWssPort, doLogin, timelyUsername, timelyPassword, keyStoreFile,
keyStoreType, keyStorePass, trustStoreFile, trustStoreType, trustStorePass, hostVerificationEnabled,
bufferSize);
subscriptionId = UUID.randomUUID().toString();
LOG.trace("Created WebSocketClient with subscriptionId {}", this.subscriptionId);
}
@Override
public void open(ClientHandler clientEndpoint) throws IOException, DeploymentException, URISyntaxException {
super.open(clientEndpoint);
CreateSubscription create = new CreateSubscription();
create.setSubscriptionId(subscriptionId);
session.getBasicRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(create));
}
@Override
public synchronized void close() throws IOException {
if (null != session) {
CloseSubscription close = new CloseSubscription();
close.setSubscriptionId(subscriptionId);
try {
session.getBasicRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(close));
session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "Client called close."));
} catch (Exception e) {
LOG.info("Unable to send close message to server: {}", e.getMessage());
}
}
super.close();
}
public Future<Void> addSubscription(String metric, Map<String, String> tags, long startTime, long endTime,
long delayTime) throws IOException {
AddSubscription add = new AddSubscription();
add.setSubscriptionId(subscriptionId);
add.setMetric(metric);
add.setTags(Optional.ofNullable(tags));
add.setStartTime(Optional.ofNullable(startTime));
add.setEndTime(Optional.ofNullable(endTime));
add.setDelayTime(Optional.ofNullable(delayTime));
return session.getAsyncRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(add));
}
public Future<Void> removeSubscription(String metric) throws Exception {
RemoveSubscription remove = new RemoveSubscription();
remove.setSubscriptionId(subscriptionId);
remove.setMetric(metric);
return session.getAsyncRemote().sendText(JsonSerializer.getObjectMapper().writeValueAsString(remove));
}
}
@@ -1,190 +0,0 @@
package timely.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import timely.model.parse.TagParser;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
/**
* A Metric consists of a metric name, tags, and a Value
*
* Json has been flattened to reduce overhead. Example:
* {"name":"m1","timestamp":1,"measure":1.0,"tags":[{"k1":"v1"}]}
*
*/
@JsonRootName("metric")
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({ "name" })
public class Metric implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private List<Tag> tags;
private Value value;
public Metric() {
tags = new ArrayList<>();
value = new Value();
}
public Metric(Metric other) {
this();
this.name = other.getName();
this.tags.addAll(other.getTags());
this.value = new Value(other.getValue());
}
public Metric(String name, long timestamp, double measure) {
this();
this.name = name;
this.value.setTimestamp(timestamp);
this.value.setMeasure(measure);
}
public Metric(String name, long timestamp, double measure, List<Tag> tags) {
this(name, timestamp, measure);
this.setTags(tags);
}
public Metric(String name, List<Tag> tags) {
this();
this.name = name;
this.setTags(tags);
}
public static Builder newBuilder() {
return new Builder();
}
@JsonGetter("name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@JsonGetter("tags")
public List<Tag> getTags() {
return tags;
}
public void setTags(List<Tag> tags) {
this.tags.addAll(tags);
}
public void addTag(Tag tag) {
tags.add(new Tag(tag));
}
@JsonUnwrapped
public Value getValue() {
return value;
}
public void setValue(Value value) {
this.value = value;
}
@Override
public String toString() {
Collections.sort(tags);
return "Metric{" + "name='" + name + '\'' + ", tags=" + tags + ", value=" + value + '}';
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Metric metric = (Metric) o;
if (name != null ? !name.equals(metric.name) : metric.name != null)
return false;
if (tags != null) {
if (tags.size() != metric.tags.size()) {
return false;
} else if (!tags.containsAll(metric.tags)) {
return false;
}
}
return value != null ? value.equals(metric.value) : metric.value == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (tags != null ? tags.hashCode() : 0);
result = 31 * result + (value != null ? value.hashCode() : 0);
return result;
}
/**
* Simple Builder for Metric. Note: cannot re-use a builder after build is
* called.
*/
public static class Builder {
Metric metric;
private Builder() {
metric = new Metric();
}
private static TagParser parser = new TagParser();
public Builder tag(Tag tag) {
metric.addTag(tag);
return this;
}
public Builder tags(List<Tag> tags) {
metric.setTags(tags);
return this;
}
public Builder tag(String key, String value) {
metric.addTag(new Tag(key, value));
return this;
}
public Builder tag(String rawTag) {
metric.addTag(parser.parse(rawTag));
return this;
}
public Builder name(String name) {
metric.setName(name);
return this;
}
public Builder value(Value value) {
metric.setValue(value);
return this;
}
public Builder value(long timestamp, double measure) {
metric.setValue(new Value(timestamp, measure));
return this;
}
public Metric build() {
return this.metric;
}
}
}
@@ -1,200 +0,0 @@
package timely.model;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Logger;
/**
* A simple interface that objects can implement to return the object size.
*/
public interface ObjectSizeOf {
/**
* The (approximate) size of the object
*/
long sizeInBytes();
public static class ObjectInstance {
private Object o;
public ObjectInstance(Object _o) {
this.o = _o;
}
public Object getObject() {
return o;
}
@Override
public int hashCode() {
return System.identityHashCode(o);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ObjectInstance)) {
return false;
}
return ((ObjectInstance) obj).o == this.o;
}
}
public static class Sizer {
private static final Logger log = Logger.getLogger(Sizer.class.getCanonicalName());
public static final short OBJECT_OVERHEAD = 8;
public static final short ARRAY_OVERHEAD = 12;
public static final short REFERENCE = 4;
// The size of the basic Number constructs (and Boolean and Character)
// is 16: roundUp(8 + primitiveSize)
public static final short NUMBER_SIZE = 16;
/**
* Get the size of an object. Note that we want something relatively
* fast that gives us an order of magnitude here. The java
* Instrumentation agent mechanism is a little too costly for general
* use here. This will look for the ObjectSizeOf interface and if
* implemented on the object will use that. Otherwise it will do a
* simple navigation of the fields using reflection.
*
* @param o
* @return an approximation of the object size
*/
public static long getObjectSize(Object o, boolean useSizeInBytesMethod, boolean debug) {
long estSize = getObjectSize(o, new HashSet<ObjectInstance>(), new Stack<ObjectInstance>(),
useSizeInBytesMethod, debug);
return estSize;
}
public static long getObjectSize(Object o) {
long estSize = getObjectSize(o, new HashSet<ObjectInstance>(), new Stack<ObjectInstance>(), true, false);
return estSize;
}
public static long getObjectSize(Object o, Set<ObjectInstance> visited, Stack<ObjectInstance> stack,
boolean useSizeInBytesMethod, boolean debug) {
long totalSize = 0;
stack.add(new ObjectInstance(o));
while (!stack.isEmpty()) {
long size = 0;
ObjectInstance oi = stack.pop();
o = oi.getObject();
if (o != null && !visited.contains(oi)) {
visited.add(oi);
try {
if (useSizeInBytesMethod) {
try {
if (o instanceof ObjectSizeOf) {
size = ((ObjectSizeOf) o).sizeInBytes();
} else {
Method sizeInBytes = o.getClass().getMethod("sizeInBytes", (Class<?>[]) null);
size = (Long) sizeInBytes.invoke(o);
}
} catch (Throwable t) {
// ok, lets do this the hard way...
}
}
if (size == 0) {
// the hard way...
// do not include Class related objects or
// reflection objects
if ((o instanceof Class)
|| (o instanceof ClassLoader)
|| (o.getClass().getPackage() != null && o.getClass().getPackage().getName()
.startsWith("java.lang.reflect"))) {
size = 0;
} else if (o instanceof Number || o instanceof Boolean || o instanceof Character) {
size = NUMBER_SIZE;
} else {
// lets do a simple sizing
Class<?> c = o.getClass();
if (c.isArray()) {
size = ARRAY_OVERHEAD;
int length = Array.getLength(o);
if (c.getComponentType().isPrimitive()) {
size += length * getPrimitiveObjectSize(c.getComponentType());
} else {
size += length * REFERENCE;
for (int i = 0; i < length; i++) {
Object element = Array.get(o, i);
if (element != null) {
stack.add(new ObjectInstance(element));
}
}
}
} else {
size += OBJECT_OVERHEAD;
while (c != null) {
for (Field field : c.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
if (field.getType().isPrimitive()) {
size += getPrimitiveObjectSize(field.getType());
} else {
size += REFERENCE;
boolean accessible = field.isAccessible();
field.setAccessible(true);
try {
Object fieldObject = field.get(o);
if (fieldObject != null) {
stack.push(new ObjectInstance(fieldObject));
}
} catch (Exception e) {
// cannot get to field, so
// ignore it in this size
// calculation
e.printStackTrace();
}
field.setAccessible(accessible);
}
}
c = c.getSuperclass();
}
}
size = roundUp(size);
}
}
} catch (Throwable t) {
log.warning("Unable to determine object size for " + o);
}
if (debug) {
System.out.println(o.getClass().getCanonicalName() + "=" + size);
}
}
totalSize += size;
}
return totalSize;
}
public static long roundUp(long size) {
long extra = size % 8;
if (extra > 0) {
size = size + 8 - extra;
}
return size;
}
public static short getPrimitiveObjectSize(Class<?> primitiveType) {
if (primitiveType.equals(int.class) || primitiveType.equals(float.class)) {
return 4;
} else if (primitiveType.equals(boolean.class) || primitiveType.equals(byte.class)) {
return 1;
} else if (primitiveType.equals(char.class) || primitiveType.equals(short.class)) {
return 2;
} else if (primitiveType.equals(long.class) || primitiveType.equals(double.class)) {
return 8;
} else { // if (primitiveType.equals(void.class)) {
return 0;
}
}
}
}
-111
View File
@@ -1,111 +0,0 @@
package timely.model;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonRootName;
import com.google.common.base.Preconditions;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import timely.model.parse.TagParser;
import java.io.Serializable;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Tag consists of key value pair
*/
@JsonRootName("tag")
public class Tag implements Comparable<Tag>, Serializable {
private static final long serialVersionUID = 1L;
private static final TagParser tagParser = new TagParser();
private String key;
private String value;
public Tag() {
}
public Tag(Tag other) {
this.setKey(other.getKey());
this.setValue(other.getValue());
}
public Tag(String tag) {
this(tagParser.parse(tag));
}
public Tag(String key, String value) {
Preconditions.checkNotNull(key);
Preconditions.checkNotNull(value);
this.setKey(key);
this.setValue(value);
}
@JsonAnyGetter
public Map<String, String> get() {
return Stream.of(this).collect(Collectors.toMap(Tag::getKey, Tag::getValue));
}
@JsonAnySetter
public void set(String key, String value) {
this.key = key;
this.value = value;
}
@JsonIgnore
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
@JsonIgnore
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
/**
* Joins key and value into key=value
*
* @return
*/
public String join() {
return tagParser.combine(this);
}
@Override
public String toString() {
return "Tag{" + join() + "}";
}
@Override
public int hashCode() {
return this.toString().hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (null == o || getClass() != o.getClass())
return false;
Tag other = (Tag) o;
return new EqualsBuilder().append(this.key, other.key).append(this.value, other.value).isEquals();
}
@Override
public int compareTo(Tag other) {
return new CompareToBuilder().append(this.key, other.key).append(this.value, other.value).toComparison();
}
}
@@ -1,93 +0,0 @@
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 + "}";
}
}
@@ -1,6 +0,0 @@
package timely.model.parse;
public interface Combiner<T> {
String combine(T o);
}
@@ -1,30 +0,0 @@
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();
}
}
@@ -1,7 +0,0 @@
package timely.model.parse;
@FunctionalInterface
public interface Parser<T> {
T parse(String t);
}
@@ -1,53 +0,0 @@
package timely.model.parse;
import com.google.common.base.Splitter;
import timely.model.Tag;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* Parses tag1=val1,tag2=val2,tag3=val3 into a {@code List} of {@code Tag}
* Combines {@code List} of {@code Tag} into {@code String} of
* tag1=val1,tag2=val2,tag3=val3.
*/
public class TagListParser implements Parser<List<Tag>>, Combiner<Collection<Tag>> {
private static final Splitter commaSplitter = Splitter.on(",").omitEmptyStrings();
private static final TagParser tagParser = new TagParser();
@Override
public List<Tag> parse(String t) {
ArrayList<Tag> tags = new ArrayList<>();
commaSplitter.splitToList(t).forEach(p -> tags.add(tagParser.parse(p)));
return tags;
}
@Override
public String combine(Collection<Tag> tags) {
StringBuilder builder = new StringBuilder();
if (!tags.isEmpty()) {
tags.forEach(p -> builder.append(tagParser.combine(p)).append(','));
builder.setLength(builder.length() - 1);
}
return builder.toString();
}
/**
* An alternative combiner for a map of string to string instead of a list
* of tags
*
* @param tags
* @return string representation
*/
public String combine(Map<String, String> tags) {
StringBuilder builder = new StringBuilder();
if (!tags.isEmpty()) {
tags.forEach((k, v) -> builder.append(tagParser.combine(new Tag(k, v))).append(','));
builder.setLength(builder.length() - 1);
}
return builder.toString();
}
}
@@ -1,32 +0,0 @@
package timely.model.parse;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import timely.model.Tag;
import java.util.List;
/**
* Parses tag1=val1 into a {@code Tag} Combines {@code Tag} into {@code String}
* of tag1=val1
*/
public class TagParser implements Parser<Tag>, Combiner<Tag> {
private static final Splitter equalSplitter = Splitter.on("=").trimResults();
private static final Joiner equalsJoiner = Joiner.on("=");
@Override
public Tag parse(String t) {
List<String> parts = equalSplitter.splitToList(t);
if (parts.size() != 2) {
throw new IllegalArgumentException("Invalid tag format: " + t);
}
return new Tag(parts.get(0), parts.get(1));
}
@Override
public String combine(Tag t) {
return equalsJoiner.join(t.getKey(), t.getValue());
}
}
@@ -1,22 +0,0 @@
package timely.serialize;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
public class JsonSerializer {
private static ObjectMapper mapper = new ObjectMapper();
static {
mapper.registerModule(new Jdk8Module());
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true);
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
mapper.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
}
public static ObjectMapper getObjectMapper() {
return mapper;
}
}
-12
View File
@@ -1,12 +0,0 @@
from setuptools import setup
setup(
name='timely',
version='${python.client.version}',
packages=['timely'],
install_requires=[
'seaborn',
'plotly'
],
license='Apache License, Version 2.0'
)
@@ -1,328 +0,0 @@
import time
from datetime import timedelta
from datetime import datetime
from TimeDateRange import UTC
import pandas
import matplotlib.dates as mdates
import plotly.graph_objs as go
import plotly.offline as py
import seaborn
import matplotlib.ticker as tkr
import numpy as np
import os
utc = UTC()
def pivot(df, metric, groupByColumn=None):
dataFrame = pandas.DataFrame(df, copy=True)
if dataFrame is not None:
if groupByColumn is not None:
dataFrame["date"] = dataFrame.index.to_pydatetime()
dataFrame = dataFrame.pivot_table(index="date", columns=groupByColumn, values=metric)
return dataFrame
def resample(df, sample, how='mean'):
dataFrame = pandas.DataFrame(df, copy=True)
if dataFrame is not None:
if sample is not None:
dataFrame = dataFrame.resample(sample, how=how).interpolate()
return dataFrame
def unpivot(df, metric, groupByColumn=None):
dataFrame = pandas.DataFrame(df, copy=True)
if dataFrame is not None:
dataFrame['date'] = dataFrame.index.values
dataFrame = pandas.melt(dataFrame, id_vars=['date'], value_name=metric, var_name=groupByColumn)
dataFrame = dataFrame.set_index('date')
return dataFrame
def rolling_average(df, metric, rolling_average=None):
dataFrame = pandas.DataFrame(df, copy=True)
if dataFrame is not None:
if rolling_average is not None:
dataFrame[metric] = pandas.rolling_mean(dataFrame[metric], rolling_average)
return dataFrame
def graph(analyticConfig, df, timelyMetric, seriesConfig={}, graphConfig={}, notebook=False, type='png'):
if type == 'png':
return graphSeaborn(analyticConfig, df, timelyMetric, seriesConfig=seriesConfig, graphConfig=graphConfig, notebook=notebook)
else:
return graphPlotly(analyticConfig, df, timelyMetric, seriesConfig=seriesConfig, graphConfig=graphConfig, notebook=notebook)
def graphSeaborn(analyticConfig, df, timelyMetric, seriesConfig={}, graphConfig={}, notebook=False):
dataFrame = pandas.DataFrame(df, copy=True)
if dataFrame is not None:
dataFrame = ensureMinSeriesLength(dataFrame, analyticConfig.groupByColumn)
dataFrame['date'] = dataFrame.index.values
dataFrame['dateFloat'] = dataFrame['date'].apply(lambda x: datetime2graphdays(x))
dataFrame['index'] = dataFrame['dateFloat']
groupByColumn = analyticConfig.groupByColumn
if groupByColumn is not None:
# sort on date and the groupByColumn so that the series legend is sorted
dataFrame = dataFrame.sort_values(['index', analyticConfig.groupByColumn])
else:
dataFrame = dataFrame.sort_values(['index'])
#dataFrame = dataFrame.set_index('index', drop=True)
dataFrame = dataFrame.dropna()
seaborn.set(style="darkgrid", palette="Set2")
fig, ax = seaborn.plt.subplots()
colors = np.random.random((len(dataFrame), 3))
i = 0
for col in df[analyticConfig.groupByColumn].unique():
tempDataFrame = dataFrame.loc[dataFrame[analyticConfig.groupByColumn] == col]
addlColConfig = seriesConfig.get(col, seriesConfig.get('default', dict()))
markerDict = addlColConfig.get("marker", dict())
color = markerDict.get("color", "")
if color == "red":
seaborn.tsplot(tempDataFrame, time="dateFloat", unit=None, interpolate=False, color="red", marker="d",
estimator=np.nanmean, condition=groupByColumn, value=timelyMetric.metric, ax=ax)
else:
seaborn.tsplot(tempDataFrame, time="dateFloat", unit=None, interpolate=True, color=colors[i],
estimator=np.nanmean, condition=groupByColumn, value=timelyMetric.metric, ax=ax)
i = i + 1
ax.xaxis_date()
ax.xaxis.set_major_locator(mdates.AutoDateLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y/%m/%d %H:%M:%S'))
ax.set_xlim(xmin=dataFrame['dateFloat'].min(), xmax=dataFrame['dateFloat'].max())
formatter = tkr.ScalarFormatter(useMathText=False)
formatter.set_scientific(False)
ax.yaxis.set_major_formatter(formatter)
graphTitle = getTitle(timelyMetric, analyticConfig)
seaborn.plt.title(graphTitle, fontsize='large')
seaborn.plt.xlabel('date/time')
seaborn.plt.ylabel(timelyMetric.metric)
legendTitle = "Legend"
if groupByColumn is not None:
legendTitle = groupByColumn
seaborn.plt.legend(loc='upper center', prop={'size':8}, ncol=10, title=legendTitle, bbox_to_anchor=(0.5,-0.4))
fig.autofmt_xdate(rotation=45)
seaborn.plt.autoscale(tight=False)
if notebook == True:
seaborn.plt.show()
return None
else:
directory = analyticConfig.output_dir
try:
os.makedirs(directory, mode=0755)
except OSError, e:
# be happy if someone already created the path
pass
baseFilename = getFilename(timelyMetric.metric, analyticConfig)
filename = directory+'/'+baseFilename
fig.savefig(filename + '.png')
return baseFilename + '.png'
def graphPlotly(analyticConfig, df, timelyMetric, seriesConfig={}, graphConfig={}, notebook=False):
dataFrame = pandas.DataFrame(df, copy=True)
if dataFrame is not None:
dataFrame['colFromIndex'] = dataFrame.index
if analyticConfig.groupByColumn is not None:
# sort on date and the groupByColumn so that the series legend is sorted
dataFrame = dataFrame.sort_values(['colFromIndex', analyticConfig.groupByColumn])
else:
dataFrame = dataFrame.sort_values(['colFromIndex'])
title = getTitle(timelyMetric, analyticConfig)
dataFrame['date'] = dataFrame.index.values
layoutConfig = dict(
title=title,
autosize=False,
width=1000,
height=700,
showlegend=True,
xaxis=dict(
autorange=True,
tickangle=-45
),
yaxis=dict(
autorange=True,
title=timelyMetric.metric
)
)
layoutConfig.update(graphConfig)
layout = go.Layout(layoutConfig)
data = None
groupByValues = sorted(dataFrame[analyticConfig.groupByColumn].unique())
for col in groupByValues:
tempDataFrame = dataFrame.loc[dataFrame[analyticConfig.groupByColumn] == col]
addlColConfig = seriesConfig.get(col, seriesConfig.get('default', dict()))
config = dict(
name=col,
x=tempDataFrame.index,
y=tempDataFrame[timelyMetric.metric],
hoverinfo='x+y+text',
text=col
)
config.update(addlColConfig)
s = go.Scatter(config)
if data is None:
data = [s]
else:
data.append(s)
directory = analyticConfig.output_dir
try:
os.makedirs(directory, mode=0755)
except OSError, e:
# be happy if someone already created the path
pass
baseFilename = getFilename(timelyMetric.metric, analyticConfig)
filename = directory+'/'+baseFilename
fig = go.Figure(data=data, layout=layout)
if notebook:
py.iplot(fig, filename=filename, show_link=False)
return None
else:
py.plot(fig, output_type='file', filename=filename+'.html', image_filename=filename, image=None, auto_open=False, show_link=False)
return baseFilename+'.html'
def ensureMinSeriesLength(df, groupByColumn):
dataFrame = df
if groupByColumn is not None:
dataFrame = pandas.DataFrame(df, copy=True)
dataFrame = dataFrame.dropna()
extra = pandas.DataFrame()
for c, (cond, df_c) in enumerate(dataFrame.groupby(groupByColumn, sort=False)):
if len(df_c) <= 1:
extra = extra.append(df_c)
extra.index = extra.index + pandas.DateOffset(seconds=1)
dataFrame = dataFrame.append(extra)
return dataFrame
def datetime2graphdays(dt):
return mdates.epoch2num((time.mktime(dt.timetuple()) / 86400) * mdates.SEC_PER_DAY)
def graphdays2datetime(x):
epoch = mdates.num2epoch(x)
return datetime.fromtimestamp(int(epoch), utc)
def getFilename(metric, analyticConfig):
now = datetime.now(tz=utc)
format = "%Y%m%d%H%M%S"
nowStr = time.strftime(format, now.timetuple())
fileNameBase = metric
if analyticConfig.sample is not None:
fileNameBase += "-" + analyticConfig.sample
if analyticConfig.how is not None:
fileNameBase += "-" + analyticConfig.how
return fileNameBase + '-' + nowStr
def getDirectoryPathForDate(format='%Y/%m/%d'):
now = datetime.now(tz=utc)
return time.strftime(format, now.timetuple())
def getTitle(timelyMetric, config, separator='\n'):
if config.orCondition:
condition = "OR"
else:
condition = "AND"
metricTitle = timelyMetric.metric
if timelyMetric.tags is not None and len(timelyMetric.tags) > 0:
metricTitle += ' (' + timelyMetric.tags + ')'
sampleTitle = ""
alertTitle = ""
if config.sample_period is not None:
sampleTitle = config.sample_period + " " + config.how + " samples"
if config.rolling_average_period is not None:
sampleTitle += ', ' + config.rolling_average_period + ' rolling average'
if config.min_threshold is not None:
if alertTitle != "":
alertTitle += " " + condition + " "
alertTitle += "(y < " + str(config.min_threshold) + ")"
if config.average_min_threshold is not None:
if alertTitle != "":
alertTitle += " " + condition + " "
alertTitle += "(y-avg < " + str(config.average_min_threshold) + ")"
if config.max_threshold is not None:
if alertTitle != "":
alertTitle += " " + condition + " "
alertTitle += "(y > " + str(config.max_threshold) + ")"
if config.average_max_threshold is not None:
if alertTitle != "":
alertTitle += " " + condition + " "
alertTitle += "(y-avg > " + str(config.average_max_threshold) + ")"
if config.min_threshold_percentage is not None:
if alertTitle != "":
alertTitle += " " + condition + " "
if config.min_threshold_percentage >= 0:
descriptivePercentage = 100 + config.min_threshold_percentage
else:
descriptivePercentage = abs(config.min_threshold_percentage)
alertTitle += "(y < " + str(descriptivePercentage) + "% of " + str(
config.rolling_average_period) + " sample average)"
if config.max_threshold_percentage is not None:
if alertTitle != "":
alertTitle += " " + condition + " "
if config.max_threshold_percentage >= 0:
descriptivePercentage = 100 + config.max_threshold_percentage
else:
descriptivePercentage = abs(config.max_threshold_percentage)
alertTitle += "(y > " + str(descriptivePercentage) + "% of " + str(
config.rolling_average_period) + " sample average)"
if config.system_name is None:
title = metricTitle
else:
title = config.system_name + ' - ' + metricTitle
if sampleTitle != "":
title += separator + sampleTitle
if alertTitle != "":
if config.min_alert_period is not None:
alertTitle = '(' + alertTitle + ') for at least ' + config.min_alert_period
if config.last_alert is not None:
alertTitle = alertTitle + ' in last ' + config.last_alert
title += separator + alertTitle
return title
@@ -1,128 +0,0 @@
import time
from datetime import datetime
from datetime import timedelta
from datetime import tzinfo
from pandas.tslib import Timedelta
import pandas
class TimeDateError(ValueError):
def __init__(self, message, *args):
self.message = message
super(TimeDateError, self).__init__(message, *args)
ZERO = timedelta(0)
# A UTC class.
class UTC(tzinfo):
"""UTC"""
def __str__(self):
return "UTC"
def utcoffset(self, dt):
return ZERO
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return ZERO
utc = UTC()
class TimeDateRange:
beginDt = None
endDt = None
format = "%Y%m%d %H%M%S"
def getBeginMs(self):
if self.beginDt == None:
return None
return int(time.mktime(self.beginDt.timetuple()) * 1000)
def getBeginStr(self):
if self.beginDt == None:
return None
return time.strftime(self.format, self.beginDt.timetuple())
def getEndMs(self):
if self.endDt == None:
return None
return int(time.mktime(self.endDt.timetuple()) * 1000)
def getEndStr(self):
if self.endDt == None:
return None
return time.strftime(self.format, self.endDt.timetuple())
def __init__(self, beginStr, endStr, period, format="%Y%m%d-%H%M%S"):
now = datetime.now(tz=utc)
nowMs = TimeDateRange.unix_time_millis(now)
if beginStr != None and endStr != None and period != None:
raise TimeDateError("You can not provide a begin, end, and period")
elif (beginStr == None and endStr == None and period == None) or (period == None and beginStr == None):
raise TimeDateError("You must provide a time range")
if period == None:
# calculate begin time
beginTuple = time.strptime(beginStr, self.format)
self.beginDt = datetime(*beginTuple[0:6], tzinfo=utc)
# calculate end time
# end is either specified or now
if endStr == None or endStr == 'now':
self.endDt = now
else:
self.endDt = datetime(*time.strptime(endStr, self.format)[0:6], tzinfo=utc)
if self.endDt > now:
self.endDt = now
else:
# period must be specified
td = pandas.to_timedelta(period)
rangeInSec = td.total_seconds()
if beginStr == None:
# calculate begin time from end tme and period
# calculate end time
# end is either specified or now
if endStr == None or endStr == 'now':
self.endDt = now
else:
self.endDt = datetime(*time.strptime(endStr, self.format)[0:6], tzinfo=utc)
if self.endDt > now:
self.endDt = now
# calculate begin time
self.beginDt = self.endDt - timedelta(milliseconds=rangeInSec * 1000)
else:
# calculate end time from begin tme and period
# calculate begin time
self.beginDt = datetime(*time.strptime(beginStr, self.format)[0:6], tzinfo=utc)
# calculate end time
self.endDt = self.beginDt + timedelta(milliseconds=rangeInSec * 1000)
if self.endDt > now:
self.endDt = now
if self.beginDt > now:
raise TimeDateError("begin date/time can not be in the future")
if self.beginDt > self.endDt:
raise TimeDateError("begin date/time can not be past end date/time")
epoch = datetime.utcfromtimestamp(0).replace(tzinfo=utc)
@classmethod
def unix_time_millis(cls, dt):
return (dt - TimeDateRange.epoch).total_seconds() * 1000.0
@@ -1,72 +0,0 @@
import smtplib
from os.path import basename
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate
import TimelyMetric
import syslog
import DataOperations
syslog.openlog("TimelyNotifications")
class TimelyAlert():
def __init__(self, timelyMetric, dataFrame, message, seriesConfig, analyticConfig, notebook):
self.timelyMetric = timelyMetric
self.dataFrame = dataFrame
self.seriesConfig = seriesConfig
self.analyticConfig = analyticConfig
self.notebook = notebook
self.message = message
def email(self, send_from, send_to, subject, text, files=None, server="127.0.0.1"):
assert isinstance(send_to, list)
msg = MIMEMultipart()
msg['From'] = send_from
msg['To'] = COMMASPACE.join(send_to)
msg['Date'] = formatdate(localtime=True)
msg['Subject'] = subject
msg.attach(MIMEText(text))
for f in files or []:
with open(f, "rb") as fil:
part = MIMEApplication(
fil.read(),
Name=basename(f)
)
part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
msg.attach(part)
smtp = smtplib.SMTP(server)
smtp.sendmail(send_from, send_to, msg.as_string())
smtp.close()
def log(self, message):
syslog.systlog(syslog.LOG_ALERT, message)
def graph(self, type="png"):
graphConfig = {}
graphConfig["title"] = DataOperations.getTitle(self.timelyMetric, self.analyticConfig)
return TimelyMetric.graph(self.analyticConfig, self.dataFrame, self.timelyMetric, seriesConfig=self.seriesConfig, graphConfig=graphConfig, notebook=self.notebook, type=type)
def getDataFrame(self):
return self.dataFrame
def getAnalyticConfig(self):
return self.analyticConfig
def getSeriesConfig(self):
return self.seriesConfig
def getTimelyMetric(self):
return self.timelyMetric
def getMessage(self):
return self.message
@@ -1,224 +0,0 @@
import TimelyMetric
from TimeDateRange import TimeDateRange
from TimeDateRange import UTC
from TimelyAnalyticConfiguration import TimelyAnalyticConfiguration
import DataOperations
import pandas
import re
from datetime import datetime
from datetime import timedelta
from TimelyAlert import TimelyAlert
import numpy as np
utc = UTC()
def logTiming(timelyMetric, startTime, stopTime):
df = timelyMetric.getDataFrame()
print("start: " + str(startTime))
print("stop: " + str(stopTime))
print("num records: " + str(len(df)))
elapsedSec = (TimeDateRange.unix_time_millis(stopTime) - TimeDateRange.unix_time_millis(startTime)) / 1000
print("elapsed seconds: " + str(elapsedSec))
recPerSec = len(df) / elapsedSec
print("records per second: " + recPerSec)
def addCondition(orCondition, currResult, condition):
if orCondition:
currResult = currResult | condition
else:
currResult = currResult & condition
return currResult
def keepConsecutiveAlerts(dataFrame, exceptions, minimumSpan):
if exceptions.size > 0 and minimumSpan is not None:
currentFirst = None
currentLast = None
result_span_values = pandas.DataFrame()
result_span_values['bool'] = np.zeros(exceptions.shape, bool)
result_span_values = result_span_values.set_index(exceptions.index)
current_result_span_values = pandas.DataFrame()
current_result_span_values['bool'] = np.zeros(exceptions.shape, bool)
current_result_span_values = current_result_span_values.set_index(exceptions.index)
for index, row in dataFrame.iterrows():
if index in exceptions.index:
current_result_span_values.loc[index]['bool'] = True
currentLast = index
if currentFirst is None:
currentFirst = index
if int((currentLast - currentFirst).total_seconds() / 60) >= int(minimumSpan):
result_span_values['bool'] = result_span_values['bool'] | current_result_span_values['bool']
else:
current_result_span_values['bool'] = np.zeros(exceptions.shape, bool)
currentFirst = None
currentLast = None
return exceptions.loc[result_span_values['bool']]
else:
return exceptions
def convertCounterToRate(timelyMetric, analyticConfig):
# Adjust counter metric into a rate metric
df = timelyMetric.getDataFrame()
columnNames = df[analyticConfig.groupByColumn].unique()
df = DataOperations.pivot(df, timelyMetric.metric, analyticConfig.groupByColumn)
df = DataOperations.resample(df, analyticConfig.sample, how=analyticConfig.how)
for c in columnNames:
df[c] = df[c].diff(1) / (analyticConfig.sample_minutes * 60 * 1000)
df = DataOperations.unpivot(df, timelyMetric.metric, analyticConfig.groupByColumn)
df = df.dropna()
timelyMetric.setDataFrame(df)
def find_alerts(timelyMetric, analyticConfig, notebook=False):
if (analyticConfig.counter == True):
convertCounterToRate(timelyMetric, analyticConfig)
df = timelyMetric.getDataFrame()
graphDF = TimelyMetric.pivot(df, timelyMetric.metric, groupByColumn=analyticConfig.groupByColumn)
if analyticConfig.excludeColRegex is not None:
graphDF = graphDF.select(lambda x : not (re.search(analyticConfig.excludeColRegex, x)), axis=1)
if analyticConfig.includeColRegex is not None:
graphDF = graphDF.select(lambda x : re.search(analyticConfig.includeColRegex, x), axis=1)
if analyticConfig.sample is not None:
graphDF = TimelyMetric.resample(graphDF, analyticConfig.sample, how=analyticConfig.how)
graphDF_avg = pandas.DataFrame(graphDF, copy=True)
combined = pandas.DataFrame()
seriesConfig = {}
for i in graphDF_avg.columns:
col = str(i)
any_conditions_values = False
result_values = np.ones(graphDF[col].shape, bool)
if analyticConfig.orCondition:
result_values = np.zeros(graphDF[col].shape, bool)
any_conditions_average = False
result_average = np.ones(graphDF_avg[col].shape, bool)
if analyticConfig.orCondition:
result_average = np.zeros(graphDF_avg[col].shape, bool)
if analyticConfig.min_threshold is not None:
currCondition = graphDF[col].astype(float) < analyticConfig.min_threshold
result_values = addCondition(analyticConfig.orCondition, result_values, currCondition)
any_conditions_values = True
if analyticConfig.max_threshold is not None:
currCondition = graphDF[col].astype(float) > analyticConfig.max_threshold
result_values = addCondition(analyticConfig.orCondition, result_values, currCondition)
any_conditions_values = True
if analyticConfig.rolling_average_samples is not None:
graphDF_avg = TimelyMetric.rolling_average(graphDF_avg, col, rolling_average=analyticConfig.rolling_average_samples)
if analyticConfig.min_threshold_percentage is not None:
if analyticConfig.min_threshold_percentage >= 0:
multiple = 1.0 + (float(abs(analyticConfig.min_threshold_percentage)) / float(100))
else:
multiple = 1.0 - (float(abs(analyticConfig.min_threshold_percentage)) / float(100))
currCondition = graphDF[col].astype(float) < (graphDF_avg[col].astype(float) * multiple)
result_values = addCondition(analyticConfig.orCondition, result_values, currCondition)
any_conditions_values = True
if analyticConfig.max_threshold_percentage is not None:
if analyticConfig.max_threshold_percentage >= 0:
multiple = 1.0 + (float(abs(analyticConfig.max_threshold_percentage)) / float(100))
else:
multiple = 1.0 - (float(abs(analyticConfig.max_threshold_percentage)) / float(100))
currCondition = graphDF[col].astype(float) > (graphDF_avg[col].astype(float) * multiple)
result_values = addCondition(analyticConfig.orCondition, result_values, currCondition)
any_conditions_values = True
if analyticConfig.average_min_threshold is not None:
currCondition = graphDF_avg[col].astype(float) < analyticConfig.average_min_threshold
result_average = addCondition(analyticConfig.orCondition, result_average, currCondition)
any_conditions_average = True
if analyticConfig.average_max_threshold is not None:
currCondition = graphDF_avg[col].astype(float) > analyticConfig.average_max_threshold
result_average = addCondition(analyticConfig.orCondition, result_average, currCondition)
any_conditions_average = True
# if orCondition is AND and no exceptional conditions have been found, then result_values will be all True
if any_conditions_values == False:
result_values = np.zeros(graphDF[col].shape, bool)
exceptional_values = graphDF.loc[result_values, col]
# if orCondition is AND and no exceptional conditions have been found, then result_average will be all True
if any_conditions_average == False:
result_average = np.zeros(graphDF_avg[col].shape, bool)
exceptional_average = graphDF_avg.loc[result_average, col]
# only keep alerts that are in consecutive periods of length analyticConfig.min_alert_minutes
exceptional_values = keepConsecutiveAlerts(graphDF, exceptional_values, analyticConfig.min_alert_minutes)
exceptional_average = keepConsecutiveAlerts(graphDF_avg, exceptional_average, analyticConfig.min_alert_minutes)
# only evaluate the last analyticConfig.last_alert_minutes if set
if analyticConfig.last_alert_minutes is not None:
end = datetime.fromtimestamp(timelyMetric.timeDateRange.getEndMs() / 1000.00, DataOperations.utc)
recentEnoughBegin = end - timedelta(minutes=analyticConfig.last_alert_minutes)
exceptional_values = exceptional_values.ix[recentEnoughBegin:end]
exceptional_average = exceptional_average.ix[recentEnoughBegin:end]
anyValueExceptions = exceptional_values.size > 0
anyAverageExceptions = exceptional_average.size > 0
if (analyticConfig.display.lower() == "all") or (analyticConfig.display.lower() == "alerts" and anyValueExceptions):
combined[col] = graphDF[col]
if analyticConfig.rolling_average_samples is not None:
if (analyticConfig.display.lower() == "all"):
combined[col + '_avg'] = graphDF_avg[col]
else:
if (anyAverageExceptions):
combined[col + '_avg'] = graphDF_avg[col]
if (anyValueExceptions and (analyticConfig.min_threshold_percentage is not None or analyticConfig.max_threshold_percentage is not None)):
combined[col + '_avg'] = graphDF_avg[col]
if ((analyticConfig.display.lower() == "all") or (analyticConfig.display.lower() == "alerts" and anyValueExceptions)):
combined[col + '_warn'] = exceptional_values.dropna()
seriesConfig[col + '_warn'] = {
"mode" : "markers",
"marker" : {
"symbol" : "hash-open",
"color" : "red"
}
}
if ((analyticConfig.display.lower() == "all") or (analyticConfig.display.lower() == "alerts" and anyAverageExceptions)):
combined[col + '_avg_warn'] = exceptional_average.dropna()
seriesConfig[col + '_avg_warn'] = {
"mode" : "markers",
"marker" : {
"symbol" : "hash-open",
"color" : "red"
}
}
timelyAlert = None
if not combined.empty:
alertAnalyticConfig = TimelyAnalyticConfiguration(analyticConfig)
if alertAnalyticConfig.groupByColumn is None:
alertAnalyticConfig.groupByColumn = timelyMetric.metric + "_obs"
combined = TimelyMetric.unpivot(combined, timelyMetric.metric, groupByColumn=alertAnalyticConfig.groupByColumn)
combined = combined.sort_index()
combined['date'] = combined.index.values
combined = combined.sort_values(['date', alertAnalyticConfig.groupByColumn])
combined = combined.drop(['date'], 1)
combined = combined.dropna()
combined = DataOperations.ensureMinSeriesLength(combined, alertAnalyticConfig.groupByColumn)
message = DataOperations.getTitle(timelyMetric, analyticConfig, separator=', ')
timelyAlert = TimelyAlert(timelyMetric, combined, message, seriesConfig, alertAnalyticConfig, notebook)
return timelyAlert
@@ -1,84 +0,0 @@
import pandas
class TimelyAnalyticConfiguration():
def __init__(self, analyticConfig):
if isinstance(analyticConfig, dict):
self.groupByColumn = analyticConfig.get('groupByColumn', None)
self.includeColRegex = analyticConfig.get('includeColRegex', None)
self.excludeColRegex = analyticConfig.get('excludeColRegex', None)
self.counter = analyticConfig.get('counter', False)
self.sample_period = analyticConfig.get('sample', None)
self.how = analyticConfig.get('how', 'mean')
self.rolling_average_period = analyticConfig.get('rolling_average_period', None)
self.min_threshold = analyticConfig.get('min_threshold', None)
self.average_min_threshold = analyticConfig.get('average_min_threshold', None)
self.max_threshold = analyticConfig.get('max_threshold', None)
self.average_max_threshold = analyticConfig.get('average_max_threshold', None)
self.min_threshold_percentage = analyticConfig.get('min_threshold_percentage', None)
self.max_threshold_percentage = analyticConfig.get('max_threshold_percentage', None)
self.min_alert_period = analyticConfig.get('min_alert_period', None)
boolean = analyticConfig.get('boolean', 'or')
self.orCondition = boolean == 'or' or boolean == 'OR'
# alerts or all
self.display = analyticConfig.get('display', 'alerts')
self.send_alerts_to = analyticConfig.get('send_alerts_to', [])
self.output_dir = analyticConfig.get('output_dir', '/tmp')
self.last_alert = analyticConfig.get('last_alert', None)
self.system_name = analyticConfig.get('system_name', None)
self.sample = None
self.sample_minutes = None
if self.sample_period is not None:
td = pandas.to_timedelta(self.sample_period)
self.sample_minutes = int(td.total_seconds() / 60)
self.sample = str(self.sample_minutes) + 'min'
self.rolling_average_samples = None
self.rolling_average_minutes = None
if (self.rolling_average_period is not None) and (self.sample_minutes is not None):
td = pandas.to_timedelta(self.rolling_average_period)
self.rolling_average_minutes = int(td.total_seconds() / 60)
self.rolling_average_samples = int(self.rolling_average_minutes / self.sample_minutes)
self.min_alert_minutes = None
if self.min_alert_period is not None:
td = pandas.to_timedelta(self.min_alert_period)
self.min_alert_minutes = int(td.total_seconds() / 60)
self.last_alert_minutes = None
if self.last_alert is not None:
td = pandas.to_timedelta(self.last_alert)
self.last_alert_minutes = int(td.total_seconds() / 60)
elif isinstance(analyticConfig, TimelyAnalyticConfiguration):
self.groupByColumn = analyticConfig.groupByColumn
self.includeColRegex = analyticConfig.includeColRegex
self.excludeColRegex = analyticConfig.excludeColRegex
self.counter = analyticConfig.counter
self.sample_period = analyticConfig.sample_period
self.sample_minutes = analyticConfig.sample_minutes
self.sample = analyticConfig.sample
self.how = analyticConfig.how
self.rolling_average_period = analyticConfig.rolling_average_period
self.rolling_average_samples = analyticConfig.rolling_average_samples
self.rolling_average_minutes = analyticConfig.rolling_average_minutes
self.min_threshold = analyticConfig.min_threshold
self.average_min_threshold = analyticConfig.average_min_threshold
self.max_threshold = analyticConfig.max_threshold
self.average_max_threshold = analyticConfig.average_max_threshold
self.min_threshold_percentage = analyticConfig.min_threshold_percentage
self.max_threshold_percentage = analyticConfig.max_threshold_percentage
self.min_alert_period = analyticConfig.min_alert_period
self.min_alert_minutes = analyticConfig.min_alert_minutes
self.orCondition = analyticConfig.orCondition
# alerts or all
self.display = analyticConfig.display
self.send_alerts_to = analyticConfig.send_alerts_to
self.output_dir = analyticConfig.output_dir
self.last_alert = analyticConfig.last_alert
self.last_alert_minutes = analyticConfig.last_alert_minutes
self.system_name = analyticConfig.system_name
@@ -1,216 +0,0 @@
from TimeDateRange import TimeDateRange
from TimeDateRange import TimeDateError
from TimeDateRange import UTC
from DataOperations import *
import json
import pandas
import getopt
import sys
import random
from WebSocketClient import WebSocketClient
from tornado import ioloop
utc = UTC()
class TimelyWebSocketClient(WebSocketClient):
def __init__(self, hostport, metric, tags, startTime, endTime, connect_timeout=WebSocketClient.DEFAULT_CONNECT_TIMEOUT,
request_timeout=WebSocketClient.DEFAULT_REQUEST_TIMEOUT):
self.metric = metric
self.tags = tags
self.startTime = startTime
self.endTime = endTime
self.subscriptionId = random.randint(1000000000, 9999999999)
WebSocketClient.__init__(self, hostport, connect_timeout, request_timeout)
def _on_message(self, msg):
# implement in subclass
pass
def _on_connection_success(self):
print('Connected.')
create = {
"operation": "create",
"subscriptionId": self.subscriptionId,
}
self.send(create)
self.send(create)
m1 = {
"operation": "add",
"subscriptionId": self.subscriptionId,
"metric": self.metric,
"startTime": self.startTime,
"endTime" : self.endTime
}
if self.tags is not None:
t = self.tags.strip().split(',')
tagDict = {}
for pair in t:
k = pair.split('=')[0].strip()
v = pair.split('=')[1].strip()
tagDict = dict(tagDict.items() + dict({k : v}).items())
m1["tags"] = tagDict
self.send(m1)
def _on_connection_close(self):
print('Connection closed!')
exit()
def _on_connection_error(self, exception):
print('Connection error: %s', exception)
class TimelyMetric(TimelyWebSocketClient):
client = None
endtime = None
def __init__(self, hostport, metric, tags, beginStr, endStr, period, sample):
self.series = pandas.Series()
self.metric = metric
self.tags = tags
self.sample = sample
self.debug = False
self.dataFrame = None
self.data = []
self.timeDateRange = TimeDateRange(beginStr, endStr, period)
TimelyWebSocketClient.__init__(self, hostport, metric, tags, self.timeDateRange.getBeginMs(), self.timeDateRange.getEndMs())
def debugOn(self):
self.debug = True
def debugOff(self):
self.debug = False
def fetch(self):
ioloop.IOLoop().make_current()
self.connect(ioloop.IOLoop.current(instance=False))
ioloop.IOLoop.current(instance=False).start()
return self
def _on_message(self, msg):
global df
global endtime
responsesObj = json.loads(msg)
responses = responsesObj.get("responses")
for obj in responses:
complete = bool(obj.get("complete"))
if complete:
self._on_connection_close()
return
else:
date = int(obj.get("timestamp")/1000)
dt = pandas.datetime.utcfromtimestamp(date)
metricName = str(obj.get("metric"))
metricValue = obj.get("value")
newData = {}
newData["date"] = dt
newData[metricName] = metricValue
tags = obj.get("tags")
for d in tags:
for k,v in d.items():
newData[k] = v
self.data.append(newData)
def _on_connection_close(self):
global client
self.dataFrame = pandas.DataFrame(self.data)
if len(self.dataFrame) > 0:
self.dataFrame['date'] = pandas.DatetimeIndex(self.dataFrame['date'])
self.dataFrame = self.dataFrame.set_index('date')
self.close()
ioloop.IOLoop.current(instance=False).stop()
print("Exiting.")
def getDataFrame(self):
return self.dataFrame;
def setDataFrame(self, dataFrame):
self.dataFrame = dataFrame
def print_debug(self):
if self.debug:
print(self.dataFrame)
def graph(self, groupByColumn=None):
return graph(self.dataFrame, self, sample=self.sample, how=self.how, groupByColumn=groupByColumn)
def main():
period = None
beginStr = None
endStr = None
metric = "timely.metrics.received"
sample = None
how = None
tags = None
groupByColumn = None
try:
argv = sys.argv
options, remainder = getopt.getopt(argv[1:], 'h', ['metric=', 'tags=', 'period=', 'groupByColumn=', 'begin=', 'end=', 'sample=', 'how=', 'hostport='])
except getopt.GetoptError:
print('TimelyMetric.py ---hostport=<host:port> --metric=<metric> --tags=<tag1=val1,tag2=val2> --period=<period>, --groupByColumn=<groupByColumn>, --sample=<sample_period> --how=<mean|min|max>')
sys.exit(2)
for opt, arg in options:
if opt == '-h':
print('TimelyMetric.py --hostport=<host:port> --metric=<metric> --tags=<tag1=val1,tag2=val2> --period=<period>, --groupByColumn=<groupByColumn>, --sample=<sample_period> --how=<mean|min|max>')
sys.exit()
elif opt in ("--metric"):
metric = arg
elif opt in ("--period"):
period = arg
elif opt in ("--begin"):
beginStr = arg
elif opt in ("--end"):
endStr = arg
elif opt in ("--groupByColumn"):
groupByColumn = arg
elif opt in ("--sample"):
sample = arg
elif opt in ("--how"):
how = arg
elif opt in ("--hostport"):
hostport = arg
try:
timelyMetric = TimelyMetric(hostport, metric, tags, beginStr, endStr, period, sample).fetch()
dataFrame = timelyMetric.getDataFrame()
if dataFrame is not None:
dataFrame = resample(dataFrame, metric, sample, how)
dataFrame = pivot(dataFrame, metric, groupByColumn=groupByColumn)
graph(dataFrame, timelyMetric, sample=sample, groupByColumn=groupByColumn, graphConfig={}, notebook=False)
except TimeDateError as e:
print(e.message)
if __name__ == '__main__':
main()
@@ -1,91 +0,0 @@
from tornado import escape
from tornado import gen
from tornado import ioloop
from tornado import websocket
import json
class WebSocketClient():
"""Base for web socket clients.
"""
DEFAULT_CONNECT_TIMEOUT = 60
DEFAULT_REQUEST_TIMEOUT = 60
APPLICATION_JSON = 'application/json'
def __init__(self, hostport, connect_timeout=DEFAULT_CONNECT_TIMEOUT,
request_timeout=DEFAULT_REQUEST_TIMEOUT):
self.connect_timeout = connect_timeout
self.request_timeout = request_timeout
self.url = 'wss://' + hostport + '/websocket'
def connect(self, ioloop=ioloop.IOLoop.current(instance=False)):
"""Connect to the server.
:param str url: server URL.
"""
request = websocket.httpclient.HTTPRequest(self.url, connect_timeout=self.connect_timeout, request_timeout=self.request_timeout, validate_cert=False)
websocket.websocket_connect(request, io_loop=ioloop, callback=self._connect_callback)
def send(self, data):
"""Send message to the server
:param str data: message.
"""
if not self._ws_connection:
raise RuntimeError('Web socket connection is closed.')
self._ws_connection.write_message(escape.utf8(json.dumps(data)))
def close(self):
"""Close connection.
"""
if not self._ws_connection:
raise RuntimeError('Web socket connection is already closed.')
self._ws_connection.close()
self._ws_connection = None
def _connect_callback(self, future):
if future.exception() is None:
self._ws_connection = future.result()
self._on_connection_success()
self._read_messages()
else:
self._on_connection_error(future.exception())
@gen.coroutine
def _read_messages(self):
while True and not self._ws_connection is None:
msg = yield self._ws_connection.read_message()
if msg is None:
self._on_connection_close()
break
self._on_message(msg)
def _on_message(self, msg):
"""This is called when new message is available from the server.
:param str msg: server message.
"""
pass
def _on_connection_success(self):
"""This is called on successful connection ot the server.
"""
pass
def _on_connection_close(self):
"""This is called when server closed the connection.
"""
pass
def _on_connection_error(self, exception):
"""This is called in case if connection to the server could
not established.
"""
pass
Whitespace-only changes.
@@ -1,47 +0,0 @@
import TimelyMetric
import TimelyAnalytic
import DataOperations
import os
from TimelyAnalyticConfiguration import TimelyAnalyticConfiguration
hostport = "127.0.0.1:4244"
timelyMetric = TimelyMetric.TimelyMetric(hostport, '', None, None, None, 48, None).fetch()
analyticConfig = TimelyAnalyticConfiguration({
'system_name' : 'TestSystem',
'counter' : False,
'includeColRegex' : None,
'excludeColRegex' : None,
'groupByColumn' : 'instance',
'sample' : '10 minutes',
'how' : 'mean',
'rolling_average_period' : '12 hours',
'min_threshold' : None,
'average_min_threshold' : None,
'max_threshold' : None,
'average_max_threshold' : None,
'min_threshold_percentage' : -50,
'max_threshold_percentage' : 50,
'boolean' : 'and',
'min_alert_period' : '5 minutes',
'last_alert' : '1 hour',
'display' : 'all',
'output_dir' : '/path/to/output'
})
alert = TimelyAnalytic.find_alerts(timelyMetric, analyticConfig)
if alert is not None:
# write graph to file
oldmask = os.umask(022)
file = alert.graph(type='html')
os.umask(oldmask)
text = DataOperations.getTitle(timelyMetric, analyticConfig)
# send email with graph attached
alert.email("", "", text, text, [file])
# log to syslog
alert.log(text)
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
<Or>
<Bug pattern="DM_DEFAULT_ENCODING"/>
<Method name="connect" />
<Class name="timely.client.tcp.TcpClient"/>
</Or>
</FindBugsFilter>
@@ -1,58 +0,0 @@
package timely.api;
import org.junit.Assert;
import org.junit.Test;
import timely.serialize.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
public class SerializationTest {
private ObjectMapper mapper = JsonSerializer.getObjectMapper();
@Test
public void testBasicAuth() throws Exception {
BasicAuthLogin login = new BasicAuthLogin();
login.setUsername("test");
login.setPassword("pass");
testSerialization(login);
}
@Test
public void testCreateSubscription() throws Exception {
CreateSubscription create = new CreateSubscription();
create.setSubscriptionId("1234");
testSerialization(create);
}
@Test
public void testCloseSubscription() throws Exception {
CloseSubscription close = new CloseSubscription();
close.setSubscriptionId("1234");
testSerialization(close);
}
@Test
public void testAddSubscription() throws Exception {
AddSubscription add = new AddSubscription();
add.setSubscriptionId("1234");
add.setMetric("sys.cpu.user");
testSerialization(add);
}
@Test
public void testRemoveSubscription() throws Exception {
RemoveSubscription remove = new RemoveSubscription();
remove.setSubscriptionId("1234");
remove.setMetric("sys.cpu.user");
testSerialization(remove);
}
@SuppressWarnings("unchecked")
private <T> void testSerialization(T o) throws Exception {
String ser = mapper.writeValueAsString(o);
T des = mapper.readValue(ser, (Class<T>) o.getClass());
Assert.assertEquals(o, des);
}
}
@@ -1,63 +0,0 @@
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);
}
}
@@ -1,40 +0,0 @@
package timely.model;
import org.junit.Assert;
import org.junit.Test;
import timely.model.parse.TagListParser;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class TagListParserTest {
@Test
public void testListParse() {
String value = "tag1=value1,tag2=value2";
List<Tag> tags = new TagListParser().parse(value);
Assert.assertEquals(2, tags.size());
Assert.assertEquals(new Tag("tag1", "value1"), tags.get(0));
Assert.assertEquals(new Tag("tag2", "value2"), tags.get(1));
}
@Test
public void testListCombine() {
List<Tag> tags = new ArrayList<>();
tags.add(new Tag("tag1", "value1"));
tags.add(new Tag("tag2", "value2"));
String combined = new TagListParser().combine(tags);
Assert.assertEquals("tag1=value1,tag2=value2", combined);
}
@Test
public void testListCombineMap() {
Map<String, String> map = new TreeMap<>();
map.put("tag1", "value1");
map.put("tag2", "value2");
String combined = new TagListParser().combine(map);
Assert.assertEquals("tag1=value1,tag2=value2", combined);
}
}
-73
View File
@@ -1,73 +0,0 @@
<?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.7-SNAPSHOT</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>org.apache.commons</groupId>
<artifactId>commons-pool2</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>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -1,97 +0,0 @@
package timely.collectd.plugin;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.collectd.api.OConfigItem;
import java.util.concurrent.TimeUnit;
public class PooledCloseableHttpClientFactory implements PooledObjectFactory {
private int connectionRequestTimeout = 10000; // 10 seconds in milliseconds
private int connectTimeout = 30000; // 30 seconds in milliseconds
private int socketTimeout = 60000; // 60 seconds in milliseconds
private long connectionTimeToLive = 300000; // 300 seconds in milliseconds
public int config(OConfigItem config) {
for (OConfigItem child : config.getChildren()) {
switch (child.getKey()) {
case "connectionRequestTimeout":
case "ConnectionRequestTimeout":
connectionRequestTimeout = Integer.parseInt(child.getValues().get(0).getString());
break;
case "connectTimeout":
case "ConnectTimeout":
connectTimeout = Integer.parseInt(child.getValues().get(0).getString());
break;
case "socketTimeout":
case "SocketTimeout":
socketTimeout = Integer.parseInt(child.getValues().get(0).getString());
break;
case "connectionTimeToLive":
case "ConnectionTimeToLive":
connectionTimeToLive = Long.parseLong(child.getValues().get(0).getString());
break;
default:
}
}
return 0;
}
@Override
public PooledObject makeObject() throws Exception {
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout)
.setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setDefaultRequestConfig(requestConfig);
builder.setConnectionTimeToLive(connectionTimeToLive, TimeUnit.MILLISECONDS);
return new DefaultPooledObject(builder.build());
}
@Override
public void destroyObject(PooledObject pooledObject) throws Exception {
try {
((CloseableHttpClient) pooledObject.getObject()).close();
} catch (Exception e) {
// do nothing
} finally {
pooledObject.invalidate();
;
}
}
@Override
public boolean validateObject(PooledObject pooledObject) {
return pooledObject.getObject() != null;
}
@Override
public void activateObject(PooledObject pooledObject) throws Exception {
// do nothing
}
@Override
public void passivateObject(PooledObject pooledObject) throws Exception {
// do nothing
}
public void setConnectionRequestTimeout(int connectionRequestTimeout) {
this.connectionRequestTimeout = connectionRequestTimeout;
}
public void setConnectTimeout(int connectTimeout) {
this.connectTimeout = connectTimeout;
}
public void setSocketTimeout(int socketTimeout) {
this.socketTimeout = socketTimeout;
}
public void setConnectionTimeToLive(long connectionTimeToLive) {
this.connectionTimeToLive = connectionTimeToLive;
}
}
@@ -1,165 +0,0 @@
package timely.collectd.plugin;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.http.HttpStatus;
import org.apache.http.client.entity.EntityBuilder;
import org.apache.http.client.methods.CloseableHttpResponse;
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 GenericObjectPool<CloseableHttpClient> clientPool = null;
// pool should be limited by the number of WriteThreads configured in
// collectd
final private int POOL_MAX_SIZE = Integer.MAX_VALUE;
public WriteNSQPlugin() {
Collectd.registerConfig(WriteNSQPlugin.class.getName(), this);
Collectd.registerShutdown(WriteNSQPlugin.class.getName(), this);
Collectd.registerWrite(WriteNSQPlugin.class.getName(), this);
}
public int write(ValueList vl) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(baos);
super.process(vl, out);
CloseableHttpClient client = null;
try {
out.flush();
HttpPost post = new HttpPost(endpoint);
EntityBuilder request = EntityBuilder.create();
request.setBinary(baos.toByteArray());
post.setEntity(request.build());
client = clientPool.borrowObject();
CloseableHttpResponse response = client.execute(post);
try {
int code = response.getStatusLine().getStatusCode();
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 (Exception e) {
Collectd.logError("Error sending metrics to NSQ: " + e.getMessage());
if (client != null) {
try {
client.close();
} catch (IOException e1) {
}
try {
clientPool.invalidateObject(client);
} catch (Exception e2) {
}
}
} finally {
if (client != null) {
clientPool.returnObject(client);
}
if (null != out) {
try {
out.close();
} catch (IOException e) {
}
}
}
return 0;
}
@Override
public void write(String metric, OutputStream out) {
try {
((DataOutputStream) 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 int shutdown() {
Collectd.logInfo("Shutting down connection to NSQ at " + host + ":" + port);
clientPool.close();
return 0;
}
public int config(OConfigItem config) {
super.config(config);
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
// use max size for maxTotal and maxIdle
// no need to activate or passivate
poolConfig.setMaxTotal(POOL_MAX_SIZE);
poolConfig.setMaxIdle(POOL_MAX_SIZE);
poolConfig.setTestOnReturn(true);
PooledCloseableHttpClientFactory pooledCloseableHttpClientFactory = new PooledCloseableHttpClientFactory();
pooledCloseableHttpClientFactory.config(config);
for (OConfigItem child : config.getChildren()) {
switch (child.getKey()) {
case "host":
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:
}
}
if (host == null || port == 0 || topic == null) {
Collectd.logError("NSQ host, port, and topic must be configured");
return -1;
}
this.clientPool = new GenericObjectPool(pooledCloseableHttpClientFactory, poolConfig);
this.endpoint = "http://" + host + ":" + port + "/mpub?topic=" + topic;
return 0;
}
}
@@ -1,3 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
</FindBugsFilter>
-64
View File
@@ -1,64 +0,0 @@
<?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.7-SNAPSHOT</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>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -1,261 +0,0 @@
package timely.collectd.plugin;
import java.io.OutputStream;
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 NAME = " name=";
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-_=]+)\\]");
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, OutputStream out);
public void process(ValueList vl, OutputStream out) {
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")) {
metric.append("sys.haproxy.").append(vl.getTypeInstance());
Matcher m = HAPROXY_PATTERN.matcher(vl.getPluginInstance());
if (m.matches()) {
tags.append(" ").append(m.group(1));
tags.append(" ").append(m.group(2));
}
} else if (vl.getPlugin().equals("ipmi")) {
metric.append("sys.ipmi.").append(vl.getType());
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 (vl.getPlugin().equals("GenericJMX")) {
metric.append("sys.").append(vl.getPlugin()).append(PERIOD).append(vl.getType()).append(PERIOD)
.append(vl.getTypeInstance());
String[] pluginInstanceSplit = vl.getPluginInstance().split("-");
if (pluginInstanceSplit.length > 0) {
tags.append(INSTANCE).append(pluginInstanceSplit[0].replaceAll(" ", "_"));
}
if (pluginInstanceSplit.length > 1) {
tags.append(NAME).append(pluginInstanceSplit[1].replaceAll(" ", "_"));
}
} else if (notEmpty(vl.getTypeInstance()) && notEmpty(vl.getType()) && notEmpty(vl.getPluginInstance())
&& notEmpty(vl.getPlugin())) {
metric.append("sys.").append(vl.getPlugin()).append(PERIOD).append(vl.getType()).append(PERIOD)
.append(vl.getTypeInstance());
tags.append(INSTANCE).append(vl.getPluginInstance().replaceAll(" ", "_"));
} else if (notEmpty(vl.getTypeInstance()) && notEmpty(vl.getType()) && notEmpty(vl.getPlugin())) {
metric.append("sys.").append(vl.getPlugin()).append(PERIOD).append(vl.getType()).append(PERIOD)
.append(vl.getTypeInstance());
} else if (notEmpty(vl.getType()) && notEmpty(vl.getPluginInstance()) && notEmpty(vl.getPlugin())) {
metric.append("sys.").append(vl.getPlugin()).append(PERIOD).append(vl.getType());
tags.append(INSTANCE).append(vl.getPluginInstance().replaceAll(" ", "_"));
} 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, out);
}
}
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(""));
}
}
@@ -1,169 +0,0 @@
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();
}
}
@@ -1,3 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
</FindBugsFilter>
@@ -1,338 +0,0 @@
package timely.collectd.plugin;
import static org.junit.Assert.*;
import java.io.OutputStream;
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, OutputStream out) {
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, null);
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, null);
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, null);
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, null);
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, null);
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, null);
assertEquals(
"put sys.smart.raw-read-error-rate 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo instance=sda sample=value sampleType=GAUGE\n",
result);
}
@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, null);
assertEquals(
"put sys.smart.Total_LBAs_Read 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo code=242 instance=sda sample=value sampleType=GAUGE\n",
result);
}
@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, null);
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, null);
assertEquals(
"put sys.sensors.temperature.coretemp-isa-0000 1456156976840 35.0 host=r01n01 rack=r01 addl1=foo instance=1 sample=value sampleType=GAUGE\n",
result);
}
@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, null);
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.setPluginInstance("[proxy_name=proxy1,service_name=server1]");
vl.setTime(TIME);
vl.setType("gauge");
vl.setTypeInstance("queue_current");
vl.setValues(Collections.singletonList((Number) 0.0D));
DataSet ds = new DataSet("GAUGE");
ds.addDataSource(new DataSource("value", 1, 0.0D, 100.0D));
vl.setDataSet(ds);
TestPlugin test = new TestPlugin();
test.process(vl, null);
assertEquals(
"put sys.haproxy.queue_current 1456156976840 0.0 host=r01n01 rack=r01 addl1=foo proxy_name=proxy1 service_name=server1 sample=value sampleType=GAUGE\n",
result);
}
@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, null);
assertEquals(
"put sys.ethstat.tx_comp_queue_full 1456156976840 6.0 host=r01n01 rack=r01 addl1=foo instance=eth0 sample=value sampleType=GAUGE\n",
result);
}
@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, null);
assertEquals(
"put sys.ethstat.rx_bytes 1456156976840 6.0 host=r01n01 rack=r01 addl1=foo queue=1 instance=eth0 sample=value sampleType=GAUGE\n",
result);
}
@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, null);
assertEquals(
"put sys.ipmi.temperature 1456156976840 6.0 host=r01n01 rack=r01 addl1=foo instance=LAN_NIC_Temp_system_board_(3.2) sample=value sampleType=GAUGE\n",
result);
}
}
-98
View File
@@ -1,98 +0,0 @@
<?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.7-SNAPSHOT</version>
</parent>
<artifactId>collectd-timely-plugin</artifactId>
<dependencies>
<dependency>
<groupId>collectd</groupId>
<artifactId>collectd-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<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>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -1,125 +0,0 @@
package timely.collectd.plugin;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.collectd.api.Collectd;
import org.collectd.api.OConfigItem;
import java.net.Socket;
public class PooledSocketFactory implements PooledObjectFactory {
private String host = null;
private int port = 0;
private static final long initialBackoff = 2000;
private int socketTimeout = 60000; // 60 seconds in milliseconds
private long connectionTimeToLive = 300000; // 300 seconds in milliseconds
public int config(OConfigItem config) {
for (OConfigItem child : config.getChildren()) {
switch (child.getKey()) {
case "host":
case "hostname":
case "Host":
case "HostName":
host = child.getValues().get(0).getString();
break;
case "Port":
case "port":
port = Integer.parseInt(child.getValues().get(0).getString());
break;
case "socketTimeout":
case "SocketTimeout":
socketTimeout = Integer.parseInt(child.getValues().get(0).getString());
break;
case "connectionTimeToLive":
case "ConnectionTimeToLive":
connectionTimeToLive = Long.parseLong(child.getValues().get(0).getString());
break;
default:
}
}
if (null != host) {
return 0;
}
if (host == null) {
Collectd.logError("Timely host must be configured");
}
if (port == 0) {
Collectd.logError("Timely port must be configured");
}
return -1;
}
private Socket connect() {
Socket socket = null;
long currentBackoff = initialBackoff;
while (socket == null) {
try {
socket = new Socket(host, port);
if (socketTimeout > -1) {
socket.setSoTimeout(socketTimeout);
}
Collectd.logInfo("Connected to Timely at " + host + ":" + port + " from local port:"
+ socket.getLocalPort());
} catch (Exception e) {
Collectd.logError("Error connecting to Timely at " + host + ":" + port + ". Error: " + e.getMessage()
+ ". Will retry connection in " + currentBackoff + " ms.");
try {
Thread.sleep(currentBackoff);
} catch (InterruptedException e1) {
}
// max out reconnect period at one minute
currentBackoff = (currentBackoff * 2 > 60000) ? 60000 : currentBackoff * 2;
}
}
return socket;
}
@Override
public PooledObject makeObject() throws Exception {
return new DefaultPooledObject(connect());
}
@Override
public void destroyObject(PooledObject pooledObject) throws Exception {
try {
Collectd.logDebug("Shutting down connection to Timely at " + host + ":" + port);
Socket socket = (Socket) pooledObject.getObject();
if (socket != null) {
socket.close();
}
} catch (Exception e) {
Collectd.logError("Error closing connection to Timely at " + host + ":" + port + ". Error: "
+ e.getMessage());
} finally {
pooledObject.invalidate();
;
}
}
@Override
public boolean validateObject(PooledObject pooledObject) {
if (connectionTimeToLive > -1) {
if (pooledObject.getCreateTime() + connectionTimeToLive > System.currentTimeMillis()) {
return false;
}
}
Socket socket = (Socket) pooledObject.getObject();
return socket != null && !socket.isClosed();
}
@Override
public void activateObject(PooledObject pooledObject) throws Exception {
// do nothing
}
@Override
public void passivateObject(PooledObject pooledObject) throws Exception {
// do nothing
}
}
@@ -1,96 +0,0 @@
package timely.collectd.plugin;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.collectd.api.Collectd;
import org.collectd.api.CollectdConfigInterface;
import org.collectd.api.CollectdShutdownInterface;
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 GenericObjectPool<Socket> socketPool = null;
// pool should be limited by the number of WriteThreads configured in
// collectd
final private int POOL_MAX_SIZE = Integer.MAX_VALUE;
public WriteTimelyPlugin() {
Collectd.registerConfig(WriteTimelyPlugin.class.getName(), this);
Collectd.registerShutdown(WriteTimelyPlugin.class.getName(), this);
Collectd.registerWrite(WriteTimelyPlugin.class.getName(), this);
}
public int write(ValueList vl) {
Socket socket = null;
try {
socket = socketPool.borrowObject();
if (socket == null) {
return -1;
}
super.process(vl, socket.getOutputStream());
} catch (Exception e) {
Collectd.logWarning(e.getMessage());
try {
// close socket so that the object pool will discard it and
// reconnect
socket.close();
} catch (IOException e1) {
Collectd.logError(e1.getMessage());
}
return -1;
} finally {
if (socket != null) {
socketPool.returnObject(socket);
}
}
return 0;
}
@Override
public void write(String metric, OutputStream out) {
PrintWriter printWriter = new PrintWriter(out, false);
printWriter.write(metric);
printWriter.flush();
if (printWriter.checkError()) {
throw new RuntimeException("Error writing to Timely");
}
}
public int shutdown() {
socketPool.close();
return 0;
}
public int config(OConfigItem config) {
super.config(config);
int retval = 0;
PooledSocketFactory socketFactory = new PooledSocketFactory();
retval = socketFactory.config(config);
if (retval == 0) {
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
// use max size for maxTotal and maxIdle
// no need to activate and passivate
poolConfig.setMaxTotal(POOL_MAX_SIZE);
poolConfig.setMaxIdle(POOL_MAX_SIZE);
poolConfig.setTestOnReturn(true);
socketPool = new GenericObjectPool(socketFactory, poolConfig);
}
return retval;
}
}
@@ -1,8 +0,0 @@
<?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>
@@ -1,204 +0,0 @@
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.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Collectd.class })
@NotThreadSafe
@PowerMockIgnore("javax.management.*")
public class WriteTimelyPluginTest {
private WriteTimelyPlugin plugin = null;
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()));
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()));
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()));
Thread.sleep(100);
Assert.assertTrue(server.messageReceived());
server.shutdown();
t.join();
Thread.sleep(2000);
server.create();
Thread t2 = new Thread(server);
t2.start();
// Need to call this again because the server is not guaranteed to be
// listening on the same local port as the first time that it was
// started
setupPlugin();
while (!server.ready()) {
Thread.sleep(1000);
// Keep sending metrics to plugin to force reconnect
int result = plugin.write(createMetric());
System.out.println("Wrote to client, result: " + result);
Assert.assertEquals(0, result);
}
Assert.assertEquals(0, plugin.write(createMetric()));
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();
System.out.println("Local port " + port);
}
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.");
}
}
}
@@ -1,13 +0,0 @@
<?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>
-1
View File
@@ -1 +0,0 @@
/target/
-24
View File
@@ -1,24 +0,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.7-SNAPSHOT</version>
</parent>
<artifactId>timely-common</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -1,4 +0,0 @@
package timely.test;
public interface IntegrationTest {
}
+44
View File
@@ -0,0 +1,44 @@
# 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
Executable
+222
View File
@@ -0,0 +1,222 @@
#!/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
@@ -1,295 +0,0 @@
<?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
@@ -0,0 +1,148 @@
{
"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
@@ -1,15 +0,0 @@
<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>
-36
View File
@@ -1,36 +0,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-app</artifactId>
<parent>
<groupId>timely</groupId>
<artifactId>timely</artifactId>
<version>0.0.7-SNAPSHOT</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>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
-2
View File
@@ -1,2 +0,0 @@
node_modules/
-65
View File
@@ -1,65 +0,0 @@
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
@@ -1,3 +0,0 @@
# Timely
Timely: a scalable, distributed, **secure** time series database.
-3
View File
@@ -1,3 +0,0 @@
# Timely
Timely: a scalable, distributed, **secure** time series database.
@@ -1,10 +0,0 @@
<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
@@ -1,52 +0,0 @@
<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
@@ -1,146 +0,0 @@
'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
@@ -1 +0,0 @@
{"version":3,"sources":["../../src/components/auths.js"],"names":["_","AuthsCtrl","backendSrv","$rootScope","$timeout","datasource","fetching","done","show","status","title","uri","_getURI","jsonData","basicAuths","basicAuthUser","basicAuthPassword","authBlob","username","password","doPostLogin","appEvent","name","doGetLogin","doXHR","verb","data","r","XMLHttpRequest","open","withCredentials","setRequestHeader","onreadystatechange","handleLoginResult","bind","send","JSON","stringify","response","readyState","cookie","document","match","console","log","statusText","alert","getResponseHeader","timelyHost","httpsPort"],"mappings":";;;;;;;;;;;;;;;AAAOA,O;;;;;;;;;;;;;;;;;;;;;2BAEMC,S;AAEX,2BAAYC,UAAZ,EAAwBC,UAAxB,EAAoCC,QAApC,EAA6C;AAAA;;AAC3C,eAAKD,UAAL,GAAkBA,UAAlB;AACA,eAAKC,QAAL,GAAgBA,QAAhB;AACA,eAAKF,UAAL,GAAkBA,UAAlB;AACD;;;;gCAEKG,U,EAAW;AACf,iBAAKC,QAAL,GAAgB,EAAhB;AACA,iBAAKA,QAAL,CAAcC,IAAd,GAAqB,KAArB;AACA,iBAAKD,QAAL,CAAcE,IAAd,GAAqB,IAArB;AACA,iBAAKF,QAAL,CAAcG,MAAd,GAAuB,SAAvB;AACA,iBAAKH,QAAL,CAAcI,KAAd,GAAsB,mBAAtB;;AAEA;AACA;AACA;;AAEA,gBAAIC,MAAM,KAAKC,OAAL,CAAaP,WAAWQ,QAAxB,CAAV;;AAEA,gBAAGR,WAAWQ,QAAX,CAAoBC,UAAvB,EAAkC;AAChC,kBAAI,KAAKC,aAAL,IAAsB,KAAKC,iBAA/B,EAAiD;AAC/C,oBAAIC,WAAW,EAACC,UAAU,KAAKH,aAAhB,EAA+BI,UAAU,KAAKH,iBAA9C,EAAf;AACA,qBAAKI,WAAL,CAAiBT,GAAjB,EAAsBM,QAAtB;AACD,eAHD,MAGO;AACL,qBAAKd,UAAL,CAAgBkB,QAAhB,CAAyB,eAAzB,EAA0C,CAAChB,WAAWiB,IAAZ,EAAkB,wBAAlB,CAA1C;AACA,qBAAKhB,QAAL,CAAcG,MAAd,GAAuB,SAAvB;AACA,qBAAKH,QAAL,CAAcI,KAAd,GAAsB,wBAAtB;;AAEA;AACD;AACF,aAXD,MAWO;AACL,mBAAKa,UAAL,CAAgBZ,GAAhB;AACD;AAEF;;;sCAEWA,G,EAAKM,Q,EAAS;AACxB,iBAAKO,KAAL,CAAW,MAAX,EAAmBb,GAAnB,EAAwBM,QAAxB;AACD;;;qCAEUN,G,EAAI;AACb,iBAAKa,KAAL,CAAW,KAAX,EAAkBb,GAAlB;AACD;;;gCAEKc,I,EAAMd,G,EAAKe,I,EAAK;AACpB,gBAAI,CAACA,IAAL,EAAU;AACRA,qBAAO,EAAP;AACD;AACD,gBAAIC,IAAI,IAAIC,cAAJ,EAAR;AACAD,cAAEE,IAAF,CAAOJ,IAAP,EAAad,GAAb,EAAkB,IAAlB;AACAgB,cAAEG,eAAF,GAAoB,IAApB;AACAH,cAAEI,gBAAF,CAAmB,cAAnB,EAAmC,kBAAnC;AACAJ,cAAEK,kBAAF,GAAuB,YAAY;AACjC,mBAAKC,iBAAL,CAAuBN,CAAvB;AACD,aAFsB,CAErBO,IAFqB,CAEhB,IAFgB,CAAvB;AAGAP,cAAEQ,IAAF,CAAOC,KAAKC,SAAL,CAAeX,IAAf,CAAP;AACD;;;4CAEiBY,Q,EAAS;AACzB;AACA,gBAAIA,SAASC,UAAT,IAAuB,CAA3B,EAA8B;;AAE9B,iBAAKjC,QAAL,CAAcC,IAAd,GAAqB,IAArB;;AAEA,oBAAO+B,SAAS7B,MAAhB;AACE,mBAAK,GAAL;AACE,oBAAI+B,SAAS,CAACC,SAASD,MAAT,CAAgBE,KAAhB,CAAsB,qCAAtB,KAA8D,GAAE,IAAF,CAA/D,EAAwE,CAAxE,CAAb;AACAC,wBAAQC,GAAR,CAAYJ,MAAZ;AACAG,wBAAQC,GAAR,CAAYH,SAASD,MAArB;;AAEA,qBAAKlC,QAAL,CAAcG,MAAd,GAAuB,SAAvB;AACA,qBAAKH,QAAL,CAAcI,KAAd,GAAsB,kBAAtB;AACA,qBAAKP,UAAL,CAAgBkB,QAAhB,CAAyB,eAAzB,EAA0C,CAAC,SAAD,EAAY,EAAZ,CAA1C;AACA;AACF;AACE,qBAAKf,QAAL,CAAcG,MAAd,GAAuB,SAAvB;AACA,qBAAKH,QAAL,CAAcI,KAAd,GAAsB4B,SAASO,UAA/B;AACA,qBAAK1C,UAAL,CAAgBkB,QAAhB,CAAyB,eAAzB,EAA0C,CAACiB,SAAS7B,MAAT,GAAgB,IAAhB,GAAqB6B,SAASO,UAA/B,EAA0C,EAA1C,CAA1C;AACA;AAdJ;;AAiBA,gBAAIlB,EAAEY,UAAF,IAAgB,CAAhB,IAAqBZ,EAAElB,MAAF,IAAY,GAArC,EAA0C;AAC1CqC,kBAAM,cAAcnB,EAAEoB,iBAAF,CAAoB,YAApB,CAApB;AACD;;;kCAEOlC,Q,EAAS;AACf,mBAAO,aAAWA,SAASmC,UAApB,GAA+B,GAA/B,GAAmCnC,SAASoC,SAA5C,GAAsD,QAA7D;AACD;;;yCAEa,CAEb","file":"auths.js","sourcesContent":["import _ from 'lodash';\n\nexport class AuthsCtrl {\n\n constructor(backendSrv, $rootScope, $timeout){\n this.$rootScope = $rootScope;\n this.$timeout = $timeout;\n this.backendSrv = backendSrv;\n }\n\n login(datasource){\n this.fetching = {};\n this.fetching.done = false;\n this.fetching.show = true;\n this.fetching.status = 'warning';\n this.fetching.title = 'Fetching auths...';\n\n //this.$rootScope.appEvent('alert-success', ['Authorization Cookie Received', '']);\n //this.$rootScope.appEvent('alert-error', ['Authorization Failed', '']);\n //this.$rootScope.appEvent('alert-warning', ['Fetching Authorizations', '']);\n\n var uri = this._getURI(datasource.jsonData);\n\n if(datasource.jsonData.basicAuths){\n if( this.basicAuthUser && this.basicAuthPassword){\n var authBlob = {username: this.basicAuthUser, password: this.basicAuthPassword};\n this.doPostLogin(uri, authBlob);\n } else {\n this.$rootScope.appEvent('alert-warning', [datasource.name, 'requires User/Password']);\n this.fetching.status = 'warning';\n this.fetching.title = 'User/Password required';\n\n return;\n }\n } else {\n this.doGetLogin(uri);\n }\n\n }\n\n doPostLogin(uri, authBlob){\n this.doXHR('POST', uri, authBlob);\n }\n\n doGetLogin(uri){\n this.doXHR('GET', uri)\n }\n\n doXHR(verb, uri, data){\n if( !data){\n data = \"\";\n }\n var r = new XMLHttpRequest();\n r.open(verb, uri, true);\n r.withCredentials = true;\n r.setRequestHeader('Content-Type', 'application/json');\n r.onreadystatechange = function () {\n this.handleLoginResult(r);\n }.bind(this);\n r.send(JSON.stringify(data));\n }\n\n handleLoginResult(response){\n // wait for readyState to be '4 => done'\n if (response.readyState != 4) return;\n\n this.fetching.done = true;\n\n switcLine truncated
-80
View File
@@ -1,80 +0,0 @@
'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
@@ -1 +0,0 @@
{"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
@@ -1,10 +0,0 @@
<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
@@ -1,27 +0,0 @@
'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
@@ -1 +0,0 @@
{"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"]}
Loaded 100 of 425 files, more files were not shown because too many files have changed in this diff. Show more