├── .editorconfig
├── .github
└── dependabot.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── src
├── main
└── java
│ └── metrics_influxdb
│ ├── HttpInfluxdbProtocol.java
│ ├── InfluxdbProtocol.java
│ ├── InfluxdbReporter.java
│ ├── UdpInfluxdbProtocol.java
│ ├── VersionNumber.java
│ ├── api
│ └── measurements
│ │ ├── CategoriesMetricMeasurementTransformer.java
│ │ ├── KeyValueMetricMeasurementTransformer.java
│ │ └── MetricMeasurementTransformer.java
│ ├── measurements
│ ├── AbstractSender.java
│ ├── HttpInlinerSender.java
│ ├── Measure.java
│ ├── MeasurementReporter.java
│ ├── QueueableSender.java
│ ├── Sender.java
│ └── UdpInlinerSender.java
│ ├── misc
│ ├── BoundedFIFO.java
│ ├── HttpDatabaseCreator.java
│ ├── Miscellaneous.java
│ └── VisibilityIncreasedForTests.java
│ ├── serialization
│ └── line
│ │ ├── InfluxDBSortedMap.java
│ │ └── Inliner.java
│ └── v08
│ ├── Influxdb.java
│ ├── InfluxdbHttp.java
│ ├── InfluxdbUdp.java
│ ├── JsonBuilder.java
│ ├── JsonBuilderDefault.java
│ └── ReporterV08.java
└── test
├── java
├── metrics_influxdb
│ ├── InfluxdbReporterBuilderTest.java
│ ├── SortedMaps.java
│ ├── api
│ │ └── measurements
│ │ │ ├── TestCategoriesMetricMeasurementTransformer.java
│ │ │ └── TestKeyValueMetricMeasurementTransformer.java
│ ├── measurements
│ │ ├── ListInlinerSender.java
│ │ ├── MeasureTest.java
│ │ ├── MeasurementReporterTest.java
│ │ └── MeasurementReporterWithBaseTagsTest.java
│ └── serialization
│ │ └── line
│ │ └── InlinerTest.java
└── sandbox
│ ├── InfluxdbUdpSandbox.java
│ ├── SendToLocalInfluxDB.java
│ └── SendToLocalInfluxDB_V09.java
└── resources
└── simplelogger.properties
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 |
3 |
4 | # top-most EditorConfig file
5 | root = true
6 |
7 | # Unix-style newlines with a newline ending every file
8 | [*]
9 | end_of_line = lf
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 | tab_width = 2
13 | charset = utf-8
14 |
15 | # 4 space indentation
16 | [*.py]
17 | indent_style = space
18 | indent_size = 4
19 |
20 | # Tab indentation (no size specified)
21 | [Makefile]
22 | indent_style = tab
23 |
24 | [build.gradle]
25 | indent_style = tab
26 |
27 | # Matches the exact files either package.json or .travis.yml
28 | [{package.json,.travis.yml}]
29 | indent_style = space
30 | indent_size = 2
31 |
32 | [**.js]
33 | indent_style = tab
34 | indent_size = 2
35 | ; Path to the external file format
36 | ; The default is taken from the lib folder inside the folder extension.
37 | path=~/.vim/bundle/js-beautify/js/lib/beautify.js
38 | ; Javascript interpreter to be invoked by default 'node'
39 | bin=node
40 |
41 | [**.json]
42 | indent_style = tab
43 | indent_size = 2
44 |
45 | [**.jsx]
46 | e4x = true
47 | indent_style = tab
48 | indent_size = 2
49 |
50 | [**.css]
51 | indent_style = tab
52 | indent_size = 2
53 | path=~/.vim/bundle/js-beautify/js/lib/beautify-css.js
54 |
55 | [**.html]
56 | indent_style = tab
57 | indent_size = 2
58 | max_char = 78
59 | brace_style = expand
60 | ; Using special comments
61 | ; And such comments or apply only in global configuration
62 | ; So it's best to avoid them
63 | ;vim:path=~/.vim/bundle/js-beautify/js/lib/beautify-html.js
64 | ;vim:max_char=78:brace_style=expand
65 |
66 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: gradle
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | time: "04:00"
8 | open-pull-requests-limit: 10
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .cache
2 | .classpath
3 | .project
4 | .settings
5 | .gradle
6 | target
7 | bin
8 | build
9 | test-output
10 |
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: java
3 | env:
4 | - GRADLE_USER_HOME=gradle-cache
5 | cache:
6 | directories:
7 | - gradle-cache
8 | - netbeans
9 | jdk:
10 | - openjdk8
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12 | HEREUNDER.
13 |
14 | Statement of Purpose
15 |
16 | The laws of most jurisdictions throughout the world automatically confer
17 | exclusive Copyright and Related Rights (defined below) upon the creator
18 | and subsequent owner(s) (each and all, an "owner") of an original work of
19 | authorship and/or a database (each, a "Work").
20 |
21 | Certain owners wish to permanently relinquish those rights to a Work for
22 | the purpose of contributing to a commons of creative, cultural and
23 | scientific works ("Commons") that the public can reliably and without fear
24 | of later claims of infringement build upon, modify, incorporate in other
25 | works, reuse and redistribute as freely as possible in any form whatsoever
26 | and for any purposes, including without limitation commercial purposes.
27 | These owners may contribute to the Commons to promote the ideal of a free
28 | culture and the further production of creative, cultural and scientific
29 | works, or to gain reputation or greater distribution for their Work in
30 | part through the use and efforts of others.
31 |
32 | For these and/or other purposes and motivations, and without any
33 | expectation of additional consideration or compensation, the person
34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35 | is an owner of Copyright and Related Rights in the Work, voluntarily
36 | elects to apply CC0 to the Work and publicly distribute the Work under its
37 | terms, with knowledge of his or her Copyright and Related Rights in the
38 | Work and the meaning and intended legal effect of CC0 on those rights.
39 |
40 | 1. Copyright and Related Rights. A Work made available under CC0 may be
41 | protected by copyright and related or neighboring rights ("Copyright and
42 | Related Rights"). Copyright and Related Rights include, but are not
43 | limited to, the following:
44 |
45 | i. the right to reproduce, adapt, distribute, perform, display,
46 | communicate, and translate a Work;
47 | ii. moral rights retained by the original author(s) and/or performer(s);
48 | iii. publicity and privacy rights pertaining to a person's image or
49 | likeness depicted in a Work;
50 | iv. rights protecting against unfair competition in regards to a Work,
51 | subject to the limitations in paragraph 4(a), below;
52 | v. rights protecting the extraction, dissemination, use and reuse of data
53 | in a Work;
54 | vi. database rights (such as those arising under Directive 96/9/EC of the
55 | European Parliament and of the Council of 11 March 1996 on the legal
56 | protection of databases, and under any national implementation
57 | thereof, including any amended or successor version of such
58 | directive); and
59 | vii. other similar, equivalent or corresponding rights throughout the
60 | world based on applicable law or treaty, and any national
61 | implementations thereof.
62 |
63 | 2. Waiver. To the greatest extent permitted by, but not in contravention
64 | of, applicable law, Affirmer hereby overtly, fully, permanently,
65 | irrevocably and unconditionally waives, abandons, and surrenders all of
66 | Affirmer's Copyright and Related Rights and associated claims and causes
67 | of action, whether now known or unknown (including existing as well as
68 | future claims and causes of action), in the Work (i) in all territories
69 | worldwide, (ii) for the maximum duration provided by applicable law or
70 | treaty (including future time extensions), (iii) in any current or future
71 | medium and for any number of copies, and (iv) for any purpose whatsoever,
72 | including without limitation commercial, advertising or promotional
73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74 | member of the public at large and to the detriment of Affirmer's heirs and
75 | successors, fully intending that such Waiver shall not be subject to
76 | revocation, rescission, cancellation, termination, or any other legal or
77 | equitable action to disrupt the quiet enjoyment of the Work by the public
78 | as contemplated by Affirmer's express Statement of Purpose.
79 |
80 | 3. Public License Fallback. Should any part of the Waiver for any reason
81 | be judged legally invalid or ineffective under applicable law, then the
82 | Waiver shall be preserved to the maximum extent permitted taking into
83 | account Affirmer's express Statement of Purpose. In addition, to the
84 | extent the Waiver is so judged Affirmer hereby grants to each affected
85 | person a royalty-free, non transferable, non sublicensable, non exclusive,
86 | irrevocable and unconditional license to exercise Affirmer's Copyright and
87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
88 | maximum duration provided by applicable law or treaty (including future
89 | time extensions), (iii) in any current or future medium and for any number
90 | of copies, and (iv) for any purpose whatsoever, including without
91 | limitation commercial, advertising or promotional purposes (the
92 | "License"). The License shall be deemed effective as of the date CC0 was
93 | applied by Affirmer to the Work. Should any part of the License for any
94 | reason be judged legally invalid or ineffective under applicable law, such
95 | partial invalidity or ineffectiveness shall not invalidate the remainder
96 | of the License, and in such case Affirmer hereby affirms that he or she
97 | will not (i) exercise any of his or her remaining Copyright and Related
98 | Rights in the Work or (ii) assert any associated claims and causes of
99 | action with respect to the Work, in either case contrary to Affirmer's
100 | express Statement of Purpose.
101 |
102 | 4. Limitations and Disclaimers.
103 |
104 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
105 | surrendered, licensed or otherwise affected by this document.
106 | b. Affirmer offers the Work as-is and makes no representations or
107 | warranties of any kind concerning the Work, express, implied,
108 | statutory or otherwise, including without limitation warranties of
109 | title, merchantability, fitness for a particular purpose, non
110 | infringement, or the absence of latent or other defects, accuracy, or
111 | the present or absence of errors, whether or not discoverable, all to
112 | the greatest extent permissible under applicable law.
113 | c. Affirmer disclaims responsibility for clearing rights of other persons
114 | that may apply to the Work or any use thereof, including without
115 | limitation any person's Copyright and Related Rights in the Work.
116 | Further, Affirmer disclaims responsibility for obtaining any necessary
117 | consents, permissions or other rights required for any use of the
118 | Work.
119 | d. Affirmer understands and acknowledges that Creative Commons is not a
120 | party to this document and has no duty or obligation with respect to
121 | this CC0 or use of the Work.
122 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 | To the extent possible under law,
8 |
10 | Novaquark
11 | has waived all copyright and related or neighboring rights to
12 | this work.
13 |
14 |
15 | [](https://travis-ci.org/davidB/metrics-influxdb)
16 | [](https://bitdeli.com/free "Bitdeli Badge")
17 | [ ](https://bintray.com/davidb/maven/metrics-influxdb/_latestVersion)
18 |
19 | # The library provide :
20 |
21 | * a lighter client than influxdb-java to push only series to an [InfluxDB](http://influxdb.org) server.
22 | * A reporter for [metrics](http://metrics.codahale.com/) which announces measurements.
23 |
24 | The library provide a lighter client than influxdb-java to push only metrics.
25 |
26 | ## Dependencies :
27 |
28 | * slf4j-api for logging.
29 | * metrics-core, to provide, if you use InfluxdbReporter.
30 |
31 | ## Install:
32 |
33 | ### Released
34 | ```
35 | dependencies {
36 | compile 'com.github.davidb:metrics-influxdb:0.9.3'
37 | }
38 | ```
39 |
40 | ### Dev
41 | ```
42 | repositories {
43 | maven { url "https://jitpack.io" }
44 | }
45 | dependencies {
46 | compile 'com.github.davidb:metrics-influxdb:-SNAPSHOT'
47 | }
48 | ```
49 | ## Usage :
50 |
51 | Using the Builder API and its defaults, it is easy to use InfluxdbReporter:
52 |
53 | ScheduledReporter reporter = InfluxdbReporter.forRegistry(registry).build();
54 | reporter.start(10, TimeUnit.SECONDS);
55 |
56 | With the previous simple configuration, all defaults will be used, mainly:
57 |
58 | - protocol: `HTTP`
59 | - server: `127.0.0.1`
60 | - port: `8086`
61 | - authentication: `none`
62 | - database name: `metrics`
63 | - rates: converted to `TimeUnit.SECONDS`
64 | - duration: converted to `TimeUnit.MILLISECONDS`
65 | - idle metrics: `do not report`
66 | - influxdb protocol: `v09` [line protocol](https://influxdb.com/docs/v0.9/write_protocols/line.html)
67 | - ...
68 |
69 | But you are free of course to define all settings by yourself :
70 | ```
71 | final ScheduledReporter reporter = InfluxdbReporter.forRegistry(registry)
72 | .protocol(new HttpInfluxdbProtocol("http", "influxdb-server", 8086, "admin", "53CR3TP455W0RD", "metrics"))
73 | .convertRatesTo(TimeUnit.SECONDS)
74 | .convertDurationsTo(TimeUnit.MILLISECONDS)
75 | .filter(MetricFilter.ALL)
76 | .skipIdleMetrics(false)
77 | .tag("cluster", "CL01")
78 | .tag("client", "OurImportantClient")
79 | .tag("server", serverIP)
80 | .transformer(new CategoriesMetricMeasurementTransformer("module", "artifact"))
81 | .build();
82 | reporter.start(10, TimeUnit.SECONDS);
83 | ```
84 |
85 | And if you are still using v08 influxdb
86 |
87 | ```
88 | final InfluxdbReporter reporter = InfluxdbReporter
89 | .forRegistry(registry)
90 | .protocol(new HttpInfluxdbProtocol("influxdb-server", 8086, "admin", "53CR3TP455W0RD", "metrics"))
91 | .v08()
92 | .build();
93 | ...
94 | ```
95 |
96 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "java-library"
3 | id "maven-publish"
4 | id "com.jfrog.bintray" version "1.8.5"
5 | }
6 |
7 | group = "com.github.davidb"
8 | def description = "A reporter for metrics which announces measurements to an InfluxDB server."
9 | version = "git describe --always --dirty".execute().text.trim()
10 | println("version : '${version}'")
11 |
12 | repositories {
13 | jcenter()
14 | }
15 |
16 | dependencies {
17 | implementation 'io.dropwizard.metrics:metrics-core:4.2.14'
18 | implementation 'org.slf4j:slf4j-api:2.0.6'
19 |
20 | testImplementation 'junit:junit:4.13.2'
21 | testImplementation 'org.testng:testng:7.7.0'
22 | testImplementation 'org.hamcrest:hamcrest-all:1.3'
23 | testImplementation 'org.easytesting:fest-assert-core:2.0M10'
24 | testImplementation 'org.mockito:mockito-all:1.10.19'
25 | testImplementation 'com.google.guava:guava:23.0'
26 | testRuntimeOnly 'org.slf4j:slf4j-simple:2.0.6'
27 | }
28 |
29 | sourceCompatibility = JavaVersion.VERSION_1_8
30 | targetCompatibility = JavaVersion.VERSION_1_8
31 | [compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
32 | test {
33 | // enable TestNG support (default is JUnit)
34 | useTestNG()
35 | }
36 |
37 | task sourcesJar(type: Jar) {
38 | from sourceSets.main.allSource
39 | classifier = 'sources'
40 | }
41 | task javadocJar(type: Jar, dependsOn: javadoc) {
42 | from javadoc.destinationDir
43 | classifier = 'javadoc'
44 | }
45 |
46 | // add javadoc/source jar tasks as artifacts
47 | artifacts {
48 | archives sourcesJar, javadocJar
49 | }
50 |
51 | def pomConfig = {
52 | name project.name
53 | url "https://github.com/davidB/${project.name}"
54 | inceptionYear "2016"
55 | licenses {
56 | license {
57 | name "Public domain (CC0-1.0)"
58 | url "http://creativecommons.org/publicdomain/zero/1.0/"
59 | distribution "repo"
60 | }
61 | }
62 | scm {
63 | connection "scm:git:git://github.com/davidB/${project.name}.git"
64 | developerConnection "scm:git:git@github.com:davidB/${project.name}.git"
65 | url "https://github.com/davidB/${project.name}/"
66 | }
67 | developers {
68 | developer {
69 | id "davidB"
70 | name "David Bernard"
71 | }
72 | developer {
73 | id "McFoggy"
74 | name "Matthieu Brouillard"
75 | email "matthieu@brouillard.fr"
76 | }
77 | }
78 | }
79 |
80 | publishing {
81 | publications {
82 | mavenStuff(MavenPublication) {
83 | from components.java
84 | artifact sourcesJar
85 | artifact javadocJar
86 | pom.withXml {
87 | def root = asNode()
88 | root.appendNode('description', description)
89 | root.children().last() + pomConfig
90 | }
91 | }
92 | }
93 | }
94 | bintray {
95 | user = bintray_user
96 | key = bintray_api_key
97 |
98 | publications = ['mavenStuff'] //When uploading Maven-based publication files
99 | //dryRun = false //Whether to run this as dry-run, without deploying
100 | publish = true //If version should be auto published after an upload
101 | pkg {
102 | repo = 'maven'
103 | name = project.name
104 | desc = description
105 | websiteUrl = "https://github.com/davidB/${project.name}"
106 | issueTrackerUrl = "https://github.com/davidB/${project.name}/issues"
107 | vcsUrl = "https://github.com/davidB/${project.name}.git"
108 | licenses = ['CC0-1.0']
109 | publicDownloadNumbers = true
110 | version {
111 | name = project.version
112 | vcsTag = project.version
113 | //attributes = []
114 | //gpg {
115 | // sign = true //Determines whether to GPG sign the files. The default is false
116 | // passphrase = 'optional, the passphrase for GPG signing'
117 | //}
118 | }
119 | }
120 | }
121 |
122 | bintrayUpload.dependsOn(check, assemble)
123 | bintrayUpload.onlyIf {
124 | bintray_api_key.trim().length() > 0
125 | }
126 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Bintray settings to override in $HOME/.gradle/gradle.properties or ENV or commandline
2 | bintray_user=
3 | bintray_api_key=
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/davidB/metrics-influxdb/6c725678d24449e38a2ef2aeaa9f5360b92d5d0a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Jan 13 14:38:05 CET 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/HttpInfluxdbProtocol.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb;
2 |
3 | public class HttpInfluxdbProtocol implements InfluxdbProtocol {
4 | public final static String DEFAULT_HOST = "127.0.0.1";
5 | public final static int DEFAULT_PORT = 8086;
6 | public final static String DEFAULT_DATABASE = "metrics";
7 | public final static long DEFAULT_CONNECT_TIMEOUT_SECONDS = 2;
8 | public final static long DEFAULT_READ_TIMEOUT_SECONDS = 2;
9 |
10 | public final String scheme;
11 | public final String user;
12 | public final String password;
13 | public final String host;
14 | public final int port;
15 | public final boolean secured;
16 | public final String database;
17 | public final long connectTimeout;
18 | public final long readTimeout;
19 |
20 | public HttpInfluxdbProtocol(String scheme, String host, int port, String user, String password, String db, long connectTimeout, long readTimeout) {
21 | super();
22 | this.scheme = scheme;
23 | this.host = host;
24 | this.port = port;
25 | this.user = user;
26 | this.password = password;
27 | this.database = db;
28 | this.secured = (user != null) && (password != null);
29 | this.connectTimeout = connectTimeout;
30 | this.readTimeout = readTimeout;
31 | }
32 |
33 | public HttpInfluxdbProtocol(String scheme, String host, int port, String user, String password, String db) {
34 | this(scheme, host, port, user, password, db, DEFAULT_CONNECT_TIMEOUT_SECONDS, DEFAULT_READ_TIMEOUT_SECONDS);
35 | }
36 |
37 | public HttpInfluxdbProtocol(String host, int port, String user, String password, String db) {
38 | this("http", host, port, user, password, db);
39 | }
40 |
41 | public HttpInfluxdbProtocol(String host) {
42 | this(host, DEFAULT_PORT);
43 | }
44 |
45 | public HttpInfluxdbProtocol(String host, int port) {
46 | this(host, port, null, null);
47 | }
48 |
49 | public HttpInfluxdbProtocol(String host, int port, String database) {
50 | this(host, port, null, null, database);
51 | }
52 |
53 | public HttpInfluxdbProtocol() {
54 | this(DEFAULT_HOST, DEFAULT_PORT);
55 | }
56 |
57 | public HttpInfluxdbProtocol(String host, int port, String user, String password) {
58 | this(host, port, user, password, DEFAULT_DATABASE);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/InfluxdbProtocol.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb;
2 |
3 | public interface InfluxdbProtocol {
4 | }
5 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/InfluxdbReporter.java:
--------------------------------------------------------------------------------
1 | // metrics-influxdb
2 | //
3 | // Written in 2014 by David Bernard
4 | //
5 | // [other author/contributor lines as appropriate]
6 | //
7 | // To the extent possible under law, the author(s) have dedicated all copyright and
8 | // related and neighboring rights to this software to the public domain worldwide.
9 | // This software is distributed without any warranty.
10 | //
11 | // You should have received a copy of the CC0 Public Domain Dedication along with
12 | // this software. If not, see .
13 | package metrics_influxdb;
14 |
15 | import java.util.HashMap;
16 | import java.util.Map;
17 | import java.util.Objects;
18 | import java.util.concurrent.ScheduledExecutorService;
19 | import java.util.concurrent.TimeUnit;
20 |
21 | import com.codahale.metrics.Clock;
22 | import com.codahale.metrics.MetricFilter;
23 | import com.codahale.metrics.MetricRegistry;
24 | import com.codahale.metrics.ScheduledReporter;
25 |
26 | import metrics_influxdb.api.measurements.MetricMeasurementTransformer;
27 | import metrics_influxdb.measurements.HttpInlinerSender;
28 | import metrics_influxdb.measurements.MeasurementReporter;
29 | import metrics_influxdb.measurements.Sender;
30 | import metrics_influxdb.measurements.UdpInlinerSender;
31 | import metrics_influxdb.misc.HttpDatabaseCreator;
32 | import metrics_influxdb.misc.Miscellaneous;
33 | import metrics_influxdb.misc.VisibilityIncreasedForTests;
34 | import metrics_influxdb.v08.Influxdb;
35 | import metrics_influxdb.v08.InfluxdbHttp;
36 | import metrics_influxdb.v08.InfluxdbUdp;
37 | import metrics_influxdb.v08.ReporterV08;
38 |
39 | /**
40 | * A reporter which publishes metric values to a InfluxDB server.
41 | *
42 | * @see InfluxDB - An open-source distributed
43 | * time series database with no external dependencies.
44 | */
45 | public class InfluxdbReporter {
46 |
47 | static enum InfluxdbCompatibilityVersions {
48 | V08, LATEST;
49 | }
50 |
51 | /**
52 | * Returns a new {@link Builder} for {@link InfluxdbReporter}.
53 | *
54 | * @param registry
55 | * the registry to report
56 | * @return a {@link Builder} instance for a {@link InfluxdbReporter}
57 | */
58 | public static Builder forRegistry(MetricRegistry registry) {
59 | return new Builder(registry);
60 | }
61 |
62 | /**
63 | * A builder for {@link InfluxdbReporter} instances. Defaults to not using a
64 | * prefix, using the default clock, converting rates to events/second,
65 | * converting durations to milliseconds, and not filtering metrics.
66 | */
67 | public static class Builder {
68 |
69 | private final MetricRegistry registry;
70 | private boolean autoCreateDB;
71 | private Clock clock;
72 | private String prefix;
73 | private TimeUnit rateUnit;
74 | private TimeUnit durationUnit;
75 | private MetricFilter filter;
76 | private boolean skipIdleMetrics;
77 | private ScheduledExecutorService executor;
78 |
79 | @VisibilityIncreasedForTests InfluxdbCompatibilityVersions influxdbVersion;
80 | @VisibilityIncreasedForTests InfluxdbProtocol protocol;
81 | @VisibilityIncreasedForTests Influxdb influxdbDelegate;
82 | @VisibilityIncreasedForTests Map tags;
83 | @VisibilityIncreasedForTests MetricMeasurementTransformer transformer = MetricMeasurementTransformer.NOOP;
84 |
85 | private Builder(MetricRegistry registry) {
86 | this.registry = registry;
87 | this.clock = Clock.defaultClock();
88 | this.prefix = null;
89 | this.rateUnit = TimeUnit.SECONDS;
90 | this.durationUnit = TimeUnit.MILLISECONDS;
91 | this.filter = MetricFilter.ALL;
92 | this.protocol = new HttpInfluxdbProtocol();
93 | this.influxdbVersion = InfluxdbCompatibilityVersions.LATEST;
94 | this.tags = new HashMap<>();
95 | this.autoCreateDB=true;
96 | }
97 |
98 | /**
99 | * Use the given {@link Clock} instance for the time.
100 | *
101 | * @param clock a {@link Clock} instance
102 | * @return {@code this}
103 | */
104 | public Builder withClock(Clock clock) {
105 | this.clock = clock;
106 | return this;
107 | }
108 |
109 | /**
110 | * Automatically create the database if it does not exist.
111 | *
112 | * @param autocreate a boolean
113 | * @return {@code this}
114 | */
115 | public Builder withAutoCreateDB(boolean autocreate) {
116 | this.autoCreateDB = autocreate;
117 | return this;
118 | }
119 |
120 | public Builder withScheduler(ScheduledExecutorService executor) {
121 | this.executor = executor;
122 | return this;
123 | }
124 |
125 | /**
126 | * Prefix all metric names with the given string.
127 | *
128 | * @param prefix the prefix for all metric names
129 | * @return {@code this}
130 | */
131 | public Builder prefixedWith(String prefix) {
132 | this.prefix = prefix;
133 | return this;
134 | }
135 |
136 | /**
137 | * Convert rates to the given time unit.
138 | *
139 | * @param rateUnit a unit of time
140 | * @return {@code this}
141 | */
142 | public Builder convertRatesTo(TimeUnit rateUnit) {
143 | this.rateUnit = rateUnit;
144 | return this;
145 | }
146 |
147 | /**
148 | * Convert durations to the given time unit.
149 | *
150 | * @param durationUnit a unit of time
151 | * @return {@code this}
152 | */
153 | public Builder convertDurationsTo(TimeUnit durationUnit) {
154 | this.durationUnit = durationUnit;
155 | return this;
156 | }
157 |
158 | /**
159 | * Only report metrics which match the given filter.
160 | *
161 | * @param filter a {@link MetricFilter}
162 | * @return {@code this}
163 | */
164 | public Builder filter(MetricFilter filter) {
165 | this.filter = filter;
166 | return this;
167 | }
168 |
169 | /**
170 | * Only report metrics that have changed.
171 | *
172 | * @param skipIdleMetrics
173 | * @return {@code this}
174 | */
175 | public Builder skipIdleMetrics(boolean skipIdleMetrics) {
176 | this.skipIdleMetrics = skipIdleMetrics;
177 | return this;
178 | }
179 |
180 | /**
181 | * Builds a {@link ScheduledReporter} with the given properties, sending
182 | * metrics using the given InfluxDB.
183 | *
184 | * @return a {@link ScheduledReporter}
185 | */
186 | public ScheduledReporter build() {
187 | ScheduledReporter reporter;
188 |
189 | switch (influxdbVersion) {
190 | case V08:
191 | Influxdb influxdb = buildInfluxdb();
192 | reporter = (executor == null)
193 | ? new ReporterV08(registry, influxdb, clock, prefix, rateUnit, durationUnit, filter, skipIdleMetrics)
194 | : new ReporterV08(registry, influxdb, clock, prefix, rateUnit, durationUnit, filter, skipIdleMetrics, executor)
195 | ;
196 | break;
197 | default:
198 | Sender s = buildSender();
199 | reporter = executor == null
200 | ? new MeasurementReporter(s, registry, filter, rateUnit, durationUnit, clock, tags, transformer)
201 | : new MeasurementReporter(s, registry, filter, rateUnit, durationUnit, clock, tags, transformer, executor)
202 | ;
203 | }
204 | return reporter;
205 | }
206 |
207 | /**
208 | * Operates with influxdb version less or equal than 08.
209 | * @return the builder itself
210 | */
211 | public Builder v08() {
212 | this.influxdbVersion = InfluxdbCompatibilityVersions.V08;
213 | return this;
214 | }
215 |
216 | /**
217 | * Override the protocol to use.
218 | * @param protocol a non null protocol
219 | * @return
220 | */
221 | public Builder protocol(InfluxdbProtocol protocol) {
222 | Objects.requireNonNull(protocol, "given InfluxdbProtocol cannot be null");
223 | this.protocol = protocol;
224 | return this;
225 | }
226 |
227 | /**
228 | * Sets the metric2measurement transformer to be used.
229 | * @param transformer a non null transformer
230 | * @return
231 | */
232 | public Builder transformer(MetricMeasurementTransformer transformer) {
233 | Objects.requireNonNull(transformer, "given MetricMeasurementTransformer cannot be null");
234 | this.transformer = transformer;
235 | return this;
236 | }
237 |
238 | /**
239 | * Registers the given key/value as a default tag for the generated measurements.
240 | * @param tagKey the key to register, cannot be null or empty
241 | * @param tagValue the value to register against the given key, cannot be null or empty
242 | */
243 | public Builder tag(String tagKey, String tagValue) {
244 | Miscellaneous.requireNotEmptyParameter(tagKey, "tag");
245 | Miscellaneous.requireNotEmptyParameter(tagValue, "value");
246 | tags.put(tagKey, tagValue);
247 | return this;
248 | }
249 |
250 | private Influxdb buildInfluxdb() {
251 | if (protocol instanceof HttpInfluxdbProtocol) {
252 | try {
253 | HttpInfluxdbProtocol p = (HttpInfluxdbProtocol) protocol;
254 | return new InfluxdbHttp(p.scheme, p.host, p.port, p.database, p.user, p.password, durationUnit);
255 | } catch(RuntimeException exc) {
256 | throw exc;
257 | } catch(Exception exc) {
258 | // wrap exception into RuntimeException
259 | throw new RuntimeException(exc.getMessage(), exc);
260 | }
261 | } else if (protocol instanceof UdpInfluxdbProtocol) {
262 | UdpInfluxdbProtocol p = (UdpInfluxdbProtocol) protocol;
263 | return new InfluxdbUdp(p.host, p.port);
264 | } else {
265 | throw new IllegalStateException("unsupported protocol: " + protocol);
266 | }
267 | }
268 |
269 | private Sender buildSender() {
270 | if (protocol instanceof HttpInfluxdbProtocol) {
271 | HttpInfluxdbProtocol httpInfluxdbProtocol = (HttpInfluxdbProtocol) this.protocol;
272 | if (this.autoCreateDB ) {
273 | HttpDatabaseCreator.run(httpInfluxdbProtocol);
274 | }
275 | return new HttpInlinerSender(httpInfluxdbProtocol);
276 | // TODO allow registration of transformers
277 | // TODO evaluate need of prefix (vs tags)
278 | } else if (protocol instanceof UdpInfluxdbProtocol) {
279 | return new UdpInlinerSender((UdpInfluxdbProtocol) protocol);
280 | } else {
281 | throw new IllegalStateException("unsupported protocol: " + protocol);
282 | }
283 |
284 | }
285 | }
286 | }
287 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/UdpInfluxdbProtocol.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb;
2 |
3 | public class UdpInfluxdbProtocol implements InfluxdbProtocol {
4 | public final String host;
5 | public final int port;
6 |
7 | public UdpInfluxdbProtocol(String host, int port) {
8 | this.host = host;
9 | this.port = port;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/VersionNumber.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb;
2 |
3 | import java.util.regex.Matcher;
4 | import java.util.regex.Pattern;
5 |
6 | public class VersionNumber /* implements Serializable */implements Comparable {
7 | private static final Pattern _regexp = Pattern.compile("(\\d+)\\.(\\d+)(\\.\\d+)?([-\\.].+)?");
8 |
9 | public int major;
10 | public int minor;
11 | public int bugfix;
12 | public String modifier;
13 |
14 | public VersionNumber() {
15 | major = 0;
16 | minor = 0;
17 | bugfix = 0;
18 | }
19 |
20 | public VersionNumber(String s) {
21 | Matcher match = _regexp.matcher(s);
22 | if (!match.find()) {
23 | throw new IllegalArgumentException("invalid versionNumber : major.minor(.bugfix)(modifier) :" + s);
24 | }
25 | major = Integer.parseInt(match.group(1));
26 | minor = Integer.parseInt(match.group(2));
27 | if ((match.group(3) != null) && (match.group(3).length() > 1)) {
28 | bugfix = Integer.parseInt(match.group(3).substring(1));
29 | }
30 | if ((match.group(4) != null) && (match.group(4).length() > 1)) {
31 | modifier = match.group(4);
32 | }
33 | }
34 |
35 | @Override
36 | public String toString() {
37 | StringBuilder str = new StringBuilder();
38 | str.append(major)
39 | .append('.')
40 | .append(minor)
41 | .append('.')
42 | .append(bugfix);
43 | if ((modifier != null) && (modifier.length() > 0)) {
44 | str.append(modifier);
45 | }
46 | return str.toString();
47 | }
48 |
49 | /**
50 | * Not a commutative compareTo !! Can return 0 for any VersionNumber o that match this version (same defined major,
51 | * minor, bugfix) undefined part are ignored.
52 | */
53 | @Override
54 | public int compareTo(VersionNumber o) {
55 | int back = 0;
56 | if ((back == 0) && (major > o.major)) {
57 | back = 1;
58 | }
59 | if ((back == 0) && (major < o.major)) {
60 | back = -1;
61 | }
62 | if ((back == 0) && (minor > o.minor)) {
63 | back = 1;
64 | }
65 | if ((back == 0) && (minor < o.minor)) {
66 | back = -1;
67 | }
68 | if ((back == 0) && (bugfix > o.bugfix)) {
69 | back = 1;
70 | }
71 | if ((back == 0) && (bugfix < o.bugfix)) {
72 | back = -1;
73 | }
74 | return back;
75 | }
76 |
77 | public boolean isZero() {
78 | return (major == 0) && (minor == 0) && (bugfix == 0);
79 | }
80 |
81 | }
82 |
83 | class VersionNumberMask extends VersionNumber {
84 | private static final Pattern _regexp = Pattern.compile("(\\d+)(\\.\\d+)?(\\.\\d+)?([-\\.].+)?");
85 |
86 | public VersionNumberMask(String s) {
87 | Matcher match = _regexp.matcher(s);
88 | if (!match.find()) {
89 | throw new IllegalArgumentException("invalid versionNumber : major.minor(.bugfix)(modifier) :" + s);
90 | }
91 | major = Integer.parseInt(match.group(1));
92 | minor = -1;
93 | if ((match.group(2) != null) && (match.group(2).length() > 1)) {
94 | minor = Integer.parseInt(match.group(2).substring(1));
95 | }
96 | bugfix = -1;
97 | if ((match.group(3) != null) && (match.group(3).length() > 1)) {
98 | bugfix = Integer.parseInt(match.group(3).substring(1));
99 | }
100 | modifier = null;
101 | if ((match.group(4) != null) && (match.group(4).length() > 1)) {
102 | modifier = match.group(4);
103 | }
104 | }
105 |
106 | /**
107 | * Doesn't compare modifier
108 | */
109 | @Override
110 | public int compareTo(VersionNumber o) {
111 | int back = 0;
112 | if ((back == 0) && (major > o.major)) {
113 | back = 1;
114 | }
115 | if ((back == 0) && (major < o.major)) {
116 | back = -1;
117 | }
118 | if ((back == 0) && (minor > -1) && (minor > o.minor)) {
119 | back = 1;
120 | }
121 | if ((back == 0) && (minor > -1) && (minor < o.minor)) {
122 | back = -1;
123 | }
124 | if ((back == 0) && (bugfix > -1) && (bugfix > o.bugfix)) {
125 | back = 1;
126 | }
127 | if ((back == 0) && (bugfix > -1) && (bugfix < o.bugfix)) {
128 | back = -1;
129 | }
130 | return back;
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/api/measurements/CategoriesMetricMeasurementTransformer.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.api.measurements;
2 |
3 | import java.util.Arrays;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | /**
8 | * This transformer uses a provided list of categories in order to extract tag values from the given metrics name.
9 | * Each metric name is splitted, and each splitted string falls into a given category bucket.
10 | *
11 | * Example using the categories ["server", "type"] a metric called `actarus.production.cpu_load` will be turned into
12 | * a measurement:
13 | *
10 | * Finally this transformer will generate a measurement named `metric-name` with tags [[key1=val1],[key2=val2], ..., [key2n+1=val2n+1]].
11 | *
12 | * If when splitting the initial metric name using the '.' character, the number of strings is not even, then the last 2 strings will be used to generate
13 | * the measurement-name.
14 | *
15 | * Examples:
16 | *
17 | *
`server.actarus.cpu_load` will be transformed to a measurement called `cpu_load` with tags [[server=actarus]]
18 | *
`server.actarus.cores.cpu_load` will be transformed to a measurement called `cores.cpu_load` with tags [[server=actarus]]
19 | *
20 | */
21 | public class KeyValueMetricMeasurementTransformer implements MetricMeasurementTransformer {
22 | private final String seperator;
23 |
24 | public KeyValueMetricMeasurementTransformer() {
25 | this(null);
26 | }
27 |
28 | public KeyValueMetricMeasurementTransformer(String customSeperatorRegex) {
29 | if(customSeperatorRegex != null) {
30 | this.seperator = customSeperatorRegex;
31 | }
32 | else {
33 | this.seperator = "\\.";
34 | }
35 | }
36 |
37 | @Override
38 | public Map tags(String metricName) {
39 | Map generatedTags = new HashMap<>();
40 | String[] splitted = metricName.split(seperator);
41 |
42 | int nbPairs = isEven(splitted.length)?(splitted.length-1)/2:(splitted.length/2)-1;
43 |
44 | for (int i = 0; i < nbPairs; i++) {
45 | generatedTags.put(splitted[2*i], splitted[2*i+1]);
46 | }
47 |
48 | return generatedTags;
49 | }
50 |
51 | public boolean isEven(int number) {
52 | return (number % 2)==1;
53 | }
54 |
55 | @Override
56 | public String measurementName(String metricName) {
57 | String[] splitted = metricName.split(seperator);
58 |
59 | if (isEven(splitted.length)) {
60 | return splitted[splitted.length - 1];
61 | } else {
62 | return splitted[splitted.length - 2] + "." + splitted[splitted.length - 1];
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/api/measurements/MetricMeasurementTransformer.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.api.measurements;
2 |
3 | import java.util.Collections;
4 | import java.util.Map;
5 |
6 | public interface MetricMeasurementTransformer {
7 | public Map tags(String metricName);
8 |
9 | public String measurementName(String metricName);
10 |
11 | public static final MetricMeasurementTransformer NOOP = new MetricMeasurementTransformer() {
12 | @Override
13 | public Map tags(String metricName) {
14 | return Collections.emptyMap();
15 | }
16 |
17 | @Override
18 | public String measurementName(String metricName) {
19 | return metricName;
20 | }
21 | };
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/measurements/AbstractSender.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.measurements;
2 |
3 | import java.util.Collection;
4 |
5 | public abstract class AbstractSender implements Sender {
6 | @Override
7 | public void send(Collection measures) {
8 | for (Measure m : measures) {
9 | send(m);
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/measurements/HttpInlinerSender.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.measurements;
2 |
3 | import java.io.IOException;
4 | import java.io.OutputStream;
5 | import java.io.UnsupportedEncodingException;
6 | import java.net.HttpURLConnection;
7 | import java.net.MalformedURLException;
8 | import java.net.URL;
9 | import java.util.Collection;
10 | import java.util.concurrent.TimeUnit;
11 |
12 | import org.slf4j.Logger;
13 | import org.slf4j.LoggerFactory;
14 |
15 | import metrics_influxdb.HttpInfluxdbProtocol;
16 | import metrics_influxdb.misc.Miscellaneous;
17 | import metrics_influxdb.serialization.line.Inliner;
18 |
19 | public class HttpInlinerSender extends QueueableSender {
20 | private final static Logger LOGGER = LoggerFactory.getLogger(HttpInlinerSender.class);
21 | private static int MAX_MEASURES_IN_SINGLE_POST = 5000;
22 | private final URL writeURL;
23 | private final Inliner inliner;
24 | private final long connectTimeout;
25 | private final long readTimeout;
26 |
27 | public HttpInlinerSender(HttpInfluxdbProtocol protocol) {
28 | super(MAX_MEASURES_IN_SINGLE_POST);
29 | URL toJoin;
30 |
31 | inliner = new Inliner(TimeUnit.MILLISECONDS);
32 | connectTimeout = protocol.connectTimeout;
33 | readTimeout = protocol.readTimeout;
34 |
35 | try {
36 | if (protocol.secured) {
37 | toJoin = new URL(protocol.scheme, protocol.host, protocol.port, "/write?precision=ms&db=" + Miscellaneous.urlEncode(protocol.database) + "&u="
38 | + Miscellaneous.urlEncode(protocol.user) + "&p=" + Miscellaneous.urlEncode(protocol.password));
39 | } else {
40 | toJoin = new URL(protocol.scheme, protocol.host, protocol.port, "/write?precision=ms&db=" + Miscellaneous.urlEncode(protocol.database));
41 | }
42 | } catch (MalformedURLException | UnsupportedEncodingException e) {
43 | toJoin = null;
44 | }
45 |
46 | writeURL = toJoin;
47 | }
48 |
49 | @Override
50 | protected boolean doSend(Collection measures) {
51 | if (measures.isEmpty()) {
52 | return true;
53 | }
54 |
55 | HttpURLConnection con = null;
56 | try {
57 | con = (HttpURLConnection) writeURL.openConnection();
58 | con.setRequestMethod("POST");
59 | con.setConnectTimeout(Long.valueOf(TimeUnit.SECONDS.toMillis(connectTimeout)).intValue());
60 | con.setReadTimeout(Long.valueOf(TimeUnit.SECONDS.toMillis(readTimeout)).intValue());
61 |
62 | // Send post request
63 | con.setDoOutput(true);
64 | OutputStream wr = con.getOutputStream();
65 | String measuresAsString = inliner.inline(measures);
66 |
67 | if (LOGGER.isDebugEnabled()) {
68 | LOGGER.debug("Measures being sent:\n{}", measuresAsString);
69 | }
70 | wr.write(measuresAsString.getBytes(Miscellaneous.UTF8));
71 |
72 | wr.flush();
73 | wr.close();
74 |
75 | int responseCode = con.getResponseCode();
76 |
77 | switch (responseCode) {
78 | case HttpURLConnection.HTTP_NO_CONTENT:
79 | LOGGER.debug("{} Measures sent to {}://{}:{}", measures.size(), writeURL.getProtocol(), writeURL.getHost(), writeURL.getPort());
80 | break;
81 | case HttpURLConnection.HTTP_OK:
82 | LOGGER.info("{} Measures sent to {}://{}:{} but not saved by infludb, reason:\n{}", measures.size(), writeURL.getProtocol(), writeURL.getHost(), writeURL.getPort(), Miscellaneous.readFrom(con.getInputStream()));
83 | break;
84 | default:
85 | LOGGER.info("failed to send {} Measures to {}://{}:{}, HTTP CODE received: {}\n", measures.size(), writeURL.getProtocol(), writeURL.getHost(), writeURL.getPort(), responseCode, Miscellaneous.readFrom(con.getInputStream()));
86 | break;
87 | }
88 |
89 | return true;
90 | } catch (IOException e) {
91 | // Here the influxdb is potentially temporary unreachable
92 | // we do not clear held measures so that we'll eb able to retry to post them
93 | LOGGER.warn("couldn't sent metrics to {}://{}:{}, reason: {}", writeURL.getProtocol(), writeURL.getHost(), writeURL.getPort(), e.getMessage(), e);
94 | } finally {
95 | // cleanup connection streams
96 | if (con != null) {
97 | try {
98 | con.getInputStream().close();
99 | } catch (Exception ignore) {
100 | // ignore
101 | }
102 | }
103 | }
104 |
105 | return false;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/measurements/Measure.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.measurements;
2 |
3 | import java.util.Collections;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | import com.codahale.metrics.Clock;
8 |
9 | import metrics_influxdb.misc.Miscellaneous;
10 |
11 | public class Measure {
12 | private String name;
13 | private Map tags;
14 | private Map values;
15 | private long timestamp;
16 |
17 | public Measure(String name) {
18 | this(name, (Map)null, (Map)null, Clock.defaultClock().getTime());
19 | }
20 |
21 | public Measure(String name, Map tags, Map values, long timestamp) {
22 | super();
23 | this.name = name;
24 | this.tags = new HashMap();
25 | this.values = new HashMap();
26 | this.timestamp = timestamp;
27 |
28 | if (tags != null) {
29 | this.tags.putAll(tags);
30 | }
31 | if (values != null) {
32 | this.values.putAll(values);
33 | }
34 | }
35 |
36 | public Measure(String name, Map tags, long value) {
37 | this(name, tags, value, Clock.defaultClock().getTime());
38 | }
39 |
40 | public Measure(String name, Map tags, long value, long timestamp) {
41 | this(name, tags, Collections.singletonMap("value", value+"i"), timestamp);
42 | }
43 |
44 | public Measure(String name, long value, long timestamp) {
45 | this(name, Collections.emptyMap(), value, timestamp);
46 | }
47 |
48 | public Measure(String name, long value) {
49 | this(name, value, Clock.defaultClock().getTime());
50 | }
51 |
52 | public Measure(String name, Map tags, int value) {
53 | this(name, tags, Long.valueOf(value), Clock.defaultClock().getTime());
54 | }
55 |
56 | public Measure(String name, Map tags, int value, long timestamp) {
57 | this(name, tags, Long.valueOf(value), timestamp);
58 | }
59 |
60 | public Measure(String name, int value, long timestamp) {
61 | this(name, null, Long.valueOf(value), timestamp);
62 | }
63 |
64 | public Measure(String name, int value) {
65 | this(name, Long.valueOf(value), Clock.defaultClock().getTime());
66 | }
67 |
68 | public Measure(String name, Map tags, double value) {
69 | this(name, tags, value, Clock.defaultClock().getTime());
70 | }
71 |
72 | public Measure(String name, Map tags, double value, long timestamp) {
73 | this(name, tags, Collections.singletonMap("value", ""+value), timestamp);
74 | }
75 |
76 | public Measure(String name, double value, long timestamp) {
77 | this(name, Collections.emptyMap(), value, timestamp);
78 | }
79 |
80 | public Measure(String name, double value) {
81 | this(name, value, Clock.defaultClock().getTime());
82 | }
83 |
84 | public Measure(String name, Map tags, float value) {
85 | this(name, tags, Double.valueOf(value), Clock.defaultClock().getTime());
86 | }
87 |
88 | public Measure(String name, Map tags, float value, long timestamp) {
89 | this(name, tags, Double.valueOf(value), timestamp);
90 | }
91 |
92 | public Measure(String name, float value, long timestamp) {
93 | this(name, null, Double.valueOf(value), timestamp);
94 | }
95 |
96 | public Measure(String name, float value) {
97 | this(name, Double.valueOf(value), Clock.defaultClock().getTime());
98 | }
99 |
100 | public Measure(String name, Map tags, String value) {
101 | this(name, tags, value, Clock.defaultClock().getTime());
102 | }
103 |
104 | public Measure(String name, Map tags, String value, long timestamp) {
105 | this(name, tags, Collections.singletonMap("value", asStringValue(value)), timestamp);
106 | }
107 |
108 | public Measure(String name, String value, long timestamp) {
109 | this(name, null, value, timestamp);
110 | }
111 |
112 | public Measure(String name, String value) {
113 | this(name, value, Clock.defaultClock().getTime());
114 | }
115 |
116 | public Measure(String name, Map tags, boolean value) {
117 | this(name, tags, value, Clock.defaultClock().getTime());
118 | }
119 |
120 | public Measure(String name, Map tags, boolean value, long timestamp) {
121 | this(name, tags, Collections.singletonMap("value", ""+value), timestamp);
122 | }
123 |
124 | public Measure(String name, boolean value, long timestamp) {
125 | this(name, null, value, timestamp);
126 | }
127 |
128 | public Measure(String name, boolean value) {
129 | this(name, value, Clock.defaultClock().getTime());
130 | }
131 |
132 | private static String asStringValue(String value) {
133 | return "\"" + Miscellaneous.escape(value, '"') + "\"";
134 | }
135 |
136 | public String getName() {
137 | return name;
138 | }
139 |
140 | public Map getTags() {
141 | return tags;
142 | }
143 |
144 | public Map getValues() {
145 | return values;
146 | }
147 |
148 | public long getTimestamp() {
149 | return timestamp;
150 | }
151 |
152 | public void setName(String name) {
153 | this.name = name;
154 | }
155 |
156 | public void setTags(Map tags) {
157 | this.tags.clear();
158 | if (tags != null) {
159 | this.tags.putAll(tags);
160 | }
161 | }
162 |
163 | public void setValues(Map values) {
164 | this.values.clear();
165 | if (values != null) {
166 | this.values.putAll(values);
167 | }
168 | }
169 |
170 | public void setTimestamp(long timestamp) {
171 | this.timestamp = timestamp;
172 | }
173 |
174 | public Measure timestamp(long timestamp) {
175 | setTimestamp(timestamp);
176 | return this;
177 | }
178 |
179 | public Measure addTag(String tagKey, String tagValue) {
180 | tags.put(tagKey, tagValue);
181 | return this;
182 | }
183 | public Measure addTag(Map tags) {
184 | this.tags.putAll(tags);
185 | return this;
186 | }
187 | public Measure addValue(String key, String value) {
188 | values.put(key, asStringValue(value));
189 | return this;
190 | }
191 | public Measure addValue(String key, float value) {
192 | return addValue(key, Double.valueOf(value));
193 | }
194 | public Measure addValue(String key, double value) {
195 | if (!((Double.isNaN(value)) || Double.isInfinite(value))) {
196 | values.put(key, "" + value);
197 | }
198 | return this;
199 | }
200 | public Measure addValue(String key, int value) {
201 | return addValue(key, Long.valueOf(value));
202 | }
203 | public Measure addValue(String key, long value) {
204 | values.put(key, value+"i");
205 | return this;
206 | }
207 | public Measure addValue(String key, boolean value) {
208 | values.put(key, ""+value);
209 | return this;
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/measurements/MeasurementReporter.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.measurements;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 | import java.util.SortedMap;
6 | import java.util.concurrent.ScheduledExecutorService;
7 | import java.util.concurrent.TimeUnit;
8 |
9 | import com.codahale.metrics.Clock;
10 | import com.codahale.metrics.Counter;
11 | import com.codahale.metrics.Gauge;
12 | import com.codahale.metrics.Histogram;
13 | import com.codahale.metrics.Meter;
14 | import com.codahale.metrics.MetricFilter;
15 | import com.codahale.metrics.MetricRegistry;
16 | import com.codahale.metrics.ScheduledReporter;
17 | import com.codahale.metrics.Snapshot;
18 | import com.codahale.metrics.Timer;
19 |
20 | import metrics_influxdb.api.measurements.MetricMeasurementTransformer;
21 |
22 | public class MeasurementReporter extends ScheduledReporter{
23 | private final Sender sender;
24 | private final Clock clock;
25 | private Map baseTags;
26 | private MetricMeasurementTransformer transformer;
27 |
28 | public MeasurementReporter(Sender sender, MetricRegistry registry, MetricFilter filter, TimeUnit rateUnit, TimeUnit durationUnit, Clock clock, Map baseTags, MetricMeasurementTransformer transformer, ScheduledExecutorService executor) {
29 | super(registry, "measurement-reporter", filter, rateUnit, durationUnit, executor);
30 | this.baseTags = baseTags;
31 | this.sender = sender;
32 | this.clock = clock;
33 | this.transformer = transformer;
34 | }
35 |
36 | public MeasurementReporter(Sender sender, MetricRegistry registry, MetricFilter filter, TimeUnit rateUnit, TimeUnit durationUnit, Clock clock, Map baseTags, MetricMeasurementTransformer transformer) {
37 | super(registry, "measurement-reporter", filter, rateUnit, durationUnit);
38 | this.baseTags = baseTags;
39 | this.sender = sender;
40 | this.clock = clock;
41 | this.transformer = transformer;
42 | }
43 |
44 | @SuppressWarnings("rawtypes")
45 | @Override
46 | public void report(SortedMap gauges
47 | , SortedMap counters
48 | , SortedMap histograms
49 | , SortedMap meters
50 | , SortedMap timers) {
51 |
52 | final long timestamp = clock.getTime();
53 |
54 | for (Map.Entry entry : gauges.entrySet()) {
55 | sender.send(fromGauge(entry.getKey(), entry.getValue(), timestamp));
56 | }
57 |
58 | for (Map.Entry entry : counters.entrySet()) {
59 | sender.send(fromCounter(entry.getKey(), entry.getValue(), timestamp));
60 | }
61 |
62 | for (Map.Entry entry : histograms.entrySet()) {
63 | sender.send(fromHistogram(entry.getKey(), entry.getValue(), timestamp));
64 | }
65 |
66 | for (Map.Entry entry : meters.entrySet()) {
67 | sender.send(fromMeter(entry.getKey(), entry.getValue(), timestamp));
68 | }
69 |
70 | for (Map.Entry entry : timers.entrySet()) {
71 | sender.send(fromTimer(entry.getKey(), entry.getValue(), timestamp));
72 | }
73 |
74 | sender.flush();
75 | }
76 |
77 | private Measure fromTimer(String metricName, Timer t, long timestamp) {
78 | Snapshot snapshot = t.getSnapshot();
79 |
80 | Map tags = new HashMap(baseTags);
81 | tags.putAll(transformer.tags(metricName));
82 |
83 | Measure measure = new Measure(transformer.measurementName(metricName))
84 | .timestamp(timestamp)
85 | .addTag(tags)
86 | .addValue("count", snapshot.size())
87 | .addValue("min", convertDuration(snapshot.getMin()))
88 | .addValue("max", convertDuration(snapshot.getMax()))
89 | .addValue("mean", convertDuration(snapshot.getMean()))
90 | .addValue("std-dev", convertDuration(snapshot.getStdDev()))
91 | .addValue("50-percentile", convertDuration(snapshot.getMedian()))
92 | .addValue("75-percentile", convertDuration(snapshot.get75thPercentile()))
93 | .addValue("95-percentile", convertDuration(snapshot.get95thPercentile()))
94 | .addValue("99-percentile", convertDuration(snapshot.get99thPercentile()))
95 | .addValue("999-percentile", convertDuration(snapshot.get999thPercentile()))
96 | .addValue("one-minute", convertRate(t.getOneMinuteRate()))
97 | .addValue("five-minute", convertRate(t.getFiveMinuteRate()))
98 | .addValue("fifteen-minute", convertRate(t.getFifteenMinuteRate()))
99 | .addValue("mean-minute", convertRate(t.getMeanRate()))
100 | .addValue("run-count", t.getCount());
101 |
102 | return measure;
103 | }
104 |
105 | private Measure fromMeter(String metricName, Meter mt, long timestamp) {
106 | Map tags = new HashMap(baseTags);
107 | tags.putAll(transformer.tags(metricName));
108 |
109 | Measure measure = new Measure(transformer.measurementName(metricName))
110 | .timestamp(timestamp)
111 | .addTag(tags)
112 | .addValue("count", mt.getCount())
113 | .addValue("one-minute", convertRate(mt.getOneMinuteRate()))
114 | .addValue("five-minute", convertRate(mt.getFiveMinuteRate()))
115 | .addValue("fifteen-minute", convertRate(mt.getFifteenMinuteRate()))
116 | .addValue("mean-minute", convertRate(mt.getMeanRate()));
117 | return measure;
118 | }
119 |
120 | private Measure fromHistogram(String metricName, Histogram h, long timestamp) {
121 | Snapshot snapshot = h.getSnapshot();
122 |
123 | Map tags = new HashMap(baseTags);
124 | tags.putAll(transformer.tags(metricName));
125 |
126 | Measure measure = new Measure(transformer.measurementName(metricName))
127 | .timestamp(timestamp)
128 | .addTag(tags)
129 | .addValue("count", snapshot.size())
130 | .addValue("min", snapshot.getMin())
131 | .addValue("max", snapshot.getMax())
132 | .addValue("mean", snapshot.getMean())
133 | .addValue("std-dev", snapshot.getStdDev())
134 | .addValue("50-percentile", snapshot.getMedian())
135 | .addValue("75-percentile", snapshot.get75thPercentile())
136 | .addValue("95-percentile", snapshot.get95thPercentile())
137 | .addValue("99-percentile", snapshot.get99thPercentile())
138 | .addValue("999-percentile", snapshot.get999thPercentile())
139 | .addValue("run-count", h.getCount());
140 | return measure;
141 | }
142 |
143 | private Measure fromCounter(String metricName, Counter c, long timestamp) {
144 | Map tags = new HashMap(baseTags);
145 | tags.putAll(transformer.tags(metricName));
146 |
147 | Measure measure = new Measure(transformer.measurementName(metricName))
148 | .timestamp(timestamp)
149 | .addTag(tags)
150 | .addValue("count", c.getCount());
151 |
152 | return measure;
153 | }
154 |
155 | @SuppressWarnings("rawtypes")
156 | private Measure fromGauge(String metricName, Gauge g, long timestamp) {
157 | Map tags = new HashMap(baseTags);
158 | tags.putAll(transformer.tags(metricName));
159 |
160 | Measure measure = new Measure(transformer.measurementName(metricName))
161 | .timestamp(timestamp)
162 | .addTag(tags);
163 | Object o = g.getValue();
164 |
165 | if (o == null) {
166 | // skip null values
167 | return null;
168 | }
169 | if (o instanceof Long || o instanceof Integer) {
170 | long value = ((Number)o).longValue();
171 | measure.addValue("value", value);
172 | } else if (o instanceof Double) {
173 | Double d = (Double) o;
174 | if (d.isInfinite() || d.isNaN()) {
175 | // skip Infinite & NaN
176 | return null;
177 | }
178 | measure.addValue("value", d.doubleValue());
179 | } else if (o instanceof Float) {
180 | Float f = (Float) o;
181 | if (f.isInfinite() || f.isNaN()) {
182 | // skip Infinite & NaN
183 | return null;
184 | }
185 | measure.addValue("value", f.floatValue());
186 | } else {
187 | String value = ""+o;
188 | measure.addValue("value", value);
189 | }
190 |
191 | return measure;
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/measurements/QueueableSender.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.measurements;
2 |
3 | import java.io.IOException;
4 | import java.util.Collection;
5 |
6 | import metrics_influxdb.misc.BoundedFIFO;
7 |
8 | public class QueueableSender extends AbstractSender {
9 | private final Collection measures;
10 | private int queueSize;
11 |
12 | protected QueueableSender(int queueSize) {
13 | this.queueSize = queueSize;
14 | measures = new BoundedFIFO<>(queueSize);
15 | }
16 |
17 | @Override
18 | public void flush() {
19 | if (doSend(measures)) {
20 | measures.clear();
21 | }
22 | }
23 |
24 | @Override
25 | public void send(Measure m) {
26 | if (m == null) {
27 | return; // NOOP for null measures
28 | }
29 | if (measures.size() == queueSize) {
30 | // we have already reached the maximumn number of measure that can be sent in one shot
31 | // let's send them before adding a new one
32 | if (doSend(measures)) {
33 | measures.clear();
34 | }
35 | }
36 | measures.add(m);
37 | }
38 |
39 | /**
40 | * Realizes the action to send the measures
41 | * @param measuresToSend the collection of measure to be sent
42 | * @return true if the measures have been sent and can be discarded, false otherwise
43 | */
44 | protected boolean doSend(Collection measuresToSend) {
45 | return true;
46 | }
47 |
48 | @Override
49 | public void close() throws IOException {
50 | measures.clear();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/measurements/Sender.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.measurements;
2 |
3 | import java.io.Closeable;
4 | import java.util.Collection;
5 |
6 | public interface Sender extends Closeable {
7 | /**
8 | * Flushes measurements still held and forces them to be sent.
9 | */
10 | public void flush();
11 | /**
12 | * Send the given {@link Measure}.
13 | * Depending on the implementation, the {@link Sender} is allowed to enqueue the real sending action.
14 | * @param m the Measure to be sent, if null this method is a NOOP
15 | */
16 | public void send(Measure m);
17 | /**
18 | * Send the given Measures.
19 | * Depending on the implementation, the {@link Sender} is allowed to enqueue the real sending action.
20 | * @param measures the Measures to be sent, if null this method is a NOOP
21 | */
22 | public void send(Collection measures);
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/measurements/UdpInlinerSender.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.measurements;
2 |
3 | import java.io.IOException;
4 | import java.net.InetSocketAddress;
5 | import java.nio.ByteBuffer;
6 | import java.nio.channels.DatagramChannel;
7 | import java.util.Collection;
8 | import java.util.Iterator;
9 | import java.util.concurrent.TimeUnit;
10 |
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import metrics_influxdb.UdpInfluxdbProtocol;
15 | import metrics_influxdb.misc.Miscellaneous;
16 | import metrics_influxdb.serialization.line.Inliner;
17 |
18 | public class UdpInlinerSender extends QueueableSender {
19 | private final static Logger LOGGER = LoggerFactory.getLogger(UdpInlinerSender.class);
20 | private static int MAX_MEASURES_IN_SINGLE_POST = 5000;
21 | private final Inliner inliner;
22 | private final InetSocketAddress serverAddress;
23 |
24 | public UdpInlinerSender(UdpInfluxdbProtocol protocol) {
25 | super(MAX_MEASURES_IN_SINGLE_POST);
26 | inliner = new Inliner(TimeUnit.NANOSECONDS);
27 | serverAddress = new InetSocketAddress(protocol.host, protocol.port);
28 | }
29 |
30 | @Override
31 | protected boolean doSend(Collection measures) {
32 | if (measures.isEmpty()) {
33 | return true;
34 | }
35 |
36 | DatagramChannel channel = null;
37 | try {
38 | channel = DatagramChannel.open();
39 | } catch (IOException e) {
40 | LOGGER.error("failed open udp channel", e);
41 | return false;
42 | }
43 | Iterator measuresIterator = measures.iterator();
44 | int errorCounter = 0;
45 | int successCounter = 0;
46 | while(measuresIterator.hasNext()) {
47 | String measuresAsString = inliner.inline(measuresIterator.next());
48 | try {
49 | if (LOGGER.isDebugEnabled()) {
50 | LOGGER.debug("Measure being sent:\n{}", measuresAsString);
51 | }
52 |
53 | ByteBuffer buffer = ByteBuffer.wrap(measuresAsString.getBytes(Miscellaneous.UTF8));
54 | channel.send(buffer, serverAddress);
55 | successCounter++;
56 | } catch (Throwable e) {
57 | errorCounter++;
58 | }
59 | }
60 | LOGGER.debug("{} Measures sent to UDP[{}:{}]; successes: {}, failures: {}",
61 | measures.size(), serverAddress.getHostString(), serverAddress.getPort(), successCounter, errorCounter);
62 | try {
63 | channel.close();
64 | } catch (IOException e) {
65 | LOGGER.error("failed close udp channel", e);
66 | }
67 | return successCounter > 0;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/misc/BoundedFIFO.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.misc;
2 |
3 | import java.util.Collection;
4 | import java.util.Iterator;
5 | import java.util.Queue;
6 | import java.util.concurrent.LinkedBlockingQueue;
7 | import java.util.concurrent.TimeUnit;
8 |
9 | public class BoundedFIFO implements Queue {
10 | private final LinkedBlockingQueue delegate;
11 |
12 | public BoundedFIFO(int capacity) {
13 | this.delegate = new LinkedBlockingQueue<>(capacity);
14 | }
15 |
16 | public int hashCode() {
17 | return delegate.hashCode();
18 | }
19 |
20 | public boolean add(T e) {
21 | while (!delegate.offer(e)) {
22 | delegate.poll();
23 | }
24 | return true;
25 | }
26 |
27 | public boolean isEmpty() {
28 | return delegate.isEmpty();
29 | }
30 |
31 | public T remove() {
32 | return delegate.remove();
33 | }
34 |
35 | public boolean equals(Object obj) {
36 | return delegate.equals(obj);
37 | }
38 |
39 | public T element() {
40 | return delegate.element();
41 | }
42 |
43 | public boolean addAll(Collection extends T> c) {
44 | return delegate.addAll(c);
45 | }
46 |
47 | public int size() {
48 | return delegate.size();
49 | }
50 |
51 | public int remainingCapacity() {
52 | return delegate.remainingCapacity();
53 | }
54 |
55 | public void put(T e) throws InterruptedException {
56 | delegate.put(e);
57 | }
58 |
59 | public boolean containsAll(Collection> c) {
60 | return delegate.containsAll(c);
61 | }
62 |
63 | public boolean offer(T e, long timeout, TimeUnit unit) throws InterruptedException {
64 | return offer(e);
65 | }
66 |
67 | public boolean removeAll(Collection> c) {
68 | return delegate.removeAll(c);
69 | }
70 |
71 | public boolean offer(T e) {
72 | while (!delegate.offer(e)) {
73 | delegate.poll();
74 | }
75 | return true;
76 | }
77 |
78 | public boolean retainAll(Collection> c) {
79 | return delegate.retainAll(c);
80 | }
81 |
82 | public T take() throws InterruptedException {
83 | return delegate.take();
84 | }
85 |
86 | public T poll(long timeout, TimeUnit unit) throws InterruptedException {
87 | return delegate.poll(timeout, unit);
88 | }
89 |
90 | public T poll() {
91 | return delegate.poll();
92 | }
93 |
94 | public T peek() {
95 | return delegate.peek();
96 | }
97 |
98 | public boolean remove(Object o) {
99 | return delegate.remove(o);
100 | }
101 |
102 | public boolean contains(Object o) {
103 | return delegate.contains(o);
104 | }
105 |
106 | public Object[] toArray() {
107 | return delegate.toArray();
108 | }
109 |
110 | public E[] toArray(E[] a) {
111 | return delegate.toArray(a);
112 | }
113 |
114 | public String toString() {
115 | return delegate.toString();
116 | }
117 |
118 | public void clear() {
119 | delegate.clear();
120 | }
121 |
122 | public int drainTo(Collection super T> c) {
123 | return delegate.drainTo(c);
124 | }
125 |
126 | public int drainTo(Collection super T> c, int maxElements) {
127 | return delegate.drainTo(c, maxElements);
128 | }
129 |
130 | public Iterator iterator() {
131 | return delegate.iterator();
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/misc/HttpDatabaseCreator.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.misc;
2 |
3 | import metrics_influxdb.HttpInfluxdbProtocol;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | import java.io.IOException;
8 | import java.io.OutputStream;
9 | import java.io.UnsupportedEncodingException;
10 | import java.net.HttpURLConnection;
11 | import java.net.MalformedURLException;
12 | import java.net.URL;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | public final class HttpDatabaseCreator {
16 | private static final Logger LOGGER = LoggerFactory.getLogger(HttpDatabaseCreator.class);
17 |
18 | /**
19 | * Runs a CREATE DATABASE against influx. Influx does not do any action if the database already exists.
20 | */
21 | public static void run(HttpInfluxdbProtocol protocol) {
22 | URL toJoin;
23 |
24 | try {
25 | if (protocol.secured) {
26 | toJoin = new URL(protocol.scheme, protocol.host, protocol.port, "/query&u="
27 | + Miscellaneous.urlEncode(protocol.user) + "&p=" + Miscellaneous.urlEncode(protocol.password));
28 | } else {
29 | toJoin = new URL(protocol.scheme, protocol.host, protocol.port, "/query");
30 | }
31 | } catch (MalformedURLException | UnsupportedEncodingException e) {
32 | toJoin = null;
33 | }
34 | String database = protocol.database;
35 | URL queryUrl = toJoin;
36 | try {
37 | HttpURLConnection con;
38 |
39 | con = (HttpURLConnection) queryUrl.openConnection();
40 | con.setRequestMethod("GET");
41 | con.setConnectTimeout(Long.valueOf(TimeUnit.SECONDS.toMillis(2)).intValue());
42 | con.setReadTimeout(Long.valueOf(TimeUnit.SECONDS.toMillis(2)).intValue());
43 |
44 | con.setDoOutput(true);
45 | OutputStream wr = con.getOutputStream();
46 | wr.write(("q=CREATE DATABASE " + database).getBytes());
47 | wr.flush();
48 | wr.close();
49 | } catch (IOException e) {
50 | LOGGER.warn("Tried to create database, but failed.", e);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/misc/Miscellaneous.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.misc;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.InputStreamReader;
6 | import java.io.UnsupportedEncodingException;
7 | import java.net.URLEncoder;
8 | import java.nio.charset.Charset;
9 | import java.util.Objects;
10 |
11 | public class Miscellaneous {
12 | public static Charset UTF8 = Charset.forName("UTF-8");
13 |
14 | public static String escape(String name, char... toEscape) {
15 | String result = name;
16 |
17 | for (char c : toEscape) {
18 | result = result.replace(Character.toString(c), "\\" + c);
19 | }
20 |
21 | return result;
22 | }
23 |
24 | public static String urlEncode(String s) throws UnsupportedEncodingException {
25 | return URLEncoder.encode(s, UTF8.name());
26 | }
27 |
28 | public static String readFrom(InputStream is) throws IOException {
29 | try (InputStreamReader isr = new InputStreamReader(is, UTF8)) {
30 | StringBuffer sb = new StringBuffer();
31 | char[] buffer = new char[2048];
32 |
33 | int read;
34 | while ((read = isr.read(buffer, 0, 2048)) != -1) {
35 | sb.append(buffer, 0, read);
36 | }
37 |
38 | return sb.toString();
39 | }
40 | }
41 |
42 | /**
43 | * Checks that given string is not empty (null check is also performed)
44 | * @param s the string to check
45 | * @throws IllegalArgumentException if the string is empty
46 | * @throws NullPointerException if the string is null
47 | */
48 | public static void requireNotEmpty(String s) {
49 | requireNotEmptyParameter(s, "string");
50 | }
51 |
52 | /**
53 | * Checks that given string is not empty (null check is also performed)
54 | * @param s the string to check
55 | * @param parameter the name of the parameter to be used in error messages
56 | * @throws IllegalArgumentException if the string is empty
57 | * @throws NullPointerException if the string is null
58 | */
59 | public static void requireNotEmptyParameter(String s, String parameter) {
60 | Objects.requireNonNull(s, "given " + parameter + " cannot be null");
61 | if ("".equals(s.trim())) {
62 | throw new IllegalArgumentException("given " + parameter + " cannot be empty");
63 | }
64 | }
65 |
66 | /**
67 | * Checks that given string is not empty (null check is also performed)
68 | * @param s the string to check
69 | * @param message the message to use in case it is empty
70 | * @throws IllegalArgumentException if the string is empty
71 | * @throws NullPointerException if the string is null
72 | */
73 | public static void requireNotEmpty(String s, String message) {
74 | Objects.requireNonNull(s);
75 | if ("".equals(s.trim())) {
76 | throw new IllegalArgumentException(message);
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/misc/VisibilityIncreasedForTests.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.misc;
2 |
3 | import java.lang.annotation.Retention;
4 | import java.lang.annotation.RetentionPolicy;
5 |
6 | @Retention(RetentionPolicy.SOURCE)
7 | /**
8 | * Simple marker annotation
9 | */
10 | public @interface VisibilityIncreasedForTests {
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/serialization/line/InfluxDBSortedMap.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.serialization.line;
2 |
3 | import java.util.TreeMap;
4 |
5 | /**
6 | * Not sure if something needs to be done to match golang byte comparison as described in influxdb documentation
7 | * Let's use a simple TreeMap with no comparator so that lexical order will be used.
8 | */
9 | public class InfluxDBSortedMap extends TreeMap {
10 | private static final long serialVersionUID = -7218529992523196655L;
11 |
12 | public InfluxDBSortedMap() {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/serialization/line/Inliner.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.serialization.line;
2 |
3 | import java.util.Map;
4 | import java.util.concurrent.TimeUnit;
5 |
6 | import metrics_influxdb.measurements.Measure;
7 | import metrics_influxdb.misc.Miscellaneous;
8 |
9 | public class Inliner {
10 | private static char[] ESCAPE_CHARS = {' ', ',', '='};
11 |
12 | private TimeUnit precision;
13 |
14 | public Inliner(TimeUnit precision) {
15 | this.precision = precision;
16 | }
17 |
18 | public String inline(Measure m) {
19 | String key = buildMeasureKey(m.getName(), m.getTags());
20 | String values = buildMeasureFields(m.getValues());
21 | String timestamp = "" + precision.convert(m.getTimestamp(), TimeUnit.MILLISECONDS);
22 |
23 | return key + " " + values + " " + timestamp;
24 | }
25 |
26 | public String inline(Iterable measures) {
27 | StringBuilder sb = new StringBuilder();
28 | String join = "";
29 | String cr = "\n";
30 | for (Measure m : measures) {
31 | sb.append(join).append(inline(m));
32 | join = cr;
33 | }
34 | return sb.toString();
35 | }
36 |
37 | private String buildMeasureFields(Map values) {
38 | Map sortedValues = new InfluxDBSortedMap();
39 | sortedValues.putAll(values);
40 |
41 | StringBuilder fields = new StringBuilder();
42 | String join = "";
43 |
44 | for (Map.Entry v: sortedValues.entrySet()) {
45 | fields.append(join).append(Miscellaneous.escape(v.getKey(), ESCAPE_CHARS)).append("=").append(v.getValue()); // values are already escaped
46 | join = ",";
47 | }
48 | return fields.toString();
49 | }
50 |
51 | private String buildMeasureKey(String name, Map tags) {
52 | StringBuilder key = new StringBuilder(Miscellaneous.escape(name, ESCAPE_CHARS));
53 | Map sortedTags = new InfluxDBSortedMap();
54 | sortedTags.putAll(tags);
55 |
56 | for (Map.Entry e: sortedTags.entrySet()) {
57 | key.append(',').append(Miscellaneous.escape(e.getKey(), ESCAPE_CHARS)).append("=").append(Miscellaneous.escape(e.getValue(), ESCAPE_CHARS));
58 | }
59 |
60 | return key.toString();
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/v08/Influxdb.java:
--------------------------------------------------------------------------------
1 | package metrics_influxdb.v08;
2 |
3 | public interface Influxdb {
4 | public void resetRequest();
5 | public boolean hasSeriesData();
6 | public long convertTimestamp(long timestamp);
7 | public void appendSeries(String namePrefix, String name, String nameSuffix, String[] columns, Object[][] points);
8 | public int sendRequest(boolean throwExc, boolean printJson) throws Exception;
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/metrics_influxdb/v08/InfluxdbHttp.java:
--------------------------------------------------------------------------------
1 | // metrics-influxdb
2 | //
3 | // Written in 2014 by David Bernard
4 | //
5 | // [other author/contributor lines as appropriate]
6 | //
7 | // To the extent possible under law, the author(s) have dedicated all copyright and
8 | // related and neighboring rights to this software to the public domain worldwide.
9 | // This software is distributed without any warranty.
10 | //
11 | // You should have received a copy of the CC0 Public Domain Dedication along with
12 | // this software. If not, see .
13 | package metrics_influxdb.v08;
14 |
15 | import java.io.IOException;
16 | import java.io.OutputStream;
17 | import java.net.HttpURLConnection;
18 | import java.net.URI;
19 | import java.net.URL;
20 | import java.net.URLEncoder;
21 | import java.nio.charset.Charset;
22 | import java.util.concurrent.TimeUnit;
23 |
24 | /**
25 | * A client to send data to a InfluxDB server via HTTP protocol.
26 | *
27 | * The usage :
28 | *
29 | *