├── .dockerignore ├── .editorconfig ├── .gitignore ├── .travis.yml ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── README.md ├── debug.sh ├── docker ├── Dockerfile.final ├── build.sh └── push.sh ├── kernel_tuning.txt ├── src ├── bin │ ├── carbon.rs │ ├── graphite.rs │ └── whisper.rs ├── carbon │ ├── cache_writer.rs │ ├── config.rs │ ├── handlers │ │ ├── mod.rs │ │ ├── tcp.rs │ │ └── udp.rs │ └── mod.rs ├── graphite │ ├── cache_holder.rs │ ├── config.rs │ ├── error.rs │ ├── expander.rs │ ├── handlers │ │ ├── metrics_find.rs │ │ ├── mod.rs │ │ └── render.rs │ ├── middleware │ │ ├── mod.rs │ │ └── path_fixer.rs │ ├── mod.rs │ └── server.rs └── lib.rs └── test └── scripts └── tcp_multipoint.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | [*.rs] 12 | indent_style = space 13 | indent_size = 4 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | test 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: nightly 3 | sudo: false 4 | env: 5 | global: 6 | secure: II3sCfqoqziRQtsuEmS7C/nUS7BMMktJAbXSMEoO2jz7JUA3MoYk2vBqWTP0MQj6Sasbitp6a1mH1YCoF8AG5aQIzlUiD1AWgoP0wWcqEvIywZHoqoD0yejOrt4l/LZueTFbu7ugOtSnXIf7qoGzwsN/sLXTUSS94QahXW7UWew= 7 | after_success: | 8 | cargo doc \ 9 | && echo '' > target/doc/index.html && \ 10 | sudo pip install ghp-import && \ 11 | ghp-import -n target/doc && \ 12 | git push -qf https://${GH_TOKEN}@github.com/tureus/graphite-rust.git gh-pages 13 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "graphite" 3 | version = "0.2.3" 4 | authors = ["Xavier Lange "] 5 | description = "A fast, pure rust graphite implementation. Includes whisper, carbon, and graphite." 6 | license = "MIT" 7 | homepage = "https://www.github.com/tureus/graphite-rust" 8 | repository = "https://github.com/tureus/graphite-rust.git" 9 | 10 | [lib] 11 | name="graphite" 12 | path="src/lib.rs" 13 | 14 | # [[bin]] 15 | # name="whisper" 16 | 17 | [[bin]] 18 | name="carbon" 19 | 20 | ## [[bin]] 21 | ## name="graphite" 22 | ## [[graphite.dependencies]] # not valid code! 23 | ## iron = "*" 24 | ## # router = "*" 25 | ## urlencoded = "*" 26 | ## glob = "*" 27 | ## # iron-test = "*" 28 | ## persistent = "*" # Not a great name for a HTTP middle lib... there's already a Haskell lib for doing real data persistence with the same name. 29 | ## router = "*" 30 | 31 | ## Out of date deps? 32 | # num = "*" 33 | 34 | [dependencies] 35 | byteorder = "*" 36 | gcc = "*" 37 | time = "*" 38 | log = "*" 39 | env_logger = "*" 40 | docopt = "0.6.64" 41 | regex = "*" 42 | libc = "*" 43 | rustc-serialize = "*" 44 | whisper = "*" 45 | 46 | # [dependencies.router] 47 | # git = "https://github.com/iron/router.git" 48 | 49 | # The documentation profile, used for `cargo doc` 50 | [profile.doc] 51 | opt-level = 0 52 | debug = true 53 | rpath = false 54 | lto = false 55 | debug-assertions = true 56 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM andrewd/rust-musl 2 | 3 | RUN curl -sSL https://get.docker.io/builds/Linux/x86_64/docker-1.2.0 -o /tmp/docker && \ 4 | echo "540459bc5d9f1cac17fe8654891814314db15e77 /tmp/docker" | sha1sum -c - && \ 5 | mv /tmp/docker /usr/local/bin/docker && \ 6 | chmod +x /usr/local/bin/docker 7 | 8 | ADD . /graphite-rust 9 | WORKDIR /graphite-rust 10 | RUN cargo build --release --target x86_64-unknown-linux-musl 11 | 12 | WORKDIR /graphite-rust/target/x86_64-unknown-linux-musl/release 13 | 14 | ADD docker/Dockerfile.final /graphite-rust/target/x86_64-unknown-linux-musl/release/Dockerfile 15 | 16 | CMD docker build -t xrlx/graphite . 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Xavier Lange, Vincent Grato 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The graphite ecosystem in one easy-to-install package. 2 | 3 | [![Build status](https://api.travis-ci.org/tureus/graphite-rust.png)](https://travis-ci.org/tureus/graphite-rust) 4 | 5 | [![](https://badge.imagelayers.io/xrlx/graphite:latest.svg)](https://imagelayers.io/?images=xrlx/graphite:latest 'Get your own badge on imagelayers.io') 6 | 7 | ## Docker 8 | 9 | By far the easiest experience for getting up and running 10 | 11 | docker pull xrlx/graphite 12 | mkdir data 13 | docker run -v ./data:/data xrlx/graphite 14 | 15 | ## Docker in Production 16 | 17 | How I run `graphite-rust` with `graphite-web` in production: 18 | 19 | $ cat run_graphite.sh 20 | docker run -e "RUST_LOG=warning" --name graphite -d -p 2003:2003/udp -p 2003:2003 -v /var/data/graphite:/data xrlx/graphite 21 | $ cat run_graphite_web.sh 22 | docker run -d -it --name graphite-web -v /var/data/graphite:/opt/graphite/storage/whisper -p 80:80 banno/graphite-web 23 | $ sudo sysctl -w vm.dirty_background_ratio=30 vm.dirty_ratio=60 vm.dirty_expire_centisecs=1080000 vm.dirty_writeback_centisecs=1080000 24 | 25 | ## Building 26 | 27 | Note: you'll need a nightly rust build to build this 28 | 29 | $ git clone git@github.com:tureus/graphite-rust.git 30 | $ cd graphite-rust 31 | $ cargo build --release 32 | $ RUST_LOG=debug ./target/debug/carbon 33 | 34 | ## Tasks 35 | 36 | - [X] Read headers 37 | - [X] Read single point 38 | - [X] Write to single archive 39 | - [X] Write through all archives with downsampling 40 | - [X] Create files 41 | - [X] Read many points 42 | - [ ] Advisory lock files 43 | - [x] `mmap` files (PROFILING) 44 | - [ ] Use `cfg()` guards to provide conditional checks for sysctl settings 45 | - [X] UDP daemon 46 | - [X] TCP daemon 47 | - [ ] Custom schema support when creating new WSPs 48 | - [ ] Pickle daemon 49 | - [ ] HTTP frontend 50 | - [ ] Make logging useful for ops 51 | - [ ] Validate .wsp when opening (archives need to cleanly multiply, etc) 52 | 53 | ## Documentation 54 | 55 | [http://tureus.github.io/graphite-rust](http://tureus.github.io/graphite-rust) 56 | 57 | ## Reference 58 | 59 | Documentation for the whisper file format is slim/nil. Clone the official repo and take a look at `whisper.py` 60 | 61 | $ git clone git@github.com:graphite-project/whisper.git 62 | 63 | ## Talking to Carbon 64 | 65 | On OSX you need to specify IPv4: 66 | 67 | echo -e "local.random.diceroll 4 `date +%s`" | nc -4u -w0 localhost 2003 68 | 69 | On linux: 70 | 71 | echo "local.random.diceroll 4 `date +%s`" | nc -u -w 1 localhost 2003 72 | 73 | Memory stats: 74 | 75 | yum install -y sysstat 76 | toolbox sar -B 1 77 | -------------------------------------------------------------------------------- /debug.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | set -o pipefail 3 | 4 | export TS=`date +%s` 5 | echo TS is $TS 6 | 7 | # pushd ../whisper && python ../whisper/setup.py install > /dev/null && popd 8 | 9 | # export FNAME="1-5-5-5-10-5" 10 | # export ARCHIVE="1:5 5:5 10:5" 11 | 12 | # export FNAME="1s-6h-1h-1d-24h-20y" 13 | # export ARCHIVE="1s:6h 1h:1d 24h:20y" 14 | 15 | export FNAME="1s-24h-1h-30d-24h-30y" 16 | export ARCHIVE="1s:24h 1h:30d 24h:30y" 17 | 18 | rm test/fixtures/$FNAME.wsp.{python,rust} 19 | whisper-create.py test/fixtures/$FNAME.wsp.python $ARCHIVE 20 | whisper-create.py test/fixtures/$FNAME.wsp.rust $ARCHIVE 21 | 22 | echo "PYTHON TIME" 23 | time { 24 | for i in `seq 1 100000`; 25 | do 26 | whisper-update.py test/fixtures/$FNAME.wsp.python $TS:10 27 | done 28 | } 29 | 30 | echo "RUST TIME" 31 | time { 32 | for i in `seq 1 100000`; 33 | do 34 | RUST_LOG=warning target/release/whisper update test/fixtures/$FNAME.wsp.rust $TS 10 35 | done 36 | } 37 | 38 | diff test/fixtures/$FNAME.wsp.* 39 | 40 | if [[ $? -eq 0 ]]; then 41 | echo "whisper files match" 42 | fi 43 | -------------------------------------------------------------------------------- /docker/Dockerfile.final: -------------------------------------------------------------------------------- 1 | FROM busybox 2 | 3 | ADD carbon /usr/bin/carbon 4 | 5 | ENV RUST_LOG debug 6 | 7 | VOLUME /data 8 | EXPOSE 2003 9 | EXPOSE 2003/udp 10 | 11 | ENTRYPOINT ["/usr/bin/carbon", "--storage-path", "/data"] 12 | -------------------------------------------------------------------------------- /docker/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | set -xe 3 | 4 | docker build -t xrlx/graphite_build . 5 | # run the build env CMD for copying deb and installing to minimal image 6 | docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -ti xrlx/graphite_build 7 | -------------------------------------------------------------------------------- /docker/push.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | set -xe 3 | 4 | docker push xrlx/graphite 5 | -------------------------------------------------------------------------------- /kernel_tuning.txt: -------------------------------------------------------------------------------- 1 | # https://www.kernel.org/doc/Documentation/sysctl/vm.txt 2 | # http://jmoiron.net/ 3 | 4 | # DEFAULTS 5 | vm.dirty_background_bytes = 0 6 | vm.dirty_background_ratio = 10 7 | vm.dirty_expire_centisecs = 3000 8 | vm.dirty_bytes = 0 9 | vm.dirty_ratio = 20 10 | vm.dirty_writeback_centisecs = 500 11 | vm.dirtytime_expire_seconds = 43200 12 | 13 | # FIRST TRY 14 | sysctl -w vm.dirty_background_ratio=30 vm.dirty_ratio=60 vm.dirty_expire_centisecs=18000 vm.dirty_writeback_centisecs=3000 15 | 16 | # SECOND TRY (smoothing out sync by disabling writeback thread (3000 -> 0)) 17 | sysctl -w vm.dirty_background_ratio=30 vm.dirty_ratio=60 vm.dirty_expire_centisecs=18000 vm.dirty_writeback_centisecs=0 18 | 19 | # THIRD TRY (fixed a default schema bug which had artificially small number of dirty pages, kernel died in mysterious way and had iops storm. time to reel it back and run the dirty_writeback every once in a while) 20 | # Wake up every 3 hours to flush data 21 | sysctl -w vm.dirty_background_ratio=30 vm.dirty_ratio=60 vm.dirty_expire_centisecs=1080000 vm.dirty_writeback_centisecs=1080000 22 | 23 | sysctl -w vm.dirty_background_ratio=30 vm.dirty_ratio=60 vm.dirty_expire_centisecs=1080000 vm.dirty_writeback_centisecs=1080000 24 | -------------------------------------------------------------------------------- /src/bin/carbon.rs: -------------------------------------------------------------------------------- 1 | #![feature(unmarked_api)] 2 | 3 | extern crate graphite; 4 | extern crate whisper; 5 | 6 | #[macro_use] 7 | extern crate log; 8 | extern crate env_logger; 9 | extern crate rustc_serialize; 10 | extern crate docopt; 11 | extern crate time; 12 | 13 | use graphite::carbon; 14 | use whisper::{ WhisperCache, Schema }; 15 | 16 | use std::path::Path; 17 | 18 | use docopt::Docopt; 19 | static USAGE: &'static str = " 20 | Carbon is the network service for writing data to disk 21 | 22 | Usage: 23 | carbon [--port PORT] [--bind HOST] [--chan DEPTH] [--storage-path STORAGEPATH] [--cache-size CACHESIZE] 24 | carbon --help 25 | 26 | Options: 27 | -h --help show this screen 28 | --bind HOST host to bind to [default: 0.0.0.0:2003] 29 | --chan DEPTH how many carbon messages can be in-flight [default: 1000] 30 | --storage-path STORAGEPATH where to find the whisper file [default: /tmp] 31 | --cache-size CACHESIZE max number of open files to keep in memory [default: 60000] 32 | "; 33 | 34 | #[derive(RustcDecodable, Debug)] 35 | struct Args { 36 | flag_bind: String, 37 | flag_chan: usize, 38 | flag_storage_path: String, 39 | flag_cache_size: usize 40 | } 41 | 42 | pub fn main(){ 43 | env_logger::init().unwrap(); 44 | let args: Args = Docopt::new(USAGE) 45 | .and_then(|d| d.decode()) 46 | .unwrap_or_else(|e| e.exit()); 47 | 48 | let bind_spec = unsafe { 49 | args.flag_bind.slice_unchecked(0, args.flag_bind.len()) 50 | }; 51 | 52 | let config = carbon::Config{ 53 | bind_spec: bind_spec, 54 | chan_depth: args.flag_chan, 55 | base_path: Path::new(&args.flag_storage_path), 56 | cache_size: args.flag_cache_size 57 | }; 58 | 59 | info!("preparing whisper cache..."); 60 | let default_specs = vec!["5s:1y".to_string()]; 61 | let schema = Schema::new_from_retention_specs(default_specs); 62 | let cache = WhisperCache::new(&config.base_path.to_owned(), config.cache_size, schema); 63 | 64 | let (tx,_) = carbon::cache_writer::spawn(cache, &config); 65 | 66 | let udp_server = carbon::udp::run_server(tx.clone(), &config).unwrap(); 67 | let tcp_server = carbon::tcp::run_server(tx, &config).unwrap(); 68 | 69 | udp_server.join().unwrap(); 70 | tcp_server.join().unwrap(); 71 | } 72 | -------------------------------------------------------------------------------- /src/bin/graphite.rs: -------------------------------------------------------------------------------- 1 | extern crate graphite; 2 | 3 | #[macro_use] 4 | extern crate log; 5 | extern crate env_logger; 6 | extern crate rustc_serialize; 7 | extern crate docopt; 8 | extern crate time; 9 | 10 | use std::path::Path; 11 | 12 | use docopt::Docopt; 13 | static USAGE: &'static str = " 14 | Graphite is the HTTP REST API for querying data from the database 15 | 16 | Usage: 17 | graphite server 18 | graphite expand [--storage-path STORAGEPATH] 19 | Options: 20 | 21 | --bind HOST host to bind to [default: 0.0.0.0:8080] 22 | --storage-path STORAGEPATH where to find the whisper file [default: /tmp] 23 | "; 24 | 25 | use self::graphite::graphite::{ Config, server, expander }; 26 | use self::graphite::whisper::Cache; 27 | 28 | #[derive(RustcDecodable, Debug)] 29 | struct Args { 30 | cmd_server: bool, 31 | cmd_expand: bool, 32 | 33 | arg_pattern: String, 34 | 35 | flag_bind: String, 36 | flag_storage_path: String 37 | } 38 | 39 | pub fn main(){ 40 | env_logger::init().unwrap(); 41 | let args: Args = Docopt::new(USAGE) 42 | .and_then(|d| d.decode()) 43 | .unwrap_or_else(|e| e.exit()); 44 | 45 | let bind_spec : &str = unsafe { 46 | args.flag_bind.slice_unchecked(0, args.flag_bind.len()) 47 | }; 48 | 49 | let config = Config{ 50 | bind_spec: bind_spec, 51 | base_path: Path::new(&args.flag_storage_path) 52 | }; 53 | 54 | if args.cmd_server { 55 | let cache = Cache::new(config.base_path); 56 | server::run(config, cache); 57 | } else if args.cmd_expand { 58 | let cache = Cache::new(config.base_path); 59 | expander::expand(&args.arg_pattern, &cache); 60 | } else { 61 | println!("command not specified"); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/bin/whisper.rs: -------------------------------------------------------------------------------- 1 | extern crate graphite; 2 | 3 | #[macro_use] 4 | extern crate log; 5 | extern crate env_logger; 6 | extern crate rustc_serialize; 7 | extern crate docopt; 8 | extern crate time; 9 | 10 | use docopt::Docopt; 11 | use graphite::whisper::{ WhisperFile, RefCellWhisperFile, Point }; 12 | use graphite::whisper::schema::Schema; 13 | 14 | use std::path::Path; 15 | 16 | static USAGE: &'static str = " 17 | Whisper is the fast file manipulator 18 | 19 | Usage: 20 | whisper info 21 | whisper dump 22 | whisper update 23 | whisper mark 24 | whisper thrash 25 | whisper create ... 26 | 27 | Options: 28 | --xff 29 | --aggregation_method 30 | "; 31 | 32 | #[derive(RustcDecodable, Debug)] 33 | struct Args { 34 | cmd_info: bool, 35 | cmd_dump: bool, 36 | cmd_update: bool, 37 | cmd_mark: bool, 38 | cmd_thrash: bool, 39 | cmd_create: bool, 40 | 41 | arg_file: String, 42 | arg_timestamp: String, 43 | arg_value: String, 44 | arg_times: String, 45 | 46 | arg_timespec: Vec 47 | } 48 | 49 | 50 | pub fn main(){ 51 | env_logger::init().unwrap(); 52 | let args: Args = Docopt::new(USAGE) 53 | .and_then(|d| d.decode()) 54 | .unwrap_or_else(|e| e.exit()); 55 | 56 | let arg_file = args.arg_file.clone(); 57 | let path_str : &str = unsafe { 58 | arg_file.slice_unchecked(0, args.arg_file.len()) 59 | }; 60 | let path = Path::new(path_str); 61 | 62 | 63 | let current_time = time::get_time().sec as u64; 64 | 65 | if args.cmd_info { 66 | cmd_info(path); 67 | } else if args.cmd_dump { 68 | cmd_dump(path); 69 | } else if args.cmd_update { 70 | cmd_update(args, path, current_time); 71 | } else if args.cmd_mark { 72 | cmd_mark(args, path, current_time); 73 | } else if args.cmd_thrash { 74 | cmd_thrash(args, path, current_time); 75 | } else if args.cmd_create { 76 | cmd_create(args, path); 77 | } else { 78 | println!("Must specify command."); 79 | } 80 | } 81 | 82 | fn cmd_info(path: &Path) { 83 | let file_open = RefCellWhisperFile::open(path); 84 | match file_open { 85 | Ok(whisper_file) => println!("{}", whisper_file), 86 | Err(why) => { 87 | println!("could create whisper file: {:?}", why) 88 | } 89 | } 90 | } 91 | 92 | fn cmd_dump(path: &Path) { 93 | let file_open = RefCellWhisperFile::open(path); 94 | match file_open { 95 | Ok(whisper_file) => println!("{:?}", whisper_file), 96 | Err(why) => { 97 | println!("could create whisper file: {:?}", why) 98 | } 99 | } 100 | } 101 | 102 | fn cmd_update(args: Args, path: &Path, current_time: u64) { 103 | let mut file = RefCellWhisperFile::open(path).unwrap(); 104 | let point = Point{ 105 | timestamp: args.arg_timestamp.parse::().unwrap(), 106 | value: args.arg_value.parse::().unwrap() 107 | }; 108 | debug!("Updating TS: {} with value: {}", point.timestamp, point.value); 109 | 110 | file.write(current_time, point); 111 | } 112 | 113 | fn cmd_mark(args: Args, path: &Path, current_time: u64) { 114 | let mut file = RefCellWhisperFile::open(path).unwrap(); 115 | let point = Point{ 116 | timestamp: current_time, 117 | value: args.arg_value.parse::().unwrap() 118 | }; 119 | 120 | file.write(current_time, point); 121 | } 122 | 123 | fn cmd_thrash(args: Args, path: &Path, current_time: u64) { 124 | let times = args.arg_times.parse::().unwrap(); 125 | let mut file = RefCellWhisperFile::open(path).unwrap(); 126 | for index in 1..times { 127 | let point = Point{ 128 | timestamp: current_time+index, 129 | value: args.arg_value.parse::().unwrap() 130 | }; 131 | 132 | file.write(current_time+index, point); 133 | } 134 | } 135 | 136 | fn cmd_create(args: Args, path: &Path) { 137 | let schema = Schema::new_from_retention_specs(args.arg_timespec); 138 | let new_result = RefCellWhisperFile::new(path, schema); 139 | match new_result { 140 | Ok(whisper_file) => println!("Success! {}", whisper_file), 141 | Err(why) => println!("Failed: {:?}", why) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/carbon/cache_writer.rs: -------------------------------------------------------------------------------- 1 | use whisper::{ WhisperCache }; 2 | 3 | use std::thread::{ self, JoinHandle }; 4 | // extern crate time; 5 | use std::sync::mpsc::{ sync_channel, SyncSender }; 6 | 7 | use super::Config; 8 | use super::handlers::Action; 9 | 10 | pub fn spawn(cache: WhisperCache, config: &Config) -> (SyncSender, JoinHandle<()>) { 11 | let (tx, rx) = sync_channel(config.chan_depth); 12 | 13 | info!("spawning file writer..."); 14 | let mut cache = cache; // gotta alias the value as mut! 15 | 16 | let writer = thread::spawn(move || { 17 | loop { 18 | let recv = rx.recv(); 19 | // let current_time = time::get_time().sec as u64; 20 | 21 | match recv { 22 | Ok(Action::Write(named_point)) => { 23 | let write_res = cache.write( named_point ); 24 | 25 | match write_res { 26 | Ok(()) => (), 27 | Err(reason) => debug!("err: {:?}", reason) 28 | } 29 | }, 30 | Err(_) => { 31 | debug!("shutting down writer thread"); 32 | return () 33 | } 34 | } 35 | } 36 | }); 37 | 38 | (tx,writer) 39 | } 40 | -------------------------------------------------------------------------------- /src/carbon/config.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | 3 | pub struct Config<'a> { 4 | pub bind_spec: &'a str, 5 | pub chan_depth: usize, 6 | pub base_path: &'a Path, 7 | pub cache_size: usize 8 | } 9 | -------------------------------------------------------------------------------- /src/carbon/handlers/mod.rs: -------------------------------------------------------------------------------- 1 | use whisper::NamedPoint; 2 | 3 | pub mod udp; 4 | pub mod tcp; 5 | 6 | // Room to add functionality such as 7 | // - USR1 signal print state of cache to STDOUT 8 | // - USR2 signal flush state of cache to DISK 9 | pub enum Action { 10 | Write(NamedPoint) 11 | } 12 | -------------------------------------------------------------------------------- /src/carbon/handlers/tcp.rs: -------------------------------------------------------------------------------- 1 | use whisper::{ NamedPoint }; 2 | 3 | use std::net::{ TcpListener, TcpStream }; 4 | use std::io::{ Error, BufReader, BufRead }; 5 | extern crate time; 6 | 7 | use std::sync::mpsc::{ sync_channel, SyncSender }; 8 | use std::thread::{ self, JoinHandle }; 9 | 10 | use super::super::Config; 11 | use super::Action; 12 | 13 | pub fn run_server(tx: SyncSender, config: &Config) -> Result>,Error> { 14 | info!("TCP server binding to `{}`", config.bind_spec); 15 | let listener = try!( TcpListener::bind(config.bind_spec) ); 16 | 17 | let listener_tx = tx.clone(); 18 | let accept_thread = thread::spawn(move ||{ 19 | let listener_tx = listener_tx; 20 | 21 | debug!("waiting for incoming streams"); 22 | for listen_result in listener.incoming() { 23 | let tcp_stream = try!(listen_result); 24 | let thread_tx = listener_tx.clone(); 25 | debug!("handling new stream"); 26 | thread::spawn(move || { 27 | do_server(thread_tx, tcp_stream); 28 | }); 29 | }; 30 | 31 | drop(listener); 32 | 33 | Ok(()) 34 | }); 35 | 36 | debug!("cool, done booting TCP server"); 37 | 38 | Ok(accept_thread) 39 | } 40 | 41 | fn do_server(tx: SyncSender, tcp_stream: TcpStream) { 42 | let mut line_buf = String::new(); 43 | let mut reader = BufReader::new(tcp_stream); 44 | 45 | loop { 46 | match reader.read_line(&mut line_buf) { 47 | Ok(bytes_read) => { 48 | if bytes_read == 0 { 49 | debug!("connection was closed"); 50 | break; 51 | } 52 | 53 | debug!("tcp listener read {} bytes", bytes_read); 54 | let parsed_line = NamedPoint::parse_line(&(line_buf.trim_right())[..]); 55 | match parsed_line { 56 | Ok(np) => tx.send(Action::Write(np)).unwrap(), 57 | Err(err) => { 58 | error!("could not parse incoming data: {:?}", err); 59 | break; 60 | } 61 | } 62 | 63 | line_buf.clear(); 64 | }, 65 | Err(err) => { 66 | info!("shutting down tcp listener: {:?}", err); 67 | break 68 | } 69 | }; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/carbon/handlers/udp.rs: -------------------------------------------------------------------------------- 1 | use whisper::{ NamedPoint }; 2 | 3 | use std::thread::{ self, JoinHandle }; 4 | use std::net::UdpSocket; 5 | use std::io::Error; 6 | use std::sync::mpsc::{ SyncSender }; 7 | 8 | use super::super::Config; 9 | use super::Action; 10 | 11 | pub fn run_server<'a>(tx: SyncSender, config: &Config) -> Result,Error> { 12 | info!("UDP server binding to `{}`", config.bind_spec); 13 | let mut buf_box = create_buffer(); 14 | let socket = try!( UdpSocket::bind(config.bind_spec) ); 15 | 16 | let join_handle = thread::spawn(move ||{ 17 | loop { 18 | let (bytes_read,_) = { 19 | // debug!("waiting on recv from socket"); 20 | 21 | match socket.recv_from( &mut buf_box[..] ) { 22 | Ok(res) => { 23 | res 24 | }, 25 | Err(err) => { 26 | error!("error reading from socket: {:?}", err); 27 | continue; 28 | } 29 | } 30 | }; 31 | 32 | debug!("parsing point..."); 33 | 34 | match NamedPoint::from_datagram(&buf_box[0..bytes_read]) { 35 | Ok(named_points) => { 36 | // Dies if the receiver is closed 37 | debug!("putting message on tx"); 38 | for named_point in named_points { 39 | tx.send(Action::Write(named_point)).unwrap(); 40 | } 41 | }, 42 | Err(err) => { 43 | debug!("wtf mate: {:?}", err); 44 | } 45 | }; 46 | } 47 | }); 48 | Ok(join_handle) 49 | } 50 | 51 | fn create_buffer() -> Box<[u8]> { 52 | let buf : [u8; 8*1024] = [0; 8*1024]; 53 | Box::new( buf ) 54 | } 55 | -------------------------------------------------------------------------------- /src/carbon/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | All the necessary code for listening on network interfaces 4 | for 5 | 6 | */ 7 | 8 | mod handlers; 9 | pub mod cache_writer; 10 | mod config; 11 | 12 | pub use self::handlers::{ tcp, udp }; 13 | pub use self::config::Config; 14 | -------------------------------------------------------------------------------- /src/graphite/cache_holder.rs: -------------------------------------------------------------------------------- 1 | use iron; 2 | use super::super::whisper::Cache; 3 | 4 | // This is some weird voodoo so I can use persistent 5 | // apparently I have to give a vtable which is used to resolve the 6 | // type of the stored value so it can be recast "safely" 7 | // but it adds one more level of indirection. Caveat emptor folks. 8 | pub struct CacheHolder; 9 | impl iron::typemap::Key for CacheHolder { 10 | // TODO: my brain hurts. what does this mean? 11 | type Value = Cache; 12 | } -------------------------------------------------------------------------------- /src/graphite/config.rs: -------------------------------------------------------------------------------- 1 | // Just a re-export of the carbon config 2 | 3 | use std::path::Path; 4 | 5 | pub struct Config<'a> { 6 | pub bind_spec: &'a str, 7 | pub base_path: &'a Path 8 | } 9 | -------------------------------------------------------------------------------- /src/graphite/error.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt::{self, Debug}; 3 | 4 | #[derive(Debug)] 5 | pub struct StringError(pub String); 6 | 7 | impl fmt::Display for StringError { 8 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 9 | Debug::fmt(self, f) 10 | } 11 | } 12 | 13 | impl Error for StringError { 14 | fn description(&self) -> &str { &*self.0 } 15 | } 16 | -------------------------------------------------------------------------------- /src/graphite/expander.rs: -------------------------------------------------------------------------------- 1 | use glob::glob; 2 | use super::super::whisper::cache::Cache; 3 | use std::path::{ Path, PathBuf }; 4 | use std::fs::{ PathExt, read_dir }; 5 | // use std::collections::BTreeMap; 6 | // use rustc_serialize::json::{self, ToJson, Json}; 7 | 8 | #[derive(Debug)] 9 | pub enum QueryResultNode { 10 | WspNode(PathBuf, PathBuf), 11 | // path to dir, has children, 12 | DirNode(PathBuf, PathBuf, bool, ) 13 | } 14 | 15 | const EXPANDABLE : i8 = 1; 16 | const NOT_EXPANDABLE : i8 = 2; 17 | 18 | fn text_and_file_name<'a>(cache_root: &'a Path, path: &'a Path) -> (&'a str,String) { 19 | let mut text = path.file_name().unwrap().to_str().unwrap(); 20 | text = &text[0..text.len()-4]; 21 | 22 | let cache_root_str : &str = &cache_root.to_str().unwrap(); 23 | let path_str : &str = &path.to_str().unwrap(); 24 | 25 | // Subtract the common cache path bits. And trim off the .wsp while we're at it. 26 | // One of the most reckless code path in here! 8-) 27 | let without_root : &str = &path_str[ cache_root_str.len()+1 .. path_str.len()-4 ]; 28 | let mut metric_name = without_root.to_string(); 29 | metric_name = metric_name.replace("/","."); 30 | 31 | return (text, metric_name) 32 | } 33 | 34 | fn text_and_folder_name<'a>(cache_root: &'a Path, path: &'a Path) -> (&'a str,String) { 35 | let text = path.file_name().unwrap().to_str().unwrap(); 36 | 37 | let cache_root_str : &str = &cache_root.to_str().unwrap(); 38 | let path_str : &str = &path.to_str().unwrap(); 39 | 40 | // Subtract the common cache path bits. And trim off the .wsp while we're at it. 41 | // One of the most reckless code path in here! 8-) 42 | let without_root : &str = &path_str[ cache_root_str.len()+1 .. path_str.len() ]; 43 | let mut metric_name = without_root.to_string(); 44 | metric_name = metric_name.replace("/","."); 45 | 46 | return (text, metric_name) 47 | } 48 | 49 | 50 | impl QueryResultNode { 51 | fn to_json(&self) -> String { 52 | match *self { 53 | QueryResultNode::WspNode(ref cache_root, ref path) => { 54 | let pair = text_and_file_name(cache_root, path); 55 | 56 | format!(r#"{{"leaf": {leaf}, "context": {{}}, "text": "{text}", "expandable": {expandable}, "id": "{id}", "allowChildren": {allow_children}}}"#, 57 | allow_children=0, expandable=0, leaf=0, 58 | text=pair.0, id=pair.1) 59 | }, 60 | QueryResultNode::DirNode(ref cache_root, ref path, ref has_children) => { 61 | let pair = text_and_folder_name(cache_root, path); 62 | 63 | format!(r#"{{"leaf": {leaf}, "context": {{}}, "text": "{text}", "expandable": {expandable}, "id": "{id}", "allowChildren": {allow_children}}}"#, 64 | allow_children=0, expandable= if *has_children { EXPANDABLE } else { NOT_EXPANDABLE } , leaf=0, 65 | text=pair.0, id=pair.1) 66 | } 67 | } 68 | } 69 | } 70 | 71 | // A file-system only operation which can detect 72 | // whisper files 73 | pub fn expand(query: &String, cache: &Cache) -> Vec { 74 | let glob_pattern = dots_to_full_path_glob(query, cache); 75 | 76 | debug!("expanding {}", glob_pattern); 77 | 78 | let mut retval = vec![]; 79 | let search = glob(&glob_pattern).unwrap(); 80 | 81 | for search_result in search { 82 | match search_result { 83 | Ok(path_buf) => { 84 | debug!("expansion match: {:?}", path_buf); 85 | let is_dir = { 86 | let path = path_buf.as_path(); 87 | path.is_dir() 88 | }; 89 | 90 | let has_children = if is_dir { 91 | read_dir( &path_buf ).unwrap().any(|f| { 92 | let metadata = f.unwrap().metadata().unwrap(); 93 | metadata.is_dir() || metadata.is_file() 94 | }) 95 | } else { 96 | false 97 | }; 98 | 99 | if is_dir { 100 | retval.push( QueryResultNode::DirNode( cache.base_path.clone(), path_buf, has_children).to_json() ) 101 | } else { 102 | retval.push( QueryResultNode::WspNode( cache.base_path.clone(), path_buf).to_json() ) 103 | } 104 | }, 105 | Err(e) => { 106 | info!("error in search: {:?}", e) 107 | } 108 | } 109 | } 110 | 111 | debug!("retval len: {}", retval.len()); 112 | 113 | return retval 114 | } 115 | 116 | // TODO: is it really this much work? 117 | // TODO: what about security concerns for traversing the file system? Can you craft a query such that ".." shows up? (Don't think so) 118 | fn dots_to_full_path_glob(query: &String, cache: &Cache) -> String { 119 | let replaced = query.replace(".","/"); 120 | 121 | let qualified_path = cache.base_path.join(replaced); 122 | let path : &Path = qualified_path.as_path(); 123 | let str_rep = path.to_str().unwrap(); 124 | let string_rep = str_rep.to_string(); 125 | // string_rep.push_str(".wsp"); 126 | 127 | return string_rep; 128 | } 129 | 130 | #[cfg(test)] 131 | mod tests { 132 | use std::path::Path; 133 | use super::super::super::whisper::cache::Cache; 134 | use super::QueryResultNode; 135 | 136 | #[test] 137 | fn has_full_path(){ 138 | let cache = Cache::new(Path::new("/tmp")); 139 | let input = "what.*.ever".to_string(); 140 | let expected = "/tmp/what/*/ever"; 141 | 142 | let full_glob = super::dots_to_full_path_glob(&input, &cache); 143 | 144 | assert_eq!(full_glob, expected) 145 | } 146 | 147 | // Not trying that hard but a simple sanity check 148 | #[test] 149 | fn wont_go_up_directory(){ 150 | let cache = Cache::new(Path::new("/tmp")); 151 | let input = "what.*.ever/../".to_string(); 152 | let expected = "/tmp/what/*/ever////"; 153 | 154 | let full_glob = super::dots_to_full_path_glob(&input, &cache); 155 | 156 | assert_eq!(full_glob, expected) 157 | } 158 | 159 | #[test] 160 | fn wsp_node_json(){ 161 | let root = Path::new("/tmp/thing").to_path_buf(); 162 | let deep = Path::new("/tmp/thing/is/cool/bear.wsp").to_path_buf(); 163 | let wsp_node = QueryResultNode::WspNode( root, deep ); 164 | let expected = "{\"leaf\": 0, \"context\": {}, \"text\": \"bear\", \"expandable\": 0, \"id\": \"is.cool.bear\", \"allowChildren\": 0}"; 165 | assert_eq!( wsp_node.to_json(), expected.to_string() ) 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/graphite/handlers/metrics_find.rs: -------------------------------------------------------------------------------- 1 | use super::super::super::whisper::Cache; 2 | 3 | use super::super::expander::expand; 4 | use super::super::cache_holder::CacheHolder; 5 | use super::super::error::StringError; 6 | 7 | use iron::prelude::*; 8 | use iron; 9 | use urlencoded::UrlEncodedQuery; 10 | 11 | use persistent::State; 12 | use std::sync::{ Arc, RwLock }; 13 | use std::ops::DerefMut; 14 | 15 | pub fn metrics_find(req: &mut Request) -> IronResult { 16 | let locked_cache : Arc< RwLock > = req.get::>().unwrap(); 17 | let mut cache_writer = locked_cache.write().unwrap(); 18 | let mut cache = cache_writer.deref_mut(); 19 | 20 | // Extract the decoded data as hashmap, using the UrlEncodedQuery plugin. 21 | match req.get_ref::() { 22 | Ok(ref hashmap) => { 23 | match hashmap.get("query") { 24 | Some(query) => { 25 | if query.len() == 1 { 26 | let ref first_query = query[0]; 27 | let http_body = do_find_metrics(first_query, &mut cache); 28 | let mut http_res = Response::with((iron::status::Ok, http_body)); 29 | 30 | let jsony_ctype = iron::headers::ContentType( 31 | iron::mime::Mime( 32 | iron::mime::TopLevel::Application, 33 | iron::mime::SubLevel::Json, 34 | vec![(iron::mime::Attr::Charset, iron::mime::Value::Utf8)] 35 | ) 36 | ); 37 | http_res.headers.set::(jsony_ctype); 38 | Ok(http_res) 39 | } else { 40 | error!("must provide only 1 query string"); 41 | Err(IronError::new(StringError("Must provide only one query".to_string()), iron::status::BadRequest)) 42 | } 43 | }, 44 | None => { 45 | error!("no query was provided"); 46 | Err(IronError::new(StringError("Must provide query".to_string()), iron::status::BadRequest)) 47 | } 48 | } 49 | }, 50 | Err(_) => { 51 | error!("unknown error"); 52 | Err(IronError::new(StringError("Error whoaaa".to_string()), iron::status::BadRequest)) 53 | } 54 | } 55 | } 56 | 57 | fn do_find_metrics(query: &String, cache: &mut Cache) -> String { 58 | let hits = expand(query, cache); 59 | format!("[{}]", hits.join(",")) 60 | } -------------------------------------------------------------------------------- /src/graphite/handlers/mod.rs: -------------------------------------------------------------------------------- 1 | mod metrics_find; 2 | mod render; 3 | 4 | pub use self::render::render; 5 | pub use self::metrics_find::metrics_find; -------------------------------------------------------------------------------- /src/graphite/handlers/render.rs: -------------------------------------------------------------------------------- 1 | use iron::prelude::*; 2 | use iron; 3 | use urlencoded::UrlEncodedQuery; 4 | 5 | use std::io::Read; 6 | 7 | // [{ 8 | // "target": "entries", 9 | // "datapoints": [ 10 | // [1.0, 1311836008], 11 | // [2.0, 1311836009], 12 | // [3.0, 1311836010], 13 | // [5.0, 1311836011], 14 | // [6.0, 1311836012] 15 | // ] 16 | // }] 17 | pub fn render(req: &mut Request) -> IronResult { 18 | let mut buf : Vec = Vec::new(); 19 | let bytes_read = req.body.read_to_end(&mut buf); 20 | println!("body ({bytes_read:?}: {:#?}", buf, bytes_read=bytes_read); 21 | 22 | match req.get_ref::() { 23 | Ok(ref hashmap) => println!("Parsed GET request query string:\n {:?}", hashmap), 24 | Err(ref e) => println!("err {:?}", e) 25 | }; 26 | 27 | Ok( Response::with( (iron::status::Ok, "hey".to_string() ) ) ) 28 | } 29 | 30 | // target=hey.select%20metric&from=-6h&until=now&format=json&maxDataPoints=1425 31 | // fn do_render() { 32 | 33 | // } -------------------------------------------------------------------------------- /src/graphite/middleware/mod.rs: -------------------------------------------------------------------------------- 1 | mod path_fixer; 2 | 3 | pub use self::path_fixer::PathFixer; 4 | -------------------------------------------------------------------------------- /src/graphite/middleware/path_fixer.rs: -------------------------------------------------------------------------------- 1 | use iron::prelude::*; 2 | use iron; 3 | 4 | pub struct PathFixer; 5 | 6 | impl iron::middleware::BeforeMiddleware for PathFixer { 7 | fn before(&self, req: &mut Request) -> IronResult<()> { 8 | let ref mut path = req.url.path; 9 | if path.last().unwrap().len() == 0 { 10 | path.pop(); 11 | } 12 | 13 | Ok(()) 14 | } 15 | 16 | // fn catch(&self, _: &mut Request, err: IronError) -> IronResult<()> { 17 | // Err(err) 18 | // } 19 | } -------------------------------------------------------------------------------- /src/graphite/mod.rs: -------------------------------------------------------------------------------- 1 | extern crate iron; 2 | extern crate router; 3 | extern crate urlencoded; 4 | extern crate glob; 5 | extern crate persistent; 6 | // extern crate bodyparser; 7 | 8 | mod config; 9 | pub mod server; 10 | mod error; 11 | pub mod expander; 12 | mod middleware; 13 | mod handlers; 14 | mod cache_holder; 15 | 16 | pub use self::config::Config; 17 | 18 | // Query root namespace 19 | // curl 'http://10.69.8.54/graphite-web/metrics/find/?query=*' -H 'Pragma: no-cache' -H 'Origin: http://10.69.8.55' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36' -H 'Accept: application/json, text/plain, */*' -H 'Referer: http://10.69.8.55/grafana/' -H 'Connection: keep-alive' -H 'Cache-Control: no-cache' --compressed 20 | // [{"leaf": 0, "context": {}, "text": "carbon", "expandable": 1, "id": "carbon", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "cisco", "expandable": 1, "id": "cisco", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "collectd", "expandable": 1, "id": "collectd", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "es_xle", "expandable": 1, "id": "es_xle", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "logstash", "expandable": 1, "id": "logstash", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "misc", "expandable": 1, "id": "misc", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "stats", "expandable": 1, "id": "stats", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "stats_counts", "expandable": 1, "id": "stats_counts", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "statsd", "expandable": 1, "id": "statsd", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "uwsgi", "expandable": 1, "id": "uwsgi", "allowChildren": 1}] 21 | 22 | // Query a sub namespace 23 | // curl 'http://10.69.8.54/graphite-web/metrics/find/?query=carbon' -H 'Pragma: no-cache' -H 'Origin: http://10.69.8.55' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36' -H 'Accept: application/json, text/plain, */*' -H 'Referer: http://10.69.8.55/grafana/' -H 'Connection: keep-alive' -H 'Cache-Control: no-cache' --compressed 24 | 25 | // Query a sub namespace with wildcard 26 | // curl 'http://10.69.8.54/graphite-web/metrics/find/?query=collectd.xle.*' -H 'Pragma: no-cache' -H 'Origin: http://10.69.8.55' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36' -H 'Accept: application/json, text/plain, */*' -H 'Referer: http://10.69.8.55/grafana/' -H 'Connection: keep-alive' -H 'Cache-Control: no-cache' --compressed 27 | // [{"leaf": 0, "context": {}, "text": "xle-broker-01", "expandable": 1, "id": "collectd.xle.xle-broker-01", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-broker-02", "expandable": 1, "id": "collectd.xle.xle-broker-02", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-broker-03", "expandable": 1, "id": "collectd.xle.xle-broker-03", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-06", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-06", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-07", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-07", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-08", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-08", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-09", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-09", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-10", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-10", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-13", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-13", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-14", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-14", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-15", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-15", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-16", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-16", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-17", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-17", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-18", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-18", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-19", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-19", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-elasticsearch-20", "expandable": 1, "id": "collectd.xle.xle-elasticsearch-20", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-forwarder-01", "expandable": 1, "id": "collectd.xle.xle-forwarder-01", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-forwarder-02", "expandable": 1, "id": "collectd.xle.xle-forwarder-02", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-forwarder-03", "expandable": 1, "id": "collectd.xle.xle-forwarder-03", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-forwarder-04", "expandable": 1, "id": "collectd.xle.xle-forwarder-04", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-forwarder-05", "expandable": 1, "id": "collectd.xle.xle-forwarder-05", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-forwarder-06", "expandable": 1, "id": "collectd.xle.xle-forwarder-06", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-forwarder-07", "expandable": 1, "id": "collectd.xle.xle-forwarder-07", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-forwarder-08", "expandable": 1, "id": "collectd.xle.xle-forwarder-08", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-forwarder-102", "expandable": 1, "id": "collectd.xle.xle-forwarder-102", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-frontend-01", "expandable": 1, "id": "collectd.xle.xle-frontend-01", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-frontend-02-temp", "expandable": 1, "id": "collectd.xle.xle-frontend-02-temp", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-sensor-01vcasensorp01_hq_corp_viasat_com", "expandable": 1, "id": "collectd.xle.xle-sensor-01vcasensorp01_hq_corp_viasat_com", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-stats-01", "expandable": 1, "id": "collectd.xle.xle-stats-01", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-syslog-archiver-01", "expandable": 1, "id": "collectd.xle.xle-syslog-archiver-01", "allowChildren": 1}, {"leaf": 0, "context": {}, "text": "xle-syslog-forwarder-01vcasyslogp02_hq_corp_viasat_com", "expandable": 1, "id": "collectd.xle.xle-syslog-forwarder-01vcasyslogp02_hq_corp_viasat_com", "allowChildren": 1}] 28 | 29 | // Query a mixed namespace with wildcard 30 | // curl 'http://10.69.8.54/graphite-web/render' -H 'Pragma: no-cache' -H 'Origin: http://10.69.8.55' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: application/json, text/plain, */*' -H 'Cache-Control: no-cache' -H 'Referer: http://10.69.8.55/grafana/' -H 'Connection: keep-alive' --data 'target=collectd.xle.xle-elasticsearch-20.*.*.*&from=-5min&until=now&format=json&maxDataPoints=362' --compressed 31 | // [{"target": "collectd.xle.xle-elasticsearch-20.disk-sr0.disk_merged.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-sr0.disk_merged.write", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-sr0.disk_octets.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-sr0.disk_octets.write", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-sr0.disk_ops.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-sr0.disk_ops.write", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-sr0.disk_time.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-sr0.disk_time.write", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda.disk_merged.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda.disk_merged.write", "datapoints": [[0.05, 1437548400], [0.099998, 1437548460], [0.033334, 1437548520], [0.033334, 1437548580], [0.033333, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda.disk_octets.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda.disk_octets.write", "datapoints": [[1365.344167, 1437548400], [1843.164623, 1437548460], [1160.55345, 1437548520], [1160.532349, 1437548580], [1160.517175, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda.disk_ops.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda.disk_ops.write", "datapoints": [[0.150001, 1437548400], [0.183328, 1437548460], [0.11667, 1437548520], [0.116667, 1437548580], [0.116666, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda.disk_time.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda.disk_time.write", "datapoints": [[2.21667, 1437548400], [1.083311, 1437548460], [2.283368, 1437548520], [1.150014, 1437548580], [1.716652, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda1.disk_merged.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda1.disk_merged.write", "datapoints": [[0.05, 1437548400], [0.099998, 1437548460], [0.033334, 1437548520], [0.033334, 1437548580], [0.033333, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda1.disk_octets.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda1.disk_octets.write", "datapoints": [[1365.335251, 1437548400], [1843.162884, 1437548460], [1160.548773, 1437548520], [1160.54616, 1437548580], [1160.527822, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda1.disk_ops.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda1.disk_ops.write", "datapoints": [[0.15, 1437548400], [0.18333, 1437548460], [0.116668, 1437548520], [0.116668, 1437548580], [0.116666, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda1.disk_time.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vda1.disk_time.write", "datapoints": [[2.21667, 1437548400], [1.083312, 1437548460], [2.283362, 1437548520], [1.150014, 1437548580], [1.716659, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb.disk_merged.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb.disk_merged.write", "datapoints": [[22.766694, 1437548400], [40.449326, 1437548460], [26.200252, 1437548520], [21.083653, 1437548580], [23.133223, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb.disk_octets.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb.disk_octets.write", "datapoints": [[931090.118875, 1437548400], [1433847.928078, 1437548460], [1266018.975983, 1437548520], [893145.302494, 1437548580], [960575.70446, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb.disk_ops.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb.disk_ops.write", "datapoints": [[7.516675, 1437548400], [19.016339, 1437548460], [9.983438, 1437548520], [7.233437, 1437548580], [8.716625, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb.disk_time.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb.disk_time.write", "datapoints": [[7.150008, 1437548400], [4.949916, 1437548460], [11.633449, 1437548520], [6.683433, 1437548580], [5.999972, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb1.disk_merged.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb1.disk_merged.write", "datapoints": [[22.766691, 1437548400], [40.449393, 1437548460], [26.200222, 1437548520], [21.083678, 1437548580], [23.133223, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb1.disk_octets.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb1.disk_octets.write", "datapoints": [[931090.115522, 1437548400], [1433850.034798, 1437548460], [1266017.149898, 1437548520], [893146.625558, 1437548580], [960575.707561, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb1.disk_ops.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb1.disk_ops.write", "datapoints": [[7.416674, 1437548400], [15.216429, 1437548460], [9.450085, 1437548520], [7.050111, 1437548580], [8.44996, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb1.disk_time.read", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.disk-vdb1.disk_time.write", "datapoints": [[7.233341, 1437548400], [6.016575, 1437548460], [12.250107, 1437548520], [6.816776, 1437548580], [6.166637, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.interface-eth0.if_errors.rx", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.interface-eth0.if_errors.tx", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.interface-eth0.if_octets.rx", "datapoints": [[206384.034396, 1437548400], [181786.848038, 1437548460], [187141.228723, 1437548520], [185586.058428, 1437548580], [188129.387048, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.interface-eth0.if_octets.tx", "datapoints": [[73172.681439, 1437548400], [58449.103321, 1437548460], [58215.881876, 1437548520], [60515.573755, 1437548580], [58241.422936, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.interface-eth0.if_packets.rx", "datapoints": [[289.384544, 1437548400], [262.561301, 1437548460], [273.485892, 1437548520], [267.752853, 1437548580], [268.297009, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.interface-eth0.if_packets.tx", "datapoints": [[258.984417, 1437548400], [235.561853, 1437548460], [237.902226, 1437548520], [238.552542, 1437548580], [237.13069, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.interface-lo.if_errors.rx", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.interface-lo.if_errors.tx", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.interface-lo.if_octets.rx", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.interface-lo.if_octets.tx", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.interface-lo.if_packets.rx", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.interface-lo.if_packets.tx", "datapoints": [[0.0, 1437548400], [0.0, 1437548460], [0.0, 1437548520], [0.0, 1437548580], [0.0, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.load.load.longterm", "datapoints": [[0.35, 1437548400], [0.35, 1437548460], [0.35, 1437548520], [0.34, 1437548580], [0.35, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.load.load.midterm", "datapoints": [[0.26, 1437548400], [0.31, 1437548460], [0.31, 1437548520], [0.3, 1437548580], [0.34, 1437548640]]}, {"target": "collectd.xle.xle-elasticsearch-20.load.load.shortterm", "datapoints": [[0.18, 1437548400], [0.42, 1437548460], [0.38, 1437548520], [0.23, 1437548580], [0.43, 1437548640]]}] 32 | 33 | // Query one metric 34 | // curl 'http://10.69.8.54/graphite-web/metrics/find/?query=carbon.agents.xle-stats-01-a.cache.*' -H 'Pragma: no-cache' -H 'Origin: http://10.69.8.55' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36' -H 'Accept: application/json, text/plain, */*' -H 'Referer: http://10.69.8.55/grafana/' -H 'Connection: keep-alive' -H 'Cache-Control: no-cache' --compressed 35 | 36 | // Render a single query 37 | // curl 'http://10.69.8.54/graphite-web/render' -H 'Pragma: no-cache' -H 'Origin: http://10.69.8.55' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: application/json, text/plain, */*' -H 'Cache-Control: no-cache' -H 'Referer: http://10.69.8.55/grafana/' -H 'Connection: keep-alive' --data 'target=carbon.agents.xle-stats-01-a.cache.size&from=-6h&until=now&format=json&maxDataPoints=611' --compressed 38 | 39 | // Render two queries 40 | // curl 'http://10.69.8.54/graphite-web/render' -H 'Pragma: no-cache' -H 'Origin: http://10.69.8.55' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: application/json, text/plain, */*' -H 'Cache-Control: no-cache' -H 'Referer: http://10.69.8.55/grafana/' -H 'Connection: keep-alive' --data 'target=carbon.agents.xle-stats-01-a.cache.size&target=carbon.agents.xle-stats-01-a.cache.queues&from=-6h&until=now&format=json&maxDataPoints=611' --compressed 41 | // [{"target": "carbon.agents.xle-stats-01-a.cache.size", "datapoints": [[0.0, 1437321720], [76.0, 1437321780], [7.0, 1437321840], [0.0, 1437321900], [76.0, 1437321960], [7.0, 1437322020], [77.0, 1437322080], [12045.0, 1437322140], [77.0, 1437322200], [7.0, 1437322260], [0.0, 1437322320], [77.0, 1437322380], [76.0, 1437322440], [78.0, 1437322500], [0.0, 1437322560], [4.0, 1437322620], [76.0, 1437322680], [78.0, 1437322740], [59.0, 1437322800], [0.0, 1437322860], [0.0, 1437322920], [0.0, 1437322980], [0.0, 1437323040], [7.0, 1437323100], [91.0, 1437323160], [7.0, 1437323220], [91.0, 1437323280], [2214.0, 1437323340], [1270.0, 1437323400], [0.0, 1437323460], [92.0, 1437323520], [91.0, 1437323580], [73.0, 1437323640], [530.0, 1437323700], [14.0, 1437323760], [953.0, 1437323820], [1153.0, 1437323880], [0.0, 1437323940], [0.0, 1437324000], [669.0, 1437324060], [959.0, 1437324120], [523.0, 1437324180], [75.0, 1437324240], [856.0, 1437324300], [496.0, 1437324360], [75.0, 1437324420], [0.0, 1437324480], [7.0, 1437324540], [77.0, 1437324600], [59.0, 1437324660], [77.0, 1437324720], [77.0, 1437324780], [0.0, 1437324840], [77.0, 1437324900], [0.0, 1437324960], [0.0, 1437325020], [0.0, 1437325080], [60.0, 1437325140], [79.0, 1437325200], [75.0, 1437325260], [75.0, 1437325320], [0.0, 1437325380], [74.0, 1437325440], [0.0, 1437325500], [0.0, 1437325560], [76.0, 1437325620], [0.0, 1437325680], [7.0, 1437325740], [59.0, 1437325800], [4.0, 1437325860], [0.0, 1437325920], [7.0, 1437325980], [0.0, 1437326040], [7.0, 1437326100], [76.0, 1437326160], [0.0, 1437326220], [0.0, 1437326280], [76.0, 1437326340], [77.0, 1437326400], [59.0, 1437326460], [0.0, 1437326520], [78.0, 1437326580], [75.0, 1437326640], [0.0, 1437326700], [7.0, 1437326760], [77.0, 1437326820], [0.0, 1437326880], [0.0, 1437326940], [0.0, 1437327000], [61.0, 1437327060], [63.0, 1437327120], [79.0, 1437327180], [52.0, 1437327240], [7.0, 1437327300], [7.0, 1437327360], [75.0, 1437327420], [74.0, 1437327480], [0.0, 1437327540], [76.0, 1437327600], [75.0, 1437327660], [58.0, 1437327720], [77.0, 1437327780], [75.0, 1437327840], [75.0, 1437327900], [0.0, 1437327960], [77.0, 1437328020], [213.0, 1437328080], [0.0, 1437328140], [0.0, 1437328200], [490.0, 1437328260], [0.0, 1437328320], [2733.0, 1437328380], [0.0, 1437328440], [1719.0, 1437328500], [0.0, 1437328560], [7.0, 1437328620], [7.0, 1437328680], [60.0, 1437328740], [77.0, 1437328800], [1711.0, 1437328860], [2735.0, 1437328920], [2734.0, 1437328980], [76.0, 1437329040], [2715.0, 1437329100], [1326.0, 1437329160], [2734.0, 1437329220], [2484.0, 1437329280], [2735.0, 1437329340], [2665.0, 1437329400], [0.0, 1437329460], [0.0, 1437329520], [75.0, 1437329580], [77.0, 1437329640], [0.0, 1437329700], [59.0, 1437329760], [2000.0, 1437329820], [0.0, 1437329880], [75.0, 1437329940], [0.0, 1437330000], [7.0, 1437330060], [77.0, 1437330120], [4.0, 1437330180], [0.0, 1437330240], [0.0, 1437330300], [0.0, 1437330360], [76.0, 1437330420], [77.0, 1437330480], [77.0, 1437330540], [75.0, 1437330600], [7.0, 1437330660], [76.0, 1437330720], [76.0, 1437330780], [0.0, 1437330840], [77.0, 1437330900], [59.0, 1437330960], [7.0, 1437331020], [0.0, 1437331080], [0.0, 1437331140], [7.0, 1437331200], [58.0, 1437331260], [7.0, 1437331320], [78.0, 1437331380], [0.0, 1437331440], [0.0, 1437331500], [0.0, 1437331560], [0.0, 1437331620], [75.0, 1437331680], [0.0, 1437331740], [59.0, 1437331800], [0.0, 1437331860], [77.0, 1437331920], [76.0, 1437331980], [7.0, 1437332040], [0.0, 1437332100], [77.0, 1437332160], [0.0, 1437332220], [77.0, 1437332280], [0.0, 1437332340], [7.0, 1437332400], [76.0, 1437332460], [0.0, 1437332520], [75.0, 1437332580], [0.0, 1437332640], [90.0, 1437332700], [91.0, 1437332760], [91.0, 1437332820], [91.0, 1437332880], [74.0, 1437332940], [21.0, 1437333000], [0.0, 1437333060], [74.0, 1437333120], [92.0, 1437333180], [14.0, 1437333240], [14.0, 1437333300], [61.0, 1437333360], [7.0, 1437333420], [7.0, 1437333480], [0.0, 1437333540], [76.0, 1437333600], [75.0, 1437333660], [61.0, 1437333720], [7.0, 1437333780], [0.0, 1437333840], [0.0, 1437333900], [0.0, 1437333960], [77.0, 1437334020], [7.0, 1437334080], [0.0, 1437334140], [76.0, 1437334200], [75.0, 1437334260], [7.0, 1437334320], [60.0, 1437334380], [0.0, 1437334440], [76.0, 1437334500], [76.0, 1437334560], [77.0, 1437334620], [0.0, 1437334680], [0.0, 1437334740], [0.0, 1437334800], [77.0, 1437334860], [75.0, 1437334920], [0.0, 1437334980], [60.0, 1437335040], [75.0, 1437335100], [0.0, 1437335160], [77.0, 1437335220], [77.0, 1437335280], [58.0, 1437335340], [75.0, 1437335400], [7.0, 1437335460], [77.0, 1437335520], [7.0, 1437335580], [0.0, 1437335640], [76.0, 1437335700], [77.0, 1437335760], [75.0, 1437335820], [0.0, 1437335880], [7.0, 1437335940], [0.0, 1437336000], [76.0, 1437336060], [77.0, 1437336120], [76.0, 1437336180], [61.0, 1437336240], [78.0, 1437336300], [0.0, 1437336360], [75.0, 1437336420], [77.0, 1437336480], [76.0, 1437336540], [0.0, 1437336600], [75.0, 1437336660], [78.0, 1437336720], [77.0, 1437336780], [0.0, 1437336840], [7.0, 1437336900], [0.0, 1437336960], [76.0, 1437337020], [75.0, 1437337080], [7.0, 1437337140], [59.0, 1437337200], [0.0, 1437337260], [78.0, 1437337320], [4.0, 1437337380], [0.0, 1437337440], [0.0, 1437337500], [77.0, 1437337560], [77.0, 1437337620], [7.0, 1437337680], [60.0, 1437337740], [76.0, 1437337800], [0.0, 1437337860], [75.0, 1437337920], [18.0, 1437337980], [59.0, 1437338040], [7.0, 1437338100], [7.0, 1437338160], [77.0, 1437338220], [0.0, 1437338280], [0.0, 1437338340], [19.0, 1437338400], [0.0, 1437338460], [78.0, 1437338520], [77.0, 1437338580], [7.0, 1437338640], [77.0, 1437338700], [0.0, 1437338760], [0.0, 1437338820], [0.0, 1437338880], [0.0, 1437338940], [0.0, 1437339000], [75.0, 1437339060], [77.0, 1437339120], [75.0, 1437339180], [0.0, 1437339240], [7.0, 1437339300], [0.0, 1437339360], [77.0, 1437339420], [60.0, 1437339480], [3.0, 1437339540], [0.0, 1437339600], [7.0, 1437339660], [0.0, 1437339720], [0.0, 1437339780], [77.0, 1437339840], [0.0, 1437339900], [77.0, 1437339960], [7.0, 1437340020], [57.0, 1437340080], [0.0, 1437340140], [7.0, 1437340200], [77.0, 1437340260], [0.0, 1437340320], [60.0, 1437340380], [76.0, 1437340440], [7.0, 1437340500], [0.0, 1437340560], [0.0, 1437340620], [78.0, 1437340680], [77.0, 1437340740], [0.0, 1437340800], [60.0, 1437340860], [75.0, 1437340920], [75.0, 1437340980], [76.0, 1437341040], [77.0, 1437341100], [0.0, 1437341160], [58.0, 1437341220], [0.0, 1437341280], [78.0, 1437341340], [76.0, 1437341400], [7.0, 1437341460], [61.0, 1437341520], [7.0, 1437341580], [0.0, 1437341640], [76.0, 1437341700], [75.0, 1437341760], [59.0, 1437341820], [7.0, 1437341880], [76.0, 1437341940], [76.0, 1437342000], [76.0, 1437342060], [89.0, 1437342120], [72.0, 1437342180], [78.0, 1437342240], [7.0, 1437342300], [92.0, 1437342360], [7.0, 1437342420], [21.0, 1437342480], [93.0, 1437342540], [11050.0, 1437342600], [21.0, 1437342660], [14.0, 1437342720], [14.0, 1437342780], [80.0, 1437342840], [0.0, 1437342900], [0.0, 1437342960], [77.0, 1437343020], [76.0, 1437343080], [76.0, 1437343140], [0.0, 1437343200], [null, 1437343260]]}, {"target": "carbon.agents.xle-stats-01-a.cache.queues", "datapoints": [[0.0, 1437321720], [64.0, 1437321780], [7.0, 1437321840], [0.0, 1437321900], [73.0, 1437321960], [7.0, 1437322020], [73.0, 1437322080], [11842.0, 1437322140], [72.0, 1437322200], [7.0, 1437322260], [0.0, 1437322320], [67.0, 1437322380], [69.0, 1437322440], [73.0, 1437322500], [0.0, 1437322560], [4.0, 1437322620], [70.0, 1437322680], [71.0, 1437322740], [55.0, 1437322800], [0.0, 1437322860], [0.0, 1437322920], [0.0, 1437322980], [0.0, 1437323040], [7.0, 1437323100], [85.0, 1437323160], [7.0, 1437323220], [87.0, 1437323280], [2203.0, 1437323340], [1267.0, 1437323400], [0.0, 1437323460], [87.0, 1437323520], [85.0, 1437323580], [73.0, 1437323640], [516.0, 1437323700], [14.0, 1437323760], [949.0, 1437323820], [1138.0, 1437323880], [0.0, 1437323940], [0.0, 1437324000], [665.0, 1437324060], [933.0, 1437324120], [521.0, 1437324180], [73.0, 1437324240], [851.0, 1437324300], [494.0, 1437324360], [73.0, 1437324420], [0.0, 1437324480], [7.0, 1437324540], [73.0, 1437324600], [57.0, 1437324660], [61.0, 1437324720], [73.0, 1437324780], [0.0, 1437324840], [72.0, 1437324900], [0.0, 1437324960], [0.0, 1437325020], [0.0, 1437325080], [60.0, 1437325140], [71.0, 1437325200], [71.0, 1437325260], [65.0, 1437325320], [0.0, 1437325380], [69.0, 1437325440], [0.0, 1437325500], [0.0, 1437325560], [65.0, 1437325620], [0.0, 1437325680], [7.0, 1437325740], [59.0, 1437325800], [4.0, 1437325860], [0.0, 1437325920], [7.0, 1437325980], [0.0, 1437326040], [7.0, 1437326100], [73.0, 1437326160], [0.0, 1437326220], [0.0, 1437326280], [65.0, 1437326340], [69.0, 1437326400], [55.0, 1437326460], [0.0, 1437326520], [64.0, 1437326580], [66.0, 1437326640], [0.0, 1437326700], [7.0, 1437326760], [71.0, 1437326820], [0.0, 1437326880], [0.0, 1437326940], [0.0, 1437327000], [61.0, 1437327060], [56.0, 1437327120], [69.0, 1437327180], [52.0, 1437327240], [7.0, 1437327300], [7.0, 1437327360], [73.0, 1437327420], [63.0, 1437327480], [0.0, 1437327540], [73.0, 1437327600], [73.0, 1437327660], [56.0, 1437327720], [73.0, 1437327780], [70.0, 1437327840], [72.0, 1437327900], [0.0, 1437327960], [73.0, 1437328020], [211.0, 1437328080], [0.0, 1437328140], [0.0, 1437328200], [485.0, 1437328260], [0.0, 1437328320], [2731.0, 1437328380], [0.0, 1437328440], [1719.0, 1437328500], [0.0, 1437328560], [7.0, 1437328620], [7.0, 1437328680], [57.0, 1437328740], [65.0, 1437328800], [1711.0, 1437328860], [2731.0, 1437328920], [2731.0, 1437328980], [73.0, 1437329040], [2713.0, 1437329100], [1326.0, 1437329160], [2720.0, 1437329220], [2484.0, 1437329280], [2729.0, 1437329340], [2665.0, 1437329400], [0.0, 1437329460], [0.0, 1437329520], [73.0, 1437329580], [73.0, 1437329640], [0.0, 1437329700], [57.0, 1437329760], [2000.0, 1437329820], [0.0, 1437329880], [70.0, 1437329940], [0.0, 1437330000], [7.0, 1437330060], [73.0, 1437330120], [4.0, 1437330180], [0.0, 1437330240], [0.0, 1437330300], [0.0, 1437330360], [67.0, 1437330420], [73.0, 1437330480], [69.0, 1437330540], [71.0, 1437330600], [7.0, 1437330660], [73.0, 1437330720], [65.0, 1437330780], [0.0, 1437330840], [73.0, 1437330900], [59.0, 1437330960], [7.0, 1437331020], [0.0, 1437331080], [0.0, 1437331140], [7.0, 1437331200], [55.0, 1437331260], [7.0, 1437331320], [72.0, 1437331380], [0.0, 1437331440], [0.0, 1437331500], [0.0, 1437331560], [0.0, 1437331620], [65.0, 1437331680], [0.0, 1437331740], [55.0, 1437331800], [0.0, 1437331860], [63.0, 1437331920], [66.0, 1437331980], [7.0, 1437332040], [0.0, 1437332100], [67.0, 1437332160], [0.0, 1437332220], [70.0, 1437332280], [0.0, 1437332340], [7.0, 1437332400], [65.0, 1437332460], [0.0, 1437332520], [69.0, 1437332580], [0.0, 1437332640], [73.0, 1437332700], [85.0, 1437332760], [81.0, 1437332820], [85.0, 1437332880], [74.0, 1437332940], [21.0, 1437333000], [0.0, 1437333060], [74.0, 1437333120], [83.0, 1437333180], [14.0, 1437333240], [14.0, 1437333300], [59.0, 1437333360], [7.0, 1437333420], [7.0, 1437333480], [0.0, 1437333540], [66.0, 1437333600], [73.0, 1437333660], [61.0, 1437333720], [7.0, 1437333780], [0.0, 1437333840], [0.0, 1437333900], [0.0, 1437333960], [71.0, 1437334020], [7.0, 1437334080], [0.0, 1437334140], [64.0, 1437334200], [69.0, 1437334260], [7.0, 1437334320], [60.0, 1437334380], [0.0, 1437334440], [71.0, 1437334500], [64.0, 1437334560], [71.0, 1437334620], [0.0, 1437334680], [0.0, 1437334740], [0.0, 1437334800], [73.0, 1437334860], [73.0, 1437334920], [0.0, 1437334980], [60.0, 1437335040], [73.0, 1437335100], [0.0, 1437335160], [68.0, 1437335220], [72.0, 1437335280], [57.0, 1437335340], [69.0, 1437335400], [7.0, 1437335460], [69.0, 1437335520], [7.0, 1437335580], [0.0, 1437335640], [61.0, 1437335700], [73.0, 1437335760], [73.0, 1437335820], [0.0, 1437335880], [7.0, 1437335940], [0.0, 1437336000], [67.0, 1437336060], [65.0, 1437336120], [73.0, 1437336180], [61.0, 1437336240], [72.0, 1437336300], [0.0, 1437336360], [71.0, 1437336420], [69.0, 1437336480], [73.0, 1437336540], [0.0, 1437336600], [73.0, 1437336660], [64.0, 1437336720], [73.0, 1437336780], [0.0, 1437336840], [7.0, 1437336900], [0.0, 1437336960], [65.0, 1437337020], [71.0, 1437337080], [7.0, 1437337140], [59.0, 1437337200], [0.0, 1437337260], [71.0, 1437337320], [4.0, 1437337380], [0.0, 1437337440], [0.0, 1437337500], [67.0, 1437337560], [71.0, 1437337620], [7.0, 1437337680], [59.0, 1437337740], [73.0, 1437337800], [0.0, 1437337860], [71.0, 1437337920], [18.0, 1437337980], [59.0, 1437338040], [7.0, 1437338100], [7.0, 1437338160], [69.0, 1437338220], [0.0, 1437338280], [0.0, 1437338340], [19.0, 1437338400], [0.0, 1437338460], [71.0, 1437338520], [71.0, 1437338580], [7.0, 1437338640], [63.0, 1437338700], [0.0, 1437338760], [0.0, 1437338820], [0.0, 1437338880], [0.0, 1437338940], [0.0, 1437339000], [73.0, 1437339060], [73.0, 1437339120], [69.0, 1437339180], [0.0, 1437339240], [7.0, 1437339300], [0.0, 1437339360], [73.0, 1437339420], [60.0, 1437339480], [3.0, 1437339540], [0.0, 1437339600], [7.0, 1437339660], [0.0, 1437339720], [0.0, 1437339780], [59.0, 1437339840], [0.0, 1437339900], [73.0, 1437339960], [7.0, 1437340020], [57.0, 1437340080], [0.0, 1437340140], [7.0, 1437340200], [73.0, 1437340260], [0.0, 1437340320], [60.0, 1437340380], [72.0, 1437340440], [7.0, 1437340500], [0.0, 1437340560], [0.0, 1437340620], [73.0, 1437340680], [69.0, 1437340740], [0.0, 1437340800], [60.0, 1437340860], [73.0, 1437340920], [73.0, 1437340980], [73.0, 1437341040], [73.0, 1437341100], [0.0, 1437341160], [58.0, 1437341220], [0.0, 1437341280], [64.0, 1437341340], [73.0, 1437341400], [7.0, 1437341460], [61.0, 1437341520], [7.0, 1437341580], [0.0, 1437341640], [71.0, 1437341700], [71.0, 1437341760], [57.0, 1437341820], [7.0, 1437341880], [63.0, 1437341940], [68.0, 1437342000], [71.0, 1437342060], [85.0, 1437342120], [72.0, 1437342180], [62.0, 1437342240], [7.0, 1437342300], [87.0, 1437342360], [7.0, 1437342420], [21.0, 1437342480], [77.0, 1437342540], [10757.0, 1437342600], [21.0, 1437342660], [14.0, 1437342720], [14.0, 1437342780], [69.0, 1437342840], [0.0, 1437342900], [0.0, 1437342960], [61.0, 1437343020], [73.0, 1437343080], [72.0, 1437343140], [0.0, 1437343200], [null, 1437343260]]}] 42 | 43 | // Render a single query with a wild card 44 | // curl 'http://10.69.8.54/graphite-web/render' -H 'Pragma: no-cache' -H 'Origin: http://10.69.8.55' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: en-US,en;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Accept: application/json, text/plain, */*' -H 'Cache-Control: no-cache' -H 'Referer: http://10.69.8.55/grafana/' -H 'Connection: keep-alive' --data 'target=carbon.agents.*.cache.size&from=-6h&until=now&format=json&maxDataPoints=611' --compressed 45 | // [{"target": "carbon.agents.xle-stats-01-a.cache.size", "datapoints": [[76.0, 1437321780], [7.0, 1437321840], [0.0, 1437321900], [76.0, 1437321960], [7.0, 1437322020], [77.0, 1437322080], [12045.0, 1437322140], [77.0, 1437322200], [7.0, 1437322260], [0.0, 1437322320], [77.0, 1437322380], [76.0, 1437322440], [78.0, 1437322500], [0.0, 1437322560], [4.0, 1437322620], [76.0, 1437322680], [78.0, 1437322740], [59.0, 1437322800], [0.0, 1437322860], [0.0, 1437322920], [0.0, 1437322980], [0.0, 1437323040], [7.0, 1437323100], [91.0, 1437323160], [7.0, 1437323220], [91.0, 1437323280], [2214.0, 1437323340], [1270.0, 1437323400], [0.0, 1437323460], [92.0, 1437323520], [91.0, 1437323580], [73.0, 1437323640], [530.0, 1437323700], [14.0, 1437323760], [953.0, 1437323820], [1153.0, 1437323880], [0.0, 1437323940], [0.0, 1437324000], [669.0, 1437324060], [959.0, 1437324120], [523.0, 1437324180], [75.0, 1437324240], [856.0, 1437324300], [496.0, 1437324360], [75.0, 1437324420], [0.0, 1437324480], [7.0, 1437324540], [77.0, 1437324600], [59.0, 1437324660], [77.0, 1437324720], [77.0, 1437324780], [0.0, 1437324840], [77.0, 1437324900], [0.0, 1437324960], [0.0, 1437325020], [0.0, 1437325080], [60.0, 1437325140], [79.0, 1437325200], [75.0, 1437325260], [75.0, 1437325320], [0.0, 1437325380], [74.0, 1437325440], [0.0, 1437325500], [0.0, 1437325560], [76.0, 1437325620], [0.0, 1437325680], [7.0, 1437325740], [59.0, 1437325800], [4.0, 1437325860], [0.0, 1437325920], [7.0, 1437325980], [0.0, 1437326040], [7.0, 1437326100], [76.0, 1437326160], [0.0, 1437326220], [0.0, 1437326280], [76.0, 1437326340], [77.0, 1437326400], [59.0, 1437326460], [0.0, 1437326520], [78.0, 1437326580], [75.0, 1437326640], [0.0, 1437326700], [7.0, 1437326760], [77.0, 1437326820], [0.0, 1437326880], [0.0, 1437326940], [0.0, 1437327000], [61.0, 1437327060], [63.0, 1437327120], [79.0, 1437327180], [52.0, 1437327240], [7.0, 1437327300], [7.0, 1437327360], [75.0, 1437327420], [74.0, 1437327480], [0.0, 1437327540], [76.0, 1437327600], [75.0, 1437327660], [58.0, 1437327720], [77.0, 1437327780], [75.0, 1437327840], [75.0, 1437327900], [0.0, 1437327960], [77.0, 1437328020], [213.0, 1437328080], [0.0, 1437328140], [0.0, 1437328200], [490.0, 1437328260], [0.0, 1437328320], [2733.0, 1437328380], [0.0, 1437328440], [1719.0, 1437328500], [0.0, 1437328560], [7.0, 1437328620], [7.0, 1437328680], [60.0, 1437328740], [77.0, 1437328800], [1711.0, 1437328860], [2735.0, 1437328920], [2734.0, 1437328980], [76.0, 1437329040], [2715.0, 1437329100], [1326.0, 1437329160], [2734.0, 1437329220], [2484.0, 1437329280], [2735.0, 1437329340], [2665.0, 1437329400], [0.0, 1437329460], [0.0, 1437329520], [75.0, 1437329580], [77.0, 1437329640], [0.0, 1437329700], [59.0, 1437329760], [2000.0, 1437329820], [0.0, 1437329880], [75.0, 1437329940], [0.0, 1437330000], [7.0, 1437330060], [77.0, 1437330120], [4.0, 1437330180], [0.0, 1437330240], [0.0, 1437330300], [0.0, 1437330360], [76.0, 1437330420], [77.0, 1437330480], [77.0, 1437330540], [75.0, 1437330600], [7.0, 1437330660], [76.0, 1437330720], [76.0, 1437330780], [0.0, 1437330840], [77.0, 1437330900], [59.0, 1437330960], [7.0, 1437331020], [0.0, 1437331080], [0.0, 1437331140], [7.0, 1437331200], [58.0, 1437331260], [7.0, 1437331320], [78.0, 1437331380], [0.0, 1437331440], [0.0, 1437331500], [0.0, 1437331560], [0.0, 1437331620], [75.0, 1437331680], [0.0, 1437331740], [59.0, 1437331800], [0.0, 1437331860], [77.0, 1437331920], [76.0, 1437331980], [7.0, 1437332040], [0.0, 1437332100], [77.0, 1437332160], [0.0, 1437332220], [77.0, 1437332280], [0.0, 1437332340], [7.0, 1437332400], [76.0, 1437332460], [0.0, 1437332520], [75.0, 1437332580], [0.0, 1437332640], [90.0, 1437332700], [91.0, 1437332760], [91.0, 1437332820], [91.0, 1437332880], [74.0, 1437332940], [21.0, 1437333000], [0.0, 1437333060], [74.0, 1437333120], [92.0, 1437333180], [14.0, 1437333240], [14.0, 1437333300], [61.0, 1437333360], [7.0, 1437333420], [7.0, 1437333480], [0.0, 1437333540], [76.0, 1437333600], [75.0, 1437333660], [61.0, 1437333720], [7.0, 1437333780], [0.0, 1437333840], [0.0, 1437333900], [0.0, 1437333960], [77.0, 1437334020], [7.0, 1437334080], [0.0, 1437334140], [76.0, 1437334200], [75.0, 1437334260], [7.0, 1437334320], [60.0, 1437334380], [0.0, 1437334440], [76.0, 1437334500], [76.0, 1437334560], [77.0, 1437334620], [0.0, 1437334680], [0.0, 1437334740], [0.0, 1437334800], [77.0, 1437334860], [75.0, 1437334920], [0.0, 1437334980], [60.0, 1437335040], [75.0, 1437335100], [0.0, 1437335160], [77.0, 1437335220], [77.0, 1437335280], [58.0, 1437335340], [75.0, 1437335400], [7.0, 1437335460], [77.0, 1437335520], [7.0, 1437335580], [0.0, 1437335640], [76.0, 1437335700], [77.0, 1437335760], [75.0, 1437335820], [0.0, 1437335880], [7.0, 1437335940], [0.0, 1437336000], [76.0, 1437336060], [77.0, 1437336120], [76.0, 1437336180], [61.0, 1437336240], [78.0, 1437336300], [0.0, 1437336360], [75.0, 1437336420], [77.0, 1437336480], [76.0, 1437336540], [0.0, 1437336600], [75.0, 1437336660], [78.0, 1437336720], [77.0, 1437336780], [0.0, 1437336840], [7.0, 1437336900], [0.0, 1437336960], [76.0, 1437337020], [75.0, 1437337080], [7.0, 1437337140], [59.0, 1437337200], [0.0, 1437337260], [78.0, 1437337320], [4.0, 1437337380], [0.0, 1437337440], [0.0, 1437337500], [77.0, 1437337560], [77.0, 1437337620], [7.0, 1437337680], [60.0, 1437337740], [76.0, 1437337800], [0.0, 1437337860], [75.0, 1437337920], [18.0, 1437337980], [59.0, 1437338040], [7.0, 1437338100], [7.0, 1437338160], [77.0, 1437338220], [0.0, 1437338280], [0.0, 1437338340], [19.0, 1437338400], [0.0, 1437338460], [78.0, 1437338520], [77.0, 1437338580], [7.0, 1437338640], [77.0, 1437338700], [0.0, 1437338760], [0.0, 1437338820], [0.0, 1437338880], [0.0, 1437338940], [0.0, 1437339000], [75.0, 1437339060], [77.0, 1437339120], [75.0, 1437339180], [0.0, 1437339240], [7.0, 1437339300], [0.0, 1437339360], [77.0, 1437339420], [60.0, 1437339480], [3.0, 1437339540], [0.0, 1437339600], [7.0, 1437339660], [0.0, 1437339720], [0.0, 1437339780], [77.0, 1437339840], [0.0, 1437339900], [77.0, 1437339960], [7.0, 1437340020], [57.0, 1437340080], [0.0, 1437340140], [7.0, 1437340200], [77.0, 1437340260], [0.0, 1437340320], [60.0, 1437340380], [76.0, 1437340440], [7.0, 1437340500], [0.0, 1437340560], [0.0, 1437340620], [78.0, 1437340680], [77.0, 1437340740], [0.0, 1437340800], [60.0, 1437340860], [75.0, 1437340920], [75.0, 1437340980], [76.0, 1437341040], [77.0, 1437341100], [0.0, 1437341160], [58.0, 1437341220], [0.0, 1437341280], [78.0, 1437341340], [76.0, 1437341400], [7.0, 1437341460], [61.0, 1437341520], [7.0, 1437341580], [0.0, 1437341640], [76.0, 1437341700], [75.0, 1437341760], [59.0, 1437341820], [7.0, 1437341880], [76.0, 1437341940], [76.0, 1437342000], [76.0, 1437342060], [89.0, 1437342120], [72.0, 1437342180], [78.0, 1437342240], [7.0, 1437342300], [92.0, 1437342360], [7.0, 1437342420], [21.0, 1437342480], [93.0, 1437342540], [11050.0, 1437342600], [21.0, 1437342660], [14.0, 1437342720], [14.0, 1437342780], [80.0, 1437342840], [0.0, 1437342900], [0.0, 1437342960], [77.0, 1437343020], [76.0, 1437343080], [76.0, 1437343140], [0.0, 1437343200], [61.0, 1437343260], [null, 1437343320]]}] 46 | 47 | -------------------------------------------------------------------------------- /src/graphite/server.rs: -------------------------------------------------------------------------------- 1 | use super::config::Config; 2 | use super::middleware::PathFixer; 3 | 4 | use iron::prelude::*; 5 | use persistent::State; 6 | 7 | use router::Router; 8 | 9 | use super::super::whisper::Cache; 10 | use super::handlers; 11 | use super::cache_holder::CacheHolder; 12 | 13 | pub fn run(config: Config, cache: Cache) { 14 | let mut router = Router::new(); 15 | router.get("/metrics/find", handlers::metrics_find); 16 | router.post("/render", handlers::render); 17 | 18 | let mut chain = Chain::new(router); 19 | chain.link_before(PathFixer); 20 | chain.link( State::::both(cache) ); 21 | 22 | Iron::new(chain).http(config.bind_spec).unwrap(); 23 | } 24 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! 2 | 3 | # graphite-rust 4 | 5 | Herein lies a humble reimplementation of the graphite metrics system -- a time series database system, 6 | with HTTP frontend and management tools. 7 | It strikes a reasonable balance between features you need, easy management, and a rich ecosystem of tools which can talk to graphite. 8 | 9 | `graphite-rust` aims to maintain total compatibility in both features and file formats. 10 | The big selling point should be the ease of installation: it's just one 11 | binary. It may be higher performance but that's not the main goal. 12 | 13 | This work falls under the name `graphite` but in reality the package has distinct components you may want to understand: 14 | 15 | * [`whisper`](whisper/index.html) - all the heavy lifting for parsing and writing to whisper database files 16 | * `carbon` - the network daemon which mediates access to whisper files 17 | * `graphite` - the HTTP REST server which handles queries. It has a minimal HTML 18 | application for creating dashboard but I'll be skipping that. For dashboard you'll want [`grafana`](http://grafana.org/). 19 | 20 | Status of the codes: 21 | 22 | * `whisper` 23 | * *DOES* open and parse header/metadata/archive info 24 | * *IN PROGRESS* take a metric value and provide a WriteOp 25 | * *NOT STARTED* write `vec![WriteOp]` to file 26 | * `carbon` 27 | * *DOESN'T DO ANYTHING* 28 | * `graphite` 29 | * *DOESN'T EXIST* 30 | 31 | ## Also, this is brand-new code. In the true rust spirit it does not guarantee the safety of your kittens. 32 | 33 | */ 34 | 35 | #![crate_name = "graphite"] 36 | #![feature(trace_macros)] 37 | 38 | #![feature(test)] 39 | extern crate test; 40 | 41 | extern crate time; 42 | extern crate byteorder; 43 | 44 | #[macro_use] 45 | extern crate log; 46 | extern crate env_logger; 47 | 48 | extern crate regex; 49 | 50 | extern crate whisper; 51 | 52 | pub mod carbon; 53 | // TODO: scuttled until I want to fix all the iron related issues 54 | // pub mod graphite; 55 | -------------------------------------------------------------------------------- /test/scripts/tcp_multipoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | set -xe 3 | 4 | BODY=$( cat <