├── src ├── .gitignore ├── mygnuplot.bat ├── tsd │ ├── static │ │ └── favicon.ico │ ├── QueryUi.gwt.xml │ ├── client │ │ ├── GotJsonCallback.java │ │ ├── ValidatedTextBox.java │ │ ├── QueryString.java │ │ └── EventsHandler.java │ ├── HttpRpc.java │ ├── GnuplotException.java │ ├── TelnetRpc.java │ ├── WordSplitter.java │ ├── StaticFileRpc.java │ ├── RpcPlugin.java │ ├── LineBasedFrameDecoder.java │ ├── SuggestRpc.java │ ├── ConnectionManager.java │ └── LogsRpc.java ├── mygnuplot.sh ├── logback.xml ├── upgrade_1to2.sh ├── core │ ├── IllegalDataException.java │ ├── DataPoint.java │ ├── Aggregator.java │ ├── SeekableView.java │ ├── RowKey.java │ ├── Const.java │ ├── ByteBufferList.java │ ├── MutableDataPoint.java │ ├── DataPointsIterator.java │ ├── RateOptions.java │ └── IncomingDataPoint.java ├── create_table.sh ├── utils │ ├── JSONException.java │ ├── FileSystem.java │ ├── ByteArrayPair.java │ └── Pair.java ├── uid │ ├── NoSuchUniqueId.java │ ├── NoSuchUniqueName.java │ └── UniqueIdInterface.java └── opentsdb.conf ├── test ├── META-INF │ ├── MANIFEST.MF │ └── services │ │ ├── net.opentsdb.tsd.RpcPlugin │ │ ├── net.opentsdb.search.SearchPlugin │ │ ├── net.opentsdb.tsd.RTPublisher │ │ ├── net.opentsdb.tsd.HttpSerializer │ │ └── net.opentsdb.plugin.DummyPlugin ├── plugin │ ├── DummyPlugin.java │ ├── DummyPluginA.java │ └── DummyPluginB.java ├── uid │ └── TestNoSuchUniqueId.java ├── tsd │ ├── DummyHttpSerializer.java │ ├── DummyRpcPlugin.java │ ├── DummyRTPublisher.java │ ├── TestRpcPlugin.java │ └── TestRTPublisher.java ├── utils │ ├── TestFileSystem.java │ └── TestPluginLoader.java ├── search │ ├── TestSearchQuery.java │ └── DummySearchPlugin.java ├── core │ ├── TestMutableDataPoint.java │ ├── TestTSQuery.java │ ├── TestAggregators.java │ └── TestTSSubQuery.java └── graph │ └── TestPlot.java ├── third_party ├── guava │ ├── guava-17.0.jar.md5 │ ├── guava-18.0.jar.md5 │ └── include.mk ├── junit │ ├── junit-4.10.jar.md5 │ ├── junit-4.11.jar.md5 │ └── include.mk ├── gwt │ ├── gwt-dev-2.5.0.jar.md5 │ ├── gwt-dev-2.6.0.jar.md5 │ ├── gwt-user-2.5.0.jar.md5 │ ├── gwt-user-2.6.0.jar.md5 │ └── include.mk ├── mockito │ ├── mockito-1.9.0.jar.md5 │ ├── mockito-core-1.9.5.jar.md5 │ └── include.mk ├── slf4j │ ├── slf4j-api-1.7.2.jar.md5 │ ├── slf4j-api-1.7.7.jar.md5 │ ├── log4j-over-slf4j-1.7.2.jar.md5 │ ├── log4j-over-slf4j-1.7.7.jar.md5 │ └── include.mk ├── suasync │ ├── async-1.4.0.jar.md5 │ └── include.mk ├── hamcrest │ ├── hamcrest-core-1.3.jar.md5 │ └── include.mk ├── hbase │ ├── asynchbase-1.5.0.jar.md5 │ ├── asynchbase-1.6.0.jar.md5 │ └── include.mk ├── jackson │ ├── jackson-core-2.1.5.jar.md5 │ ├── jackson-core-2.4.3.jar.md5 │ ├── jackson-databind-2.1.5.jar.md5 │ ├── jackson-databind-2.4.3.jar.md5 │ ├── jackson-annotations-2.1.5.jar.md5 │ ├── jackson-annotations-2.4.3.jar.md5 │ └── include.mk ├── logback │ ├── logback-core-1.0.9.jar.md5 │ ├── logback-classic-1.0.13.jar.md5 │ ├── logback-classic-1.0.9.jar.md5 │ ├── logback-core-1.0.13.jar.md5 │ └── include.mk ├── netty │ ├── netty-3.9.1.Final.jar.md5 │ ├── netty-3.9.4.Final.jar.md5 │ └── include.mk ├── objenesis │ ├── objenesis-1.3.jar.md5 │ ├── objenesis-2.1.jar.md5 │ └── include.mk ├── zookeeper │ ├── zookeeper-3.3.4.jar.md5 │ ├── zookeeper-3.3.6.jar.md5 │ └── include.mk ├── javassist │ ├── javassist-3.17.1-GA.jar.md5 │ ├── javassist-3.18.1-GA.jar.md5 │ └── include.mk ├── powermock │ ├── powermock-mockito-1.5.jar.md5 │ ├── powermock-mockito-release-full-1.5.4-full.jar.md5 │ └── include.mk ├── protobuf │ ├── protobuf-java-2.5.0.jar.md5 │ └── include.mk ├── validation-api │ ├── validation-api-1.0.0.GA.jar.md5 │ ├── validation-api-1.0.0.GA-sources.jar.md5 │ └── include.mk └── include.mk ├── .dir-locals.el ├── .travis.yml ├── tools ├── clean_cache.sh ├── opentsdb_restart.py └── tsddrain.py ├── .gitignore ├── bootstrap ├── AUTHORS ├── README ├── configure.ac ├── THANKS ├── opentsdb.spec.in └── tsdb.in /src/.gitignore: -------------------------------------------------------------------------------- 1 | BuildData.java 2 | -------------------------------------------------------------------------------- /test/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | 3 | -------------------------------------------------------------------------------- /third_party/guava/guava-17.0.jar.md5: -------------------------------------------------------------------------------- 1 | 89fef81c2adfa9b50a64ed5cd5d8c155 2 | -------------------------------------------------------------------------------- /third_party/guava/guava-18.0.jar.md5: -------------------------------------------------------------------------------- 1 | 947641f6bb535b1d942d1bc387c45290 2 | -------------------------------------------------------------------------------- /third_party/junit/junit-4.10.jar.md5: -------------------------------------------------------------------------------- 1 | 972c3b8fb2cc26008cbceb01ff889ec4 2 | -------------------------------------------------------------------------------- /third_party/junit/junit-4.11.jar.md5: -------------------------------------------------------------------------------- 1 | 3c42be5ea7cbf3635716abbb429cb90d 2 | -------------------------------------------------------------------------------- /third_party/gwt/gwt-dev-2.5.0.jar.md5: -------------------------------------------------------------------------------- 1 | 538df8db77bacc863f34b82c59d5632d 2 | -------------------------------------------------------------------------------- /third_party/gwt/gwt-dev-2.6.0.jar.md5: -------------------------------------------------------------------------------- 1 | 23d8bf52709230c2c7e6dd817261f9ee 2 | -------------------------------------------------------------------------------- /third_party/gwt/gwt-user-2.5.0.jar.md5: -------------------------------------------------------------------------------- 1 | c58e29c1132ee6694e8f780e045f4d13 2 | -------------------------------------------------------------------------------- /third_party/gwt/gwt-user-2.6.0.jar.md5: -------------------------------------------------------------------------------- 1 | 99226fc2764f2b8fd6db6e05d0847659 2 | -------------------------------------------------------------------------------- /third_party/mockito/mockito-1.9.0.jar.md5: -------------------------------------------------------------------------------- 1 | cab21b44958a173a5b1d55a6aff0ab54 2 | -------------------------------------------------------------------------------- /third_party/slf4j/slf4j-api-1.7.2.jar.md5: -------------------------------------------------------------------------------- 1 | ebf348e2831a3b610860fa134ad6f67f 2 | -------------------------------------------------------------------------------- /third_party/slf4j/slf4j-api-1.7.7.jar.md5: -------------------------------------------------------------------------------- 1 | ca4280bf93d64367723ae5c8d42dd0b9 2 | -------------------------------------------------------------------------------- /third_party/suasync/async-1.4.0.jar.md5: -------------------------------------------------------------------------------- 1 | 90aa9cc566423f12af88e205804d5161 2 | -------------------------------------------------------------------------------- /test/META-INF/services/net.opentsdb.tsd.RpcPlugin: -------------------------------------------------------------------------------- 1 | net.opentsdb.tsd.DummyRpcPlugin -------------------------------------------------------------------------------- /third_party/hamcrest/hamcrest-core-1.3.jar.md5: -------------------------------------------------------------------------------- 1 | 6393363b47ddcbba82321110c3e07519 2 | -------------------------------------------------------------------------------- /third_party/hbase/asynchbase-1.5.0.jar.md5: -------------------------------------------------------------------------------- 1 | 12c61569f04eb88229c90dde9fa51848 2 | -------------------------------------------------------------------------------- /third_party/hbase/asynchbase-1.6.0.jar.md5: -------------------------------------------------------------------------------- 1 | 6738dd73fd48d30cbf5c78f62bc18852 2 | -------------------------------------------------------------------------------- /third_party/jackson/jackson-core-2.1.5.jar.md5: -------------------------------------------------------------------------------- 1 | 25f14871629c6ed2408438f8285ad26d 2 | -------------------------------------------------------------------------------- /third_party/jackson/jackson-core-2.4.3.jar.md5: -------------------------------------------------------------------------------- 1 | 750ef3d86f04fe0d6d14d6ae904a6d2d 2 | -------------------------------------------------------------------------------- /third_party/logback/logback-core-1.0.9.jar.md5: -------------------------------------------------------------------------------- 1 | d1647b6efc66bd38237e4d8c484aa7b4 2 | -------------------------------------------------------------------------------- /third_party/mockito/mockito-core-1.9.5.jar.md5: -------------------------------------------------------------------------------- 1 | 6f73cf04a56eb60aaa996506e7c10fc7 2 | -------------------------------------------------------------------------------- /third_party/netty/netty-3.9.1.Final.jar.md5: -------------------------------------------------------------------------------- 1 | c1a35f5f1dbc6d8f693b836a66070d45 2 | -------------------------------------------------------------------------------- /third_party/netty/netty-3.9.4.Final.jar.md5: -------------------------------------------------------------------------------- 1 | b3701ef46c7518d0d63705e2f092dbe5 2 | -------------------------------------------------------------------------------- /third_party/objenesis/objenesis-1.3.jar.md5: -------------------------------------------------------------------------------- 1 | 2d649907bd6203f2661f70d430a6ade8 2 | -------------------------------------------------------------------------------- /third_party/objenesis/objenesis-2.1.jar.md5: -------------------------------------------------------------------------------- 1 | 32ccb1d20a42b5aaaceb90c9082a2efa 2 | -------------------------------------------------------------------------------- /third_party/zookeeper/zookeeper-3.3.4.jar.md5: -------------------------------------------------------------------------------- 1 | f922a4d30df717ca3fcab8198c53d659 2 | -------------------------------------------------------------------------------- /third_party/zookeeper/zookeeper-3.3.6.jar.md5: -------------------------------------------------------------------------------- 1 | a4425412297adf88c157a263d61e2cf1 2 | -------------------------------------------------------------------------------- /third_party/jackson/jackson-databind-2.1.5.jar.md5: -------------------------------------------------------------------------------- 1 | 18603628104fa90698bfd713ffc03beb 2 | -------------------------------------------------------------------------------- /third_party/jackson/jackson-databind-2.4.3.jar.md5: -------------------------------------------------------------------------------- 1 | 4fcb9f74280eaa21de10191212c65b11 2 | -------------------------------------------------------------------------------- /third_party/javassist/javassist-3.17.1-GA.jar.md5: -------------------------------------------------------------------------------- 1 | d6a8586b96f0a0fb5f6100371759fa17 2 | -------------------------------------------------------------------------------- /third_party/javassist/javassist-3.18.1-GA.jar.md5: -------------------------------------------------------------------------------- 1 | 5bb83868c87334320562af7eded65cc2 2 | -------------------------------------------------------------------------------- /third_party/logback/logback-classic-1.0.13.jar.md5: -------------------------------------------------------------------------------- 1 | 18586a078b51918942002ec085338e19 2 | -------------------------------------------------------------------------------- /third_party/logback/logback-classic-1.0.9.jar.md5: -------------------------------------------------------------------------------- 1 | ca99e6b10e9b2f46f264afc5cf1c13e1 2 | -------------------------------------------------------------------------------- /third_party/logback/logback-core-1.0.13.jar.md5: -------------------------------------------------------------------------------- 1 | 945c6dc3c10d3ce784d456a8bbbd0262 2 | -------------------------------------------------------------------------------- /third_party/powermock/powermock-mockito-1.5.jar.md5: -------------------------------------------------------------------------------- 1 | da9e7012d0e13f90c71829f2ac7d5462 2 | -------------------------------------------------------------------------------- /third_party/protobuf/protobuf-java-2.5.0.jar.md5: -------------------------------------------------------------------------------- 1 | a44473b98947e2a54c54e0db1387d137 2 | -------------------------------------------------------------------------------- /third_party/slf4j/log4j-over-slf4j-1.7.2.jar.md5: -------------------------------------------------------------------------------- 1 | cbd407d8ff67a6d54fd233fc0e0d8228 2 | -------------------------------------------------------------------------------- /third_party/slf4j/log4j-over-slf4j-1.7.7.jar.md5: -------------------------------------------------------------------------------- 1 | 93ab42a5216afd683c35988c6b6fc3d8 2 | -------------------------------------------------------------------------------- /test/META-INF/services/net.opentsdb.search.SearchPlugin: -------------------------------------------------------------------------------- 1 | net.opentsdb.search.DummySearchPlugin -------------------------------------------------------------------------------- /test/META-INF/services/net.opentsdb.tsd.RTPublisher: -------------------------------------------------------------------------------- 1 | net.opentsdb.tsd.DummyRTPublisher 2 | -------------------------------------------------------------------------------- /third_party/jackson/jackson-annotations-2.1.5.jar.md5: -------------------------------------------------------------------------------- 1 | bfe728a2d5f507e143ec41702a3dfc52 2 | -------------------------------------------------------------------------------- /third_party/jackson/jackson-annotations-2.4.3.jar.md5: -------------------------------------------------------------------------------- 1 | 31ef4fa866f9d24960a6807c9c299e98 2 | -------------------------------------------------------------------------------- /src/mygnuplot.bat: -------------------------------------------------------------------------------- 1 | set -e 2 | stdout=$1 3 | shift 4 | stderr=$1 5 | shift 6 | gnuplot %1 2>&1 7 | -------------------------------------------------------------------------------- /test/META-INF/services/net.opentsdb.tsd.HttpSerializer: -------------------------------------------------------------------------------- 1 | net.opentsdb.tsd.DummyHttpSerializer 2 | -------------------------------------------------------------------------------- /third_party/validation-api/validation-api-1.0.0.GA.jar.md5: -------------------------------------------------------------------------------- 1 | 40c1ee909493066397a6d4d9f8d375d8 2 | -------------------------------------------------------------------------------- /src/tsd/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/b/opentsdb/master/src/tsd/static/favicon.ico -------------------------------------------------------------------------------- /third_party/validation-api/validation-api-1.0.0.GA-sources.jar.md5: -------------------------------------------------------------------------------- 1 | f816682933b59c5ffe32bdb4ab4bf628 2 | -------------------------------------------------------------------------------- /third_party/powermock/powermock-mockito-release-full-1.5.4-full.jar.md5: -------------------------------------------------------------------------------- 1 | 5dee1dce6952bb7338d4d053157ae647 2 | -------------------------------------------------------------------------------- /test/META-INF/services/net.opentsdb.plugin.DummyPlugin: -------------------------------------------------------------------------------- 1 | net.opentsdb.plugin.DummyPluginA 2 | net.opentsdb.plugin.DummyPluginB -------------------------------------------------------------------------------- /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ;;; Directory Local Variables 2 | ;;; See Info node `(emacs) Directory Variables' for more information. 3 | 4 | ((java-mode 5 | (c-basic-offset . 2) 6 | (indent-tabs-mode . nil))) 7 | )) 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | before_script: ./build.sh pom.xml 3 | script: export MAVEN_OPTS="-Xmx1024m" && mvn test --quiet 4 | jdk: 5 | - oraclejdk7 6 | - openjdk6 7 | notifications: 8 | email: false 9 | -------------------------------------------------------------------------------- /src/mygnuplot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Because !@#$%^ Java can't fucking do this without a bazillion lines of codes. 3 | set -e 4 | stdout=$1 5 | shift 6 | stderr=$1 7 | shift 8 | exec nice gnuplot "$@" >"$stdout" 2>"$stderr" 9 | -------------------------------------------------------------------------------- /tools/clean_cache.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CACHE_DIR=/tmp/tsd 4 | 5 | diskSpaceIsShort() { 6 | df -h "$CACHE_DIR" \ 7 | | awk 'NR==2{pct=$5; sub(/%/, "", pct); if (pct < 90) exit 1; exit 0;}' 8 | } 9 | 10 | if diskSpaceIsShort; then 11 | rm -rf "$CACHE_DIR"/* 12 | fi 13 | -------------------------------------------------------------------------------- /src/tsd/QueryUi.gwt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | INSTALL 2 | Makefile 3 | Makefile.in 4 | aclocal.m4 5 | autom4te.cache 6 | build 7 | target 8 | config.log 9 | config.status 10 | configure 11 | pom.xml 12 | *.pyc 13 | .*.swp 14 | *.rrd 15 | *.class 16 | */target/* 17 | *.orig 18 | *.log 19 | 20 | #for Intellij 21 | \.idea 22 | *.iml 23 | 24 | #for guava rpm maker 25 | guava-rpm-maker/\.project 26 | 27 | # for mac finder 28 | .DS_Store 29 | 30 | # for eclipse 31 | .pydevproject 32 | .metadata 33 | .project 34 | .classpath 35 | .settings 36 | 37 | # maven 38 | src-main 39 | src-test 40 | plugin_test.jar 41 | -------------------------------------------------------------------------------- /src/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %d{ISO8601} %-5level [%thread] %logger{0}: %msg%n 8 | 9 | 10 | 11 | 12 | 1024 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (C) 2011-2012 The OpenTSDB Authors. 3 | # 4 | # This library is free software: you can redistribute it and/or modify it 5 | # under the terms of the GNU Lesser General Public License as published 6 | # by the Free Software Foundation, either version 2.1 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This library is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU Lesser General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU Lesser General Public License 15 | # along with this library. If not, see . 16 | 17 | exec autoreconf -fvi 18 | -------------------------------------------------------------------------------- /tools/opentsdb_restart.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """Restart opentsdb. Called using -XX:OnOutOfMemoryError= 3 | 4 | Because it's calling the 'service opentsdb' command, should be run as root. 5 | 6 | This is known to work with python2.6 and above. 7 | """ 8 | import os 9 | import subprocess 10 | 11 | 12 | subprocess.call(["service", "opentsdb", "stop"]) 13 | # Close any file handles we inherited from our parent JVM. We need 14 | # to do this before restarting so that the socket isn't held open. 15 | openfiles = [int(f) for f in os.listdir("/proc/self/fd")] 16 | # Don't need to close stdout/stderr/stdin, leave them open so 17 | # that there is less chance of errors with those standard streams. 18 | # Other files start at fd 3. 19 | os.closerange(3, max(openfiles)) 20 | subprocess.call(["service", "opentsdb", "start"]) 21 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | The OpenTSDB Authors 2 | -------------------- 3 | 4 | OpenTSDB was originally written by Benoit Sigoure. 5 | 6 | The following organizations and people have made significant code 7 | contributions to OpenTSDB. Note that all contributors are required 8 | to sign a standard Contribution License Agreement to ensure that the 9 | code remains free & open-source. 10 | (Please keep both lists sorted alphabetically.) 11 | 12 | 13 | Arista Networks, Inc. 14 | Betfair Group plc 15 | Box, Inc. 16 | Bump Technologies, Inc. 17 | Limelight Networks, Inc. 18 | StumbleUpon, Inc. 19 | Yahoo, Inc. 20 | 21 | 22 | Benoit Sigoure 23 | Chris Larsen 24 | David Bainbridge 25 | Geoffrey Anderson 26 | Ion Savin 27 | Nicholas Whitehead 28 | Will Moss 29 | -------------------------------------------------------------------------------- /src/tsd/client/GotJsonCallback.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package tsd.client; 14 | 15 | import com.google.gwt.json.client.JSONValue; 16 | 17 | interface GotJsonCallback { 18 | 19 | void got(JSONValue json); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /third_party/junit/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2012 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | JUNIT_VERSION := 4.11 17 | JUNIT := third_party/junit/junit-$(JUNIT_VERSION).jar 18 | JUNIT_BASE_URL := http://central.maven.org/maven2/junit/junit/$(JUNIT_VERSION) 19 | 20 | $(JUNIT): $(JUNIT).md5 21 | set dummy "$(JUNIT_BASE_URL)" "$(JUNIT)"; shift; $(FETCH_DEPENDENCY) 22 | 23 | THIRD_PARTY += $(JUNIT) 24 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ___ _____ ____ ____ ____ 2 | / _ \ _ __ ___ _ _|_ _/ ___|| _ \| __ ) 3 | | | | | '_ \ / _ \ '_ \| | \___ \| | | | _ \ 4 | | |_| | |_) | __/ | | | | ___) | |_| | |_) | 5 | \___/| .__/ \___|_| |_|_| |____/|____/|____/ 6 | |_| The modern time series database. 7 | 8 | OpenTSDB is a distributed, scalable Time Series Database (TSDB) written on 9 | top of HBase. OpenTSDB was written to address a common need: store, index 10 | and serve metrics collected from computer systems (network gear, operating 11 | systems, applications) at a large scale, and make this data easily accessible 12 | and graphable. 13 | 14 | Thanks to HBase's scalability, OpenTSDB allows you to collect thousands of 15 | metrics from tens of thousands of hosts and applications, at a high rate 16 | (every few seconds). OpenTSDB will never delete or downsample data and can 17 | easily store hundreds of billions of data points. 18 | 19 | OpenTSDB is free software and is available under both LGPLv2.1+ and GPLv3+. 20 | Find more about OpenTSDB at http://opentsdb.net 21 | -------------------------------------------------------------------------------- /third_party/suasync/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | SUASYNC_VERSION := 1.4.0 17 | SUASYNC := third_party/suasync/async-$(SUASYNC_VERSION).jar 18 | SUASYNC_BASE_URL := http://central.maven.org/maven2/com/stumbleupon/async/$(SUASYNC_VERSION) 19 | 20 | $(SUASYNC): $(SUASYNC).md5 21 | set dummy "$(SUASYNC_BASE_URL)" "$(SUASYNC)"; shift; $(FETCH_DEPENDENCY) 22 | 23 | THIRD_PARTY += $(SUASYNC) 24 | -------------------------------------------------------------------------------- /third_party/mockito/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | MOCKITO_VERSION := 1.9.5 17 | MOCKITO := third_party/mockito/mockito-core-$(MOCKITO_VERSION).jar 18 | MOCKITO_BASE_URL := http://central.maven.org/maven2/org/mockito/mockito-core/$(MOCKITO_VERSION) 19 | 20 | $(MOCKITO): $(MOCKITO).md5 21 | set dummy "$(MOCKITO_BASE_URL)" "$(MOCKITO)"; shift; $(FETCH_DEPENDENCY) 22 | 23 | THIRD_PARTY += $(MOCKITO) 24 | -------------------------------------------------------------------------------- /third_party/hamcrest/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | HAMCREST_VERSION := 1.3 17 | HAMCREST := third_party/hamcrest/hamcrest-core-$(HAMCREST_VERSION).jar 18 | HAMCREST_BASE_URL := http://central.maven.org/maven2/org/hamcrest/hamcrest-core/$(HAMCREST_VERSION) 19 | 20 | $(HAMCREST): $(HAMCREST).md5 21 | set dummy "$(HAMCREST_BASE_URL)" "$(HAMCREST)"; shift; $(FETCH_DEPENDENCY) 22 | 23 | THIRD_PARTY += $(HAMCREST) 24 | -------------------------------------------------------------------------------- /third_party/objenesis/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | OBJENESIS_VERSION := 1.3 17 | OBJENESIS := third_party/objenesis/objenesis-$(OBJENESIS_VERSION).jar 18 | OBJENESIS_BASE_URL := http://central.maven.org/maven2/org/objenesis/objenesis/$(OBJENESIS_VERSION) 19 | 20 | $(OBJENESIS): $(OBJENESIS).md5 21 | set dummy "$(OBJENESIS_BASE_URL)" "$(OBJENESIS)"; shift; $(FETCH_DEPENDENCY) 22 | 23 | THIRD_PARTY += $(OBJENESIS) 24 | -------------------------------------------------------------------------------- /third_party/protobuf/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2014 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | PROTOBUF_VERSION := 2.5.0 17 | PROTOBUF := third_party/protobuf/protobuf-java-$(PROTOBUF_VERSION).jar 18 | PROTOBUF_BASE_URL := http://central.maven.org/maven2/com/google/protobuf/protobuf-java/$(PROTOBUF_VERSION) 19 | 20 | $(PROTOBUF): $(PROTOBUF).md5 21 | set dummy "$(PROTOBUF_BASE_URL)" "$(PROTOBUF)"; shift; $(FETCH_DEPENDENCY) 22 | 23 | THIRD_PARTY += $(PROTOBUF) 24 | -------------------------------------------------------------------------------- /third_party/zookeeper/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | ZOOKEEPER_VERSION := 3.3.6 17 | ZOOKEEPER := third_party/zookeeper/zookeeper-$(ZOOKEEPER_VERSION).jar 18 | ZOOKEEPER_BASE_URL := http://central.maven.org/maven2/org/apache/zookeeper/zookeeper/$(ZOOKEEPER_VERSION) 19 | 20 | $(ZOOKEEPER): $(ZOOKEEPER).md5 21 | set dummy "$(ZOOKEEPER_BASE_URL)" "$(ZOOKEEPER)"; shift; $(FETCH_DEPENDENCY) 22 | 23 | THIRD_PARTY += $(ZOOKEEPER) 24 | -------------------------------------------------------------------------------- /test/plugin/DummyPlugin.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013-2014 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.plugin; 14 | 15 | import org.junit.Ignore; 16 | 17 | // need to ignore this class so JUnit doesn't try to run tests on it 18 | @Ignore 19 | public abstract class DummyPlugin { 20 | public String myname; 21 | 22 | public DummyPlugin() { 23 | myname = ""; 24 | } 25 | 26 | public abstract String mustImplement(); 27 | } 28 | -------------------------------------------------------------------------------- /third_party/hbase/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2014 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | ASYNCHBASE_VERSION := 1.6.0 17 | ASYNCHBASE := third_party/hbase/asynchbase-$(ASYNCHBASE_VERSION).jar 18 | ASYNCHBASE_BASE_URL := http://central.maven.org/maven2/org/hbase/asynchbase/$(ASYNCHBASE_VERSION) 19 | 20 | $(ASYNCHBASE): $(ASYNCHBASE).md5 21 | set dummy "$(ASYNCHBASE_BASE_URL)" "$(ASYNCHBASE)"; shift; $(FETCH_DEPENDENCY) 22 | 23 | THIRD_PARTY += $(ASYNCHBASE) 24 | -------------------------------------------------------------------------------- /test/plugin/DummyPluginA.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013-2014 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.plugin; 14 | 15 | import org.junit.Ignore; 16 | 17 | // need to ignore this class so JUnit doesn't try to run tests on it 18 | @Ignore 19 | public class DummyPluginA extends DummyPlugin { 20 | 21 | public DummyPluginA() { 22 | this.myname = "Dummy Plugin A"; 23 | } 24 | 25 | public String mustImplement() { 26 | return this.myname; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/plugin/DummyPluginB.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013-2014 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.plugin; 14 | 15 | import org.junit.Ignore; 16 | 17 | // need to ignore this class so JUnit doesn't try to run tests on it 18 | @Ignore 19 | public class DummyPluginB extends DummyPlugin { 20 | 21 | public DummyPluginB() { 22 | this.myname = "Dummy Plugin B"; 23 | } 24 | 25 | public String mustImplement() { 26 | return this.myname; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/tsd/HttpRpc.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import java.io.IOException; 16 | 17 | import net.opentsdb.core.TSDB; 18 | 19 | /** Base interface for all HTTP query handlers. */ 20 | interface HttpRpc { 21 | 22 | /** 23 | * Executes this RPC. 24 | * @param tsdb The TSDB to use. 25 | * @param query The HTTP query to execute. 26 | */ 27 | void execute(TSDB tsdb, HttpQuery query) throws IOException; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/tsd/GnuplotException.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | /** 16 | * Exception thrown when Gnuplot fails. 17 | */ 18 | final class GnuplotException extends RuntimeException { 19 | 20 | public GnuplotException(final int gnuplot_return_value) { 21 | super("Gnuplot returned " + gnuplot_return_value); 22 | } 23 | 24 | public GnuplotException(final String gnuplot_stderr) { 25 | super("Gnuplot stderr:\n" + gnuplot_stderr); 26 | } 27 | 28 | static final long serialVersionUID = 1287770642; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/tsd/TelnetRpc.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import com.stumbleupon.async.Deferred; 16 | 17 | import org.jboss.netty.channel.Channel; 18 | 19 | import net.opentsdb.core.TSDB; 20 | 21 | /** Base interface for all telnet-style RPC handlers. */ 22 | interface TelnetRpc { 23 | 24 | /** 25 | * Executes this RPC. 26 | * @param tsdb The TSDB to use. 27 | * @param chan The channel on which the RPC was received. 28 | * @param command The command received, split. 29 | * @return A deferred result. 30 | */ 31 | Deferred execute(TSDB tsdb, Channel chan, String[] command); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/upgrade_1to2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Small script to setup the HBase tables used by OpenTSDB. 3 | 4 | test -n "$HBASE_HOME" || { 5 | echo >&2 'The environment variable HBASE_HOME must be set' 6 | exit 1 7 | } 8 | test -d "$HBASE_HOME" || { 9 | echo >&2 "No such directory: HBASE_HOME=$HBASE_HOME" 10 | exit 1 11 | } 12 | 13 | TREE_TABLE=${TREE_TABLE-'tsdb-tree'} 14 | META_TABLE=${META_TABLE-'tsdb-meta'} 15 | BLOOMFILTER=${BLOOMFILTER-'ROW'} 16 | # LZO requires lzo2 64bit to be installed + the hadoop-gpl-compression jar. 17 | COMPRESSION=${COMPRESSION-'LZO'} 18 | # All compression codec names are upper case (NONE, LZO, SNAPPY, etc). 19 | COMPRESSION=`echo "$COMPRESSION" | tr a-z A-Z` 20 | 21 | case $COMPRESSION in 22 | (NONE|LZO|GZIP|SNAPPY) :;; # Known good. 23 | (*) 24 | echo >&2 "warning: compression codec '$COMPRESSION' might not be supported." 25 | ;; 26 | esac 27 | 28 | # HBase scripts also use a variable named `HBASE_HOME', and having this 29 | # variable in the environment with a value somewhat different from what 30 | # they expect can confuse them in some cases. So rename the variable. 31 | hbh=$HBASE_HOME 32 | unset HBASE_HOME 33 | exec "$hbh/bin/hbase" shell < 't', VERSIONS => 1, COMPRESSION => '$COMPRESSION', BLOOMFILTER => '$BLOOMFILTER'} 36 | 37 | create '$META_TABLE', 38 | {NAME => 'name', COMPRESSION => '$COMPRESSION', BLOOMFILTER => '$BLOOMFILTER'} 39 | EOF 40 | -------------------------------------------------------------------------------- /test/uid/TestNoSuchUniqueId.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.uid; 14 | 15 | import junit.framework.TestCase; 16 | 17 | public final class TestNoSuchUniqueId extends TestCase { 18 | 19 | public void testMessage() { 20 | final byte[] id = { 0, 'A', 'a' }; 21 | final NoSuchUniqueId e = new NoSuchUniqueId("Foo", id); 22 | assertEquals("No such unique ID for 'Foo': [0, 65, 97]", e.getMessage()); 23 | } 24 | 25 | public void testFields() { 26 | final String kind = "bar"; 27 | final byte[] id = { 42, '!' }; 28 | final NoSuchUniqueId e = new NoSuchUniqueId(kind, id); 29 | assertEquals(kind, e.kind()); 30 | assertEquals(id, e.id()); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /third_party/gwt/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2012 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | GWT_VERSION := 2.6.0 17 | 18 | GWT_DEV_VERSION := $(GWT_VERSION) 19 | GWT_DEV := third_party/gwt/gwt-dev-$(GWT_DEV_VERSION).jar 20 | GWT_DEV_BASE_URL := http://central.maven.org/maven2/com/google/gwt/gwt-dev/$(GWT_DEV_VERSION) 21 | 22 | $(GWT_DEV): $(GWT_DEV).md5 23 | set dummy "$(GWT_DEV_BASE_URL)" "$(GWT_DEV)"; shift; $(FETCH_DEPENDENCY) 24 | 25 | 26 | GWT_USER_VERSION := $(GWT_VERSION) 27 | GWT_USER := third_party/gwt/gwt-user-$(GWT_USER_VERSION).jar 28 | GWT_USER_BASE_URL := http://central.maven.org/maven2/com/google/gwt/gwt-user/$(GWT_USER_VERSION) 29 | 30 | $(GWT_USER): $(GWT_USER).md5 31 | set dummy "$(GWT_USER_BASE_URL)" "$(GWT_USER)"; shift; $(FETCH_DEPENDENCY) 32 | 33 | THIRD_PARTY += $(GWT_DEV) $(GWT_USER) 34 | -------------------------------------------------------------------------------- /src/core/IllegalDataException.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2011-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | /** 16 | * Some illegal / malformed / corrupted data has been found in HBase. 17 | */ 18 | public final class IllegalDataException extends IllegalStateException { 19 | 20 | /** 21 | * Constructor. 22 | * 23 | * @param msg Message describing the problem. 24 | */ 25 | public IllegalDataException(final String msg) { 26 | super(msg); 27 | } 28 | 29 | /** 30 | * Constructor. 31 | * 32 | * @param msg Message describing the problem. 33 | */ 34 | public IllegalDataException(final String msg, final Throwable cause) { 35 | super(msg, cause); 36 | } 37 | 38 | static final long serialVersionUID = 1307719142; 39 | 40 | } 41 | -------------------------------------------------------------------------------- /third_party/validation-api/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | VALIDATION_API_VERSION := 1.0.0.GA 17 | VALIDATION_API := third_party/validation-api/validation-api-$(VALIDATION_API_VERSION).jar 18 | VALIDATION_API_BASE_URL := http://central.maven.org/maven2/javax/validation/validation-api/$(VALIDATION_API_VERSION) 19 | 20 | $(VALIDATION_API): $(VALIDATION_API).md5 21 | set dummy "$(VALIDATION_API_BASE_URL)" "$(VALIDATION_API)"; shift; $(FETCH_DEPENDENCY) 22 | 23 | 24 | VALIDATION_API_SOURCES := third_party/validation-api/validation-api-$(VALIDATION_API_VERSION)-sources.jar 25 | VALIDATION_API_SOURCES_BASE_URL := $(VALIDATION_API_BASE_URL) 26 | 27 | $(VALIDATION_API_SOURCES): $(VALIDATION_API_SOURCES).md5 28 | set dummy "$(VALIDATION_API_SOURCES_BASE_URL)" "$(VALIDATION_API_SOURCES)"; shift; $(FETCH_DEPENDENCY) 29 | 30 | THIRD_PARTY += $(VALIDATION_API) $(VALIDATION_API_SOURCES) 31 | -------------------------------------------------------------------------------- /third_party/slf4j/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2013 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | SLF4J_VERSION = 1.7.7 17 | 18 | 19 | LOG4J_OVER_SLF4J_VERSION := $(SLF4J_VERSION) 20 | LOG4J_OVER_SLF4J := third_party/slf4j/log4j-over-slf4j-$(LOG4J_OVER_SLF4J_VERSION).jar 21 | LOG4J_OVER_SLF4J_BASE_URL := http://central.maven.org/maven2/org/slf4j/log4j-over-slf4j/$(LOG4J_OVER_SLF4J_VERSION) 22 | 23 | $(LOG4J_OVER_SLF4J): $(LOG4J_OVER_SLF4J).md5 24 | set dummy "$(LOG4J_OVER_SLF4J_BASE_URL)" "$(LOG4J_OVER_SLF4J)"; shift; $(FETCH_DEPENDENCY) 25 | 26 | 27 | SLF4J_API_VERSION := $(SLF4J_VERSION) 28 | SLF4J_API := third_party/slf4j/slf4j-api-$(SLF4J_API_VERSION).jar 29 | SLF4J_API_BASE_URL := http://central.maven.org/maven2/org/slf4j/slf4j-api/$(SLF4J_API_VERSION) 30 | 31 | $(SLF4J_API): $(SLF4J_API).md5 32 | set dummy "$(SLF4J_API_BASE_URL)" "$(SLF4J_API)"; shift; $(FETCH_DEPENDENCY) 33 | 34 | THIRD_PARTY += $(LOG4J_OVER_SLF4J) $(SLF4J_API) 35 | -------------------------------------------------------------------------------- /third_party/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2013 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | OPENTSDB_THIRD_PARTY_BASE_URL := http://opentsdb.googlecode.com/files 17 | FETCH_DEPENDENCY := ./build-aux/fetchdep.sh "$$@" 18 | all-am: build-aux/fetchdep.sh 19 | THIRD_PARTY = 20 | 21 | include third_party/guava/include.mk 22 | include third_party/gwt/include.mk 23 | include third_party/hamcrest/include.mk 24 | include third_party/hbase/include.mk 25 | include third_party/jackson/include.mk 26 | include third_party/javassist/include.mk 27 | include third_party/junit/include.mk 28 | include third_party/logback/include.mk 29 | include third_party/mockito/include.mk 30 | include third_party/netty/include.mk 31 | include third_party/objenesis/include.mk 32 | include third_party/powermock/include.mk 33 | include third_party/protobuf/include.mk 34 | include third_party/slf4j/include.mk 35 | include third_party/suasync/include.mk 36 | include third_party/validation-api/include.mk 37 | include third_party/zookeeper/include.mk 38 | -------------------------------------------------------------------------------- /src/tsd/WordSplitter.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import java.nio.charset.Charset; 16 | 17 | import org.jboss.netty.buffer.ChannelBuffer; 18 | import org.jboss.netty.channel.Channel; 19 | import org.jboss.netty.channel.ChannelHandlerContext; 20 | import org.jboss.netty.handler.codec.oneone.OneToOneDecoder; 21 | 22 | import net.opentsdb.core.Tags; 23 | 24 | /** 25 | * Splits a ChannelBuffer in multiple space separated words. 26 | */ 27 | final class WordSplitter extends OneToOneDecoder { 28 | 29 | private static final Charset CHARSET = Charset.forName("ISO-8859-1"); 30 | 31 | /** Constructor. */ 32 | public WordSplitter() { 33 | } 34 | 35 | @Override 36 | protected Object decode(final ChannelHandlerContext ctx, 37 | final Channel channel, 38 | final Object msg) throws Exception { 39 | return Tags.splitString(((ChannelBuffer) msg).toString(CHARSET), ' '); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /third_party/logback/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | http://central.maven.org/maven2/ch/qos/logback/logback-classic/1.0.13/logback-classic-1.0.13.jar 17 | LOGBACK_VERSION := 1.0.13 18 | 19 | LOGBACK_CLASSIC_VERSION := $(LOGBACK_VERSION) 20 | LOGBACK_CLASSIC := third_party/logback/logback-classic-$(LOGBACK_CLASSIC_VERSION).jar 21 | LOGBACK_CLASSIC_BASE_URL := http://central.maven.org/maven2/ch/qos/logback/logback-classic/$(LOGBACK_VERSION) 22 | 23 | $(LOGBACK_CLASSIC): $(LOGBACK_CLASSIC).md5 24 | set dummy "$(LOGBACK_CLASSIC_BASE_URL)" "$(LOGBACK_CLASSIC)"; shift; $(FETCH_DEPENDENCY) 25 | 26 | 27 | LOGBACK_CORE_VERSION := $(LOGBACK_VERSION) 28 | LOGBACK_CORE := third_party/logback/logback-core-$(LOGBACK_CORE_VERSION).jar 29 | LOGBACK_CORE_BASE_URL := http://central.maven.org/maven2/ch/qos/logback/logback-core/$(LOGBACK_VERSION) 30 | 31 | $(LOGBACK_CORE): $(LOGBACK_CORE).md5 32 | set dummy "$(LOGBACK_CORE_BASE_URL)" "$(LOGBACK_CORE)"; shift; $(FETCH_DEPENDENCY) 33 | 34 | THIRD_PARTY += $(LOGBACK_CLASSIC) $(LOGBACK_CORE) 35 | -------------------------------------------------------------------------------- /src/create_table.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Small script to setup the HBase tables used by OpenTSDB. 3 | 4 | test -n "$HBASE_HOME" || { 5 | echo >&2 'The environment variable HBASE_HOME must be set' 6 | exit 1 7 | } 8 | test -d "$HBASE_HOME" || { 9 | echo >&2 "No such directory: HBASE_HOME=$HBASE_HOME" 10 | exit 1 11 | } 12 | 13 | TSDB_TABLE=${TSDB_TABLE-'tsdb'} 14 | UID_TABLE=${UID_TABLE-'tsdb-uid'} 15 | TREE_TABLE=${TREE_TABLE-'tsdb-tree'} 16 | META_TABLE=${META_TABLE-'tsdb-meta'} 17 | BLOOMFILTER=${BLOOMFILTER-'ROW'} 18 | # LZO requires lzo2 64bit to be installed + the hadoop-gpl-compression jar. 19 | COMPRESSION=${COMPRESSION-'LZO'} 20 | # All compression codec names are upper case (NONE, LZO, SNAPPY, etc). 21 | COMPRESSION=`echo "$COMPRESSION" | tr a-z A-Z` 22 | 23 | case $COMPRESSION in 24 | (NONE|LZO|GZIP|SNAPPY) :;; # Known good. 25 | (*) 26 | echo >&2 "warning: compression codec '$COMPRESSION' might not be supported." 27 | ;; 28 | esac 29 | 30 | # HBase scripts also use a variable named `HBASE_HOME', and having this 31 | # variable in the environment with a value somewhat different from what 32 | # they expect can confuse them in some cases. So rename the variable. 33 | hbh=$HBASE_HOME 34 | unset HBASE_HOME 35 | exec "$hbh/bin/hbase" shell < 'id', COMPRESSION => '$COMPRESSION', BLOOMFILTER => '$BLOOMFILTER'}, 38 | {NAME => 'name', COMPRESSION => '$COMPRESSION', BLOOMFILTER => '$BLOOMFILTER'} 39 | 40 | create '$TSDB_TABLE', 41 | {NAME => 't', VERSIONS => 1, COMPRESSION => '$COMPRESSION', BLOOMFILTER => '$BLOOMFILTER'} 42 | 43 | create '$TREE_TABLE', 44 | {NAME => 't', VERSIONS => 1, COMPRESSION => '$COMPRESSION', BLOOMFILTER => '$BLOOMFILTER'} 45 | 46 | create '$META_TABLE', 47 | {NAME => 'name', COMPRESSION => '$COMPRESSION', BLOOMFILTER => '$BLOOMFILTER'} 48 | EOF 49 | -------------------------------------------------------------------------------- /src/utils/JSONException.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.utils; 14 | 15 | /** 16 | * Exception class used to wrap the myriad of typed exceptions thrown by 17 | * Jackson. 18 | * @since 2.0 19 | */ 20 | public final class JSONException extends RuntimeException { 21 | 22 | /** 23 | * Constructor. 24 | * @param msg The message of the exception, potentially including a stack 25 | * trace. 26 | */ 27 | public JSONException(final String msg) { 28 | super(msg); 29 | } 30 | 31 | /** 32 | * Constructor. 33 | * @param cause The exception that caused this one to be thrown. 34 | */ 35 | public JSONException(final Throwable cause) { 36 | super(cause); 37 | } 38 | 39 | /** 40 | * Constructor. 41 | * @param msg The message of the exception, potentially including a stack 42 | * trace. 43 | * @param cause The exception that caused this one to be thrown. 44 | */ 45 | public JSONException(final String msg, final Throwable cause) { 46 | super(msg, cause); 47 | } 48 | 49 | private static final long serialVersionUID = 1365518940; 50 | } 51 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2012 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | # Semantic Versioning (see http://semver.org/). 17 | AC_INIT([opentsdb], [2.1.3], [opentsdb@googlegroups.com]) 18 | AC_CONFIG_AUX_DIR([build-aux]) 19 | AM_INIT_AUTOMAKE([foreign]) 20 | 21 | AC_CONFIG_FILES([ 22 | Makefile 23 | ]) 24 | AC_CONFIG_FILES([opentsdb.spec]) 25 | AC_CONFIG_FILES([build-aux/fetchdep.sh], [chmod +x build-aux/fetchdep.sh]) 26 | 27 | TSDB_FIND_PROG([md5], [md5sum md5 gmd5sum digest]) 28 | if test x`basename "$MD5"` = x'digest'; then 29 | MD5='digest -a md5' 30 | fi 31 | TSDB_FIND_PROG([java]) 32 | TSDB_FIND_PROG([javac]) 33 | TSDB_FIND_PROG([jar]) 34 | # Mac OS does not have gnuplot. Falls back to /usr/bin/true to make gnuplot 35 | # optional. 36 | TSDB_FIND_PROG([gnuplot], [true]) 37 | AC_PATH_PROG([JAVADOC], [javadoc], []) 38 | AM_MISSING_PROG([JAVADOC], [javadoc]) 39 | 40 | # Find a tool to download 3rd party dependencies. 41 | AC_PATH_PROG([WGET], [wget]) 42 | AC_PATH_PROG([CURL], [curl]) 43 | # Make sure we have at least one. 44 | if test -z "$WGET$CURL"; then 45 | AC_MSG_ERROR([cannot find a tool to download an URL]) 46 | fi 47 | 48 | AC_SUBST([staticdir], ['${pkgdatadir}/static']) 49 | 50 | AC_OUTPUT 51 | -------------------------------------------------------------------------------- /src/uid/NoSuchUniqueId.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.uid; 14 | 15 | import java.util.Arrays; 16 | import java.util.NoSuchElementException; 17 | 18 | /** 19 | * Exception used when a Unique ID can't be found. 20 | * 21 | * @see UniqueId 22 | */ 23 | public final class NoSuchUniqueId extends NoSuchElementException { 24 | 25 | /** The 'kind' of the table. */ 26 | private final String kind; 27 | /** The ID that couldn't be found. */ 28 | private final byte[] id; 29 | 30 | /** 31 | * Constructor. 32 | * 33 | * @param kind The kind of unique ID that triggered the exception. 34 | * @param id The ID that couldn't be found. 35 | */ 36 | public NoSuchUniqueId(final String kind, final byte[] id) { 37 | super("No such unique ID for '" + kind + "': " + Arrays.toString(id)); 38 | this.kind = kind; 39 | this.id = id; 40 | } 41 | 42 | /** Returns the kind of unique ID that couldn't be found. */ 43 | public String kind() { 44 | return kind; 45 | } 46 | 47 | /** Returns the unique ID that couldn't be found. */ 48 | public byte[] id() { 49 | return id; 50 | } 51 | 52 | static final long serialVersionUID = 1266815251; 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/uid/NoSuchUniqueName.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.uid; 14 | 15 | import java.util.NoSuchElementException; 16 | 17 | /** 18 | * Exception used when a name's Unique ID can't be found. 19 | * 20 | * @see UniqueId 21 | */ 22 | public final class NoSuchUniqueName extends NoSuchElementException { 23 | 24 | /** The 'kind' of the table. */ 25 | private final String kind; 26 | /** The name that couldn't be found. */ 27 | private final String name; 28 | 29 | /** 30 | * Constructor. 31 | * 32 | * @param kind The kind of unique ID that triggered the exception. 33 | * @param name The name that couldn't be found. 34 | */ 35 | public NoSuchUniqueName(final String kind, final String name) { 36 | super("No such name for '" + kind + "': '" + name + "'"); 37 | this.kind = kind; 38 | this.name = name; 39 | } 40 | 41 | /** Returns the kind of unique ID that couldn't be found. */ 42 | public String kind() { 43 | return kind; 44 | } 45 | 46 | /** Returns the name for which the unique ID couldn't be found. */ 47 | public String name() { 48 | return name; 49 | } 50 | 51 | static final long serialVersionUID = 1266815261; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /test/tsd/DummyHttpSerializer.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import net.opentsdb.core.TSDB; 16 | 17 | import com.stumbleupon.async.Deferred; 18 | import org.junit.Ignore; 19 | 20 | /** 21 | * This is a dummy HTTP plugin seralizer implementation for unit test purposes 22 | * @since 2.0 23 | */ 24 | @Ignore 25 | public class DummyHttpSerializer extends HttpSerializer { 26 | 27 | public DummyHttpSerializer() { 28 | super(); 29 | this.request_content_type = "application/tsdbdummy"; 30 | this.response_content_type = "application/tsdbdummy; charset=UTF-8"; 31 | } 32 | 33 | public DummyHttpSerializer(final HttpQuery query) { 34 | super(query); 35 | this.request_content_type = "application/tsdbdummy"; 36 | this.response_content_type = "application/tsdbdummy; charset=UTF-8"; 37 | } 38 | 39 | @Override 40 | public void initialize(final TSDB tsdb) { 41 | // nothing to do 42 | } 43 | 44 | @Override 45 | public Deferred shutdown() { 46 | return new Deferred(); 47 | } 48 | 49 | @Override 50 | public String version() { 51 | return "1.0.0"; 52 | } 53 | 54 | @Override 55 | public String shortName() { 56 | return "dummy"; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /third_party/guava/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 The Async HBase Authors. All rights reserved. 2 | # This file is part of Async HBase. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | # - Redistributions of source code must retain the above copyright notice, 7 | # this list of conditions and the following disclaimer. 8 | # - Redistributions in binary form must reproduce the above copyright notice, 9 | # this list of conditions and the following disclaimer in the documentation 10 | # and/or other materials provided with the distribution. 11 | # - Neither the name of the StumbleUpon nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | # POSSIBILITY OF SUCH DAMAGE. 25 | 26 | GUAVA_VERSION := 18.0 27 | GUAVA := third_party/guava/guava-$(GUAVA_VERSION).jar 28 | GUAVA_BASE_URL := http://central.maven.org/maven2/com/google/guava/guava/$(GUAVA_VERSION) 29 | 30 | $(GUAVA): $(GUAVA).md5 31 | set dummy "$(GUAVA_BASE_URL)" "$(GUAVA)"; shift; $(FETCH_DEPENDENCY) 32 | 33 | THIRD_PARTY += $(GUAVA) 34 | -------------------------------------------------------------------------------- /test/utils/TestFileSystem.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013-2014 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.utils; 14 | 15 | import java.io.File; 16 | 17 | import net.opentsdb.utils.FileSystem; 18 | 19 | import org.junit.Before; 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.powermock.api.mockito.PowerMockito; 23 | import org.powermock.core.classloader.annotations.PrepareForTest; 24 | import org.powermock.modules.junit4.PowerMockRunner; 25 | 26 | @RunWith(PowerMockRunner.class) 27 | @PrepareForTest({File.class, FileSystem.class}) 28 | public final class TestFileSystem { 29 | 30 | File mockFile; 31 | 32 | @Before 33 | public void setUp() throws Exception { 34 | mockFile = PowerMockito.mock(File.class); 35 | PowerMockito.whenNew(File.class).withAnyArguments().thenReturn(mockFile); 36 | PowerMockito.when(mockFile, "getParent").thenReturn("/temp/opentsdb"); 37 | PowerMockito.when(mockFile, "exists").thenReturn(true); 38 | PowerMockito.when(mockFile, "isDirectory").thenReturn(true); 39 | PowerMockito.when(mockFile, "canWrite").thenReturn(true); 40 | } 41 | 42 | @Test (expected = IllegalArgumentException.class) 43 | public void checkDirectoryEmptyString() throws Exception { 44 | FileSystem.checkDirectory("", true, false); 45 | } 46 | } -------------------------------------------------------------------------------- /third_party/netty/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2012 The Async HBase Authors. All rights reserved. 2 | # This file is part of Async HBase. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | # - Redistributions of source code must retain the above copyright notice, 7 | # this list of conditions and the following disclaimer. 8 | # - Redistributions in binary form must reproduce the above copyright notice, 9 | # this list of conditions and the following disclaimer in the documentation 10 | # and/or other materials provided with the distribution. 11 | # - Neither the name of the StumbleUpon nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | # POSSIBILITY OF SUCH DAMAGE. 25 | 26 | NETTY_MAJOR_VERSION = 3.9 27 | NETTY_VERSION := 3.9.4.Final 28 | NETTY := third_party/netty/netty-$(NETTY_VERSION).jar 29 | NETTY_BASE_URL := http://central.maven.org/maven2/io/netty/netty/$(NETTY_VERSION) 30 | 31 | $(NETTY): $(NETTY).md5 32 | set dummy "$(NETTY_BASE_URL)" "$(NETTY)"; shift; $(FETCH_DEPENDENCY) 33 | 34 | THIRD_PARTY += $(NETTY) 35 | -------------------------------------------------------------------------------- /third_party/javassist/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2012 The Async HBase Authors. All rights reserved. 2 | # This file is part of Async HBase. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | # - Redistributions of source code must retain the above copyright notice, 7 | # this list of conditions and the following disclaimer. 8 | # - Redistributions in binary form must reproduce the above copyright notice, 9 | # this list of conditions and the following disclaimer in the documentation 10 | # and/or other materials provided with the distribution. 11 | # - Neither the name of the StumbleUpon nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | # POSSIBILITY OF SUCH DAMAGE. 25 | 26 | JAVASSIST_VERSION := 3.18.1-GA 27 | JAVASSIST := third_party/javassist/javassist-$(JAVASSIST_VERSION).jar 28 | JAVASSIST_BASE_URL := http://central.maven.org/maven2/org/javassist/javassist/$(JAVASSIST_VERSION) 29 | 30 | $(JAVASSIST): $(JAVASSIST).md5 31 | set dummy "$(JAVASSIST_BASE_URL)" "$(JAVASSIST)"; shift; $(FETCH_DEPENDENCY) 32 | 33 | THIRD_PARTY += $(JAVASSIST) 34 | -------------------------------------------------------------------------------- /src/utils/FileSystem.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2015 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.utils; 14 | 15 | import java.io.File; 16 | 17 | public class FileSystem { 18 | /** 19 | * Verifies a directory and checks to see if it's writeable or not if 20 | * configured 21 | * @param dir The path to check on 22 | * @param need_write Set to true if the path needs write access 23 | * @param create Set to true if the directory should be created if it does not 24 | * exist 25 | * @throws IllegalArgumentException if the path is empty, if it's not there 26 | * and told not to create it or if it needs write access and can't 27 | * be written to 28 | */ 29 | public static void checkDirectory(final String dir, 30 | final boolean need_write, final boolean create) { 31 | if (dir.isEmpty()) 32 | throw new IllegalArgumentException("Directory path is empty"); 33 | final File f = new File(dir); 34 | if (!f.exists() && !(create && f.mkdirs())) { 35 | throw new IllegalArgumentException("No such directory [" + dir + "]"); 36 | } else if (!f.isDirectory()) { 37 | throw new IllegalArgumentException("Not a directory [" + dir + "]"); 38 | } else if (need_write && !f.canWrite()) { 39 | throw new IllegalArgumentException("Cannot write to directory [" + dir 40 | + "]"); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /third_party/jackson/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2014 The OpenTSDB Authors. 2 | # 3 | # This library is free software: you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published 5 | # by the Free Software Foundation, either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This library is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU Lesser General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public License 14 | # along with this library. If not, see . 15 | 16 | JACKSON_VERSION := 2.4.3 17 | 18 | JACKSON_ANNOTATIONS_VERSION = $(JACKSON_VERSION) 19 | JACKSON_ANNOTATIONS := third_party/jackson/jackson-annotations-$(JACKSON_ANNOTATIONS_VERSION).jar 20 | JACKSON_ANNOTATIONS_BASE_URL := http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/$(JACKSON_VERSION) 21 | 22 | $(JACKSON_ANNOTATIONS): $(JACKSON_ANNOTATIONS).md5 23 | set dummy "$(JACKSON_ANNOTATIONS_BASE_URL)" "$(JACKSON_ANNOTATIONS)"; shift; $(FETCH_DEPENDENCY) 24 | 25 | JACKSON_CORE_VERSION = $(JACKSON_VERSION) 26 | JACKSON_CORE := third_party/jackson/jackson-core-$(JACKSON_CORE_VERSION).jar 27 | JACKSON_CORE_BASE_URL := http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/$(JACKSON_VERSION) 28 | 29 | $(JACKSON_CORE): $(JACKSON_CORE).md5 30 | set dummy "$(JACKSON_CORE_BASE_URL)" "$(JACKSON_CORE)"; shift; $(FETCH_DEPENDENCY) 31 | 32 | JACKSON_DATABIND_VERSION = $(JACKSON_VERSION) 33 | JACKSON_DATABIND := third_party/jackson/jackson-databind-$(JACKSON_DATABIND_VERSION).jar 34 | JACKSON_DATABIND_BASE_URL := http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/$(JACKSON_VERSION) 35 | 36 | $(JACKSON_DATABIND): $(JACKSON_DATABIND).md5 37 | set dummy "$(JACKSON_DATABIND_BASE_URL)" "$(JACKSON_DATABIND)"; shift; $(FETCH_DEPENDENCY) 38 | 39 | 40 | THIRD_PARTY += $(JACKSON_ANNOTATIONS) $(JACKSON_CORE) $(JACKSON_DATABIND) 41 | -------------------------------------------------------------------------------- /third_party/powermock/include.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011-2012 The Async HBase Authors. All rights reserved. 2 | # This file is part of Async HBase. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | # - Redistributions of source code must retain the above copyright notice, 7 | # this list of conditions and the following disclaimer. 8 | # - Redistributions in binary form must reproduce the above copyright notice, 9 | # this list of conditions and the following disclaimer in the documentation 10 | # and/or other materials provided with the distribution. 11 | # - Neither the name of the StumbleUpon nor the names of its contributors 12 | # may be used to endorse or promote products derived from this software 13 | # without specific prior written permission. 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | # POSSIBILITY OF SUCH DAMAGE. 25 | 26 | POWERMOCK_MOCKITO_VERSION := 1.5.4 27 | POWERMOCK_MOCKITO := third_party/powermock/powermock-mockito-release-full-$(POWERMOCK_MOCKITO_VERSION)-full.jar 28 | POWERMOCK_MOCKITO_BASE_URL := http://central.maven.org/maven2/org/powermock/powermock-mockito-release-full/$(POWERMOCK_MOCKITO_VERSION) 29 | 30 | $(POWERMOCK_MOCKITO): $(POWERMOCK_MOCKITO).md5 31 | set dummy "$(POWERMOCK_MOCKITO_BASE_URL)" "$(POWERMOCK_MOCKITO)"; shift; $(FETCH_DEPENDENCY) 32 | 33 | THIRD_PARTY += $(POWERMOCK_MOCKITO) 34 | -------------------------------------------------------------------------------- /src/opentsdb.conf: -------------------------------------------------------------------------------- 1 | # --------- NETWORK ---------- 2 | # The TCP port TSD should use for communications 3 | # *** REQUIRED *** 4 | tsd.network.port = 5 | 6 | # The IPv4 network address to bind to, defaults to all addresses 7 | # tsd.network.bind = 0.0.0.0 8 | 9 | # Enables Nagel's algorithm to reduce the number of packets sent over the 10 | # network, default is True 11 | #tsd.network.tcpnodelay = true 12 | 13 | # Determines whether or not to send keepalive packets to peers, default 14 | # is True 15 | #tsd.network.keepalive = true 16 | 17 | # Determines if the same socket should be used for new connections, default 18 | # is True 19 | #tsd.network.reuseaddress = true 20 | 21 | # Number of worker threads dedicated to Netty, defaults to # of CPUs * 2 22 | #tsd.network.worker_threads = 8 23 | 24 | # Whether or not to use NIO or tradditional blocking IO, defaults to True 25 | #tsd.network.async_io = true 26 | 27 | # ----------- HTTP ----------- 28 | # The location of static files for the HTTP GUI interface. 29 | # *** REQUIRED *** 30 | tsd.http.staticroot = 31 | 32 | # Where TSD should write it's cache files to 33 | # *** REQUIRED *** 34 | tsd.http.cachedir = 35 | 36 | # --------- CORE ---------- 37 | # Whether or not to automatically create UIDs for new metric types, default 38 | # is False 39 | #tsd.core.auto_create_metrics = false 40 | 41 | # --------- STORAGE ---------- 42 | # Whether or not to enable data compaction in HBase, default is True 43 | #tsd.storage.enable_compaction = true 44 | 45 | # How often, in milliseconds, to flush the data point queue to storage, 46 | # default is 1,000 47 | # tsd.storage.flush_interval = 1000 48 | 49 | # Name of the HBase table where data points are stored, default is "tsdb" 50 | #tsd.storage.hbase.data_table = tsdb 51 | 52 | # Name of the HBase table where UID information is stored, default is "tsdb-uid" 53 | #tsd.storage.hbase.uid_table = tsdb-uid 54 | 55 | # Path under which the znode for the -ROOT- region is located, default is "/hbase" 56 | #tsd.storage.hbase.zk_basedir = /hbase 57 | 58 | # A comma separated list of Zookeeper hosts to connect to, with or without 59 | # port specifiers, default is "localhost" 60 | #tsd.storage.hbase.zk_quorum = localhost -------------------------------------------------------------------------------- /test/tsd/DummyRpcPlugin.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import net.opentsdb.core.TSDB; 16 | import net.opentsdb.stats.StatsCollector; 17 | 18 | import org.junit.Ignore; 19 | 20 | import com.stumbleupon.async.Deferred; 21 | 22 | /** 23 | * This is a dummy RPC plugin implementation for unit test purposes 24 | * @since 2.0 25 | */ 26 | @Ignore 27 | public class DummyRpcPlugin extends RpcPlugin { 28 | 29 | @Override 30 | public void initialize(TSDB tsdb) { 31 | if (tsdb == null) { 32 | throw new IllegalArgumentException("The TSDB object was null"); 33 | } 34 | // some dummy configs to check to throw exceptions 35 | if (!tsdb.getConfig().hasProperty("tsd.rpcplugin.DummyRPCPlugin.hosts")) { 36 | throw new IllegalArgumentException("Missing hosts config"); 37 | } 38 | if (tsdb.getConfig().getString("tsd.rpcplugin.DummyRPCPlugin.hosts") 39 | .isEmpty()) { 40 | throw new IllegalArgumentException("Empty Hosts config"); 41 | } 42 | // throw an NFE for fun 43 | tsdb.getConfig().getInt("tsd.rpcplugin.DummyRPCPlugin.port"); 44 | } 45 | 46 | @Override 47 | public Deferred shutdown() { 48 | return Deferred.fromResult(null); 49 | } 50 | 51 | @Override 52 | public String version() { 53 | return "2.0.0"; 54 | } 55 | 56 | @Override 57 | public void collectStats(StatsCollector collector) { 58 | collector.record("rpcplugin.dummy.writes", 1); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/core/DataPoint.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | /** 16 | * Represents a single data point. 17 | *

18 | * Implementations of this interface aren't expected to be synchronized. 19 | */ 20 | public interface DataPoint { 21 | 22 | /** 23 | * Returns the timestamp (in milliseconds) associated with this data point. 24 | * @return A strictly positive, 32 bit integer. 25 | */ 26 | long timestamp(); 27 | 28 | /** 29 | * Tells whether or not the this data point is a value of integer type. 30 | * @return {@code true} if the {@code i}th value is of integer type, 31 | * {@code false} if it's of doubleing point type. 32 | */ 33 | boolean isInteger(); 34 | 35 | /** 36 | * Returns the value of the this data point as a {@code long}. 37 | * @throws ClassCastException if the {@code isInteger() == false}. 38 | */ 39 | long longValue(); 40 | 41 | /** 42 | * Returns the value of the this data point as a {@code double}. 43 | * @throws ClassCastException if the {@code isInteger() == true}. 44 | */ 45 | double doubleValue(); 46 | 47 | /** 48 | * Returns the value of the this data point as a {@code double}, even if 49 | * it's a {@code long}. 50 | * @return When {@code isInteger() == false}, this method returns the same 51 | * thing as {@link #doubleValue}. Otherwise, it returns the same thing as 52 | * {@link #longValue}'s return value casted to a {@code double}. 53 | */ 54 | double toDouble(); 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/tsd/StaticFileRpc.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import java.io.IOException; 16 | 17 | import net.opentsdb.core.TSDB; 18 | 19 | /** Implements the "/s" endpoint to serve static files. */ 20 | final class StaticFileRpc implements HttpRpc { 21 | 22 | /** 23 | * Constructor. 24 | */ 25 | public StaticFileRpc() { 26 | } 27 | 28 | public void execute(final TSDB tsdb, final HttpQuery query) 29 | throws IOException { 30 | final String uri = query.request().getUri(); 31 | if ("/favicon.ico".equals(uri)) { 32 | query.sendFile(tsdb.getConfig().getDirectoryName("tsd.http.staticroot") 33 | + "/favicon.ico", 31536000 /*=1yr*/); 34 | return; 35 | } 36 | if (uri.length() < 3) { // Must be at least 3 because of the "/s/". 37 | throw new BadRequestException("URI too short " + uri + ""); 38 | } 39 | // Cheap security check to avoid directory traversal attacks. 40 | // TODO(tsuna): This is certainly not sufficient. 41 | if (uri.indexOf("..", 3) > 0) { 42 | throw new BadRequestException("Malformed URI " + uri + ""); 43 | } 44 | final int questionmark = uri.indexOf('?', 3); 45 | final int pathend = questionmark > 0 ? questionmark : uri.length(); 46 | query.sendFile(tsdb.getConfig().getDirectoryName("tsd.http.staticroot") 47 | + uri.substring(2, pathend), // Drop the "/s" 48 | uri.contains("nocache") ? 0 : 31536000 /*=1yr*/); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/tsd/client/ValidatedTextBox.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package tsd.client; 14 | 15 | import com.google.gwt.event.dom.client.BlurEvent; 16 | import com.google.gwt.event.dom.client.BlurHandler; 17 | import com.google.gwt.user.client.Command; 18 | import com.google.gwt.user.client.DeferredCommand; 19 | import com.google.gwt.user.client.ui.TextBox; 20 | 21 | class ValidatedTextBox extends TextBox implements BlurHandler { 22 | 23 | private String regexp; 24 | 25 | public ValidatedTextBox() { 26 | } 27 | 28 | public void setValidationRegexp(final String regexp) { 29 | if (this.regexp == null) { // First call to this method. 30 | super.addBlurHandler(this); 31 | } 32 | this.regexp = regexp; 33 | } 34 | 35 | public String getValidationRegexp() { 36 | return regexp; 37 | } 38 | 39 | public void onBlur(final BlurEvent event) { 40 | final String interval = getText(); 41 | if (!interval.matches(regexp)) { 42 | // Steal the dateBoxFormatError :) 43 | addStyleName("dateBoxFormatError"); 44 | event.stopPropagation(); 45 | DeferredCommand.addCommand(new Command() { 46 | public void execute() { 47 | // TODO(tsuna): Understand why this doesn't work as expected, even 48 | // though we cancel the onBlur event and we put the focus afterwards 49 | // using a deferred command. 50 | //setFocus(true); 51 | selectAll(); 52 | } 53 | }); 54 | } else { 55 | removeStyleName("dateBoxFormatError"); 56 | } 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /THANKS: -------------------------------------------------------------------------------- 1 | OpenTSDB THANKS file 2 | -------------------- 3 | 4 | The following people have helped OpenTSDB by reporting problems, suggesting 5 | improvements, or submitting actual code. Please help us keep this list 6 | complete and free from errors. Also see the AUTHORS file for the list of 7 | people and organizations with contributions significant enough to warrant 8 | copyright assignment. 9 | 10 | 11 | Adrian Muraru 12 | Adrien Mogenet 13 | Alex Ioffe 14 | Andrey Stepachev 15 | Aravind Gottipati 16 | Arvind Jayaprakash 17 | Berk D. Demir 18 | Bryan Zubrod 19 | Chris McClymont 20 | Christophe Furmaniak 21 | Dave Barr 22 | Filippo Giunchedi 23 | Guenther Schmuelling 24 | Hong Dai Thanh 25 | Hugo Trippaers 26 | Jacek Masiulaniec 27 | Jari Takkala 28 | Jan Mangs 29 | Jesse Chang 30 | Jim Westfall 31 | Johan Zeeck 32 | Johannes Meixner 33 | Jonathan Works 34 | Josh Thomas 35 | Kieren Hynd 36 | Kimoon Kim 37 | Kris Beevers 38 | Lex Herbert 39 | Liangliang He 40 | Lou Yunlong 41 | Matt Jibson 42 | Mark Smith 43 | Martin Jansen 44 | Mike Bryant 45 | Mike Kobyakov 46 | Nicole Nagele 47 | Nikhil Benesch 48 | Paula Keezer 49 | Peter Gotz 50 | Pradeep Chhetri 51 | Ryan Berdeen 52 | Siddartha Guthikonda 53 | Simon Matic Langford 54 | Slawek Ligus 55 | Sy Le 56 | Tay Ray Chuan 57 | Thomas Sanchez 58 | Tibor Vass 59 | Tristan Colgate-McFarlane 60 | Tony Landells 61 | Vasiliy Kiryanov 62 | Zachary Kurey -------------------------------------------------------------------------------- /test/search/TestSearchQuery.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.search; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import net.opentsdb.search.SearchQuery.SearchType; 17 | 18 | import org.junit.Test; 19 | import org.junit.runner.RunWith; 20 | import org.powermock.modules.junit4.PowerMockRunner; 21 | 22 | @RunWith(PowerMockRunner.class) 23 | public final class TestSearchQuery { 24 | 25 | @Test 26 | public void parseSearchTypeTSMeta() throws Exception { 27 | assertEquals(SearchType.TSMETA, SearchQuery.parseSearchType("tsmeta")); 28 | } 29 | 30 | @Test 31 | public void parseSearchTypeTSMetaSummary() throws Exception { 32 | assertEquals(SearchType.TSMETA_SUMMARY, 33 | SearchQuery.parseSearchType("TSMeta_Summary")); 34 | } 35 | 36 | @Test 37 | public void parseSearchTypeTSUIDs() throws Exception { 38 | assertEquals(SearchType.TSUIDS, SearchQuery.parseSearchType("tsuids")); 39 | } 40 | 41 | @Test 42 | public void parseSearchTypeUIDMeta() throws Exception { 43 | assertEquals(SearchType.UIDMETA, SearchQuery.parseSearchType("UIDMeta")); 44 | } 45 | 46 | @Test 47 | public void parseSearchTypeAnnotation() throws Exception { 48 | assertEquals(SearchType.ANNOTATION, 49 | SearchQuery.parseSearchType("Annotation")); 50 | } 51 | 52 | @Test (expected = IllegalArgumentException.class) 53 | public void parseSearchTypeNull() throws Exception { 54 | SearchQuery.parseSearchType(null); 55 | } 56 | 57 | @Test (expected = IllegalArgumentException.class) 58 | public void parseSearchTypeEmtpy() throws Exception { 59 | SearchQuery.parseSearchType(""); 60 | } 61 | 62 | @Test (expected = IllegalArgumentException.class) 63 | public void parseSearchTypeInvalid() throws Exception { 64 | SearchQuery.parseSearchType("NotAType"); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /test/tsd/DummyRTPublisher.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import java.util.Map; 16 | 17 | import net.opentsdb.core.TSDB; 18 | import net.opentsdb.meta.Annotation; 19 | import net.opentsdb.stats.StatsCollector; 20 | 21 | import com.stumbleupon.async.Deferred; 22 | 23 | public final class DummyRTPublisher extends RTPublisher { 24 | 25 | @Override 26 | public void initialize(TSDB tsdb) { 27 | if (tsdb == null) { 28 | throw new IllegalArgumentException("The TSDB object was null"); 29 | } 30 | // some dummy configs to check to throw exceptions 31 | if (!tsdb.getConfig().hasProperty("tsd.rtpublisher.DummyRTPublisher.hosts")) { 32 | throw new IllegalArgumentException("Missing hosts config"); 33 | } 34 | if (tsdb.getConfig().getString("tsd.rtpublisher.DummyRTPublisher.hosts") 35 | .isEmpty()) { 36 | throw new IllegalArgumentException("Empty Hosts config"); 37 | } 38 | // throw an NFE for fun 39 | tsdb.getConfig().getInt("tsd.rtpublisher.DummyRTPublisher.port"); 40 | } 41 | 42 | @Override 43 | public Deferred shutdown() { 44 | return Deferred.fromResult(new Object()); 45 | } 46 | 47 | @Override 48 | public String version() { 49 | return "2.0.0"; 50 | } 51 | 52 | @Override 53 | public void collectStats(StatsCollector collector) { 54 | collector.record("rtpublisher.dummy.writes", 1); 55 | } 56 | 57 | @Override 58 | public Deferred publishDataPoint(String metric, long timestamp, 59 | long value, Map tags, byte[] tsuid) { 60 | return Deferred.fromResult(new Object()); 61 | } 62 | 63 | @Override 64 | public Deferred publishDataPoint(String metric, long timestamp, 65 | double value, Map tags, byte[] tsuid) { 66 | return Deferred.fromResult(new Object()); 67 | } 68 | 69 | @Override 70 | public Deferred publishAnnotation(Annotation annotation) { 71 | return Deferred.fromResult(new Object()); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /tools/tsddrain.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # This little script can be used to replace TSDs while performing prolonged 4 | # HBase or HDFS maintenances. It runs a simple, low-end TCP server to accept 5 | # all the data points from tcollectors and dump them to a bunch of files, one 6 | # per client IP address. These files can then later be batch-imported, once 7 | # HBase is back up. 8 | # 9 | # This file is part of OpenTSDB. 10 | # Copyright (C) 2013 The OpenTSDB Authors. 11 | # 12 | # This library is free software: you can redistribute it and/or modify it 13 | # under the terms of the GNU Lesser General Public License as published 14 | # by the Free Software Foundation; either version 2.1 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This library is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU Lesser General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU Lesser General Public License 23 | # along with this library. If not, see . 24 | 25 | import os 26 | import socket 27 | import sys 28 | import SocketServer 29 | 30 | class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): 31 | allow_reuse_address = True 32 | 33 | 34 | DRAINDIR = None 35 | 36 | class Handler(SocketServer.StreamRequestHandler): 37 | def handle(self): 38 | sys.stdout.write("O") 39 | sys.stdout.flush() 40 | out = open(os.path.join(DRAINDIR, self.client_address[0]), "a") 41 | n = 0 42 | while True: 43 | req = self.rfile.readline() 44 | if not req: 45 | break 46 | if req == "version\n": 47 | self.wfile.write("drain.py\n") 48 | sys.stdout.write("V") 49 | sys.stdout.flush() 50 | continue 51 | if not req.startswith("put "): 52 | sys.stdout.write("!") 53 | sys.stdout.flush() 54 | continue 55 | out.write(req[4:]) 56 | out.flush() 57 | if n % 100 == 0: 58 | sys.stdout.write(".") 59 | sys.stdout.flush() 60 | n += 1 61 | out.close() 62 | sys.stdout.write("X") 63 | sys.stdout.flush() 64 | 65 | 66 | def main(args): 67 | if len(args) != 3: 68 | sys.stderr.write("Usage: %s " % args[0]) 69 | return 1 70 | global DRAINDIR 71 | port = int(args[1]) 72 | DRAINDIR = args[2] 73 | if not os.path.isdir(DRAINDIR): 74 | os.makedirs(DRAINDIR) 75 | server = ThreadedTCPServer(("0.0.0.0", port), Handler) 76 | try: 77 | print ("Use Ctrl-C to stop me.") 78 | server.serve_forever() 79 | except KeyboardInterrupt: 80 | pass 81 | 82 | 83 | if __name__ == "__main__": 84 | sys.exit(main(sys.argv)) 85 | -------------------------------------------------------------------------------- /src/core/Aggregator.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | import java.util.NoSuchElementException; 16 | 17 | import net.opentsdb.core.Aggregators.Interpolation; 18 | 19 | /** 20 | * A function capable of aggregating multiple {@link DataPoints} together. 21 | *

22 | * All aggregators must be stateless. All they can do is run through a 23 | * sequence of {@link Longs Longs} or {@link Doubles Doubles} and return an 24 | * aggregated value. 25 | */ 26 | public interface Aggregator { 27 | 28 | /** 29 | * A sequence of {@code long}s. 30 | *

31 | * This interface is semantically equivalent to 32 | * {@code Iterator}. 33 | */ 34 | public interface Longs { 35 | 36 | /** 37 | * Returns {@code true} if this sequence has more values. 38 | * {@code false} otherwise. 39 | */ 40 | boolean hasNextValue(); 41 | 42 | /** 43 | * Returns the next {@code long} value in this sequence. 44 | * @throws NoSuchElementException if calling {@link #hasNextValue} returns 45 | * {@code false}. 46 | */ 47 | long nextLongValue(); 48 | 49 | } 50 | 51 | /** 52 | * A sequence of {@code double}s. 53 | *

54 | * This interface is semantically equivalent to 55 | * {@code Iterator}. 56 | */ 57 | public interface Doubles { 58 | 59 | /** 60 | * Returns {@code true} if this sequence has more values. 61 | * {@code false} otherwise. 62 | */ 63 | boolean hasNextValue(); 64 | 65 | /** 66 | * Returns the next {@code double} value in this sequence. 67 | * @throws NoSuchElementException if calling {@link #hasNextValue} returns 68 | * {@code false}. 69 | */ 70 | double nextDoubleValue(); 71 | 72 | } 73 | 74 | /** 75 | * Aggregates a sequence of {@code long}s. 76 | * @param values The sequence to aggregate. 77 | * @return The aggregated value. 78 | */ 79 | long runLong(Longs values); 80 | 81 | /** 82 | * Aggregates a sequence of {@code double}s. 83 | * @param values The sequence to aggregate. 84 | * @return The aggregated value. 85 | */ 86 | double runDouble(Doubles values); 87 | 88 | /** 89 | * Returns the interpolation method to use when working with data points 90 | * across time series. 91 | * @return The interpolation method to use 92 | */ 93 | Interpolation interpolationMethod(); 94 | } 95 | -------------------------------------------------------------------------------- /opentsdb.spec.in: -------------------------------------------------------------------------------- 1 | # Put the RPM in the current directory. 2 | %define _rpmdir . 3 | # Find the tarball produced by `make dist' in the current directory. 4 | %define _sourcedir %(echo $PWD) 5 | 6 | Name: @PACKAGE@ 7 | Version: @VERSION@ 8 | Release: 1 9 | Summary: A scalable, distributed Time Series Database 10 | Packager: @PACKAGE_BUGREPORT@ 11 | BuildArch: noarch 12 | Group: Service/Monitoring 13 | License: LGPLv2.1+ 14 | URL: http://opentsdb.net 15 | Source: @PACKAGE@-@VERSION@.tar.gz 16 | 17 | Requires: gnuplot 18 | 19 | # Disable the stupid stuff rpm distros include in the build process by 20 | # default: 21 | # Disable any prep shell actions. replace them with simply 'true' 22 | %define __spec_prep_pre true 23 | %define __spec_prep_post true 24 | # Disable any build shell actions. replace them with simply 'true' 25 | %define __spec_build_pre cd %{_builddir} 26 | %define __spec_build_post true 27 | # Disable any install shell actions. replace them with simply 'true' 28 | %define __spec_install_pre cd %{_builddir} 29 | %define __spec_install_post true 30 | # Disable any clean shell actions. replace them with simply 'true' 31 | %define __spec_clean_pre cd %{_builddir} 32 | %define __spec_clean_post true 33 | 34 | 35 | %description 36 | OpenTSDB is a distributed, scalable Time Series Database (TSDB) written on top 37 | of HBase. OpenTSDB was written to address a common need: store, index and 38 | serve metrics collected from computer systems (network gear, operating 39 | systems, applications) at a large scale, and make this data easily accessible 40 | and graphable. 41 | 42 | Thanks to HBase's scalability, OpenTSDB allows you to collect many thousands 43 | of metrics from thousands of hosts and applications, at a high rate (every few 44 | seconds). OpenTSDB will never delete or downsample data and can easily store 45 | billions of data points. 46 | 47 | %prep 48 | %setup -q 49 | 50 | 51 | %build 52 | %configure 53 | make 54 | 55 | %install 56 | rm -rf %{buildroot} 57 | make install DESTDIR=%{buildroot} 58 | mkdir -p %{buildroot}/var/cache/opentsdb 59 | mkdir -p %{buildroot}%{_datarootdir}/opentsdb/plugins 60 | # TODO: Use alternatives to manage the init script and configuration. 61 | 62 | %clean 63 | rm -rf %{buildroot} 64 | 65 | 66 | %files 67 | %defattr(644,root,root,755) 68 | %attr(0755,root,root) %{_bindir}/* 69 | %attr(0755,root,root) %{_datarootdir}/opentsdb/bin/*.sh 70 | %attr(0755,root,root) %{_datarootdir}/opentsdb/plugins 71 | %attr(0755,root,root) %{_datarootdir}/opentsdb/tools/* 72 | %attr(0755,root,root) %{_datarootdir}/opentsdb/etc/init.d/opentsdb 73 | %config %{_datarootdir}/opentsdb/etc/opentsdb/opentsdb.conf 74 | %config %{_datarootdir}/opentsdb/etc/opentsdb/logback.xml 75 | %doc 76 | %{_datarootdir}/opentsdb 77 | %{_bindir}/tsdb 78 | %dir %{_localstatedir}/cache/opentsdb 79 | 80 | %changelog 81 | 82 | %post 83 | 84 | if [ $1 -eq 1 ]; then 85 | # we're installing the first version of this package 86 | ln -s %{_datarootdir}/opentsdb/etc/opentsdb /etc/opentsdb 87 | ln -s %{_datarootdir}/opentsdb/etc/init.d/opentsdb /etc/init.d/opentsdb 88 | fi 89 | exit 0 90 | 91 | %postun 92 | 93 | if [ $1 -eq 0 ]; then 94 | # we're removing last version of this package 95 | rm -rf /etc/opentsdb 96 | rm -rf /etc/init.d/opentsdb 97 | fi 98 | exit 0 99 | -------------------------------------------------------------------------------- /src/core/SeekableView.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | import java.util.Iterator; 16 | import java.util.NoSuchElementException; 17 | 18 | /** 19 | * Provides a zero-copy view to iterate through data points. 20 | *

21 | * The iterator returned by classes that implement this interface must return 22 | * each {@link DataPoint} in {@code O(1)} and does not support {@link #remove}. 23 | *

24 | * Because no data is copied during iteration and no new object gets created, 25 | * the {@link DataPoint} returned must not be stored and gets 26 | * invalidated as soon as {@link #next} is called on the iterator (actually it 27 | * doesn't get invalidated but rather its contents changes). If you want to 28 | * store individual data points, you need to copy the timestamp and value out 29 | * of each {@link DataPoint} into your own data structures. 30 | *

31 | * In the vast majority of cases, the iterator will be used to go once through 32 | * all the data points, which is why it's not a problem if the iterator acts 33 | * just as a transient "view". Iterating will be very cheap since no memory 34 | * allocation is required (except to instantiate the actual iterator at the 35 | * beginning). 36 | */ 37 | public interface SeekableView extends Iterator { 38 | 39 | /** 40 | * Returns {@code true} if this view has more elements. 41 | */ 42 | boolean hasNext(); 43 | 44 | /** 45 | * Returns a view on the next data point. 46 | * No new object gets created, the referenced returned is always the same 47 | * and must not be stored since its internal data structure will change the 48 | * next time {@code next()} is called. 49 | * @throws NoSuchElementException if there were no more elements to iterate 50 | * on (in which case {@link #hasNext} would have returned {@code false}. 51 | */ 52 | DataPoint next(); 53 | 54 | /** 55 | * Unsupported operation. 56 | * @throws UnsupportedOperationException always. 57 | */ 58 | void remove(); 59 | 60 | /** 61 | * Advances the iterator to the given point in time. 62 | *

63 | * This allows the iterator to skip all the data points that are strictly 64 | * before the given timestamp. 65 | * @param timestamp A strictly positive 32 bit UNIX timestamp (in seconds). 66 | * @throws IllegalArgumentException if the timestamp is zero, or negative, 67 | * or doesn't fit on 32 bits (think "unsigned int" -- yay Java!). 68 | */ 69 | void seek(long timestamp); 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/utils/ByteArrayPair.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2014 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.utils; 14 | 15 | import java.util.Arrays; 16 | 17 | import org.hbase.async.Bytes; 18 | 19 | /** 20 | * Simple helper class to store a pair of byte arrays for use in situations 21 | * where a map or Map.Entry doesn't make sense. Extends the Pair class and 22 | * overrides the equals method using {@code Bytes.memcmp()} to determine if both 23 | * arrays have the same amount of data in the same order. 24 | * Sorting is performed on the key first, then on the value. 25 | */ 26 | public class ByteArrayPair extends Pair 27 | implements Comparable { 28 | 29 | /** 30 | * Default constructor initializes the object 31 | * @param key The key to store, may be null 32 | * @param value The value to store, may be null 33 | * @throws IllegalArgumentException If both values are null 34 | */ 35 | public ByteArrayPair(final byte[] key, final byte[] value) { 36 | this.key = key; 37 | this.value = value; 38 | } 39 | 40 | /** 41 | * Sorts on the key first then on the value. Nulls are allowed and are ordered 42 | * first. 43 | * @param a The value to compare against. 44 | */ 45 | public int compareTo(ByteArrayPair a) { 46 | final int key_compare = Bytes.memcmpMaybeNull(this.key, a.key); 47 | if (key_compare == 0) { 48 | return Bytes.memcmpMaybeNull(this.value, a.value); 49 | } 50 | return key_compare; 51 | } 52 | 53 | /** @return a descriptive string in the format "key=K, value=V" */ 54 | @Override 55 | public String toString() { 56 | return new StringBuilder().append("key=") 57 | .append(Arrays.toString(key)).append(", value=") 58 | .append(Arrays.toString(value)).toString(); 59 | } 60 | 61 | /** 62 | * Compares the two byte arrays for equality using {@code Bytes.memcmp()} 63 | * @return true if the objects refer to the same address or both objects are 64 | * have the same bytes in the same order 65 | */ 66 | @Override 67 | public boolean equals(final Object object) { 68 | if (object == this) { 69 | return true; 70 | } 71 | if (object instanceof ByteArrayPair) { 72 | final ByteArrayPair other_pair = (ByteArrayPair)object; 73 | return 74 | (key == null ? other_pair.getKey() == null : 75 | Bytes.memcmp(key, other_pair.key) == 0) 76 | && (value == null ? other_pair.getValue() == null : 77 | Bytes.memcmp(value, other_pair.value) == 0); 78 | } 79 | return false; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/core/RowKey.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | import java.util.Arrays; 16 | 17 | import org.hbase.async.Bytes; 18 | 19 | import com.stumbleupon.async.Deferred; 20 | 21 | /** Helper functions to deal with the row key. */ 22 | final public class RowKey { 23 | 24 | private RowKey() { 25 | // Can't create instances of this utility class. 26 | } 27 | 28 | /** 29 | * Extracts the name of the metric ID contained in a row key. 30 | * @param tsdb The TSDB to use. 31 | * @param row The actual row key. 32 | * @return The name of the metric. 33 | */ 34 | static String metricName(final TSDB tsdb, final byte[] row) { 35 | try { 36 | return metricNameAsync(tsdb, row).joinUninterruptibly(); 37 | } catch (RuntimeException e) { 38 | throw e; 39 | } catch (Exception e) { 40 | throw new RuntimeException("Should never be here", e); 41 | } 42 | } 43 | 44 | /** 45 | * Extracts the name of the metric ID contained in a row key. 46 | * @param tsdb The TSDB to use. 47 | * @param row The actual row key. 48 | * @return The name of the metric. 49 | * @since 1.2 50 | */ 51 | public static Deferred metricNameAsync(final TSDB tsdb, 52 | final byte[] row) { 53 | final byte[] id = Arrays.copyOfRange(row, 0, tsdb.metrics.width()); 54 | return tsdb.metrics.getNameAsync(id); 55 | } 56 | 57 | /** 58 | * Generates a row key given a TSUID and an absolute timestamp. The timestamp 59 | * will be normalized to an hourly base time. 60 | * @param tsdb The TSDB to use for fetching tag widths 61 | * @param tsuid The TSUID to use for the key 62 | * @param timestamp An absolute time from which we generate the row base time 63 | * @return A row key for use in fetching data from OpenTSDB 64 | * @since 2.0 65 | */ 66 | public static byte[] rowKeyFromTSUID(final TSDB tsdb, final byte[] tsuid, 67 | final long timestamp) { 68 | final long base_time; 69 | if ((timestamp & Const.SECOND_MASK) != 0) { 70 | // drop the ms timestamp to seconds to calculate the base timestamp 71 | base_time = ((timestamp / 1000) - 72 | ((timestamp / 1000) % Const.MAX_TIMESPAN)); 73 | } else { 74 | base_time = (timestamp - (timestamp % Const.MAX_TIMESPAN)); 75 | } 76 | final byte[] row = new byte[tsuid.length + Const.TIMESTAMP_BYTES]; 77 | System.arraycopy(tsuid, 0, row, 0, TSDB.metrics_width()); 78 | Bytes.setInt(row, (int) base_time, TSDB.metrics_width()); 79 | System.arraycopy(tsuid, TSDB.metrics_width(), row, 80 | TSDB.metrics_width() + Const.TIMESTAMP_BYTES, 81 | tsuid.length - TSDB.metrics_width()); 82 | return row; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/tsd/client/QueryString.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package tsd.client; 14 | 15 | // I (tsuna) originally wrote this code for Netty. Surprisingly, GWT has 16 | // nothing to manually parse query string parameters... 17 | 18 | import java.util.ArrayList; 19 | import java.util.HashMap; 20 | 21 | /** 22 | * Splits an HTTP query string into a path string and key-value parameter pairs. 23 | */ 24 | public final class QueryString extends HashMap> { 25 | 26 | /** 27 | * Returns the decoded key-value parameter pairs of the URI. 28 | */ 29 | public static QueryString decode(final String s) { 30 | final QueryString params = new QueryString(); 31 | String name = null; 32 | int pos = 0; // Beginning of the unprocessed region 33 | int i; // End of the unprocessed region 34 | for (i = 0; i < s.length(); i++) { 35 | final char c = s.charAt(i); 36 | if (c == '=' && name == null) { 37 | if (pos != i) { 38 | name = s.substring(pos, i); 39 | } 40 | pos = i + 1; 41 | } else if (c == '&') { 42 | if (name == null && pos != i) { 43 | // We haven't seen an `=' so far but moved forward. 44 | // Must be a param of the form '&a&' so add it with 45 | // an empty value. 46 | params.add(s.substring(pos, i), ""); 47 | } else if (name != null) { 48 | params.add(name, s.substring(pos, i)); 49 | name = null; 50 | } 51 | pos = i + 1; 52 | } 53 | } 54 | 55 | if (pos != i) { // Are there characters we haven't dealt with? 56 | if (name == null) { // Yes and we haven't seen any `='. 57 | params.add(s.substring(pos, i), ""); 58 | } else { // Yes and this must be the last value. 59 | params.add(name, s.substring(pos, i)); 60 | } 61 | } else if (name != null) { // Have we seen a name without value? 62 | params.add(name, ""); 63 | } 64 | 65 | return params; 66 | } 67 | 68 | /** 69 | * Adds a query string element. 70 | * @param name The name of the element. 71 | * @param value The value of the element. 72 | */ 73 | public void add(final String name, final String value) { 74 | ArrayList values = super.get(name); 75 | if (values == null) { 76 | values = new ArrayList(1); // Often there's only 1 value. 77 | super.put(name, values); 78 | } 79 | values.add(value); 80 | } 81 | 82 | /** 83 | * Returns the first value for the given key, or {@code null}. 84 | */ 85 | public String getFirst(final String key) { 86 | final ArrayList values = super.get(key); 87 | return values == null ? null : values.get(0); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /tsdb.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | me=`basename "$0"` 5 | mydir=`dirname "$0"` 6 | # Either: 7 | # abs_srcdir and abs_builddir are set: we're running in a dev tree 8 | # or pkgdatadir is set: we've been installed, we respect that. 9 | abs_srcdir='@abs_srcdir@' 10 | abs_builddir='@abs_builddir@' 11 | pkgdatadir='@pkgdatadir@' 12 | configdir='@configdir@' 13 | # Either we've been installed and pkgdatadir exists, or we haven't been 14 | # installed and abs_srcdir / abs_builddir aren't empty. 15 | test -d "$pkgdatadir" || test -n "$abs_srcdir$abs_builddir" || { 16 | echo >&2 "$me: Uh-oh, \`$pkgdatadir' doesn't exist, is OpenTSDB properly installed?" 17 | exit 1 18 | } 19 | 20 | if test -n "$pkgdatadir"; then 21 | localdir="$pkgdatadir/bin" 22 | for jar in "$pkgdatadir"/*.jar; do 23 | CLASSPATH="$CLASSPATH:$jar" 24 | done 25 | # Add pkgdatadir itself so we can find logback.xml 26 | CLASSPATH="$CLASSPATH:$pkgdatadir" 27 | 28 | if test -d "$pkgdatadir/bin"; then 29 | CLASSPATH="$CLASSPATH:$pkgdatadir/bin" 30 | fi 31 | 32 | if test -d "$pkgdatadir/lib"; then 33 | for jar in "$pkgdatadir"/lib/*.jar; do 34 | CLASSPATH="$CLASSPATH:$jar" 35 | done 36 | fi 37 | 38 | if test -n "$configdir" && test -d "$configdir"; then 39 | CLASSPATH="$CLASSPATH:$configdir" 40 | fi 41 | else 42 | localdir="$abs_builddir" 43 | # If we're running out of the build tree, it's especially important that we 44 | # know exactly what jars we need to build the CLASSPATH. Otherwise people 45 | # cannot easily pick up new dependencies as we might mix multiple versions 46 | # of the same dependencies on the CLASSPATH, which is bad. Looking for a 47 | # specific version of each jar prevents this problem. 48 | # TODO(tsuna): Once we jarjar all the dependencies together, this will no 49 | # longer be an issue. See issue #23. 50 | for jar in `make -C "$abs_builddir" printdeps | sed '/third_party.*jar/!d'`; do 51 | for dir in "$abs_builddir" "$abs_srcdir"; do 52 | test -f "$dir/$jar" && CLASSPATH="$CLASSPATH:$dir/$jar" && continue 2 53 | done 54 | echo >&2 "$me: error: Couldn't find \`$jar' either under \`$abs_builddir' or \`$abs_srcdir'." 55 | exit 2 56 | done 57 | # Add the src dir so we can find logback.xml 58 | CLASSPATH="$CLASSPATH:$abs_srcdir/src" 59 | fi 60 | # Remove any leading colon. 61 | CLASSPATH="${CLASSPATH#:}" 62 | 63 | usage() { 64 | echo >&2 "usage: $me [args]" 65 | echo 'Valid commands: fsck, import, mkmetric, query, tsd, scan, uid' 66 | exit 1 67 | } 68 | 69 | case $1 in 70 | (fsck) 71 | MAINCLASS=Fsck 72 | ;; 73 | (import) 74 | MAINCLASS=TextImporter 75 | ;; 76 | (mkmetric) 77 | shift 78 | set uid assign metrics "$@" 79 | MAINCLASS=UidManager 80 | ;; 81 | (query) 82 | MAINCLASS=CliQuery 83 | ;; 84 | (tsd) 85 | MAINCLASS=TSDMain 86 | ;; 87 | (scan) 88 | MAINCLASS=DumpSeries 89 | ;; 90 | (search) 91 | MAINCLASS=Search 92 | ;; 93 | (uid) 94 | MAINCLASS=UidManager 95 | ;; 96 | (*) 97 | echo >&2 "$me: error: unknown command '$1'" 98 | usage 99 | ;; 100 | esac 101 | shift 102 | 103 | JAVA=${JAVA-'java'} 104 | JVMARGS=${JVMARGS-'-enableassertions -enablesystemassertions'} 105 | test -r "$localdir/tsdb.local" && . "$localdir/tsdb.local" 106 | exec $JAVA $JVMARGS -classpath "$CLASSPATH" net.opentsdb.tools.$MAINCLASS "$@" 107 | -------------------------------------------------------------------------------- /src/tsd/client/EventsHandler.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package tsd.client; 14 | 15 | import com.google.gwt.event.dom.client.BlurEvent; 16 | import com.google.gwt.event.dom.client.BlurHandler; 17 | import com.google.gwt.event.dom.client.ChangeEvent; 18 | import com.google.gwt.event.dom.client.ChangeHandler; 19 | import com.google.gwt.event.dom.client.ClickEvent; 20 | import com.google.gwt.event.dom.client.ClickHandler; 21 | import com.google.gwt.event.dom.client.DomEvent; 22 | import com.google.gwt.event.dom.client.KeyCodes; 23 | import com.google.gwt.event.dom.client.KeyPressEvent; 24 | import com.google.gwt.event.dom.client.KeyPressHandler; 25 | import com.google.gwt.event.shared.EventHandler; 26 | import com.google.gwt.user.client.Command; 27 | import com.google.gwt.user.client.DeferredCommand; 28 | 29 | /** 30 | * Handler for multiple events that indicate that the widget may have changed. 31 | *

32 | * This handler is just a convenient 4-in-1 handler that can be re-used on a 33 | * wide range of widgets such as {@code TextBox} and its derivative, 34 | * {@code CheckBox}, {@code ListBox} etc. 35 | */ 36 | abstract class EventsHandler implements BlurHandler, ChangeHandler, 37 | ClickHandler, KeyPressHandler { 38 | 39 | /** 40 | * Called after one of the events (click, blur, change or "enter" 41 | * is pressed) occurs. 42 | *

43 | * This method is NOT called while the event is happening. It's invoked via 44 | * a {@link DeferredCommand deferred command}. This entails that the event 45 | * can't be cancelled as it has already executed. The reason the call is 46 | * deferred is that this way, things like {@code SuggestBox}s will have 47 | * already done their auto-completion by the time this method is called, and 48 | * thus the handler will see the suggested text instead of the partial input 49 | * being typed by the user. 50 | * @param event The event that occurred. 51 | */ 52 | protected abstract void onEvent(DomEvent event); 53 | 54 | public final void onClick(final ClickEvent event) { 55 | scheduleEvent(event); 56 | } 57 | 58 | public final void onBlur(final BlurEvent event) { 59 | scheduleEvent(event); 60 | } 61 | 62 | public final void onChange(final ChangeEvent event) { 63 | scheduleEvent(event); 64 | } 65 | 66 | public final void onKeyPress(final KeyPressEvent event) { 67 | if (event.getCharCode() == KeyCodes.KEY_ENTER) { 68 | scheduleEvent(event); 69 | } 70 | } 71 | 72 | /** Executes the event using a deferred command. */ 73 | private void scheduleEvent(final DomEvent event) { 74 | DeferredCommand.addCommand(new Command() { 75 | public void execute() { 76 | onEvent(event); 77 | } 78 | }); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/core/Const.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | /** Constants used in various places. */ 16 | public final class Const { 17 | 18 | /** Number of bytes on which a timestamp is encoded. */ 19 | public static final short TIMESTAMP_BYTES = 4; 20 | 21 | /** Maximum number of tags allowed per data point. */ 22 | public static final short MAX_NUM_TAGS = 8; 23 | // 8 is an aggressive limit on purpose. Can always be increased later. 24 | 25 | /** Number of LSBs in time_deltas reserved for flags. */ 26 | public static final short FLAG_BITS = 4; 27 | 28 | /** Number of LSBs in time_deltas reserved for flags. */ 29 | public static final short MS_FLAG_BITS = 6; 30 | 31 | /** 32 | * When this bit is set, the value is a floating point value. 33 | * Otherwise it's an integer value. 34 | */ 35 | public static final short FLAG_FLOAT = 0x8; 36 | 37 | /** Mask to select the size of a value from the qualifier. */ 38 | public static final short LENGTH_MASK = 0x7; 39 | 40 | /** Mask for the millisecond qualifier flag */ 41 | public static final byte MS_BYTE_FLAG = (byte)0xF0; 42 | 43 | /** Flag to set on millisecond qualifier timestamps */ 44 | public static final int MS_FLAG = 0xF0000000; 45 | 46 | /** Flag to determine if a compacted column is a mix of seconds and ms */ 47 | public static final byte MS_MIXED_COMPACT = 1; 48 | 49 | /** Mask to select all the FLAG_BITS. */ 50 | public static final short FLAGS_MASK = FLAG_FLOAT | LENGTH_MASK; 51 | 52 | /** Mask to verify a timestamp on 4 bytes in seconds */ 53 | public static final long SECOND_MASK = 0xFFFFFFFF00000000L; 54 | 55 | /** Mask to verify a timestamp on 6 bytes in milliseconds */ 56 | public static final long MILLISECOND_MASK = 0xFFFFF00000000000L; 57 | 58 | /** Max time delta (in seconds) we can store in a column qualifier. */ 59 | public static final short MAX_TIMESPAN = 3600; 60 | 61 | /** 62 | * Array containing the hexadecimal characters (0 to 9, A to F). 63 | * This array is read-only, changing its contents leads to an undefined 64 | * behavior. 65 | */ 66 | public static final byte[] HEX = { 67 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 68 | 'A', 'B', 'C', 'D', 'E', 'F' 69 | }; 70 | 71 | /** 72 | * Necessary for rate calculations where we may be trying to convert a 73 | * large Long value to a double. Doubles can only take integers up to 2^53 74 | * before losing precision. 75 | */ 76 | public static final long MAX_INT_IN_DOUBLE = 0xFFE0000000000000L; 77 | 78 | /** 79 | * Mnemonics for FileSystem.checkDirectory() 80 | */ 81 | public static final boolean DONT_CREATE = false; 82 | public static final boolean CREATE_IF_NEEDED = true; 83 | public static final boolean MUST_BE_WRITEABLE = true; 84 | } 85 | -------------------------------------------------------------------------------- /src/core/ByteBufferList.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2011-2014 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Arrays; 17 | 18 | /** 19 | * Accumulates byte buffers, analogous to a StringBuffer. 20 | * 21 | * @since 2.1 22 | */ 23 | final class ByteBufferList { 24 | 25 | private static class BufferSegment { 26 | public final byte[] buf; 27 | public final int offset; 28 | public final int len; 29 | 30 | public BufferSegment(final byte[] buf, final int offset, final int len) { 31 | this.buf = buf; 32 | this.offset = offset; 33 | this.len = len; 34 | } 35 | } 36 | 37 | private final ArrayList segments; 38 | private int total_length; 39 | 40 | /** 41 | * Create a ByteBufferList. 42 | * 43 | * @param n estimated number of segments (an overestimate is better than an underestimate) 44 | */ 45 | public ByteBufferList(final int n) { 46 | segments = new ArrayList(n); 47 | } 48 | 49 | /** 50 | * Add a segment to the buffer list. 51 | * 52 | * @param buf byte array 53 | * @param offset offset into buf 54 | * @param len length of segment, starting at offset 55 | */ 56 | public void add(final byte[] buf, final int offset, final int len) { 57 | segments.add(new BufferSegment(buf, offset, len)); 58 | total_length += len; 59 | } 60 | 61 | /** 62 | * Get the most recently added segment. 63 | * 64 | * @return byte array, a copy of the most recently added segment 65 | */ 66 | public byte[] getLastSegment() { 67 | if (segments.isEmpty()) { 68 | return null; 69 | } 70 | BufferSegment seg = segments.get(segments.size() - 1); 71 | return Arrays.copyOfRange(seg.buf, seg.offset, seg.offset + seg.len); 72 | } 73 | 74 | /** 75 | * Get the number of segments that have added to this buffer list. 76 | * 77 | * @return the segment count 78 | */ 79 | public int segmentCount() { 80 | return segments.size(); 81 | } 82 | 83 | /** 84 | * Get the accumulated bytes as a single byte array (may be a zero-byte array if empty). 85 | * 86 | * @param padding the number of additional bytes to include at the end 87 | * @return the accumulated bytes 88 | */ 89 | public byte[] toBytes(final int padding) { 90 | // special case a single entry 91 | if (padding == 0 && segments.size() == 1) { 92 | BufferSegment seg = segments.get(0); 93 | if (seg.offset == 0 && seg.len == seg.buf.length) { 94 | return seg.buf; 95 | } 96 | return Arrays.copyOfRange(seg.buf, seg.offset, seg.offset + seg.len); 97 | } 98 | byte[] result = new byte[total_length + padding]; 99 | int ofs = 0; 100 | for (BufferSegment seg : segments) { 101 | System.arraycopy(seg.buf, seg.offset, result, ofs, seg.len); 102 | ofs += seg.len; 103 | } 104 | return result; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/tsd/RpcPlugin.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import com.stumbleupon.async.Deferred; 16 | 17 | import net.opentsdb.core.TSDB; 18 | import net.opentsdb.stats.StatsCollector; 19 | 20 | /** 21 | * The RPCPlugin allows for interacting with a TSD using different protocols 22 | * such as Protobufs, Thrift, Memcache, anything folks want to create. Users 23 | * may configure one or more optional protocol plugins when starting a TSD. The 24 | * plugin is responsible for setting up necessary IO in the {@link #initialize} 25 | * method and if there is a problem, such as failure to bind to a socket or 26 | * missing config options, throw an exception so the user can fix the issue. 27 | *

28 | * Initially this plugin should be used to accept incoming data points. Simply 29 | * parse the data and call {@link TSDB#addPoint}. 30 | *

31 | * Note: Implementations must have a parameterless constructor. The 32 | * {@link #initialize(TSDB)} method will be called immediately after the plugin is 33 | * instantiated and before any other methods are called. 34 | * @since 2.0 35 | */ 36 | public abstract class RpcPlugin { 37 | 38 | /** 39 | * Called by TSDB to initialize the plugin 40 | * Implementations are responsible for setting up any IO they need as well 41 | * as starting any required background threads. 42 | * Note: Implementations should throw exceptions if they can't start 43 | * up properly. The TSD will then shutdown so the operator can fix the 44 | * problem. Please use IllegalArgumentException for configuration issues. 45 | * @param tsdb The parent TSDB object 46 | * @throws IllegalArgumentException if required configuration parameters are 47 | * missing 48 | * @throws Exception if something else goes wrong 49 | */ 50 | public abstract void initialize(final TSDB tsdb); 51 | 52 | /** 53 | * Called to gracefully shutdown the plugin. Implementations should close 54 | * any IO they have open 55 | * @return A deferred object that indicates the completion of the request. 56 | * The {@link Object} has not special meaning and can be {@code null} 57 | * (think of it as {@code Deferred}). 58 | */ 59 | public abstract Deferred shutdown(); 60 | 61 | /** 62 | * Should return the version of this plugin in the format: 63 | * MAJOR.MINOR.MAINT, e.g. "2.0.1". The MAJOR version should match the major 64 | * version of OpenTSDB the plugin is meant to work with. 65 | * @return A version string used to log the loaded version 66 | */ 67 | public abstract String version(); 68 | 69 | /** 70 | * Called by the TSD when a request for statistics collection has come in. The 71 | * implementation may provide one or more statistics. If no statistics are 72 | * available for the implementation, simply stub the method. 73 | * @param collector The collector used for emitting statistics 74 | */ 75 | public abstract void collectStats(final StatsCollector collector); 76 | 77 | } 78 | -------------------------------------------------------------------------------- /test/tsd/TestRpcPlugin.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertNotNull; 17 | import static org.mockito.Mockito.when; 18 | import static org.powermock.api.mockito.PowerMockito.mock; 19 | import net.opentsdb.core.TSDB; 20 | import net.opentsdb.utils.Config; 21 | import net.opentsdb.utils.PluginLoader; 22 | 23 | import org.junit.Before; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | import org.powermock.core.classloader.annotations.PowerMockIgnore; 27 | import org.powermock.core.classloader.annotations.PrepareForTest; 28 | import org.powermock.modules.junit4.PowerMockRunner; 29 | 30 | @PowerMockIgnore({"javax.management.*", "javax.xml.*", 31 | "ch.qos.*", "org.slf4j.*", 32 | "com.sum.*", "org.xml.*"}) 33 | @RunWith(PowerMockRunner.class) 34 | @PrepareForTest({TSDB.class, Config.class, RpcPlugin.class}) 35 | public final class TestRpcPlugin { 36 | private TSDB tsdb= mock(TSDB.class); 37 | private Config config = mock(Config.class); 38 | private RpcPlugin rpc_plugin; 39 | 40 | @Before 41 | public void before() throws Exception { 42 | // setups a good default for the config 43 | when(config.hasProperty("tsd.rpcplugin.DummyRPCPlugin.hosts")) 44 | .thenReturn(true); 45 | when(config.getString("tsd.rpcplugin.DummyRPCPlugin.hosts")) 46 | .thenReturn("localhost"); 47 | when(config.getInt("tsd.rpcplugin.DummyRPCPlugin.port")).thenReturn(42); 48 | when(tsdb.getConfig()).thenReturn(config); 49 | PluginLoader.loadJAR("plugin_test.jar"); 50 | rpc_plugin = PluginLoader.loadSpecificPlugin( 51 | "net.opentsdb.tsd.DummyRpcPlugin", RpcPlugin.class); 52 | } 53 | 54 | @Test 55 | public void initialize() throws Exception { 56 | rpc_plugin.initialize(tsdb); 57 | } 58 | 59 | @Test (expected = IllegalArgumentException.class) 60 | public void initializeMissingHost() throws Exception { 61 | when(config.hasProperty("tsd.rpcplugin.DummyRPCPlugin.hosts")) 62 | .thenReturn(false); 63 | rpc_plugin.initialize(tsdb); 64 | } 65 | 66 | public void initializeEmptyHost() throws Exception { 67 | when(config.getString("tsd.rpcplugin.DummyRPCPlugin.hosts")) 68 | .thenReturn(""); 69 | rpc_plugin.initialize(tsdb); 70 | } 71 | 72 | @Test (expected = NullPointerException.class) 73 | public void initializeMissingPort() throws Exception { 74 | when(config.getInt("tsd.rpcplugin.DummyRPCPlugin.port")) 75 | .thenThrow(new NullPointerException()); 76 | rpc_plugin.initialize(tsdb); 77 | } 78 | 79 | @Test (expected = IllegalArgumentException.class) 80 | public void initializeInvalidPort() throws Exception { 81 | when(config.getInt("tsd.rpcplugin.DummyRPCPlugin.port")) 82 | .thenThrow(new NumberFormatException()); 83 | rpc_plugin.initialize(tsdb); 84 | } 85 | 86 | @Test 87 | public void shutdown() throws Exception { 88 | assertNotNull(rpc_plugin.shutdown()); 89 | } 90 | 91 | @Test 92 | public void version() throws Exception { 93 | assertEquals("2.0.0", rpc_plugin.version()); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/tsd/LineBasedFrameDecoder.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import org.jboss.netty.buffer.ChannelBuffer; 16 | import org.jboss.netty.channel.Channel; 17 | import org.jboss.netty.channel.Channels; 18 | import org.jboss.netty.channel.ChannelHandlerContext; 19 | import org.jboss.netty.handler.codec.frame.FrameDecoder; 20 | import org.jboss.netty.handler.codec.frame.TooLongFrameException; 21 | 22 | /** 23 | * Decodes telnet-style frames delimited by new-lines. 24 | *

25 | * Both "\n" and "\r\n" are handled. 26 | *

27 | * This decoder is stateful and is thus NOT shareable. 28 | */ 29 | final class LineBasedFrameDecoder extends FrameDecoder { 30 | 31 | /** Maximum length of a frame we're willing to decode. */ 32 | private final int max_length; 33 | /** True if we're discarding input because we're already over max_length. */ 34 | private boolean discarding; 35 | 36 | /** 37 | * Creates a new decoder. 38 | * @param max_length Maximum length of a frame we're willing to decode. 39 | * If a frame is longer than that, a {@link TooLongFrameException} will 40 | * be fired on the channel causing it. 41 | */ 42 | public LineBasedFrameDecoder(final int max_length) { 43 | this.max_length = max_length; 44 | } 45 | 46 | @Override 47 | protected Object decode(final ChannelHandlerContext ctx, 48 | final Channel channel, 49 | final ChannelBuffer buffer) throws Exception { 50 | final int eol = findEndOfLine(buffer); 51 | if (eol != -1) { 52 | final ChannelBuffer frame; 53 | final int length = eol - buffer.readerIndex(); 54 | assert length >= 0: "WTF? length=" + length; 55 | if (discarding) { 56 | frame = null; 57 | buffer.skipBytes(length); 58 | } else { 59 | frame = buffer.readBytes(length); 60 | } 61 | final byte delim = buffer.readByte(); 62 | if (delim == '\r') { 63 | buffer.skipBytes(1); // Skip the \n. 64 | } 65 | return frame; 66 | } 67 | 68 | final int buffered = buffer.readableBytes(); 69 | if (!discarding && buffered > max_length) { 70 | discarding = true; 71 | Channels.fireExceptionCaught(ctx.getChannel(), 72 | new TooLongFrameException("Frame length exceeds " + max_length + " (" 73 | + buffered + " bytes buffered already)")); 74 | } 75 | if (discarding) { 76 | buffer.skipBytes(buffer.readableBytes()); 77 | } 78 | return null; 79 | } 80 | 81 | /** 82 | * Returns the index in the buffer of the end of line found. 83 | * Returns -1 if no end of line was found in the buffer. 84 | */ 85 | private static int findEndOfLine(final ChannelBuffer buffer) { 86 | final int n = buffer.writerIndex(); 87 | for (int i = buffer.readerIndex(); i < n; i ++) { 88 | final byte b = buffer.getByte(i); 89 | if (b == '\n') { 90 | return i; 91 | } else if (b == '\r' && i < n - 1 && buffer.getByte(i + 1) == '\n') { 92 | return i; // \r\n 93 | } 94 | } 95 | return -1; // Not found. 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /test/core/TestMutableDataPoint.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2014 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertFalse; 17 | import static org.junit.Assert.assertTrue; 18 | 19 | import org.junit.Test; 20 | 21 | 22 | /** 23 | * Tests {@link MutableDataPoint}. 24 | */ 25 | public class TestMutableDataPoint { 26 | 27 | @Test 28 | public void testMutableDataPoint() { 29 | MutableDataPoint dp = new MutableDataPoint(); 30 | assertTrue(dp.isInteger()); 31 | assertEquals(0, dp.longValue()); 32 | assertEquals(Long.MAX_VALUE, dp.timestamp()); 33 | assertEquals(0, dp.toDouble(), 0); 34 | } 35 | 36 | @Test 37 | public void testResetWithDoubleValue() { 38 | MutableDataPoint dp = new MutableDataPoint(); 39 | dp.reset(17L, 0.1717); 40 | assertFalse(dp.isInteger()); 41 | assertEquals(0.1717, dp.doubleValue(), 0); 42 | assertEquals(17L, dp.timestamp()); 43 | assertEquals(0.1717, dp.toDouble(), 0); 44 | } 45 | 46 | @Test 47 | public void testResetWithLongValue() { 48 | MutableDataPoint dp = new MutableDataPoint(); 49 | dp.reset(19L, 1717171L); 50 | assertTrue(dp.isInteger()); 51 | assertEquals(1717171L, dp.longValue()); 52 | assertEquals(19L, dp.timestamp()); 53 | assertEquals(1717171L, dp.toDouble(), 0); 54 | } 55 | 56 | @Test 57 | public void testReset() { 58 | MutableDataPoint dp_foo = new MutableDataPoint(); 59 | dp_foo.reset(19L, 1717171L); 60 | MutableDataPoint dp = new MutableDataPoint(); 61 | dp.reset(dp_foo); 62 | assertTrue(dp.isInteger()); 63 | assertEquals(1717171L, dp.longValue()); 64 | assertEquals(19L, dp.timestamp()); 65 | assertEquals(1717171L, dp.toDouble(), 0); 66 | dp_foo.reset(17L, 0.1717); 67 | dp.reset(dp_foo); 68 | assertFalse(dp.isInteger()); 69 | assertEquals(0.1717, dp.doubleValue(), 0); 70 | assertEquals(17L, dp.timestamp()); 71 | assertEquals(0.1717, dp.toDouble(), 0); 72 | } 73 | 74 | @Test 75 | public void testOfDoubleValue() { 76 | MutableDataPoint dp = MutableDataPoint.ofDoubleValue(17L, 0.1717); 77 | assertFalse(dp.isInteger()); 78 | assertEquals(0.1717, dp.doubleValue(), 0); 79 | assertEquals(17L, dp.timestamp()); 80 | assertEquals(0.1717, dp.toDouble(), 0); 81 | } 82 | 83 | @Test 84 | public void testOfLongValue() { 85 | MutableDataPoint dp = MutableDataPoint.ofLongValue(19L, 1717171L); 86 | assertTrue(dp.isInteger()); 87 | assertEquals(1717171L, dp.longValue()); 88 | assertEquals(19L, dp.timestamp()); 89 | assertEquals(1717171L, dp.toDouble(), 0); 90 | } 91 | 92 | @Test(expected = ClassCastException.class) 93 | public void testDoubleValue_castException() { 94 | MutableDataPoint dp = new MutableDataPoint(); 95 | dp.reset(19L, 1717171L); 96 | dp.doubleValue(); 97 | } 98 | 99 | @Test(expected = ClassCastException.class) 100 | public void testLongValue_castException() { 101 | MutableDataPoint dp = new MutableDataPoint(); 102 | dp.reset(17L, 0.1717); 103 | dp.longValue(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/uid/UniqueIdInterface.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.uid; 14 | 15 | import org.hbase.async.HBaseException; 16 | 17 | /** 18 | * Represents a table of Unique IDs, manages the lookup and creation of IDs. 19 | *

20 | * This interface is useless and deprecated. It provides no 21 | * benefits and will be removed eventually. No new methods are added to this 22 | * interface. Simply replace all uses of this interface with {@link UniqueId}. 23 | *

24 | * For efficiency, various kinds of "names" need to be mapped to small, unique 25 | * IDs. For instance, we give a unique ID to each metric name, to each tag 26 | * name, to each tag value. 27 | *

28 | * An instance of this class handles the unique IDs for one kind of ID. For 29 | * example: 30 | *

31 |  *   UniqueId metric_names = ...;
32 |  *   byte[] id = metric_names.get("sys.net.rx_bytes");
33 |  *   
34 | * 35 | * IDs are looked up in HBase and cached forever in memory (since they're 36 | * immutable). IDs are encoded on a fixed number of bytes, which is 37 | * implementation dependent. 38 | */ 39 | @Deprecated 40 | public interface UniqueIdInterface { 41 | 42 | /** 43 | * Returns what kind of Unique ID is served by this instance. 44 | */ 45 | String kind(); 46 | 47 | /** 48 | * Returns the number of bytes on which each Unique ID is encoded. 49 | */ 50 | short width(); 51 | 52 | /** 53 | * Finds the name associated with a given ID. 54 | * 55 | * @param id The ID associated with that name. 56 | * @see #getId(String) 57 | * @see #getOrCreateId(String) 58 | * @throws NoSuchUniqueId if the given ID is not assigned. 59 | * @throws HBaseException if there is a problem communicating with HBase. 60 | * @throws IllegalArgumentException if the ID given in argument is encoded 61 | * on the wrong number of bytes. 62 | */ 63 | String getName(byte[] id) throws NoSuchUniqueId, HBaseException; 64 | 65 | /** 66 | * Finds the ID associated with a given name. 67 | *

68 | * The length of the byte array is fixed in advance by the implementation. 69 | * 70 | * @param name The name to lookup in the table. 71 | * @see #getName(byte[]) 72 | * @return A non-null, non-empty {@code byte[]} array. 73 | * @throws NoSuchUniqueName if the name requested doesn't have an ID assigned. 74 | * @throws HBaseException if there is a problem communicating with HBase. 75 | * @throws IllegalStateException if the ID found in HBase is encoded on the 76 | * wrong number of bytes. 77 | */ 78 | byte[] getId(String name) throws NoSuchUniqueName, HBaseException; 79 | 80 | /** 81 | * Finds the ID associated with a given name or creates it. 82 | *

83 | * The length of the byte array is fixed in advance by the implementation. 84 | * 85 | * @param name The name to lookup in the table or to assign an ID to. 86 | * @throws HBaseException if there is a problem communicating with HBase. 87 | * @throws IllegalStateException if all possible IDs are already assigned. 88 | * @throws IllegalStateException if the ID found in HBase is encoded on the 89 | * wrong number of bytes. 90 | */ 91 | byte[] getOrCreateId(String name) throws HBaseException, IllegalStateException; 92 | 93 | } 94 | -------------------------------------------------------------------------------- /test/graph/TestPlot.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2011-2015 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.graph; 14 | 15 | import java.io.File; 16 | import java.io.PrintWriter; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | import net.opentsdb.utils.FileSystem; 21 | 22 | import org.junit.Before; 23 | import org.junit.Test; 24 | import org.junit.runner.RunWith; 25 | import org.mockito.Mockito; 26 | 27 | import static org.mockito.Mockito.times; 28 | import static org.mockito.Mockito.verify; 29 | 30 | import org.powermock.api.mockito.PowerMockito; 31 | import org.powermock.core.classloader.annotations.PrepareForTest; 32 | import org.powermock.modules.junit4.PowerMockRunner; 33 | @RunWith(PowerMockRunner.class) 34 | @PrepareForTest({PrintWriter.class, File.class, FileSystem.class, Plot.class}) 35 | public final class TestPlot { 36 | 37 | Plot plot; 38 | File mockFile; 39 | @Before 40 | public void setUp() throws Exception { 41 | plot = new Plot(0, 1234567890, null); 42 | Map params = new HashMap(); 43 | plot.setParams(params); 44 | 45 | PrintWriter mockWriter = PowerMockito.mock(PrintWriter.class); 46 | PowerMockito.whenNew(PrintWriter.class) 47 | .withAnyArguments() 48 | .thenReturn(mockWriter); 49 | 50 | // Mock the builder pattern for PrintWriter instances. 51 | PowerMockito.when(mockWriter, "append", Mockito.anyString()).thenReturn(mockWriter); 52 | PowerMockito.when(mockWriter, "append", Mockito.anyChar()).thenReturn(mockWriter); 53 | 54 | mockFile = PowerMockito.mock(File.class); 55 | PowerMockito.whenNew(File.class).withAnyArguments().thenReturn(mockFile); 56 | PowerMockito.when(mockFile, "getParent").thenReturn("/temp/opentsdb"); 57 | PowerMockito.when(mockFile, "exists").thenReturn(true); 58 | PowerMockito.when(mockFile, "isDirectory").thenReturn(true); 59 | PowerMockito.when(mockFile, "canWrite").thenReturn(true); 60 | } 61 | 62 | @Test 63 | public void dumpToFilesDirectoryExistsIsWritable() throws Exception { 64 | plot.dumpToFiles("/temp/opentsdb/s0M3haSh"); 65 | } 66 | 67 | @Test(expected = IllegalArgumentException.class) 68 | public void dumpToFilesDirectoryExistsNotWritable() throws Exception { 69 | PowerMockito.when(mockFile, "canWrite").thenReturn(false); 70 | plot.dumpToFiles("/temp/opentsdb/s0M3haSh"); 71 | } 72 | 73 | @Test 74 | public void dumpToFilesCreateNonexistentDirectory() throws Exception { 75 | PowerMockito.when(mockFile, "exists").thenReturn(false); 76 | PowerMockito.when(mockFile, "mkdirs").thenReturn(true); 77 | plot.dumpToFiles("/temp/opentsdb/s0M3haSh"); 78 | verify(mockFile, times(1)).mkdirs(); 79 | } 80 | 81 | @Test(expected = IllegalArgumentException.class) 82 | public void dumpToFilesCreateNonexistentDirectoryFail() throws Exception { 83 | PowerMockito.when(mockFile, "exists").thenReturn(false); 84 | PowerMockito.when(mockFile, "mkdirs").thenReturn(false); 85 | plot.dumpToFiles("/temp/opentsdb/s0M3haSh"); 86 | } 87 | 88 | @Test(expected = IllegalArgumentException.class) 89 | public void dumpToFilesNotADirectory() throws Exception { 90 | PowerMockito.when(mockFile, "exists").thenReturn(true); 91 | PowerMockito.when(mockFile, "isDirectory").thenReturn(false); 92 | plot.dumpToFiles("/temp/opentsdb/s0M3haSh"); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/tsd/SuggestRpc.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import java.io.IOException; 16 | import java.util.HashMap; 17 | import java.util.List; 18 | 19 | import org.jboss.netty.handler.codec.http.HttpMethod; 20 | import org.jboss.netty.handler.codec.http.HttpResponseStatus; 21 | 22 | import net.opentsdb.core.TSDB; 23 | import net.opentsdb.utils.JSON; 24 | 25 | /** 26 | * Handles the suggest endpoint that returns X number of metrics, tagks or 27 | * tagvs that start with the given string. It's used for auto-complete entries 28 | * and does not support wildcards. 29 | */ 30 | final class SuggestRpc implements HttpRpc { 31 | 32 | /** 33 | * Handles an HTTP based suggest query 34 | * Note: This method must remain backwards compatible with the 1.x 35 | * API call 36 | * @throws IOException if there is an error parsing the query or formatting 37 | * the output 38 | * @throws BadRequestException if the user supplied bad data 39 | */ 40 | public void execute(final TSDB tsdb, final HttpQuery query) 41 | throws IOException { 42 | 43 | // only accept GET/POST 44 | if (query.method() != HttpMethod.GET && query.method() != HttpMethod.POST) { 45 | throw new BadRequestException(HttpResponseStatus.METHOD_NOT_ALLOWED, 46 | "Method not allowed", "The HTTP method [" + query.method().getName() + 47 | "] is not permitted for this endpoint"); 48 | } 49 | 50 | final String type; 51 | final String q; 52 | final String max; 53 | if (query.apiVersion() > 0 && query.method() == HttpMethod.POST) { 54 | final HashMap map = query.serializer().parseSuggestV1(); 55 | type = map.get("type"); 56 | if (type == null || type.isEmpty()) { 57 | throw new BadRequestException("Missing 'type' parameter"); 58 | } 59 | q = map.get("q") == null ? "" : map.get("q"); 60 | max = map.get("max"); 61 | } else { 62 | type = query.getRequiredQueryStringParam("type"); 63 | q = query.hasQueryStringParam("q") ? query.getQueryStringParam("q") : ""; 64 | max = query.getQueryStringParam("max"); 65 | } 66 | 67 | final int max_results; 68 | if (max != null && !max.isEmpty()) { 69 | try { 70 | max_results = Integer.parseInt(max); 71 | } catch (NumberFormatException nfe) { 72 | throw new BadRequestException("Unable to parse 'max' as a number"); 73 | } 74 | } else { 75 | max_results = 0; 76 | } 77 | 78 | List suggestions; 79 | if ("metrics".equals(type)) { 80 | suggestions = max_results > 0 ? tsdb.suggestMetrics(q, max_results) : 81 | tsdb.suggestMetrics(q); 82 | } else if ("tagk".equals(type)) { 83 | suggestions = max_results > 0 ? tsdb.suggestTagNames(q, max_results) : 84 | tsdb.suggestTagNames(q); 85 | } else if ("tagv".equals(type)) { 86 | suggestions = max_results > 0 ? tsdb.suggestTagValues(q, max_results) : 87 | tsdb.suggestTagValues(q); 88 | } else { 89 | throw new BadRequestException("Invalid 'type' parameter:" + type); 90 | } 91 | 92 | if (query.apiVersion() > 0) { 93 | query.sendReply(query.serializer().formatSuggestV1(suggestions)); 94 | } else { // deprecated API 95 | query.sendReply(JSON.serializeToBytes(suggestions)); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /test/search/DummySearchPlugin.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.search; 14 | 15 | import net.opentsdb.core.TSDB; 16 | import net.opentsdb.meta.Annotation; 17 | import net.opentsdb.meta.TSMeta; 18 | import net.opentsdb.meta.UIDMeta; 19 | import net.opentsdb.stats.StatsCollector; 20 | 21 | import com.stumbleupon.async.Deferred; 22 | 23 | public final class DummySearchPlugin extends SearchPlugin { 24 | 25 | @Override 26 | public void initialize(TSDB tsdb) { 27 | if (tsdb == null) { 28 | throw new IllegalArgumentException("The TSDB object was null"); 29 | } 30 | // some dummy configs to check to throw exceptions 31 | if (!tsdb.getConfig().hasProperty("tsd.search.DummySearchPlugin.hosts")) { 32 | throw new IllegalArgumentException("Missing hosts config"); 33 | } 34 | if (tsdb.getConfig().getString("tsd.search.DummySearchPlugin.hosts") 35 | .isEmpty()) { 36 | throw new IllegalArgumentException("Empty Hosts config"); 37 | } 38 | // throw an NFE for fun 39 | tsdb.getConfig().getInt("tsd.search.DummySearchPlugin.port"); 40 | } 41 | 42 | @Override 43 | public Deferred shutdown() { 44 | return Deferred.fromResult(new Object()); 45 | } 46 | 47 | @Override 48 | public String version() { 49 | return "2.0.0"; 50 | } 51 | 52 | @Override 53 | public void collectStats(StatsCollector collector) { 54 | // Nothing to do now 55 | } 56 | 57 | @Override 58 | public Deferred indexTSMeta(TSMeta meta) { 59 | if (meta == null) { 60 | return Deferred.fromError(new IllegalArgumentException("Meta was null")); 61 | } else { 62 | return Deferred.fromResult(new Object()); 63 | } 64 | } 65 | 66 | @Override 67 | public Deferred deleteTSMeta(String tsuid) { 68 | if (tsuid == null || tsuid.isEmpty()) { 69 | return Deferred.fromError( 70 | new IllegalArgumentException("tsuid was null or empty")); 71 | } else { 72 | return Deferred.fromResult(new Object()); 73 | } 74 | } 75 | 76 | @Override 77 | public Deferred indexUIDMeta(UIDMeta meta) { 78 | if (meta == null) { 79 | return Deferred.fromError(new IllegalArgumentException("Meta was null")); 80 | } else { 81 | return Deferred.fromResult(new Object()); 82 | } 83 | } 84 | 85 | @Override 86 | public Deferred deleteUIDMeta(UIDMeta meta) { 87 | if (meta == null) { 88 | return Deferred.fromError(new IllegalArgumentException("Meta was null")); 89 | } else { 90 | return Deferred.fromResult(new Object()); 91 | } 92 | } 93 | 94 | @Override 95 | public Deferred indexAnnotation(Annotation note) { 96 | if (note == null) { 97 | return Deferred.fromError(new IllegalArgumentException("Meta was null")); 98 | } else { 99 | return Deferred.fromResult(new Object()); 100 | } 101 | } 102 | 103 | @Override 104 | public Deferred deleteAnnotation(Annotation note) { 105 | if (note == null) { 106 | return Deferred.fromError(new IllegalArgumentException("Meta was null")); 107 | } else { 108 | return Deferred.fromResult(new Object()); 109 | } 110 | } 111 | 112 | public Deferred executeQuery(final SearchQuery query) { 113 | if (query == null) { 114 | return Deferred.fromError(new IllegalArgumentException("Query was null")); 115 | } else { 116 | query.setTime(1.42F); 117 | query.setTotalResults(42); 118 | return Deferred.fromResult(query); 119 | } 120 | } 121 | 122 | 123 | } 124 | -------------------------------------------------------------------------------- /test/core/TestTSQuery.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertNotNull; 17 | import static org.mockito.Mockito.when; 18 | 19 | import java.util.ArrayList; 20 | 21 | import org.junit.Test; 22 | import org.junit.runner.RunWith; 23 | import org.powermock.api.mockito.PowerMockito; 24 | import org.powermock.core.classloader.annotations.PrepareForTest; 25 | import org.powermock.modules.junit4.PowerMockRunner; 26 | 27 | @RunWith(PowerMockRunner.class) 28 | @PrepareForTest({ TSQuery.class }) 29 | public final class TestTSQuery { 30 | 31 | @Test 32 | public void constructor() { 33 | assertNotNull(new TSQuery()); 34 | } 35 | 36 | @Test 37 | public void validate() { 38 | TSQuery q = this.getMetricForValidate(); 39 | q.validateAndSetQuery(); 40 | assertEquals(1356998400000L, q.startTime()); 41 | assertEquals(1356998460000L, q.endTime()); 42 | assertEquals("sys.cpu.0", q.getQueries().get(0).getMetric()); 43 | assertEquals("*", q.getQueries().get(0).getTags().get("host")); 44 | assertEquals("lga", q.getQueries().get(0).getTags().get("dc")); 45 | assertEquals(Aggregators.SUM, q.getQueries().get(0).aggregator()); 46 | assertEquals(Aggregators.AVG, q.getQueries().get(0).downsampler()); 47 | assertEquals(300000, q.getQueries().get(0).downsampleInterval()); 48 | } 49 | 50 | @Test (expected = IllegalArgumentException.class) 51 | public void validateNullStart() { 52 | TSQuery q = this.getMetricForValidate(); 53 | q.setStart(null); 54 | q.validateAndSetQuery(); 55 | } 56 | 57 | @Test (expected = IllegalArgumentException.class) 58 | public void validateEmptyStart() { 59 | TSQuery q = this.getMetricForValidate(); 60 | q.setStart(""); 61 | q.validateAndSetQuery(); 62 | } 63 | 64 | @Test (expected = IllegalArgumentException.class) 65 | public void validateInvalidStart() { 66 | TSQuery q = this.getMetricForValidate(); 67 | q.setStart("Not a timestamp at all"); 68 | q.validateAndSetQuery(); 69 | } 70 | 71 | @Test 72 | public void validateNullEnd() { 73 | PowerMockito.mockStatic(System.class); 74 | when(System.currentTimeMillis()).thenReturn(1357300800000L); 75 | TSQuery q = this.getMetricForValidate(); 76 | q.setEnd(null); 77 | q.validateAndSetQuery(); 78 | assertEquals(1357300800000L, q.endTime()); 79 | } 80 | 81 | @Test 82 | public void validateEmptyEnd() { 83 | PowerMockito.mockStatic(System.class); 84 | when(System.currentTimeMillis()).thenReturn(1357300800000L); 85 | TSQuery q = this.getMetricForValidate(); 86 | q.setEnd(""); 87 | q.validateAndSetQuery(); 88 | assertEquals(1357300800000L, q.endTime()); 89 | } 90 | 91 | @Test (expected = IllegalArgumentException.class) 92 | public void validateNullQueries() { 93 | TSQuery q = this.getMetricForValidate(); 94 | q.setQueries(null); 95 | q.validateAndSetQuery(); 96 | } 97 | 98 | @Test (expected = IllegalArgumentException.class) 99 | public void validateEmptyQueries() { 100 | TSQuery q = this.getMetricForValidate(); 101 | q.setQueries(new ArrayList()); 102 | q.validateAndSetQuery(); 103 | } 104 | 105 | private TSQuery getMetricForValidate() { 106 | final TSQuery query = new TSQuery(); 107 | query.setStart("1356998400"); 108 | query.setEnd("1356998460"); 109 | final ArrayList subs = new ArrayList(1); 110 | subs.add(TestTSSubQuery.getMetricForValidate()); 111 | query.setQueries(subs); 112 | return query; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /test/utils/TestPluginLoader.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013-2014 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.utils; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertNotNull; 17 | import static org.junit.Assert.assertNull; 18 | 19 | import java.io.FileNotFoundException; 20 | import java.util.List; 21 | 22 | import net.opentsdb.plugin.DummyPlugin; 23 | import net.opentsdb.utils.PluginLoader; 24 | 25 | import org.junit.Test; 26 | 27 | public final class TestPluginLoader { 28 | 29 | @Test 30 | public void loadJar() throws Exception { 31 | PluginLoader.loadJAR("plugin_test.jar"); 32 | } 33 | 34 | @Test (expected = FileNotFoundException.class) 35 | public void loadJarDoesNotExist() throws Exception { 36 | PluginLoader.loadJAR("jardoesnotexist.jar"); 37 | } 38 | 39 | @Test (expected = IllegalArgumentException.class) 40 | public void loadJarDoesNotAJar() throws Exception { 41 | PluginLoader.loadJAR("notajar.png"); 42 | } 43 | 44 | @Test (expected = NullPointerException.class) 45 | public void loadJarNull() throws Exception { 46 | PluginLoader.loadJAR(null); 47 | } 48 | 49 | @Test (expected = IllegalArgumentException.class) 50 | public void loadJarEmpty() throws Exception { 51 | PluginLoader.loadJAR(""); 52 | } 53 | 54 | // todo - test for security exceptions? 55 | 56 | @Test 57 | public void loadJars() throws Exception { 58 | PluginLoader.loadJARs("./"); 59 | } 60 | 61 | @Test (expected = IllegalArgumentException.class) 62 | public void loadJarsDoesNotExist() throws Exception { 63 | PluginLoader.loadJARs("./dirdoesnotexist"); 64 | } 65 | 66 | @Test (expected = NullPointerException.class) 67 | public void loadJarsNull() throws Exception { 68 | PluginLoader.loadJARs(null); 69 | } 70 | 71 | @Test (expected = IllegalArgumentException.class) 72 | public void loadJarsEmpty() throws Exception { 73 | PluginLoader.loadJARs(""); 74 | } 75 | 76 | @Test 77 | public void loadSpecificPlugin() throws Exception { 78 | PluginLoader.loadJAR("plugin_test.jar"); 79 | DummyPlugin plugin = PluginLoader.loadSpecificPlugin( 80 | "net.opentsdb.plugin.DummyPluginA", 81 | DummyPlugin.class); 82 | assertNotNull(plugin); 83 | assertEquals("Dummy Plugin A", plugin.myname); 84 | } 85 | 86 | @Test 87 | public void loadSpecificPluginImplementationNotFound() throws Exception { 88 | PluginLoader.loadJAR("plugin_test.jar"); 89 | DummyPlugin plugin = PluginLoader.loadSpecificPlugin( 90 | "net.opentsdb.plugin.DummyPluginC", 91 | DummyPlugin.class); 92 | assertNull(plugin); 93 | } 94 | 95 | @Test 96 | public void loadSpecificPluginNotFound() throws Exception { 97 | PluginLoader.loadJAR("plugin_test.jar"); 98 | DummyPluginBad plugin = PluginLoader.loadSpecificPlugin( 99 | "net.opentsdb.plugin.DummyPluginC", 100 | DummyPluginBad.class); 101 | assertNull(plugin); 102 | } 103 | 104 | @Test 105 | public void loadPlugins() throws Exception { 106 | List plugins = PluginLoader.loadPlugins( 107 | DummyPlugin.class); 108 | assertNotNull(plugins); 109 | assertEquals(2, plugins.size()); 110 | } 111 | 112 | @Test 113 | public void loadPluginsNotFound() throws Exception { 114 | List plugins = PluginLoader.loadPlugins( 115 | DummyPluginBad.class); 116 | assertNull(plugins); 117 | } 118 | 119 | public abstract class DummyPluginBad { 120 | protected String myname; 121 | 122 | public DummyPluginBad() { 123 | myname = ""; 124 | } 125 | 126 | public abstract String mustImplement(); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/utils/Pair.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2014 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.utils; 14 | 15 | /** 16 | * Simple key/value pair class where either of the values may be null. 17 | * Pairs are particularly useful in lists where you may have duplicate keys, 18 | * values or both. This class also deserializes easily through Jackson. 19 | * 20 | * Other implementations of pairs exist: 21 | * - {@code org.apache.commons.lang3.tuple.Pair} is one an example but we don't 22 | * want to include a whole dependency for a single class. 23 | * - {@code java.util.Map.Entry} is an interface implemented by 24 | * {@code java.util.AbstractMap.SimpleEntry} and that works great throughout the 25 | * code but Jackson chokes on deserializing and would require a complicated, 26 | * custom deserializer class. 27 | * 28 | * Thus we have this class that can be deserialized easily when nested in 29 | * another class like a list with: 30 | * {@code final TypeReference>> TR = 31 | * new TypeReference>>() \{\};} 32 | * 33 | * @param Object type for the key 34 | * @param Object type for the value 35 | */ 36 | public class Pair { 37 | 38 | /** The key or left hand value */ 39 | protected K key; 40 | 41 | /** The value or right hand value */ 42 | protected V value; 43 | 44 | /** 45 | * Default ctor that leaves the key and value objects as null 46 | */ 47 | public Pair() { 48 | } 49 | 50 | /** 51 | * Ctor that stores references to the objects 52 | * @param key The key or left hand value to store 53 | * @param value The value or right hand value to store 54 | */ 55 | public Pair(final K key, final V value) { 56 | this.key = key; 57 | this.value = value; 58 | } 59 | 60 | /** 61 | * Calculates the hash by ORing the key and value hash codes 62 | * @return a hash code for this pair 63 | */ 64 | @Override 65 | public int hashCode() { 66 | return (key == null ? 0 : key.hashCode()) ^ 67 | (value == null ? 0 : value.hashCode()); 68 | } 69 | 70 | /** @return a descriptive string in the format "key=K, value=V" */ 71 | @Override 72 | public String toString() { 73 | return new StringBuilder().append("key=") 74 | .append(key).append(", value=").append(value).toString(); 75 | } 76 | 77 | /** 78 | * Compares the two pairs for equality. If the incoming object reference is 79 | * the same, the result is true. Then {@code .equals} is called on both 80 | * objects (if they are not null) 81 | * @return true if the objects refer to the same address or both objects are 82 | * equal 83 | */ 84 | @Override 85 | public boolean equals(final Object object) { 86 | if (object == this) { 87 | return true; 88 | } 89 | if (object instanceof Pair) { 90 | final Pair other_pair = (Pair)object; 91 | return 92 | (key == null ? other_pair.getKey() == null : 93 | key.equals(other_pair.key)) 94 | && (value == null ? other_pair.getValue() == null : 95 | value.equals(other_pair.value)); 96 | } 97 | return false; 98 | } 99 | 100 | /** @return The stored key/left value, may be null */ 101 | public K getKey() { 102 | return key; 103 | } 104 | 105 | /** @return The stored value/right value, may be null */ 106 | public V getValue() { 107 | return value; 108 | } 109 | 110 | /** @param key The key/left value to store, may be null */ 111 | public void setKey(final K key) { 112 | this.key = key; 113 | } 114 | 115 | /** @param value The value/right value to store, may be null */ 116 | public void setValue(final V value) { 117 | this.value = value; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/core/MutableDataPoint.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2014 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | 16 | /** 17 | * A mutable {@link DataPoint} that stores a value and a timestamp. 18 | */ 19 | public final class MutableDataPoint implements DataPoint { 20 | 21 | // NOTE: Fields are not final to make an instance available to store a new 22 | // pair of a timestamp and a value to reduce memory burden. 23 | /** The timestamp of the value. */ 24 | private long timestamp = Long.MAX_VALUE; 25 | /** True if the value is stored as a long. */ 26 | private boolean is_integer = true; 27 | /** A long value or a double encoded on a long if {@code is_integer} is false. */ 28 | private long value = 0; 29 | 30 | /** 31 | * Resets with a new pair of a timestamp and a double value. 32 | * 33 | * @param timestamp A timestamp. 34 | * @param value A double value. 35 | */ 36 | public void reset(final long timestamp, final double value) { 37 | this.timestamp = timestamp; 38 | this.is_integer = false; 39 | this.value = Double.doubleToRawLongBits(value); 40 | } 41 | 42 | /** 43 | * Resets with a new pair of a timestamp and a long value. 44 | * 45 | * @param timestamp A timestamp. 46 | * @param value A double value. 47 | */ 48 | public void reset(final long timestamp, final long value) { 49 | this.timestamp = timestamp; 50 | this.is_integer = true; 51 | this.value = value; 52 | } 53 | 54 | /** 55 | * Resets with a new data point. 56 | * 57 | * @param dp A new data point to store. 58 | */ 59 | public void reset(DataPoint dp) { 60 | this.timestamp = dp.timestamp(); 61 | this.is_integer = dp.isInteger(); 62 | if (is_integer) { 63 | this.value = dp.longValue(); 64 | } else { 65 | this.value = Double.doubleToRawLongBits(dp.doubleValue()); 66 | } 67 | } 68 | 69 | /** 70 | * Resets with a new pair of a timestamp and a double value. 71 | * 72 | * @param timestamp A timestamp. 73 | * @param value A double value. 74 | */ 75 | public static MutableDataPoint ofDoubleValue(final long timestamp, 76 | final double value) { 77 | final MutableDataPoint dp = new MutableDataPoint(); 78 | dp.reset(timestamp, value); 79 | return dp; 80 | } 81 | 82 | /** 83 | * Resets with a new pair of a timestamp and a long value. 84 | * 85 | * @param timestamp A timestamp. 86 | * @param value A double value. 87 | */ 88 | public static MutableDataPoint ofLongValue(final long timestamp, 89 | final long value) { 90 | final MutableDataPoint dp = new MutableDataPoint(); 91 | dp.reset(timestamp, value); 92 | return dp; 93 | } 94 | 95 | @Override 96 | public long timestamp() { 97 | return timestamp; 98 | } 99 | 100 | @Override 101 | public boolean isInteger() { 102 | return is_integer; 103 | } 104 | 105 | @Override 106 | public long longValue() { 107 | if (is_integer) { 108 | return value; 109 | } 110 | throw new ClassCastException("Not a long in " + toString()); 111 | } 112 | 113 | @Override 114 | public double doubleValue() { 115 | if (!is_integer) { 116 | return Double.longBitsToDouble(value); 117 | } 118 | throw new ClassCastException("Not a double in " + toString()); 119 | } 120 | 121 | @Override 122 | public double toDouble() { 123 | if (is_integer) { 124 | return value; 125 | } 126 | return Double.longBitsToDouble(value); 127 | } 128 | 129 | @Override 130 | public String toString() { 131 | return "MutableDataPoint(timestamp=" + timestamp + ", is_integer=" + 132 | is_integer + ", value=" + 133 | (is_integer ? value : Double.longBitsToDouble(value)) + ")"; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/core/DataPointsIterator.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | import java.util.NoSuchElementException; 16 | 17 | /** Default iterator for simple implementations of {@link DataPoints}. */ 18 | final class DataPointsIterator implements SeekableView, DataPoint { 19 | 20 | /** Instance to iterate on. */ 21 | private final DataPoints dp; 22 | 23 | /** Where are we in the iteration. */ 24 | private short index = -1; 25 | 26 | /** 27 | * Ctor. 28 | * @param dp The data points to iterate on. 29 | */ 30 | DataPointsIterator(final DataPoints dp) { 31 | this.dp = dp; 32 | } 33 | 34 | // ------------------ // 35 | // Iterator interface // 36 | // ------------------ // 37 | 38 | public boolean hasNext() { 39 | return index < dp.size() - 1; 40 | } 41 | 42 | public DataPoint next() { 43 | if (hasNext()) { 44 | index++; 45 | return this; 46 | } 47 | throw new NoSuchElementException("no more elements in " + this); 48 | } 49 | 50 | public void remove() { 51 | throw new UnsupportedOperationException(); 52 | } 53 | 54 | // ---------------------- // 55 | // SeekableView interface // 56 | // ---------------------- // 57 | 58 | public void seek(final long timestamp) { 59 | if ((timestamp & 0xFFFFFFFF00000000L) != 0) { // negative or not 32 bits 60 | throw new IllegalArgumentException("invalid timestamp: " + timestamp); 61 | } 62 | // Do a binary search to find the timestamp given or the one right before. 63 | short lo = 0; 64 | short hi = (short) dp.size(); 65 | 66 | while (lo <= hi) { 67 | index = (short) ((lo + hi) >>> 1); 68 | long cmp = dp.timestamp(index) - timestamp; 69 | 70 | if (cmp < 0) { 71 | lo = (short) (index + 1); 72 | } else if (cmp > 0) { 73 | hi = (short) (index - 1); 74 | } else { 75 | index--; // 'index' is exactly on the timestamp wanted. 76 | return; // So let's go right before that for next(). 77 | } 78 | } 79 | // We found the timestamp right before as there was no exact match. 80 | // We take that position - 1 so the next call to next() returns it. 81 | index = (short) (lo - 1); 82 | // If the index we found was not the first or the last point, let's 83 | // do a small extra sanity check to ensure the position we found makes 84 | // sense: the timestamp we're at must not be >= what we're looking for. 85 | if (0 < index && index < dp.size() && dp.timestamp(index) >= timestamp) { 86 | throw new AssertionError("seeked after the time wanted!" 87 | + " timestamp=" + timestamp 88 | + ", index=" + index 89 | + ", dp.timestamp(index)=" + dp.timestamp(index) 90 | + ", this=" + this); 91 | } 92 | } 93 | 94 | /** Package-private helper to find the current index of this iterator. */ 95 | int index() { 96 | return index; 97 | } 98 | 99 | // ------------------- // 100 | // DataPoint interface // 101 | // ------------------- // 102 | 103 | public long timestamp() { 104 | return dp.timestamp(index); 105 | } 106 | 107 | public boolean isInteger() { 108 | return dp.isInteger(index); 109 | } 110 | 111 | public long longValue() { 112 | return dp.longValue(index); 113 | } 114 | 115 | public double doubleValue() { 116 | return dp.doubleValue(index); 117 | } 118 | 119 | public double toDouble() { 120 | return isInteger() ? longValue() : doubleValue(); 121 | } 122 | 123 | public String toString() { 124 | return "DataPointsIterator(index=" + index 125 | + (index >= 0 126 | ? ", current type: " + (isInteger() ? "long" : "float") 127 | + ", current value=" + (isInteger() ? longValue() : doubleValue()) 128 | : " (iteration not started)") 129 | + ", dp=" + dp + ')'; 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/core/RateOptions.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | /** 16 | * Provides additional options that will be used when calculating rates. These 17 | * options are useful when working with metrics that are raw counter values, 18 | * where a counter is defined by a value that always increases until it hits 19 | * a maximum value and then it "rolls over" to start back at 0. 20 | *

21 | * These options will only be utilized if the query is for a rate calculation 22 | * and if the "counter" options is set to true. 23 | * @since 2.0 24 | */ 25 | public class RateOptions { 26 | public static final long DEFAULT_RESET_VALUE = 0; 27 | 28 | /** 29 | * If true, then when calculating a rate of change assume that the metric 30 | * values are counters and thus non-zero, always increasing and wrap around at 31 | * some maximum 32 | */ 33 | private boolean counter; 34 | 35 | /** 36 | * If calculating a rate of change over a metric that is a counter, then this 37 | * value specifies the maximum value the counter will obtain before it rolls 38 | * over. This value will default to Long.MAX_VALUE. 39 | */ 40 | private long counter_max; 41 | 42 | /** 43 | * Specifies the the rate change value which, if exceeded, will be considered 44 | * a data anomaly, such as a system reset of the counter, and the rate will be 45 | * returned as a zero value for a given data point. 46 | */ 47 | private long reset_value; 48 | 49 | /** 50 | * Ctor 51 | */ 52 | public RateOptions() { 53 | this.counter = false; 54 | this.counter_max = Long.MAX_VALUE; 55 | this.reset_value = DEFAULT_RESET_VALUE; 56 | } 57 | 58 | /** 59 | * Ctor 60 | * @param counter If true, indicates that the rate calculation should assume 61 | * that the underlying data is from a counter 62 | * @param counter_max Specifies the maximum value for the counter before it 63 | * will roll over and restart at 0 64 | * @param reset_value Specifies the largest rate change that is considered 65 | * acceptable, if a rate change is seen larger than this value then the 66 | * counter is assumed to have been reset 67 | */ 68 | public RateOptions(final boolean counter, final long counter_max, 69 | final long reset_value) { 70 | this.counter = counter; 71 | this.counter_max = counter_max; 72 | this.reset_value = reset_value; 73 | } 74 | 75 | /** @return Whether or not the counter flag is set */ 76 | public boolean isCounter() { 77 | return counter; 78 | } 79 | 80 | /** @return The counter max value */ 81 | public long getCounterMax() { 82 | return counter_max; 83 | } 84 | 85 | /** @return The optional reset value for anomaly suppression */ 86 | public long getResetValue() { 87 | return reset_value; 88 | } 89 | 90 | /** @param counter Whether or not the time series should be considered counters */ 91 | public void setIsCounter(boolean counter) { 92 | this.counter = counter; 93 | } 94 | 95 | /** @param counter_max The value at which counters roll over */ 96 | public void setCounterMax(long counter_max) { 97 | this.counter_max = counter_max; 98 | } 99 | 100 | /** @param reset_value A difference that may be an anomaly so suppress it */ 101 | public void setResetValue(long reset_value) { 102 | this.reset_value = reset_value; 103 | } 104 | 105 | /** 106 | * Generates a String version of the rate option instance in a format that 107 | * can be utilized in a query. 108 | * @return string version of the rate option instance. 109 | */ 110 | public String toString() { 111 | StringBuilder buf = new StringBuilder(); 112 | buf.append('{'); 113 | buf.append(counter); 114 | buf.append(',').append(counter_max); 115 | buf.append(',').append(reset_value); 116 | buf.append('}'); 117 | return buf.toString(); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /test/core/TestAggregators.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | import java.util.Random; 16 | 17 | import org.junit.Assert; 18 | import org.junit.Test; 19 | 20 | public final class TestAggregators { 21 | 22 | private static final Random random; 23 | static { 24 | final long seed = System.nanoTime(); 25 | System.out.println("Random seed: " + seed); 26 | random = new Random(seed); 27 | } 28 | 29 | /** 30 | * Epsilon used to compare floating point values. 31 | * Instead of using a fixed epsilon to compare our numbers, we calculate 32 | * it based on the percentage of our actual expected values. We do things 33 | * this way because our numbers can be extremely large and if you change 34 | * the scale of the numbers a static precision may no longer work 35 | */ 36 | private static final double EPSILON_PERCENTAGE = 0.0001; 37 | 38 | /** Helper class to hold a bunch of numbers we can iterate on. */ 39 | private static final class Numbers implements Aggregator.Longs, Aggregator.Doubles { 40 | private final long[] numbers; 41 | private int i = 0; 42 | 43 | public Numbers(final long[] numbers) { 44 | this.numbers = numbers; 45 | } 46 | 47 | @Override 48 | public boolean hasNextValue() { 49 | return i < numbers.length; 50 | } 51 | 52 | @Override 53 | public long nextLongValue() { 54 | return numbers[i++]; 55 | } 56 | 57 | @Override 58 | public double nextDoubleValue() { 59 | return numbers[i++]; 60 | } 61 | 62 | void reset() { 63 | i = 0; 64 | } 65 | } 66 | 67 | @Test 68 | public void testStdDevKnownValues() { 69 | final long[] values = new long[10000]; 70 | for (int i = 0; i < values.length; i++) { 71 | values[i] = i; 72 | } 73 | // Expected value calculated by NumPy 74 | // $ python2.7 75 | // >>> import numpy 76 | // >>> numpy.std(range(10000)) 77 | // 2886.7513315143719 78 | final double expected = 2886.7513315143719D; 79 | final double epsilon = 0.01; 80 | checkSimilarStdDev(values, expected, epsilon); 81 | } 82 | 83 | @Test 84 | public void testStdDevRandomValues() { 85 | final long[] values = new long[1000]; 86 | for (int i = 0; i < values.length; i++) { 87 | values[i] = random.nextLong(); 88 | } 89 | final double expected = naiveStdDev(values); 90 | // Calculate the epsilon based on the percentage of the number. 91 | final double epsilon = EPSILON_PERCENTAGE * expected; 92 | checkSimilarStdDev(values, expected, epsilon); 93 | } 94 | 95 | @Test 96 | public void testStdDevNoDeviation() { 97 | final long[] values = {3,3,3}; 98 | 99 | final double expected = 0; 100 | checkSimilarStdDev(values, expected, 0); 101 | } 102 | 103 | @Test 104 | public void testStdDevFewDataInputs() { 105 | final long[] values = {1,2}; 106 | 107 | final double expected = 0.5; 108 | checkSimilarStdDev(values, expected, 0); 109 | } 110 | 111 | private static void checkSimilarStdDev(final long[] values, 112 | final double expected, 113 | final double epsilon) { 114 | final Numbers numbers = new Numbers(values); 115 | final Aggregator agg = Aggregators.get("dev"); 116 | 117 | Assert.assertEquals(expected, agg.runDouble(numbers), epsilon); 118 | numbers.reset(); 119 | Assert.assertEquals(expected, agg.runLong(numbers), Math.max(epsilon, 1.0)); 120 | } 121 | 122 | private static double naiveStdDev(long[] values) { 123 | double sum = 0; 124 | for (final double value : values) { 125 | sum += value; 126 | } 127 | double mean = sum / values.length; 128 | 129 | double squaresum = 0; 130 | for (final double value : values) { 131 | squaresum += Math.pow(value - mean, 2); 132 | } 133 | final double variance = squaresum / values.length; 134 | return Math.sqrt(variance); 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /test/tsd/TestRTPublisher.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertNotNull; 17 | import static org.mockito.Mockito.when; 18 | import static org.powermock.api.mockito.PowerMockito.mock; 19 | 20 | import java.util.Collections; 21 | import java.util.HashMap; 22 | 23 | import net.opentsdb.core.TSDB; 24 | import net.opentsdb.meta.Annotation; 25 | import net.opentsdb.utils.Config; 26 | import net.opentsdb.utils.PluginLoader; 27 | 28 | import org.junit.Before; 29 | import org.junit.Test; 30 | import org.junit.runner.RunWith; 31 | import org.powermock.core.classloader.annotations.PowerMockIgnore; 32 | import org.powermock.core.classloader.annotations.PrepareForTest; 33 | import org.powermock.modules.junit4.PowerMockRunner; 34 | 35 | @PowerMockIgnore({"javax.management.*", "javax.xml.*", 36 | "ch.qos.*", "org.slf4j.*", 37 | "com.sum.*", "org.xml.*"}) 38 | @RunWith(PowerMockRunner.class) 39 | @PrepareForTest({TSDB.class, Config.class}) 40 | public final class TestRTPublisher { 41 | private TSDB tsdb= mock(TSDB.class); 42 | private Config config = mock(Config.class); 43 | private RTPublisher rt_publisher; 44 | 45 | @Before 46 | public void before() throws Exception { 47 | // setups a good default for the config 48 | when(config.hasProperty("tsd.rtpublisher.DummyRTPublisher.hosts")) 49 | .thenReturn(true); 50 | when(config.getString("tsd.rtpublisher.DummyRTPublisher.hosts")) 51 | .thenReturn("localhost"); 52 | when(config.getInt("tsd.rtpublisher.DummyRTPublisher.port")).thenReturn(42); 53 | when(tsdb.getConfig()).thenReturn(config); 54 | PluginLoader.loadJAR("plugin_test.jar"); 55 | rt_publisher = PluginLoader.loadSpecificPlugin( 56 | "net.opentsdb.tsd.DummyRTPublisher", RTPublisher.class); 57 | } 58 | 59 | @Test 60 | public void initialize() throws Exception { 61 | rt_publisher.initialize(tsdb); 62 | } 63 | 64 | @Test (expected = IllegalArgumentException.class) 65 | public void initializeMissingHost() throws Exception { 66 | when(config.hasProperty("tsd.rtpublisher.DummyRTPublisher.hosts")) 67 | .thenReturn(false); 68 | rt_publisher.initialize(tsdb); 69 | } 70 | 71 | public void initializeEmptyHost() throws Exception { 72 | when(config.getString("tsd.rtpublisher.DummyRTPublisher.hosts")) 73 | .thenReturn(""); 74 | rt_publisher.initialize(tsdb); 75 | } 76 | 77 | @Test (expected = NullPointerException.class) 78 | public void initializeMissingPort() throws Exception { 79 | when(config.getInt("tsd.rtpublisher.DummyRTPublisher.port")) 80 | .thenThrow(new NullPointerException()); 81 | rt_publisher.initialize(tsdb); 82 | } 83 | 84 | @Test (expected = IllegalArgumentException.class) 85 | public void initializeInvalidPort() throws Exception { 86 | when(config.getInt("tsd.rtpublisher.DummyRTPublisher.port")) 87 | .thenThrow(new NumberFormatException()); 88 | rt_publisher.initialize(tsdb); 89 | } 90 | 91 | @Test 92 | public void shutdown() throws Exception { 93 | assertNotNull(rt_publisher.shutdown()); 94 | } 95 | 96 | @Test 97 | public void version() throws Exception { 98 | assertEquals("2.0.0", rt_publisher.version()); 99 | } 100 | 101 | @Test 102 | public void sinkDataPoint() throws Exception { 103 | assertNotNull(rt_publisher.sinkDataPoint("sys.cpu.user", 104 | System.currentTimeMillis(), new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, 105 | null, null, (short)0x7)); 106 | } 107 | 108 | @Test 109 | public void publishAnnotation() throws Exception { 110 | Annotation ann = new Annotation(); 111 | HashMap customMap = new HashMap(1); 112 | customMap.put("test-custom-key", "test-custom-value"); 113 | ann.setCustom(customMap); 114 | ann.setDescription("A test annotation"); 115 | ann.setNotes("Test annotation notes"); 116 | ann.setStartTime(System.currentTimeMillis()); 117 | assertNotNull(rt_publisher.publishAnnotation(ann)); 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /test/core/TestTSSubQuery.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | import static org.junit.Assert.assertEquals; 16 | import static org.junit.Assert.assertNotNull; 17 | import static org.junit.Assert.assertNull; 18 | 19 | import java.util.ArrayList; 20 | import java.util.HashMap; 21 | 22 | import org.junit.Test; 23 | 24 | public final class TestTSSubQuery { 25 | 26 | @Test 27 | public void constructor() { 28 | assertNotNull(new TSSubQuery()); 29 | } 30 | 31 | @Test 32 | public void validate() { 33 | TSSubQuery sub = getMetricForValidate(); 34 | sub.validateAndSetQuery(); 35 | assertEquals("sys.cpu.0", sub.getMetric()); 36 | assertEquals("*", sub.getTags().get("host")); 37 | assertEquals("lga", sub.getTags().get("dc")); 38 | assertEquals(Aggregators.SUM, sub.aggregator()); 39 | assertEquals(Aggregators.AVG, sub.downsampler()); 40 | assertEquals(300000, sub.downsampleInterval()); 41 | } 42 | 43 | @Test 44 | public void validateTS() { 45 | TSSubQuery sub = getMetricForValidate(); 46 | sub.setMetric(null); 47 | ArrayList tsuids = new ArrayList(1); 48 | tsuids.add("ABCD"); 49 | sub.setTsuids(tsuids); 50 | sub.validateAndSetQuery(); 51 | assertNotNull(sub.getTsuids()); 52 | assertEquals("*", sub.getTags().get("host")); 53 | assertEquals("lga", sub.getTags().get("dc")); 54 | assertEquals(Aggregators.SUM, sub.aggregator()); 55 | assertEquals(Aggregators.AVG, sub.downsampler()); 56 | assertEquals(300000, sub.downsampleInterval()); 57 | } 58 | 59 | @Test 60 | public void validateNoDS() { 61 | TSSubQuery sub = getMetricForValidate(); 62 | sub.setDownsample(null); 63 | sub.validateAndSetQuery(); 64 | assertEquals("sys.cpu.0", sub.getMetric()); 65 | assertEquals("*", sub.getTags().get("host")); 66 | assertEquals("lga", sub.getTags().get("dc")); 67 | assertEquals(Aggregators.SUM, sub.aggregator()); 68 | assertNull(sub.downsampler()); 69 | assertEquals(0, sub.downsampleInterval()); 70 | } 71 | 72 | @Test (expected = IllegalArgumentException.class) 73 | public void validateNullAgg() { 74 | TSSubQuery sub = getMetricForValidate(); 75 | sub.setAggregator(null); 76 | sub.validateAndSetQuery(); 77 | } 78 | 79 | @Test (expected = IllegalArgumentException.class) 80 | public void validateEmptyAgg() { 81 | TSSubQuery sub = getMetricForValidate(); 82 | sub.setAggregator(""); 83 | sub.validateAndSetQuery(); 84 | } 85 | 86 | @Test (expected = IllegalArgumentException.class) 87 | public void validateBadAgg() { 88 | TSSubQuery sub = getMetricForValidate(); 89 | sub.setAggregator("Notanagg"); 90 | sub.validateAndSetQuery(); 91 | } 92 | 93 | @Test (expected = IllegalArgumentException.class) 94 | public void validateNoMetricOrTsuids() { 95 | TSSubQuery sub = getMetricForValidate(); 96 | sub.setMetric(null); 97 | sub.setTsuids(null); 98 | sub.validateAndSetQuery(); 99 | } 100 | 101 | @Test (expected = IllegalArgumentException.class) 102 | public void validateNoMetricOrEmptyTsuids() { 103 | TSSubQuery sub = getMetricForValidate(); 104 | sub.setMetric(null); 105 | sub.setTsuids(new ArrayList()); 106 | sub.validateAndSetQuery(); 107 | } 108 | 109 | @Test (expected = IllegalArgumentException.class) 110 | public void validateBadDS() { 111 | TSSubQuery sub = getMetricForValidate(); 112 | sub.setDownsample("bad"); 113 | sub.validateAndSetQuery(); 114 | } 115 | 116 | /** 117 | * Sets up an object with good, common values for testing the validation 118 | * function with an "m" type query (no tsuids). Each test can "set" the 119 | * method it wants to fool with and call .validateAndSetQuery() 120 | * Warning: This method is also shared by {@link TestTSQuery} so be 121 | * careful if you change any values 122 | * @return A sub query object 123 | */ 124 | public static TSSubQuery getMetricForValidate() { 125 | final TSSubQuery sub = new TSSubQuery(); 126 | sub.setAggregator("sum"); 127 | sub.setDownsample("5m-avg"); 128 | sub.setMetric("sys.cpu.0"); 129 | sub.setRate(false); 130 | final HashMap tags = new HashMap(); 131 | tags.put("host", "*"); 132 | tags.put("dc", "lga"); 133 | sub.setTags(tags); 134 | return sub; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/core/IncomingDataPoint.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2013 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.core; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | import com.fasterxml.jackson.annotation.JsonInclude; 19 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 20 | 21 | /** 22 | * Bridging class that stores a normalized data point parsed from the "put" 23 | * RPC methods and gets it ready for storage. Also has some helper methods that 24 | * were formerly in the Tags class for parsing values. 25 | *

26 | * The data point value is a string in order to accept a wide range of values 27 | * including floating point and scientific. Before storage, the value will 28 | * be parsed to the appropriate numeric type. 29 | *

30 | * Note the class is not marked as final since some serializers may want to 31 | * overload with their own fields or parsing methods. 32 | * @since 2.0 33 | */ 34 | @JsonInclude(Include.NON_NULL) 35 | public class IncomingDataPoint { 36 | /** The incoming metric name */ 37 | private String metric; 38 | 39 | /** The incoming timestamp in Unix epoch seconds or milliseconds */ 40 | private long timestamp; 41 | 42 | /** The incoming value as a string, we'll parse it to float or int later */ 43 | private String value; 44 | 45 | /** A hash map of tag name/values */ 46 | private HashMap tags; 47 | 48 | /** TSUID for the data point */ 49 | private String tsuid; 50 | 51 | /** 52 | * Empty constructor necessary for some de/serializers 53 | */ 54 | public IncomingDataPoint() { 55 | 56 | } 57 | 58 | /** 59 | * Constructor used when working with a metric and tags 60 | * @param metric The metric name 61 | * @param timestamp The Unix epoch timestamp 62 | * @param value The value as a string 63 | * @param tags The tag name/value map 64 | */ 65 | public IncomingDataPoint(final String metric, 66 | final long timestamp, 67 | final String value, 68 | final HashMap tags) { 69 | this.metric = metric; 70 | this.timestamp = timestamp; 71 | this.value = value; 72 | this.tags = tags; 73 | } 74 | 75 | /** 76 | * Constructor used when working with tsuids 77 | * @param tsuid The TSUID 78 | * @param timestamp The Unix epoch timestamp 79 | * @param value The value as a string 80 | */ 81 | public IncomingDataPoint(final String tsuid, 82 | final long timestamp, 83 | final String value) { 84 | this.tsuid = tsuid; 85 | this.timestamp = timestamp; 86 | this.value = value; 87 | } 88 | 89 | /** 90 | * @return information about this object 91 | */ 92 | @Override 93 | public String toString() { 94 | final StringBuilder buf = new StringBuilder(); 95 | buf.append("metric=").append(this.metric); 96 | buf.append(" ts=").append(this.timestamp); 97 | buf.append(" value=").append(this.value).append(" "); 98 | if (this.tags != null) { 99 | for (Map.Entry entry : this.tags.entrySet()) { 100 | buf.append(entry.getKey()).append("=").append(entry.getValue()); 101 | } 102 | } 103 | return buf.toString(); 104 | } 105 | 106 | /** @return the metric */ 107 | public final String getMetric() { 108 | return metric; 109 | } 110 | 111 | /** @return the timestamp */ 112 | public final long getTimestamp() { 113 | return timestamp; 114 | } 115 | 116 | /** @return the value */ 117 | public final String getValue() { 118 | return value; 119 | } 120 | 121 | /** @return the tags */ 122 | public final HashMap getTags() { 123 | return tags; 124 | } 125 | 126 | /** @return the TSUID */ 127 | public final String getTSUID() { 128 | return tsuid; 129 | } 130 | 131 | /** @param metric the metric to set */ 132 | public final void setMetric(String metric) { 133 | this.metric = metric; 134 | } 135 | 136 | /** @param timestamp the timestamp to set */ 137 | public final void setTimestamp(long timestamp) { 138 | this.timestamp = timestamp; 139 | } 140 | 141 | /** @param value the value to set */ 142 | public final void setValue(String value) { 143 | this.value = value; 144 | } 145 | 146 | /** @param tags the tags to set */ 147 | public final void setTags(HashMap tags) { 148 | this.tags = tags; 149 | } 150 | 151 | /** @param tsuid the TSUID to set */ 152 | public final void setTSUID(String tsuid) { 153 | this.tsuid = tsuid; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/tsd/ConnectionManager.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import java.io.IOException; 16 | import java.nio.channels.ClosedChannelException; 17 | import java.util.concurrent.atomic.AtomicLong; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | import org.jboss.netty.channel.Channel; 22 | import org.jboss.netty.channel.ChannelEvent; 23 | import org.jboss.netty.channel.ChannelHandlerContext; 24 | import org.jboss.netty.channel.ChannelStateEvent; 25 | import org.jboss.netty.channel.ExceptionEvent; 26 | import org.jboss.netty.channel.SimpleChannelHandler; 27 | import org.jboss.netty.channel.group.DefaultChannelGroup; 28 | import org.jboss.netty.handler.codec.embedder.CodecEmbedderException; 29 | 30 | import net.opentsdb.stats.StatsCollector; 31 | 32 | /** 33 | * Keeps track of all existing connections. 34 | */ 35 | final class ConnectionManager extends SimpleChannelHandler { 36 | 37 | private static final Logger LOG = LoggerFactory.getLogger(ConnectionManager.class); 38 | 39 | private static final AtomicLong connections_established = new AtomicLong(); 40 | private static final AtomicLong exceptions_unknown = new AtomicLong(); 41 | private static final AtomicLong exceptions_closed = new AtomicLong(); 42 | private static final AtomicLong exceptions_reset = new AtomicLong(); 43 | private static final AtomicLong exceptions_timeout = new AtomicLong(); 44 | 45 | private static final DefaultChannelGroup channels = 46 | new DefaultChannelGroup("all-channels"); 47 | 48 | static void closeAllConnections() { 49 | channels.close().awaitUninterruptibly(); 50 | } 51 | 52 | /** Constructor. */ 53 | public ConnectionManager() { 54 | } 55 | 56 | /** 57 | * Collects the stats and metrics tracked by this instance. 58 | * @param collector The collector to use. 59 | */ 60 | public static void collectStats(final StatsCollector collector) { 61 | collector.record("connectionmgr.connections", channels.size(), "type=open"); 62 | collector.record("connectionmgr.connections", connections_established, 63 | "type=total"); 64 | collector.record("connectionmgr.exceptions", exceptions_closed, 65 | "type=closed"); 66 | collector.record("connectionmgr.exceptions", exceptions_reset, 67 | "type=reset"); 68 | collector.record("connectionmgr.exceptions", exceptions_timeout, 69 | "type=timeout"); 70 | collector.record("connectionmgr.exceptions", exceptions_unknown, 71 | "type=unknown"); 72 | } 73 | 74 | @Override 75 | public void channelOpen(final ChannelHandlerContext ctx, 76 | final ChannelStateEvent e) { 77 | channels.add(e.getChannel()); 78 | connections_established.incrementAndGet(); 79 | } 80 | 81 | @Override 82 | public void handleUpstream(final ChannelHandlerContext ctx, 83 | final ChannelEvent e) throws Exception { 84 | if (e instanceof ChannelStateEvent) { 85 | LOG.info(e.toString()); 86 | } 87 | super.handleUpstream(ctx, e); 88 | } 89 | 90 | @Override 91 | public void exceptionCaught(final ChannelHandlerContext ctx, 92 | final ExceptionEvent e) { 93 | final Throwable cause = e.getCause(); 94 | final Channel chan = ctx.getChannel(); 95 | if (cause instanceof ClosedChannelException) { 96 | exceptions_closed.incrementAndGet(); 97 | LOG.warn("Attempt to write to closed channel " + chan); 98 | return; 99 | } 100 | if (cause instanceof IOException) { 101 | final String message = cause.getMessage(); 102 | if ("Connection reset by peer".equals(message)) { 103 | exceptions_reset.incrementAndGet(); 104 | return; 105 | } else if ("Connection timed out".equals(message)) { 106 | exceptions_timeout.incrementAndGet(); 107 | // Do nothing. A client disconnecting isn't really our problem. Oh, 108 | // and I'm not kidding you, there's no better way to detect ECONNRESET 109 | // in Java. Like, people have been bitching about errno for years, 110 | // and Java managed to do something *far* worse. That's quite a feat. 111 | return; 112 | } 113 | } 114 | if (cause instanceof CodecEmbedderException) { 115 | // payload was not compressed as it was announced to be 116 | LOG.warn("Http codec error : " + cause.getMessage()); 117 | e.getChannel().close(); 118 | return; 119 | } 120 | exceptions_unknown.incrementAndGet(); 121 | LOG.error("Unexpected exception from downstream for " + chan, cause); 122 | e.getChannel().close(); 123 | } 124 | 125 | } 126 | -------------------------------------------------------------------------------- /src/tsd/LogsRpc.java: -------------------------------------------------------------------------------- 1 | // This file is part of OpenTSDB. 2 | // Copyright (C) 2010-2012 The OpenTSDB Authors. 3 | // 4 | // This program is free software: you can redistribute it and/or modify it 5 | // under the terms of the GNU Lesser General Public License as published by 6 | // the Free Software Foundation, either version 2.1 of the License, or (at your 7 | // option) any later version. This program is distributed in the hope that it 8 | // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 9 | // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 | // General Public License for more details. You should have received a copy 11 | // of the GNU Lesser General Public License along with this program. If not, 12 | // see . 13 | package net.opentsdb.tsd; 14 | 15 | import org.slf4j.LoggerFactory; 16 | 17 | import com.fasterxml.jackson.core.JsonGenerationException; 18 | 19 | import java.io.IOException; 20 | import java.util.ArrayList; 21 | import java.util.Iterator; 22 | import java.util.NoSuchElementException; 23 | 24 | import ch.qos.logback.classic.Level; 25 | import ch.qos.logback.classic.Logger; 26 | import ch.qos.logback.classic.spi.ILoggingEvent; 27 | import ch.qos.logback.classic.spi.IThrowableProxy; 28 | import ch.qos.logback.classic.spi.ThrowableProxyUtil; 29 | import ch.qos.logback.core.read.CyclicBufferAppender; 30 | 31 | import net.opentsdb.core.TSDB; 32 | import net.opentsdb.utils.JSON; 33 | 34 | /** The "/logs" endpoint. */ 35 | final class LogsRpc implements HttpRpc { 36 | 37 | public void execute(final TSDB tsdb, final HttpQuery query) 38 | throws JsonGenerationException, IOException { 39 | LogIterator logmsgs = new LogIterator(); 40 | if (query.hasQueryStringParam("json")) { 41 | ArrayList logs = new ArrayList(); 42 | for (String log : logmsgs) { 43 | logs.add(log); 44 | } 45 | query.sendReply(JSON.serializeToBytes(logs)); 46 | } else if (query.hasQueryStringParam("level")) { 47 | final Level level = Level.toLevel(query.getQueryStringParam("level"), 48 | null); 49 | if (level == null) { 50 | throw new BadRequestException("Invalid level: " 51 | + query.getQueryStringParam("level")); 52 | } 53 | final Logger root = 54 | (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); 55 | String logger_name = query.getQueryStringParam("logger"); 56 | if (logger_name == null) { 57 | logger_name = Logger.ROOT_LOGGER_NAME; 58 | } else if (root.getLoggerContext().exists(logger_name) == null) { 59 | throw new BadRequestException("Invalid logger: " + logger_name); 60 | } 61 | final Logger logger = (Logger) LoggerFactory.getLogger(logger_name); 62 | int nloggers = 0; 63 | if (logger == root) { // Update all the loggers. 64 | for (final Logger l : logger.getLoggerContext().getLoggerList()) { 65 | l.setLevel(level); 66 | nloggers++; 67 | } 68 | } else { 69 | logger.setLevel(level); 70 | nloggers++; 71 | } 72 | query.sendReply("Set the log level to " + level + " on " + nloggers 73 | + " logger" + (nloggers > 1 ? "s" : "") + ".\n"); 74 | } else { 75 | final StringBuilder buf = new StringBuilder(512); 76 | for (final String logmsg : logmsgs) { 77 | buf.append(logmsg).append('\n'); 78 | } 79 | logmsgs = null; 80 | query.sendReply(buf); 81 | } 82 | } 83 | 84 | /** Helper class to iterate over logback's recent log messages. */ 85 | private static final class LogIterator implements Iterator, 86 | Iterable { 87 | 88 | private final CyclicBufferAppender logbuf; 89 | private final StringBuilder buf = new StringBuilder(64); 90 | private int nevents; 91 | 92 | public LogIterator() { 93 | final Logger root = 94 | (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); 95 | logbuf = (CyclicBufferAppender) root.getAppender("CYCLIC"); 96 | } 97 | 98 | public Iterator iterator() { 99 | nevents = logbuf.getLength(); 100 | return this; 101 | } 102 | 103 | public boolean hasNext() { 104 | return nevents > 0; 105 | } 106 | 107 | public String next() { 108 | if (hasNext()) { 109 | nevents--; 110 | final ILoggingEvent event = (ILoggingEvent) logbuf.get(nevents); 111 | final String msg = event.getFormattedMessage(); 112 | buf.setLength(0); 113 | buf.append(event.getTimeStamp() / 1000) 114 | .append('\t').append(event.getLevel().toString()) 115 | .append('\t').append(event.getThreadName()) 116 | .append('\t').append(event.getLoggerName()) 117 | .append('\t').append(msg); 118 | final IThrowableProxy thrown = event.getThrowableProxy(); 119 | if (thrown != null) { 120 | buf.append('\t').append(ThrowableProxyUtil.asString(thrown)); 121 | } 122 | return buf.toString(); 123 | } 124 | throw new NoSuchElementException("no more elements"); 125 | } 126 | 127 | public void remove() { 128 | throw new UnsupportedOperationException(); 129 | } 130 | 131 | } 132 | 133 | } 134 | --------------------------------------------------------------------------------