├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md └── levitate ├── change-events ├── python │ ├── README.md │ ├── change_event.py │ └── requirements.txt ├── ruby │ └── change-event.rb └── rust │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ └── src │ └── main.rs ├── exporter ├── kube-state-metrics │ └── README.md └── statping │ └── README.md ├── grafana-dashboards └── cloudswatch-metric-stream │ ├── ec2 │ ├── README.md │ └── dashboard.json │ └── rds │ ├── README.md │ └── dashboard.json └── remote-write ├── jmxtrans ├── .gitignore ├── README.md ├── docker-compose.yaml ├── jmxtrans-config │ └── graphite.json ├── jvmapp │ ├── Dockerfile │ └── SampleApp.java ├── relabel.yaml └── vmagent.yaml ├── opentelemetry-collector ├── opencensus-receiver │ └── docker │ │ └── README.md └── prometheus-receiver │ ├── README.md │ ├── app │ ├── Dockerfile │ ├── go.mod │ ├── go.sum │ └── main.go │ ├── docker-compose.yaml │ └── otel-collector-config.yaml ├── prometheus-agent └── k8s │ └── README.md ├── python ├── README.md └── app.py ├── statsd ├── relay │ ├── .gitignore │ ├── README.md │ ├── docker-compose.yaml │ ├── statsd │ │ ├── Dockerfile │ │ └── config.js │ ├── test │ │ ├── requirements.txt │ │ └── statsd-test.py │ └── vmagent.yaml ├── repeater │ ├── .gitignore │ ├── README.md │ ├── docker-compose.yaml │ ├── statsd │ │ ├── Dockerfile │ │ └── config.js │ ├── test │ │ ├── requirements.txt │ │ └── statsd-test.py │ └── vmagent.yaml └── vmagent-graphite │ ├── .gitignore │ ├── README.md │ ├── docker-compose.yaml │ ├── statsd │ ├── Dockerfile │ └── config.js │ ├── test │ ├── requirements.txt │ └── statsd-test.py │ └── vmagent.yaml ├── telegraf ├── http-prometheusremotewrite │ ├── .gitignore │ ├── README.md │ ├── docker-compose.yaml │ ├── telegraf │ │ └── etc │ │ │ └── telegraf.conf │ └── test │ │ └── statsd-test.py ├── influxdb-to-vmagent │ ├── .gitignore │ ├── README.md │ ├── docker-compose.yaml │ ├── telegraf │ │ └── etc │ │ │ └── telegraf.conf │ ├── test │ │ └── statsd-test.py │ └── vmagent.yaml └── prometheus-client │ ├── .gitignore │ ├── README.md │ ├── docker-compose.yaml │ ├── telegraf │ └── etc │ │ └── telegraf.conf │ ├── test │ └── statsd-test.py │ └── vmagent.yaml └── vmagent ├── docker └── README.md ├── ecs └── README.md └── k8s └── README.md /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | . 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 last9 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # last9-integrations 4 | 5 | Integrations and reference code used for Last9 products. 6 | 7 | ## Levitate Integrations 8 | 9 | [Levitate](https://last9.io/levitate-tsdb) is Last9’s managed time series data warehouse. 10 | 11 | We built Levitate to give engineering teams a cost-effective tool to monitor large, complex systems. Now, engineering hours are not spent monitoring your monitor i.e. managing TSDB availability, scaling, replication, and multiple instances. 12 | 13 | #### Solves High Cardinality 14 | 15 | Levitate is built to handle the massive scales of data and can handle queries at any cardinality. Above all, it gives you real-time insights into what metrics are unused. 16 | 17 | #### Pay for what you use, reduce costs 18 | 19 | Levitate reduces storage costs by up to 50% compared to similar TSDBs. This is over and above the engineering time, and overheads spent maintaining internal infrastructure. 20 | With Levitate's data retention policies & tiered storage, you pay for the metrics you use. Scale without having to tune the configuration & having to run a whole setup for data scaling. 21 | 22 | #### Increase engineering productivity 23 | 24 | Levitate is fully managed. No need to worry about adding more machines, managing replication, or multiple Prometheus instances. Just change the remote-write endpoint of your one or many TSDBs. A simple UI manages it all. 25 | 26 | With Levitate, you can resolve incidents faster with decreased querying times, and allow engineering to focus on building the product. 27 | 28 | Levitate is easy to integrate with any source that can send metrics to Prometheus. 29 | 30 | ---- 31 | 32 | Find sample applications of supported integrations and some useful exporter demo setups below. 33 | 34 | ### remote-write 35 | 36 | Sample setups of common remote write integrations. 37 | 38 | - [opentelemetry collector via prometheus receiver](./levitate/remote-write/opentelemetry-collector/prometheus-receiver) 39 | - [statsd](./levitate/remote-write/statsd) 40 | - [telegraf](./levitate/remote-write/telegraf) 41 | - [jmxtrans](./levitate/remote-write/jmxtrans) 42 | - [vmagent](./levitate/remote-write/vmagent) - WIP 🏗️ 43 | 44 | ### exporters 45 | 46 | Sample setups of common Prometheus exporters. 47 | 48 | - [kube-state-metrics](./levitate/exporter/kube-state-metrics) - WIP 🏗️ 49 | - [statping](./levitate/exporter/statping) - WIP 🏗️ 50 | -------------------------------------------------------------------------------- /levitate/change-events/python/README.md: -------------------------------------------------------------------------------- 1 | ## Levitate Change Event Registration 2 | 3 | This Python script is used to register a change event with the Levitate API. 4 | 5 | ### Requirements 6 | 7 | - Python 8 | - requests library 9 | 10 | ### Setup 11 | 12 | Set up a virtual environment and activate it: 13 | 14 | ``` shell 15 | python3 -m venv venv 16 | source venv/bin/activate 17 | ``` 18 | 19 | Install the required Python libraries: 20 | 21 | ``` shell 22 | pip install -r requirements.txt 23 | ``` 24 | 25 | Set the required environment variables: 26 | 27 | ``` shell 28 | export LEVITATE_REFRESH_TOKEN= 29 | export LEVITATE_ORG= 30 | ``` 31 | 32 | Follow the instructions [here](https://docs.last9.io/docs/change-events) to obtain the values of the environment variables. 33 | 34 | ### Usage 35 | 36 | Run the script: 37 | 38 | ``` shell 39 | python change_event.py 40 | ``` 41 | 42 | If the change event is registered successfully, the script will print "Change event registered successfully". If there is an error, an exception will be raised with a message indicating the cause of the error. 43 | -------------------------------------------------------------------------------- /levitate/change-events/python/change_event.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | import json 4 | 5 | LEVITATE_REFRESH_TOKEN = os.getenv("LEVITATE_REFRESH_TOKEN") 6 | LEVITATE_ACCESS_TOKEN_API = "https://app.last9.io/api/v4/oauth/access_token" 7 | LEVITATE_ORG = os.getenv("LEVITATE_ORG") 8 | 9 | def api_token(): 10 | headers = {'Content-Type': 'application/json'} 11 | data = {"refresh_token": LEVITATE_REFRESH_TOKEN} 12 | response = requests.post(LEVITATE_ACCESS_TOKEN_API, headers=headers, data=json.dumps(data)) 13 | 14 | if response.status_code != 200: 15 | raise Exception("Access Token can't be retrieved, {}".format(response.text)) 16 | 17 | body = response.json() 18 | return body["access_token"] 19 | 20 | if not LEVITATE_REFRESH_TOKEN: 21 | raise Exception("LEVITATE_REFRESH_TOKEN is not set") 22 | 23 | if not LEVITATE_ORG: 24 | raise Exception("LEVITATE_ORG is not set") 25 | 26 | url = "https://app.last9.io/api/v4/organizations/{}/change_events".format(LEVITATE_ORG) 27 | headers = { 28 | 'Content-Type': 'application/json', 29 | 'X-LAST9-API-TOKEN': 'Bearer {}'.format(api_token()) 30 | } 31 | data = { 32 | "event_name": "deployment", 33 | "event_state": "start", 34 | "attributes": { 35 | "revision": "", 36 | "user": "john.smith", 37 | "environment": "production" 38 | } 39 | } 40 | response = requests.put(url, headers=headers, data=json.dumps(data)) 41 | 42 | if response.status_code == 200: 43 | print("Change event registered successfully") 44 | else: 45 | raise Exception("Change Event -> Levitate failed. {}".format(response.text)) 46 | -------------------------------------------------------------------------------- /levitate/change-events/python/requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.31.0 2 | -------------------------------------------------------------------------------- /levitate/change-events/ruby/change-event.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "net/http" 4 | require "uri" 5 | require "json" 6 | 7 | # Follow the guide on 8 | LEVITATE_REFRESH_TOKEN = ENV["LEVITATE_REFRESH_TOKEN"] 9 | LEVITATE_ACCESS_TOKEN_API = "https://app.last9.io/api/v4/oauth/access_token" 10 | LEVITATE_ORG = ENV["LEVITATE_ORG"] 11 | 12 | class Levitate 13 | def api_token 14 | uri = URI.parse(LEVITATE_ACCESS_TOKEN_API) 15 | request = Net::HTTP::Post.new(uri) 16 | request.content_type = "application/json" 17 | request.body = JSON.dump({ 18 | "refresh_token": LEVITATE_REFRESH_TOKEN 19 | }) 20 | req_options = { 21 | use_ssl: uri.scheme == "https", 22 | } 23 | 24 | response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http| 25 | http.request(request) 26 | end 27 | 28 | 29 | body = JSON.parse(response.body) 30 | if body["access_token"] == nil 31 | raise "Access Token can't be rertieved, #{body}" 32 | end 33 | 34 | body["access_token"] 35 | end 36 | end 37 | 38 | 39 | raise "LEVITATE_REFRESH_TOKEN is not set" unless LEVITATE_REFRESH_TOKEN 40 | raise "LEVITATE_ORG is not set" unless LEVITATE_ORG 41 | 42 | uri = URI.parse("https://app.last9.io/api/v4/organizations/#{LEVITATE_ORG}/change_events") 43 | request = Net::HTTP::Put.new(uri) 44 | request.content_type = "application/json" 45 | request["X-LAST9-API-TOKEN"] = "Bearer #{Levitate.new.api_token}" 46 | request.body = JSON.dump({ 47 | "event_name" => "deployment", 48 | "event_state" => "start", 49 | "attributes" => { 50 | # Add more metadata about which service is getting deployed 51 | "revision" => "", 52 | "user" => "john.smith", 53 | "environment" => "production" 54 | } 55 | }) 56 | req_options = { 57 | use_ssl: uri.scheme == "https", 58 | } 59 | 60 | response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http| 61 | http.request(request) 62 | end 63 | 64 | if response.code == '200' 65 | puts "Change event registered succesfully" 66 | else 67 | raise "Change Event -> Levitate failed. #{response.body}" 68 | end 69 | -------------------------------------------------------------------------------- /levitate/change-events/rust/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /levitate/change-events/rust/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "autocfg" 22 | version = "1.2.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" 25 | 26 | [[package]] 27 | name = "backtrace" 28 | version = "0.3.71" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" 31 | dependencies = [ 32 | "addr2line", 33 | "cc", 34 | "cfg-if", 35 | "libc", 36 | "miniz_oxide", 37 | "object", 38 | "rustc-demangle", 39 | ] 40 | 41 | [[package]] 42 | name = "base64" 43 | version = "0.21.7" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 46 | 47 | [[package]] 48 | name = "bitflags" 49 | version = "1.3.2" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 52 | 53 | [[package]] 54 | name = "bitflags" 55 | version = "2.5.0" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" 58 | 59 | [[package]] 60 | name = "bumpalo" 61 | version = "3.16.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 64 | 65 | [[package]] 66 | name = "bytes" 67 | version = "1.6.0" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" 70 | 71 | [[package]] 72 | name = "cc" 73 | version = "1.0.95" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "d32a725bc159af97c3e629873bb9f88fb8cf8a4867175f76dc987815ea07c83b" 76 | 77 | [[package]] 78 | name = "cfg-if" 79 | version = "1.0.0" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 82 | 83 | [[package]] 84 | name = "core-foundation" 85 | version = "0.9.4" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 88 | dependencies = [ 89 | "core-foundation-sys", 90 | "libc", 91 | ] 92 | 93 | [[package]] 94 | name = "core-foundation-sys" 95 | version = "0.8.6" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" 98 | 99 | [[package]] 100 | name = "encoding_rs" 101 | version = "0.8.34" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" 104 | dependencies = [ 105 | "cfg-if", 106 | ] 107 | 108 | [[package]] 109 | name = "equivalent" 110 | version = "1.0.1" 111 | source = "registry+https://github.com/rust-lang/crates.io-index" 112 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 113 | 114 | [[package]] 115 | name = "errno" 116 | version = "0.3.8" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" 119 | dependencies = [ 120 | "libc", 121 | "windows-sys 0.52.0", 122 | ] 123 | 124 | [[package]] 125 | name = "fastrand" 126 | version = "2.0.2" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" 129 | 130 | [[package]] 131 | name = "fnv" 132 | version = "1.0.7" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 135 | 136 | [[package]] 137 | name = "foreign-types" 138 | version = "0.3.2" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 141 | dependencies = [ 142 | "foreign-types-shared", 143 | ] 144 | 145 | [[package]] 146 | name = "foreign-types-shared" 147 | version = "0.1.1" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 150 | 151 | [[package]] 152 | name = "form_urlencoded" 153 | version = "1.2.1" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 156 | dependencies = [ 157 | "percent-encoding", 158 | ] 159 | 160 | [[package]] 161 | name = "futures-channel" 162 | version = "0.3.30" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 165 | dependencies = [ 166 | "futures-core", 167 | ] 168 | 169 | [[package]] 170 | name = "futures-core" 171 | version = "0.3.30" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 174 | 175 | [[package]] 176 | name = "futures-io" 177 | version = "0.3.30" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" 180 | 181 | [[package]] 182 | name = "futures-sink" 183 | version = "0.3.30" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 186 | 187 | [[package]] 188 | name = "futures-task" 189 | version = "0.3.30" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 192 | 193 | [[package]] 194 | name = "futures-util" 195 | version = "0.3.30" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 198 | dependencies = [ 199 | "futures-core", 200 | "futures-io", 201 | "futures-task", 202 | "memchr", 203 | "pin-project-lite", 204 | "pin-utils", 205 | "slab", 206 | ] 207 | 208 | [[package]] 209 | name = "gimli" 210 | version = "0.28.1" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 213 | 214 | [[package]] 215 | name = "h2" 216 | version = "0.3.26" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" 219 | dependencies = [ 220 | "bytes", 221 | "fnv", 222 | "futures-core", 223 | "futures-sink", 224 | "futures-util", 225 | "http", 226 | "indexmap", 227 | "slab", 228 | "tokio", 229 | "tokio-util", 230 | "tracing", 231 | ] 232 | 233 | [[package]] 234 | name = "hashbrown" 235 | version = "0.14.3" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" 238 | 239 | [[package]] 240 | name = "http" 241 | version = "0.2.12" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" 244 | dependencies = [ 245 | "bytes", 246 | "fnv", 247 | "itoa", 248 | ] 249 | 250 | [[package]] 251 | name = "http-body" 252 | version = "0.4.6" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" 255 | dependencies = [ 256 | "bytes", 257 | "http", 258 | "pin-project-lite", 259 | ] 260 | 261 | [[package]] 262 | name = "httparse" 263 | version = "1.8.0" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 266 | 267 | [[package]] 268 | name = "httpdate" 269 | version = "1.0.3" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 272 | 273 | [[package]] 274 | name = "hyper" 275 | version = "0.14.28" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" 278 | dependencies = [ 279 | "bytes", 280 | "futures-channel", 281 | "futures-core", 282 | "futures-util", 283 | "h2", 284 | "http", 285 | "http-body", 286 | "httparse", 287 | "httpdate", 288 | "itoa", 289 | "pin-project-lite", 290 | "socket2", 291 | "tokio", 292 | "tower-service", 293 | "tracing", 294 | "want", 295 | ] 296 | 297 | [[package]] 298 | name = "hyper-tls" 299 | version = "0.5.0" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" 302 | dependencies = [ 303 | "bytes", 304 | "hyper", 305 | "native-tls", 306 | "tokio", 307 | "tokio-native-tls", 308 | ] 309 | 310 | [[package]] 311 | name = "idna" 312 | version = "0.5.0" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 315 | dependencies = [ 316 | "unicode-bidi", 317 | "unicode-normalization", 318 | ] 319 | 320 | [[package]] 321 | name = "indexmap" 322 | version = "2.2.6" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" 325 | dependencies = [ 326 | "equivalent", 327 | "hashbrown", 328 | ] 329 | 330 | [[package]] 331 | name = "ipnet" 332 | version = "2.9.0" 333 | source = "registry+https://github.com/rust-lang/crates.io-index" 334 | checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" 335 | 336 | [[package]] 337 | name = "itoa" 338 | version = "1.0.11" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 341 | 342 | [[package]] 343 | name = "js-sys" 344 | version = "0.3.69" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" 347 | dependencies = [ 348 | "wasm-bindgen", 349 | ] 350 | 351 | [[package]] 352 | name = "lazy_static" 353 | version = "1.4.0" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 356 | 357 | [[package]] 358 | name = "libc" 359 | version = "0.2.153" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" 362 | 363 | [[package]] 364 | name = "linux-raw-sys" 365 | version = "0.4.13" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" 368 | 369 | [[package]] 370 | name = "log" 371 | version = "0.4.21" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 374 | 375 | [[package]] 376 | name = "memchr" 377 | version = "2.7.2" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" 380 | 381 | [[package]] 382 | name = "mime" 383 | version = "0.3.17" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 386 | 387 | [[package]] 388 | name = "miniz_oxide" 389 | version = "0.7.2" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" 392 | dependencies = [ 393 | "adler", 394 | ] 395 | 396 | [[package]] 397 | name = "mio" 398 | version = "0.8.11" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" 401 | dependencies = [ 402 | "libc", 403 | "wasi", 404 | "windows-sys 0.48.0", 405 | ] 406 | 407 | [[package]] 408 | name = "native-tls" 409 | version = "0.2.11" 410 | source = "registry+https://github.com/rust-lang/crates.io-index" 411 | checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" 412 | dependencies = [ 413 | "lazy_static", 414 | "libc", 415 | "log", 416 | "openssl", 417 | "openssl-probe", 418 | "openssl-sys", 419 | "schannel", 420 | "security-framework", 421 | "security-framework-sys", 422 | "tempfile", 423 | ] 424 | 425 | [[package]] 426 | name = "object" 427 | version = "0.32.2" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" 430 | dependencies = [ 431 | "memchr", 432 | ] 433 | 434 | [[package]] 435 | name = "once_cell" 436 | version = "1.19.0" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 439 | 440 | [[package]] 441 | name = "openssl" 442 | version = "0.10.64" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" 445 | dependencies = [ 446 | "bitflags 2.5.0", 447 | "cfg-if", 448 | "foreign-types", 449 | "libc", 450 | "once_cell", 451 | "openssl-macros", 452 | "openssl-sys", 453 | ] 454 | 455 | [[package]] 456 | name = "openssl-macros" 457 | version = "0.1.1" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 460 | dependencies = [ 461 | "proc-macro2", 462 | "quote", 463 | "syn", 464 | ] 465 | 466 | [[package]] 467 | name = "openssl-probe" 468 | version = "0.1.5" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 471 | 472 | [[package]] 473 | name = "openssl-sys" 474 | version = "0.9.102" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" 477 | dependencies = [ 478 | "cc", 479 | "libc", 480 | "pkg-config", 481 | "vcpkg", 482 | ] 483 | 484 | [[package]] 485 | name = "percent-encoding" 486 | version = "2.3.1" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 489 | 490 | [[package]] 491 | name = "pin-project-lite" 492 | version = "0.2.14" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 495 | 496 | [[package]] 497 | name = "pin-utils" 498 | version = "0.1.0" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 501 | 502 | [[package]] 503 | name = "pkg-config" 504 | version = "0.3.30" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 507 | 508 | [[package]] 509 | name = "proc-macro2" 510 | version = "1.0.81" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" 513 | dependencies = [ 514 | "unicode-ident", 515 | ] 516 | 517 | [[package]] 518 | name = "quote" 519 | version = "1.0.36" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 522 | dependencies = [ 523 | "proc-macro2", 524 | ] 525 | 526 | [[package]] 527 | name = "reqwest" 528 | version = "0.11.27" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" 531 | dependencies = [ 532 | "base64", 533 | "bytes", 534 | "encoding_rs", 535 | "futures-core", 536 | "futures-util", 537 | "h2", 538 | "http", 539 | "http-body", 540 | "hyper", 541 | "hyper-tls", 542 | "ipnet", 543 | "js-sys", 544 | "log", 545 | "mime", 546 | "native-tls", 547 | "once_cell", 548 | "percent-encoding", 549 | "pin-project-lite", 550 | "rustls-pemfile", 551 | "serde", 552 | "serde_json", 553 | "serde_urlencoded", 554 | "sync_wrapper", 555 | "system-configuration", 556 | "tokio", 557 | "tokio-native-tls", 558 | "tower-service", 559 | "url", 560 | "wasm-bindgen", 561 | "wasm-bindgen-futures", 562 | "web-sys", 563 | "winreg", 564 | ] 565 | 566 | [[package]] 567 | name = "rust" 568 | version = "0.1.0" 569 | dependencies = [ 570 | "reqwest", 571 | "serde", 572 | "serde_json", 573 | ] 574 | 575 | [[package]] 576 | name = "rustc-demangle" 577 | version = "0.1.23" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 580 | 581 | [[package]] 582 | name = "rustix" 583 | version = "0.38.34" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 586 | dependencies = [ 587 | "bitflags 2.5.0", 588 | "errno", 589 | "libc", 590 | "linux-raw-sys", 591 | "windows-sys 0.52.0", 592 | ] 593 | 594 | [[package]] 595 | name = "rustls-pemfile" 596 | version = "1.0.4" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" 599 | dependencies = [ 600 | "base64", 601 | ] 602 | 603 | [[package]] 604 | name = "ryu" 605 | version = "1.0.17" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" 608 | 609 | [[package]] 610 | name = "schannel" 611 | version = "0.1.23" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" 614 | dependencies = [ 615 | "windows-sys 0.52.0", 616 | ] 617 | 618 | [[package]] 619 | name = "security-framework" 620 | version = "2.10.0" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" 623 | dependencies = [ 624 | "bitflags 1.3.2", 625 | "core-foundation", 626 | "core-foundation-sys", 627 | "libc", 628 | "security-framework-sys", 629 | ] 630 | 631 | [[package]] 632 | name = "security-framework-sys" 633 | version = "2.10.0" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" 636 | dependencies = [ 637 | "core-foundation-sys", 638 | "libc", 639 | ] 640 | 641 | [[package]] 642 | name = "serde" 643 | version = "1.0.198" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" 646 | dependencies = [ 647 | "serde_derive", 648 | ] 649 | 650 | [[package]] 651 | name = "serde_derive" 652 | version = "1.0.198" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" 655 | dependencies = [ 656 | "proc-macro2", 657 | "quote", 658 | "syn", 659 | ] 660 | 661 | [[package]] 662 | name = "serde_json" 663 | version = "1.0.116" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" 666 | dependencies = [ 667 | "itoa", 668 | "ryu", 669 | "serde", 670 | ] 671 | 672 | [[package]] 673 | name = "serde_urlencoded" 674 | version = "0.7.1" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 677 | dependencies = [ 678 | "form_urlencoded", 679 | "itoa", 680 | "ryu", 681 | "serde", 682 | ] 683 | 684 | [[package]] 685 | name = "slab" 686 | version = "0.4.9" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 689 | dependencies = [ 690 | "autocfg", 691 | ] 692 | 693 | [[package]] 694 | name = "socket2" 695 | version = "0.5.6" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" 698 | dependencies = [ 699 | "libc", 700 | "windows-sys 0.52.0", 701 | ] 702 | 703 | [[package]] 704 | name = "syn" 705 | version = "2.0.60" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" 708 | dependencies = [ 709 | "proc-macro2", 710 | "quote", 711 | "unicode-ident", 712 | ] 713 | 714 | [[package]] 715 | name = "sync_wrapper" 716 | version = "0.1.2" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 719 | 720 | [[package]] 721 | name = "system-configuration" 722 | version = "0.5.1" 723 | source = "registry+https://github.com/rust-lang/crates.io-index" 724 | checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" 725 | dependencies = [ 726 | "bitflags 1.3.2", 727 | "core-foundation", 728 | "system-configuration-sys", 729 | ] 730 | 731 | [[package]] 732 | name = "system-configuration-sys" 733 | version = "0.5.0" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" 736 | dependencies = [ 737 | "core-foundation-sys", 738 | "libc", 739 | ] 740 | 741 | [[package]] 742 | name = "tempfile" 743 | version = "3.10.1" 744 | source = "registry+https://github.com/rust-lang/crates.io-index" 745 | checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" 746 | dependencies = [ 747 | "cfg-if", 748 | "fastrand", 749 | "rustix", 750 | "windows-sys 0.52.0", 751 | ] 752 | 753 | [[package]] 754 | name = "tinyvec" 755 | version = "1.6.0" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 758 | dependencies = [ 759 | "tinyvec_macros", 760 | ] 761 | 762 | [[package]] 763 | name = "tinyvec_macros" 764 | version = "0.1.1" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 767 | 768 | [[package]] 769 | name = "tokio" 770 | version = "1.37.0" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" 773 | dependencies = [ 774 | "backtrace", 775 | "bytes", 776 | "libc", 777 | "mio", 778 | "pin-project-lite", 779 | "socket2", 780 | "windows-sys 0.48.0", 781 | ] 782 | 783 | [[package]] 784 | name = "tokio-native-tls" 785 | version = "0.3.1" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 788 | dependencies = [ 789 | "native-tls", 790 | "tokio", 791 | ] 792 | 793 | [[package]] 794 | name = "tokio-util" 795 | version = "0.7.10" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" 798 | dependencies = [ 799 | "bytes", 800 | "futures-core", 801 | "futures-sink", 802 | "pin-project-lite", 803 | "tokio", 804 | "tracing", 805 | ] 806 | 807 | [[package]] 808 | name = "tower-service" 809 | version = "0.3.2" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 812 | 813 | [[package]] 814 | name = "tracing" 815 | version = "0.1.40" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 818 | dependencies = [ 819 | "pin-project-lite", 820 | "tracing-core", 821 | ] 822 | 823 | [[package]] 824 | name = "tracing-core" 825 | version = "0.1.32" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 828 | dependencies = [ 829 | "once_cell", 830 | ] 831 | 832 | [[package]] 833 | name = "try-lock" 834 | version = "0.2.5" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 837 | 838 | [[package]] 839 | name = "unicode-bidi" 840 | version = "0.3.15" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 843 | 844 | [[package]] 845 | name = "unicode-ident" 846 | version = "1.0.12" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 849 | 850 | [[package]] 851 | name = "unicode-normalization" 852 | version = "0.1.23" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" 855 | dependencies = [ 856 | "tinyvec", 857 | ] 858 | 859 | [[package]] 860 | name = "url" 861 | version = "2.5.0" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" 864 | dependencies = [ 865 | "form_urlencoded", 866 | "idna", 867 | "percent-encoding", 868 | ] 869 | 870 | [[package]] 871 | name = "vcpkg" 872 | version = "0.2.15" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 875 | 876 | [[package]] 877 | name = "want" 878 | version = "0.3.1" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 881 | dependencies = [ 882 | "try-lock", 883 | ] 884 | 885 | [[package]] 886 | name = "wasi" 887 | version = "0.11.0+wasi-snapshot-preview1" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 890 | 891 | [[package]] 892 | name = "wasm-bindgen" 893 | version = "0.2.92" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" 896 | dependencies = [ 897 | "cfg-if", 898 | "wasm-bindgen-macro", 899 | ] 900 | 901 | [[package]] 902 | name = "wasm-bindgen-backend" 903 | version = "0.2.92" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" 906 | dependencies = [ 907 | "bumpalo", 908 | "log", 909 | "once_cell", 910 | "proc-macro2", 911 | "quote", 912 | "syn", 913 | "wasm-bindgen-shared", 914 | ] 915 | 916 | [[package]] 917 | name = "wasm-bindgen-futures" 918 | version = "0.4.42" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" 921 | dependencies = [ 922 | "cfg-if", 923 | "js-sys", 924 | "wasm-bindgen", 925 | "web-sys", 926 | ] 927 | 928 | [[package]] 929 | name = "wasm-bindgen-macro" 930 | version = "0.2.92" 931 | source = "registry+https://github.com/rust-lang/crates.io-index" 932 | checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" 933 | dependencies = [ 934 | "quote", 935 | "wasm-bindgen-macro-support", 936 | ] 937 | 938 | [[package]] 939 | name = "wasm-bindgen-macro-support" 940 | version = "0.2.92" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" 943 | dependencies = [ 944 | "proc-macro2", 945 | "quote", 946 | "syn", 947 | "wasm-bindgen-backend", 948 | "wasm-bindgen-shared", 949 | ] 950 | 951 | [[package]] 952 | name = "wasm-bindgen-shared" 953 | version = "0.2.92" 954 | source = "registry+https://github.com/rust-lang/crates.io-index" 955 | checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" 956 | 957 | [[package]] 958 | name = "web-sys" 959 | version = "0.3.69" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" 962 | dependencies = [ 963 | "js-sys", 964 | "wasm-bindgen", 965 | ] 966 | 967 | [[package]] 968 | name = "windows-sys" 969 | version = "0.48.0" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 972 | dependencies = [ 973 | "windows-targets 0.48.5", 974 | ] 975 | 976 | [[package]] 977 | name = "windows-sys" 978 | version = "0.52.0" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 981 | dependencies = [ 982 | "windows-targets 0.52.5", 983 | ] 984 | 985 | [[package]] 986 | name = "windows-targets" 987 | version = "0.48.5" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 990 | dependencies = [ 991 | "windows_aarch64_gnullvm 0.48.5", 992 | "windows_aarch64_msvc 0.48.5", 993 | "windows_i686_gnu 0.48.5", 994 | "windows_i686_msvc 0.48.5", 995 | "windows_x86_64_gnu 0.48.5", 996 | "windows_x86_64_gnullvm 0.48.5", 997 | "windows_x86_64_msvc 0.48.5", 998 | ] 999 | 1000 | [[package]] 1001 | name = "windows-targets" 1002 | version = "0.52.5" 1003 | source = "registry+https://github.com/rust-lang/crates.io-index" 1004 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" 1005 | dependencies = [ 1006 | "windows_aarch64_gnullvm 0.52.5", 1007 | "windows_aarch64_msvc 0.52.5", 1008 | "windows_i686_gnu 0.52.5", 1009 | "windows_i686_gnullvm", 1010 | "windows_i686_msvc 0.52.5", 1011 | "windows_x86_64_gnu 0.52.5", 1012 | "windows_x86_64_gnullvm 0.52.5", 1013 | "windows_x86_64_msvc 0.52.5", 1014 | ] 1015 | 1016 | [[package]] 1017 | name = "windows_aarch64_gnullvm" 1018 | version = "0.48.5" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 1021 | 1022 | [[package]] 1023 | name = "windows_aarch64_gnullvm" 1024 | version = "0.52.5" 1025 | source = "registry+https://github.com/rust-lang/crates.io-index" 1026 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" 1027 | 1028 | [[package]] 1029 | name = "windows_aarch64_msvc" 1030 | version = "0.48.5" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 1033 | 1034 | [[package]] 1035 | name = "windows_aarch64_msvc" 1036 | version = "0.52.5" 1037 | source = "registry+https://github.com/rust-lang/crates.io-index" 1038 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" 1039 | 1040 | [[package]] 1041 | name = "windows_i686_gnu" 1042 | version = "0.48.5" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 1045 | 1046 | [[package]] 1047 | name = "windows_i686_gnu" 1048 | version = "0.52.5" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" 1051 | 1052 | [[package]] 1053 | name = "windows_i686_gnullvm" 1054 | version = "0.52.5" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" 1057 | 1058 | [[package]] 1059 | name = "windows_i686_msvc" 1060 | version = "0.48.5" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 1063 | 1064 | [[package]] 1065 | name = "windows_i686_msvc" 1066 | version = "0.52.5" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" 1069 | 1070 | [[package]] 1071 | name = "windows_x86_64_gnu" 1072 | version = "0.48.5" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 1075 | 1076 | [[package]] 1077 | name = "windows_x86_64_gnu" 1078 | version = "0.52.5" 1079 | source = "registry+https://github.com/rust-lang/crates.io-index" 1080 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" 1081 | 1082 | [[package]] 1083 | name = "windows_x86_64_gnullvm" 1084 | version = "0.48.5" 1085 | source = "registry+https://github.com/rust-lang/crates.io-index" 1086 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 1087 | 1088 | [[package]] 1089 | name = "windows_x86_64_gnullvm" 1090 | version = "0.52.5" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" 1093 | 1094 | [[package]] 1095 | name = "windows_x86_64_msvc" 1096 | version = "0.48.5" 1097 | source = "registry+https://github.com/rust-lang/crates.io-index" 1098 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 1099 | 1100 | [[package]] 1101 | name = "windows_x86_64_msvc" 1102 | version = "0.52.5" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" 1105 | 1106 | [[package]] 1107 | name = "winreg" 1108 | version = "0.50.0" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" 1111 | dependencies = [ 1112 | "cfg-if", 1113 | "windows-sys 0.48.0", 1114 | ] 1115 | -------------------------------------------------------------------------------- /levitate/change-events/rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | reqwest = { version = "0.11", features = ["blocking", "json"] } 10 | serde = { version = "1.0", features = ["derive"] } 11 | serde_json = "1.0" 12 | -------------------------------------------------------------------------------- /levitate/change-events/rust/README.md: -------------------------------------------------------------------------------- 1 | ## Levitate Change Event Registration 2 | 3 | This Rust script is used to register a change event with the Levitate API. 4 | 5 | ### Requirements 6 | 7 | - rustc 8 | - cargo 9 | 10 | ### Setup 11 | 12 | ``` shell 13 | cargo build 14 | ``` 15 | 16 | Set the required environment variables: 17 | 18 | ``` shell 19 | export LEVITATE_REFRESH_TOKEN= 20 | export LEVITATE_ORG= 21 | ``` 22 | 23 | Follow the instructions [here](https://docs.last9.io/docs/change-events) to obtain the values of the environment variables. 24 | 25 | ### Usage 26 | 27 | Run the script: 28 | 29 | ``` shell 30 | cargo run 31 | ``` 32 | 33 | If the change event is registered successfully, the script will print "Change event registered successfully". If there is an error, an exception will be raised with a message indicating the cause of the error. 34 | -------------------------------------------------------------------------------- /levitate/change-events/rust/src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate reqwest; 2 | extern crate serde; 3 | extern crate serde_json; 4 | 5 | use std::env; 6 | use serde::{Serialize, Deserialize}; 7 | 8 | #[derive(Serialize, Deserialize)] 9 | struct AccessToken { 10 | access_token: String, 11 | } 12 | 13 | #[derive(Serialize, Deserialize)] 14 | struct RefreshToken { 15 | refresh_token: String, 16 | } 17 | 18 | #[derive(Serialize, Deserialize)] 19 | struct Attributes { 20 | revision: String, 21 | user: String, 22 | environment: String, 23 | } 24 | 25 | #[derive(Serialize, Deserialize)] 26 | struct Event { 27 | event_name: String, 28 | event_state: String, 29 | attributes: Attributes, 30 | } 31 | 32 | fn main() -> Result<(), Box> { 33 | let levitate_refresh_token = env::var("LEVITATE_REFRESH_TOKEN").expect("LEVITATE_REFRESH_TOKEN is not set"); 34 | let levitate_org = env::var("LEVITATE_ORG").expect("LEVITATE_ORG is not set"); 35 | 36 | let client = reqwest::blocking::Client::new(); 37 | 38 | let refresh_token = RefreshToken { 39 | refresh_token: levitate_refresh_token, 40 | }; 41 | 42 | let res: AccessToken = client.post("https://app.last9.io/api/v4/oauth/access_token") 43 | .json(&refresh_token) 44 | .send()? 45 | .json()?; 46 | 47 | println!("Access Token: {}", res.access_token); 48 | 49 | let event = Event { 50 | event_name: String::from("deployment"), 51 | event_state: String::from("start"), 52 | attributes: Attributes { 53 | revision: String::from(""), 54 | user: String::from("john.smith"), 55 | environment: String::from("production"), 56 | }, 57 | }; 58 | 59 | let res = client.put(&format!("https://app.last9.io/api/v4/organizations/{}/change_events", levitate_org)) 60 | .header("X-LAST9-API-TOKEN", format!("Bearer {}", res.access_token)) 61 | .json(&event) 62 | .send()?; 63 | 64 | if res.status().is_success() { 65 | println!("Change event registered successfully"); 66 | } else { 67 | eprintln!("Change Event -> Levitate failed. {}", res.text()?); 68 | } 69 | 70 | Ok(()) 71 | } 72 | -------------------------------------------------------------------------------- /levitate/exporter/kube-state-metrics/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/last9/last9-integrations/8c9a66d98f253ff5e7afc0f9824c551b3f61f478/levitate/exporter/kube-state-metrics/README.md -------------------------------------------------------------------------------- /levitate/exporter/statping/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/last9/last9-integrations/8c9a66d98f253ff5e7afc0f9824c551b3f61f478/levitate/exporter/statping/README.md -------------------------------------------------------------------------------- /levitate/grafana-dashboards/cloudswatch-metric-stream/ec2/README.md: -------------------------------------------------------------------------------- 1 | ## How to use? 2 | 3 | This directory contains a sample Grafana dashboard's JSON file based on metrics from AWS Cloudwatch metric stream. 4 | 5 | You can import this into any Grafana, select a data source and start using it. 6 | 7 | ## Dashboard structure 8 | 9 | The dashboard contains following metrics and variables. 10 | 11 | ### Metrics 12 | 13 | 1. The percentage of CPU Utilization `amazonaws_com_AWS_EC2_CPUUtilization` 14 | 2. CPU Credit Balance `amazonaws_com_AWS_EC2_CPUCreditBalance` 15 | 3. Network In `amazonaws_com_AWS_EC2_NetworkIn_sum` 16 | 4. Network Out `amazonaws_com_AWS_EC2_NetworkOut_sum` 17 | 5. Status Check Failed `amazonaws_com_AWS_EC2_StatusCheckFailed_sum` 18 | 6. EBS IO Balance `amazonaws_com_AWS_EC2_EBSIOBalance_` 19 | 7. EBS Byte Balance `amazonaws_com_AWS_EC2_EBSByteBalance_` 20 | 8. CPU Surplus credits charged `amazonaws_com_AWS_EC2_CPUSurplusCreditsCharged_sum` 21 | 22 | ### Variables 23 | 24 | 1. EC2 Instance Identifier 25 | 26 | ## Integrate with AWS Cloudwatch Metric Stream for sending data to Levitate 27 | 28 | Follow our integration guide for [AWS Cloudwatch Metric Stream](https://docs.last9.io/docs/how-to-send-cloudwatch-metrics-to-levitate-via-aws-cloudstream). 29 | 30 | > Note that this step is optional, you can use the dashboard as it is with any other source apart from Levitate if you are already set up with AWS Cloudwatch Metric Stream. 31 | -------------------------------------------------------------------------------- /levitate/grafana-dashboards/cloudswatch-metric-stream/ec2/dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "annotations": { 3 | "list": [ 4 | { 5 | "builtIn": 1, 6 | "datasource": { 7 | "type": "datasource", 8 | "uid": "grafana" 9 | }, 10 | "enable": true, 11 | "hide": true, 12 | "iconColor": "rgba(0, 211, 255, 1)", 13 | "name": "Annotations & Alerts", 14 | "target": { 15 | "limit": 100, 16 | "matchAny": false, 17 | "tags": [], 18 | "type": "dashboard" 19 | }, 20 | "type": "dashboard" 21 | } 22 | ] 23 | }, 24 | "description": "Dashboard for EC2 Instances based on metrics from AWS CloudWatch metrics stream", 25 | "editable": true, 26 | "fiscalYearStartMonth": 0, 27 | "graphTooltip": 0, 28 | "id": 63, 29 | "links": [], 30 | "liveNow": false, 31 | "panels": [ 32 | { 33 | "datasource": { 34 | "type": "prometheus", 35 | "uid": "3BK8XQaVk" 36 | }, 37 | "description": "The percentage of CPU Utilization.", 38 | "fieldConfig": { 39 | "defaults": { 40 | "color": { 41 | "mode": "palette-classic" 42 | }, 43 | "custom": { 44 | "axisCenteredZero": false, 45 | "axisColorMode": "text", 46 | "axisLabel": "", 47 | "axisPlacement": "auto", 48 | "barAlignment": 0, 49 | "drawStyle": "line", 50 | "fillOpacity": 0, 51 | "gradientMode": "none", 52 | "hideFrom": { 53 | "legend": false, 54 | "tooltip": false, 55 | "viz": false 56 | }, 57 | "lineInterpolation": "linear", 58 | "lineWidth": 1, 59 | "pointSize": 5, 60 | "scaleDistribution": { 61 | "type": "linear" 62 | }, 63 | "showPoints": "auto", 64 | "spanNulls": false, 65 | "stacking": { 66 | "group": "A", 67 | "mode": "none" 68 | }, 69 | "thresholdsStyle": { 70 | "mode": "off" 71 | } 72 | }, 73 | "mappings": [], 74 | "thresholds": { 75 | "mode": "absolute", 76 | "steps": [ 77 | { 78 | "color": "green", 79 | "value": null 80 | }, 81 | { 82 | "color": "red", 83 | "value": 80 84 | } 85 | ] 86 | }, 87 | "unit": "percent" 88 | }, 89 | "overrides": [] 90 | }, 91 | "gridPos": { 92 | "h": 8, 93 | "w": 8, 94 | "x": 0, 95 | "y": 0 96 | }, 97 | "id": 2, 98 | "options": { 99 | "legend": { 100 | "calcs": [], 101 | "displayMode": "list", 102 | "placement": "bottom", 103 | "showLegend": true 104 | }, 105 | "tooltip": { 106 | "mode": "single", 107 | "sort": "none" 108 | } 109 | }, 110 | "targets": [ 111 | { 112 | "datasource": { 113 | "type": "datasource", 114 | "uid": "3BK8XQaVk" 115 | }, 116 | "exemplar": true, 117 | "expr": "sum by (InstanceId) (amazonaws_com_AWS_EC2_CPUUtilization_sum{InstanceId=~'$EC2_Instance_Identifier'}) / sum by (InstanceId) (amazonaws_com_AWS_EC2_CPUUtilization_count{InstanceId=~'$EC2_Instance_Identifier'})", 118 | "interval": "5m", 119 | "legendFormat": "", 120 | "refId": "A" 121 | } 122 | ], 123 | "title": "CPU Utilization", 124 | "type": "timeseries" 125 | }, 126 | { 127 | "datasource": { 128 | "type": "prometheus", 129 | "uid": "3BK8XQaVk" 130 | }, 131 | "description": "Status Check Failed", 132 | "fieldConfig": { 133 | "defaults": { 134 | "color": { 135 | "mode": "palette-classic" 136 | }, 137 | "custom": { 138 | "axisCenteredZero": false, 139 | "axisColorMode": "text", 140 | "axisLabel": "", 141 | "axisPlacement": "auto", 142 | "barAlignment": 0, 143 | "drawStyle": "line", 144 | "fillOpacity": 0, 145 | "gradientMode": "none", 146 | "hideFrom": { 147 | "legend": false, 148 | "tooltip": false, 149 | "viz": false 150 | }, 151 | "lineInterpolation": "linear", 152 | "lineWidth": 1, 153 | "pointSize": 5, 154 | "scaleDistribution": { 155 | "type": "linear" 156 | }, 157 | "showPoints": "auto", 158 | "spanNulls": false, 159 | "stacking": { 160 | "group": "A", 161 | "mode": "none" 162 | }, 163 | "thresholdsStyle": { 164 | "mode": "off" 165 | } 166 | }, 167 | "mappings": [], 168 | "thresholds": { 169 | "mode": "absolute", 170 | "steps": [ 171 | { 172 | "color": "green", 173 | "value": null 174 | }, 175 | { 176 | "color": "red", 177 | "value": 80 178 | } 179 | ] 180 | }, 181 | "unit": "none" 182 | }, 183 | "overrides": [] 184 | }, 185 | "gridPos": { 186 | "h": 9, 187 | "w": 8, 188 | "x": 8, 189 | "y": 0 190 | }, 191 | "id": 4, 192 | "options": { 193 | "legend": { 194 | "calcs": [], 195 | "displayMode": "list", 196 | "placement": "bottom", 197 | "showLegend": true 198 | }, 199 | "tooltip": { 200 | "mode": "single", 201 | "sort": "none" 202 | } 203 | }, 204 | "targets": [ 205 | { 206 | "datasource": { 207 | "type": "datasource", 208 | "uid": "3BK8XQaVk" 209 | }, 210 | "exemplar": true, 211 | "expr": "sum by (InstanceId) (amazonaws_com_AWS_EC2_StatusCheckFailed_sum{InstanceId=~'$EC2_Instance_Identifier'})", 212 | "interval": "5m", 213 | "legendFormat": "", 214 | "refId": "A" 215 | } 216 | ], 217 | "title": "Status Check Failed", 218 | "type": "timeseries" 219 | }, 220 | { 221 | "datasource": { 222 | "type": "prometheus", 223 | "uid": "3BK8XQaVk" 224 | }, 225 | "description": "CPU Credit Balance", 226 | "fieldConfig": { 227 | "defaults": { 228 | "color": { 229 | "mode": "palette-classic" 230 | }, 231 | "custom": { 232 | "axisCenteredZero": false, 233 | "axisColorMode": "text", 234 | "axisLabel": "", 235 | "axisPlacement": "auto", 236 | "barAlignment": 0, 237 | "drawStyle": "line", 238 | "fillOpacity": 0, 239 | "gradientMode": "none", 240 | "hideFrom": { 241 | "legend": false, 242 | "tooltip": false, 243 | "viz": false 244 | }, 245 | "lineInterpolation": "linear", 246 | "lineWidth": 1, 247 | "pointSize": 5, 248 | "scaleDistribution": { 249 | "type": "linear" 250 | }, 251 | "showPoints": "auto", 252 | "spanNulls": false, 253 | "stacking": { 254 | "group": "A", 255 | "mode": "none" 256 | }, 257 | "thresholdsStyle": { 258 | "mode": "off" 259 | } 260 | }, 261 | "mappings": [], 262 | "thresholds": { 263 | "mode": "absolute", 264 | "steps": [ 265 | { 266 | "color": "green", 267 | "value": null 268 | }, 269 | { 270 | "color": "red", 271 | "value": 80 272 | } 273 | ] 274 | }, 275 | "unit": "none" 276 | }, 277 | "overrides": [] 278 | }, 279 | "gridPos": { 280 | "h": 8, 281 | "w": 8, 282 | "x": 16, 283 | "y": 0 284 | }, 285 | "id": 3, 286 | "options": { 287 | "legend": { 288 | "calcs": [], 289 | "displayMode": "list", 290 | "placement": "bottom", 291 | "showLegend": true 292 | }, 293 | "tooltip": { 294 | "mode": "single", 295 | "sort": "none" 296 | } 297 | }, 298 | "targets": [ 299 | { 300 | "datasource": { 301 | "type": "datasource", 302 | "uid": "3BK8XQaVk" 303 | }, 304 | "exemplar": true, 305 | "expr": "sum by (InstanceId) (amazonaws_com_AWS_EC2_CPUCreditBalance{InstanceId=~'$EC2_Instance_Identifier', quantile='0'})", 306 | "interval": "5m", 307 | "legendFormat": "", 308 | "refId": "A" 309 | } 310 | ], 311 | "title": "CPU Credit Balance", 312 | "type": "timeseries" 313 | }, 314 | { 315 | "datasource": { 316 | "type": "prometheus", 317 | "uid": "3BK8XQaVk" 318 | }, 319 | "description": "Network out bytes", 320 | "fieldConfig": { 321 | "defaults": { 322 | "color": { 323 | "mode": "palette-classic" 324 | }, 325 | "custom": { 326 | "axisCenteredZero": false, 327 | "axisColorMode": "text", 328 | "axisLabel": "", 329 | "axisPlacement": "auto", 330 | "barAlignment": 0, 331 | "drawStyle": "line", 332 | "fillOpacity": 0, 333 | "gradientMode": "none", 334 | "hideFrom": { 335 | "legend": false, 336 | "tooltip": false, 337 | "viz": false 338 | }, 339 | "lineInterpolation": "linear", 340 | "lineWidth": 1, 341 | "pointSize": 5, 342 | "scaleDistribution": { 343 | "type": "linear" 344 | }, 345 | "showPoints": "auto", 346 | "spanNulls": false, 347 | "stacking": { 348 | "group": "A", 349 | "mode": "none" 350 | }, 351 | "thresholdsStyle": { 352 | "mode": "off" 353 | } 354 | }, 355 | "mappings": [], 356 | "thresholds": { 357 | "mode": "absolute", 358 | "steps": [ 359 | { 360 | "color": "green", 361 | "value": null 362 | }, 363 | { 364 | "color": "red", 365 | "value": 80 366 | } 367 | ] 368 | }, 369 | "unit": "none" 370 | }, 371 | "overrides": [] 372 | }, 373 | "gridPos": { 374 | "h": 8, 375 | "w": 8, 376 | "x": 0, 377 | "y": 8 378 | }, 379 | "id": 5, 380 | "options": { 381 | "legend": { 382 | "calcs": [], 383 | "displayMode": "list", 384 | "placement": "bottom", 385 | "showLegend": true 386 | }, 387 | "tooltip": { 388 | "mode": "single", 389 | "sort": "none" 390 | } 391 | }, 392 | "targets": [ 393 | { 394 | "datasource": { 395 | "type": "datasource", 396 | "uid": "3BK8XQaVk" 397 | }, 398 | "exemplar": true, 399 | "expr": "sum by (InstanceId) (amazonaws_com_AWS_EC2_NetworkIn_sum{InstanceId=~'$EC2_Instance_Identifier'})", 400 | "interval": "5m", 401 | "legendFormat": "", 402 | "refId": "A" 403 | } 404 | ], 405 | "title": "Network In", 406 | "type": "timeseries" 407 | }, 408 | { 409 | "datasource": { 410 | "type": "prometheus", 411 | "uid": "3BK8XQaVk" 412 | }, 413 | "description": "CPU surplus credits charged", 414 | "fieldConfig": { 415 | "defaults": { 416 | "color": { 417 | "mode": "palette-classic" 418 | }, 419 | "custom": { 420 | "axisCenteredZero": false, 421 | "axisColorMode": "text", 422 | "axisLabel": "", 423 | "axisPlacement": "auto", 424 | "barAlignment": 0, 425 | "drawStyle": "line", 426 | "fillOpacity": 0, 427 | "gradientMode": "none", 428 | "hideFrom": { 429 | "legend": false, 430 | "tooltip": false, 431 | "viz": false 432 | }, 433 | "lineInterpolation": "linear", 434 | "lineWidth": 1, 435 | "pointSize": 5, 436 | "scaleDistribution": { 437 | "type": "linear" 438 | }, 439 | "showPoints": "auto", 440 | "spanNulls": false, 441 | "stacking": { 442 | "group": "A", 443 | "mode": "none" 444 | }, 445 | "thresholdsStyle": { 446 | "mode": "off" 447 | } 448 | }, 449 | "mappings": [], 450 | "thresholds": { 451 | "mode": "absolute", 452 | "steps": [ 453 | { 454 | "color": "green", 455 | "value": null 456 | }, 457 | { 458 | "color": "red", 459 | "value": 80 460 | } 461 | ] 462 | }, 463 | "unit": "none" 464 | }, 465 | "overrides": [] 466 | }, 467 | "gridPos": { 468 | "h": 9, 469 | "w": 8, 470 | "x": 16, 471 | "y": 8 472 | }, 473 | "id": 4, 474 | "options": { 475 | "legend": { 476 | "calcs": [], 477 | "displayMode": "list", 478 | "placement": "bottom", 479 | "showLegend": true 480 | }, 481 | "tooltip": { 482 | "mode": "single", 483 | "sort": "none" 484 | } 485 | }, 486 | "targets": [ 487 | { 488 | "datasource": { 489 | "type": "datasource", 490 | "uid": "3BK8XQaVk" 491 | }, 492 | "exemplar": true, 493 | "expr": "sum by (InstanceId) (amazonaws_com_AWS_EC2_CPUSurplusCreditsCharged_sum{InstanceId=~'$EC2_Instance_Identifier'})", 494 | "interval": "5m", 495 | "legendFormat": "", 496 | "refId": "A" 497 | } 498 | ], 499 | "title": "CPU surplus credits charged", 500 | "type": "timeseries" 501 | }, 502 | { 503 | "datasource": { 504 | "type": "prometheus", 505 | "uid": "3BK8XQaVk" 506 | }, 507 | "description": "Network out bytes", 508 | "fieldConfig": { 509 | "defaults": { 510 | "color": { 511 | "mode": "palette-classic" 512 | }, 513 | "custom": { 514 | "axisCenteredZero": false, 515 | "axisColorMode": "text", 516 | "axisLabel": "", 517 | "axisPlacement": "auto", 518 | "barAlignment": 0, 519 | "drawStyle": "line", 520 | "fillOpacity": 0, 521 | "gradientMode": "none", 522 | "hideFrom": { 523 | "legend": false, 524 | "tooltip": false, 525 | "viz": false 526 | }, 527 | "lineInterpolation": "linear", 528 | "lineWidth": 1, 529 | "pointSize": 5, 530 | "scaleDistribution": { 531 | "type": "linear" 532 | }, 533 | "showPoints": "auto", 534 | "spanNulls": false, 535 | "stacking": { 536 | "group": "A", 537 | "mode": "none" 538 | }, 539 | "thresholdsStyle": { 540 | "mode": "off" 541 | } 542 | }, 543 | "mappings": [], 544 | "thresholds": { 545 | "mode": "absolute", 546 | "steps": [ 547 | { 548 | "color": "green", 549 | "value": null 550 | }, 551 | { 552 | "color": "red", 553 | "value": 80 554 | } 555 | ] 556 | }, 557 | "unit": "none" 558 | }, 559 | "overrides": [] 560 | }, 561 | "gridPos": { 562 | "h": 8, 563 | "w": 8, 564 | "x": 8, 565 | "y": 9 566 | }, 567 | "id": 5, 568 | "options": { 569 | "legend": { 570 | "calcs": [], 571 | "displayMode": "list", 572 | "placement": "bottom", 573 | "showLegend": true 574 | }, 575 | "tooltip": { 576 | "mode": "single", 577 | "sort": "none" 578 | } 579 | }, 580 | "targets": [ 581 | { 582 | "datasource": { 583 | "type": "datasource", 584 | "uid": "3BK8XQaVk" 585 | }, 586 | "exemplar": true, 587 | "expr": "sum by (InstanceId) (amazonaws_com_AWS_EC2_NetworkOut_sum{InstanceId=~'$EC2_Instance_Identifier'})", 588 | "interval": "5m", 589 | "legendFormat": "", 590 | "refId": "A" 591 | } 592 | ], 593 | "title": "Network Out", 594 | "type": "timeseries" 595 | }, 596 | { 597 | "datasource": { 598 | "type": "prometheus", 599 | "uid": "3BK8XQaVk" 600 | }, 601 | "description": "EBS IO Balance", 602 | "fieldConfig": { 603 | "defaults": { 604 | "color": { 605 | "mode": "palette-classic" 606 | }, 607 | "custom": { 608 | "axisCenteredZero": false, 609 | "axisColorMode": "text", 610 | "axisLabel": "", 611 | "axisPlacement": "auto", 612 | "barAlignment": 0, 613 | "drawStyle": "line", 614 | "fillOpacity": 0, 615 | "gradientMode": "none", 616 | "hideFrom": { 617 | "legend": false, 618 | "tooltip": false, 619 | "viz": false 620 | }, 621 | "lineInterpolation": "linear", 622 | "lineWidth": 1, 623 | "pointSize": 5, 624 | "scaleDistribution": { 625 | "type": "linear" 626 | }, 627 | "showPoints": "auto", 628 | "spanNulls": false, 629 | "stacking": { 630 | "group": "A", 631 | "mode": "none" 632 | }, 633 | "thresholdsStyle": { 634 | "mode": "off" 635 | } 636 | }, 637 | "mappings": [], 638 | "thresholds": { 639 | "mode": "absolute", 640 | "steps": [ 641 | { 642 | "color": "green", 643 | "value": null 644 | }, 645 | { 646 | "color": "red", 647 | "value": 80 648 | } 649 | ] 650 | }, 651 | "unit": "none" 652 | }, 653 | "overrides": [] 654 | }, 655 | "gridPos": { 656 | "h": 9, 657 | "w": 8, 658 | "x": 0, 659 | "y": 16 660 | }, 661 | "id": 4, 662 | "options": { 663 | "legend": { 664 | "calcs": [], 665 | "displayMode": "list", 666 | "placement": "bottom", 667 | "showLegend": true 668 | }, 669 | "tooltip": { 670 | "mode": "single", 671 | "sort": "none" 672 | } 673 | }, 674 | "targets": [ 675 | { 676 | "datasource": { 677 | "type": "datasource", 678 | "uid": "3BK8XQaVk" 679 | }, 680 | "exemplar": true, 681 | "expr": "sum by (InstanceId) (amazonaws_com_AWS_EC2_EBSIOBalance_{InstanceId=~'$EC2_Instance_Identifier', quantile='0'})", 682 | "interval": "5m", 683 | "legendFormat": "", 684 | "refId": "A" 685 | } 686 | ], 687 | "title": "EBS IO Balance", 688 | "type": "timeseries" 689 | }, 690 | { 691 | "datasource": { 692 | "type": "prometheus", 693 | "uid": "3BK8XQaVk" 694 | }, 695 | "description": "EBS Byte Balance", 696 | "fieldConfig": { 697 | "defaults": { 698 | "color": { 699 | "mode": "palette-classic" 700 | }, 701 | "custom": { 702 | "axisCenteredZero": false, 703 | "axisColorMode": "text", 704 | "axisLabel": "", 705 | "axisPlacement": "auto", 706 | "barAlignment": 0, 707 | "drawStyle": "line", 708 | "fillOpacity": 0, 709 | "gradientMode": "none", 710 | "hideFrom": { 711 | "legend": false, 712 | "tooltip": false, 713 | "viz": false 714 | }, 715 | "lineInterpolation": "linear", 716 | "lineWidth": 1, 717 | "pointSize": 5, 718 | "scaleDistribution": { 719 | "type": "linear" 720 | }, 721 | "showPoints": "auto", 722 | "spanNulls": false, 723 | "stacking": { 724 | "group": "A", 725 | "mode": "none" 726 | }, 727 | "thresholdsStyle": { 728 | "mode": "off" 729 | } 730 | }, 731 | "mappings": [], 732 | "thresholds": { 733 | "mode": "absolute", 734 | "steps": [ 735 | { 736 | "color": "green", 737 | "value": null 738 | }, 739 | { 740 | "color": "red", 741 | "value": 80 742 | } 743 | ] 744 | }, 745 | "unit": "none" 746 | }, 747 | "overrides": [] 748 | }, 749 | "gridPos": { 750 | "h": 9, 751 | "w": 8, 752 | "x": 8, 753 | "y": 17 754 | }, 755 | "id": 4, 756 | "options": { 757 | "legend": { 758 | "calcs": [], 759 | "displayMode": "list", 760 | "placement": "bottom", 761 | "showLegend": true 762 | }, 763 | "tooltip": { 764 | "mode": "single", 765 | "sort": "none" 766 | } 767 | }, 768 | "targets": [ 769 | { 770 | "datasource": { 771 | "type": "datasource", 772 | "uid": "3BK8XQaVk" 773 | }, 774 | "exemplar": true, 775 | "expr": "sum by (InstanceId) (amazonaws_com_AWS_EC2_EBSByteBalance_{InstanceId=~'$EC2_Instance_Identifier', quantile='0'})", 776 | "interval": "5m", 777 | "legendFormat": "", 778 | "refId": "A" 779 | } 780 | ], 781 | "title": "EBS Byte Balance", 782 | "type": "timeseries" 783 | } 784 | ], 785 | "schemaVersion": 37, 786 | "style": "dark", 787 | "tags": [], 788 | "templating": { 789 | "list": [ 790 | { 791 | "allValue": "", 792 | "current": { 793 | "selected": false, 794 | "text": "All", 795 | "value": "$__all" 796 | }, 797 | "datasource": { 798 | "type": "prometheus", 799 | "uid": "3BK8XQaVk" 800 | }, 801 | "definition": "label_values(amazonaws_com_AWS_EC2_CPUUtilization{}, InstanceId)", 802 | "hide": 0, 803 | "includeAll": true, 804 | "label": "EC2 Instance Identifier", 805 | "multi": true, 806 | "name": "EC2_Instance_Identifier", 807 | "options": [], 808 | "query": { 809 | "query": "label_values(amazonaws_com_AWS_EC2_CPUUtilization{}, InstanceId)", 810 | "refId": "StandardVariableQuery" 811 | }, 812 | "refresh": 1, 813 | "regex": "", 814 | "skipUrlSync": false, 815 | "sort": 1, 816 | "type": "query" 817 | } 818 | ] 819 | }, 820 | "time": { 821 | "from": "now-30m", 822 | "to": "now" 823 | }, 824 | "timepicker": {}, 825 | "timezone": "browser", 826 | "title": "EC2", 827 | "uid": "pSD2rzfff", 828 | "version": 1, 829 | "weekStart": "monday" 830 | } 831 | -------------------------------------------------------------------------------- /levitate/grafana-dashboards/cloudswatch-metric-stream/rds/README.md: -------------------------------------------------------------------------------- 1 | ## How to use? 2 | 3 | This directory contains a sample Grafana dashboard's JSON file based on metrics from AWS Cloudwatch metric stream. 4 | 5 | You can import this into any Grafana, select a data source and start using it. 6 | 7 | ## Dashboard structure 8 | 9 | The dashboard contains following metrics and variables. 10 | 11 | ### Metrics 12 | 13 | 1. The percentage of CPU Utilization `amazonaws_com_AWS_RDS_CPUUtilization` 14 | 2. Number of DB Connections `amazonaws_com_AWS_RDS_DatabaseConnections` 15 | 3. EBS Byte Balance `amazonaws_com_AWS_RDS_EBSByteBalance_` 16 | 4. EBS I/O Balance `amazonaws_com_AWS_RDS_EBSIOBalance_` 17 | 18 | ### Variables 19 | 20 | 1. DB Instance Identifier 21 | 2. Cloud Region 22 | 23 | ## Integrate with AWS Cloudwatch Metric Stream for sending data to Levitate 24 | 25 | Follow our integration guide for [AWS Cloudwatch Metric Stream](https://docs.last9.io/docs/how-to-send-cloudwatch-metrics-to-levitate-via-aws-cloudstream). 26 | 27 | > Note that this step is optional, you can use the dashboard as it is with any other source apart from Levitate if you are already set up with AWS Cloudwatch Metric Stream. 28 | -------------------------------------------------------------------------------- /levitate/grafana-dashboards/cloudswatch-metric-stream/rds/dashboard.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DATASOURCE", 5 | "label": "Datasource", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "prometheus", 9 | "pluginName": "Prometheus" 10 | } 11 | ], 12 | "__elements": [], 13 | "__requires": [ 14 | { 15 | "type": "grafana", 16 | "id": "grafana", 17 | "name": "Grafana", 18 | "version": "8.4.0" 19 | }, 20 | { 21 | "type": "datasource", 22 | "id": "prometheus", 23 | "name": "Prometheus", 24 | "version": "1.0.0" 25 | }, 26 | { 27 | "type": "panel", 28 | "id": "timeseries", 29 | "name": "Time series", 30 | "version": "" 31 | } 32 | ], 33 | "annotations": { 34 | "list": [ 35 | { 36 | "builtIn": 1, 37 | "datasource": "-- Grafana --", 38 | "enable": true, 39 | "hide": true, 40 | "iconColor": "rgba(0, 211, 255, 1)", 41 | "name": "Annotations & Alerts", 42 | "target": { 43 | "limit": 100, 44 | "matchAny": false, 45 | "tags": [], 46 | "type": "dashboard" 47 | }, 48 | "type": "dashboard" 49 | } 50 | ] 51 | }, 52 | "description": "Dashboard for RDS based on metrics from AWS CloudWatch metrics stream", 53 | "editable": true, 54 | "fiscalYearStartMonth": 0, 55 | "graphTooltip": 0, 56 | "id": null, 57 | "iteration": 1679303184200, 58 | "links": [], 59 | "liveNow": false, 60 | "panels": [ 61 | { 62 | "datasource": { 63 | "type": "prometheus", 64 | "uid": "${DATASOURCE}" 65 | }, 66 | "description": "The percentage of CPU Utilization.", 67 | "fieldConfig": { 68 | "defaults": { 69 | "color": { 70 | "mode": "palette-classic" 71 | }, 72 | "custom": { 73 | "axisLabel": "", 74 | "axisPlacement": "auto", 75 | "barAlignment": 0, 76 | "drawStyle": "line", 77 | "fillOpacity": 0, 78 | "gradientMode": "none", 79 | "hideFrom": { 80 | "legend": false, 81 | "tooltip": false, 82 | "viz": false 83 | }, 84 | "lineInterpolation": "linear", 85 | "lineWidth": 1, 86 | "pointSize": 5, 87 | "scaleDistribution": { 88 | "type": "linear" 89 | }, 90 | "showPoints": "auto", 91 | "spanNulls": false, 92 | "stacking": { 93 | "group": "A", 94 | "mode": "none" 95 | }, 96 | "thresholdsStyle": { 97 | "mode": "off" 98 | } 99 | }, 100 | "mappings": [], 101 | "thresholds": { 102 | "mode": "absolute", 103 | "steps": [ 104 | { 105 | "color": "green", 106 | "value": null 107 | }, 108 | { 109 | "color": "red", 110 | "value": 80 111 | } 112 | ] 113 | }, 114 | "unit": "percent" 115 | }, 116 | "overrides": [] 117 | }, 118 | "gridPos": { 119 | "h": 8, 120 | "w": 8, 121 | "x": 0, 122 | "y": 0 123 | }, 124 | "id": 2, 125 | "options": { 126 | "legend": { 127 | "calcs": [], 128 | "displayMode": "list", 129 | "placement": "bottom" 130 | }, 131 | "tooltip": { 132 | "mode": "single" 133 | } 134 | }, 135 | "targets": [ 136 | { 137 | "datasource": { 138 | "type": "datasource", 139 | "uid": "${DATASOURCE}" 140 | }, 141 | "exemplar": true, 142 | "expr": "sum by (DBInstanceIdentifier, cloud_region) (amazonaws_com_AWS_RDS_CPUUtilization{DBInstanceIdentifier=~\"$DB_Instance_Identifier\", cloud_region=~\"$Cloud_Region\"})", 143 | "interval": "1m", 144 | "legendFormat": "", 145 | "refId": "A" 146 | } 147 | ], 148 | "title": "CPU Utilization", 149 | "type": "timeseries" 150 | }, 151 | { 152 | "datasource": { 153 | "type": "prometheus", 154 | "uid": "${DATASOURCE}" 155 | }, 156 | "description": "Number of DB Connections", 157 | "fieldConfig": { 158 | "defaults": { 159 | "color": { 160 | "mode": "palette-classic" 161 | }, 162 | "custom": { 163 | "axisLabel": "", 164 | "axisPlacement": "auto", 165 | "barAlignment": 0, 166 | "drawStyle": "line", 167 | "fillOpacity": 0, 168 | "gradientMode": "none", 169 | "hideFrom": { 170 | "legend": false, 171 | "tooltip": false, 172 | "viz": false 173 | }, 174 | "lineInterpolation": "linear", 175 | "lineWidth": 1, 176 | "pointSize": 5, 177 | "scaleDistribution": { 178 | "type": "linear" 179 | }, 180 | "showPoints": "auto", 181 | "spanNulls": false, 182 | "stacking": { 183 | "group": "A", 184 | "mode": "none" 185 | }, 186 | "thresholdsStyle": { 187 | "mode": "off" 188 | } 189 | }, 190 | "mappings": [], 191 | "thresholds": { 192 | "mode": "absolute", 193 | "steps": [ 194 | { 195 | "color": "green", 196 | "value": null 197 | }, 198 | { 199 | "color": "red", 200 | "value": 80 201 | } 202 | ] 203 | }, 204 | "unit": "none" 205 | }, 206 | "overrides": [] 207 | }, 208 | "gridPos": { 209 | "h": 8, 210 | "w": 8, 211 | "x": 8, 212 | "y": 0 213 | }, 214 | "id": 3, 215 | "options": { 216 | "legend": { 217 | "calcs": [], 218 | "displayMode": "list", 219 | "placement": "bottom" 220 | }, 221 | "tooltip": { 222 | "mode": "single" 223 | } 224 | }, 225 | "targets": [ 226 | { 227 | "datasource": { 228 | "type": "datasource", 229 | "uid": "${DATASOURCE}" 230 | }, 231 | "exemplar": true, 232 | "expr": "sum by (DBInstanceIdentifier, cloud_region) (amazonaws_com_AWS_RDS_DatabaseConnections{DBInstanceIdentifier=~\"$DB_Instance_Identifier\", cloud_region=~\"$Cloud_Region\"})", 233 | "interval": "1m", 234 | "legendFormat": "", 235 | "refId": "A" 236 | } 237 | ], 238 | "title": "Connections", 239 | "type": "timeseries" 240 | }, 241 | { 242 | "datasource": { 243 | "type": "prometheus", 244 | "uid": "${DATASOURCE}" 245 | }, 246 | "description": "The percentage of throughput credits remaining in the burst bucket of your RDS database. This metric is available for basic monitoring only.", 247 | "fieldConfig": { 248 | "defaults": { 249 | "color": { 250 | "mode": "palette-classic" 251 | }, 252 | "custom": { 253 | "axisLabel": "", 254 | "axisPlacement": "auto", 255 | "barAlignment": 0, 256 | "drawStyle": "line", 257 | "fillOpacity": 0, 258 | "gradientMode": "none", 259 | "hideFrom": { 260 | "legend": false, 261 | "tooltip": false, 262 | "viz": false 263 | }, 264 | "lineInterpolation": "linear", 265 | "lineWidth": 1, 266 | "pointSize": 5, 267 | "scaleDistribution": { 268 | "type": "linear" 269 | }, 270 | "showPoints": "auto", 271 | "spanNulls": false, 272 | "stacking": { 273 | "group": "A", 274 | "mode": "none" 275 | }, 276 | "thresholdsStyle": { 277 | "mode": "off" 278 | } 279 | }, 280 | "mappings": [], 281 | "thresholds": { 282 | "mode": "absolute", 283 | "steps": [ 284 | { 285 | "color": "green", 286 | "value": null 287 | }, 288 | { 289 | "color": "red", 290 | "value": 80 291 | } 292 | ] 293 | }, 294 | "unit": "none" 295 | }, 296 | "overrides": [] 297 | }, 298 | "gridPos": { 299 | "h": 8, 300 | "w": 8, 301 | "x": 16, 302 | "y": 0 303 | }, 304 | "id": 5, 305 | "options": { 306 | "legend": { 307 | "calcs": [], 308 | "displayMode": "list", 309 | "placement": "bottom" 310 | }, 311 | "tooltip": { 312 | "mode": "single" 313 | } 314 | }, 315 | "targets": [ 316 | { 317 | "datasource": { 318 | "type": "datasource", 319 | "uid": "${DATASOURCE}" 320 | }, 321 | "exemplar": true, 322 | "expr": "sum by (DBInstanceIdentifier, cloud_region) (amazonaws_com_AWS_RDS_EBSByteBalance_{DBInstanceIdentifier=~\"$DB_Instance_Identifier\", cloud_region=~\"$Cloud_Region\"})", 323 | "interval": "1m", 324 | "legendFormat": "", 325 | "refId": "A" 326 | } 327 | ], 328 | "title": "EBS Byte Balance", 329 | "type": "timeseries" 330 | }, 331 | { 332 | "datasource": { 333 | "type": "prometheus", 334 | "uid": "${DATASOURCE}" 335 | }, 336 | "description": "The percentage of I/O credits remaining in the burst bucket of your RDS database. This metric is available for basic monitoring only.", 337 | "fieldConfig": { 338 | "defaults": { 339 | "color": { 340 | "mode": "palette-classic" 341 | }, 342 | "custom": { 343 | "axisLabel": "", 344 | "axisPlacement": "auto", 345 | "barAlignment": 0, 346 | "drawStyle": "line", 347 | "fillOpacity": 0, 348 | "gradientMode": "none", 349 | "hideFrom": { 350 | "legend": false, 351 | "tooltip": false, 352 | "viz": false 353 | }, 354 | "lineInterpolation": "linear", 355 | "lineWidth": 1, 356 | "pointSize": 5, 357 | "scaleDistribution": { 358 | "type": "linear" 359 | }, 360 | "showPoints": "auto", 361 | "spanNulls": false, 362 | "stacking": { 363 | "group": "A", 364 | "mode": "none" 365 | }, 366 | "thresholdsStyle": { 367 | "mode": "off" 368 | } 369 | }, 370 | "mappings": [], 371 | "thresholds": { 372 | "mode": "absolute", 373 | "steps": [ 374 | { 375 | "color": "green", 376 | "value": null 377 | }, 378 | { 379 | "color": "red", 380 | "value": 80 381 | } 382 | ] 383 | }, 384 | "unit": "none" 385 | }, 386 | "overrides": [] 387 | }, 388 | "gridPos": { 389 | "h": 9, 390 | "w": 8, 391 | "x": 0, 392 | "y": 8 393 | }, 394 | "id": 4, 395 | "options": { 396 | "legend": { 397 | "calcs": [], 398 | "displayMode": "list", 399 | "placement": "bottom" 400 | }, 401 | "tooltip": { 402 | "mode": "single" 403 | } 404 | }, 405 | "targets": [ 406 | { 407 | "datasource": { 408 | "type": "datasource", 409 | "uid": "${DATASOURCE}" 410 | }, 411 | "exemplar": true, 412 | "expr": "sum by (DBInstanceIdentifier, cloud_region) (amazonaws_com_AWS_RDS_EBSIOBalance_{DBInstanceIdentifier=~\"$DB_Instance_Identifier\", cloud_region=~\"$Cloud_Region\"})", 413 | "interval": "1m", 414 | "legendFormat": "", 415 | "refId": "A" 416 | } 417 | ], 418 | "title": "EBS I/O Balance", 419 | "type": "timeseries" 420 | } 421 | ], 422 | "schemaVersion": 34, 423 | "style": "dark", 424 | "tags": [], 425 | "templating": { 426 | "list": [ 427 | { 428 | "allValue": "", 429 | "current": {}, 430 | "datasource": { 431 | "type": "prometheus", 432 | "uid": "${DATASOURCE}" 433 | }, 434 | "definition": "label_values(amazonaws_com_AWS_RDS_CPUUtilization{}, DBInstanceIdentifier)", 435 | "hide": 0, 436 | "includeAll": true, 437 | "label": "DB Instance Identifier", 438 | "multi": true, 439 | "name": "DB_Instance_Identifier", 440 | "options": [], 441 | "query": { 442 | "query": "label_values(amazonaws_com_AWS_RDS_CPUUtilization{}, DBInstanceIdentifier)", 443 | "refId": "StandardVariableQuery" 444 | }, 445 | "refresh": 1, 446 | "regex": "", 447 | "skipUrlSync": false, 448 | "sort": 1, 449 | "type": "query" 450 | }, 451 | { 452 | "allValue": "", 453 | "current": {}, 454 | "datasource": { 455 | "type": "prometheus", 456 | "uid": "${DATASOURCE}" 457 | }, 458 | "definition": "label_values(amazonaws_com_AWS_RDS_CPUUtilization{}, cloud_region)", 459 | "hide": 0, 460 | "includeAll": true, 461 | "label": "Cloud Region", 462 | "multi": true, 463 | "name": "Cloud_Region", 464 | "options": [], 465 | "query": { 466 | "query": "label_values(amazonaws_com_AWS_RDS_CPUUtilization{}, cloud_region)", 467 | "refId": "StandardVariableQuery" 468 | }, 469 | "refresh": 1, 470 | "regex": "", 471 | "skipUrlSync": false, 472 | "sort": 1, 473 | "type": "query" 474 | } 475 | ] 476 | }, 477 | "time": { 478 | "from": "now-30m", 479 | "to": "now" 480 | }, 481 | "timepicker": {}, 482 | "timezone": "browser", 483 | "title": "RDS", 484 | "uid": "pSD2rzf4k", 485 | "version": 12, 486 | "weekStart": "monday" 487 | } 488 | -------------------------------------------------------------------------------- /levitate/remote-write/jmxtrans/.gitignore: -------------------------------------------------------------------------------- 1 | *.env 2 | -------------------------------------------------------------------------------- /levitate/remote-write/jmxtrans/README.md: -------------------------------------------------------------------------------- 1 | This directory contains demo code for jmxtrans to Levitate remote write integration 2 | using jmxtrans Graphite output plugin pointing to vmagent. 3 | 4 | [jmxtrans/jmxtrans](https://hub.docker.com/r/jmxtrans/jmxtrans) image does not work on MacOS M1 chipset. To test this docker-compose 5 | setup, please use a Linux variant. 6 | 7 | ### Steps 8 | 9 | 1. Update the following variables in [docker-compose.yaml](./docker-compose.yaml) or update export them as environment variables 10 | - $LEVITATE_REMOTE_WRITE_URL 11 | - $LEVITATE_REMOTE_WRITE_USERNAME 12 | - $LEVITATE_REMOTE_WRITE_PASSWORD 13 | 2. Run `docker-compose up --build --force-recreate --remove-orphans` 14 | 15 | ### Validate 16 | 17 | 1. The above run should publish the [sample app](./jvmapp/SampleApp.java) metrics to Levitate. 18 | 2. By default, graphite metrics are dumped in `a.b.c.d` format. This can lead to increase in metric names and remove the flexibility of labels i.e. instead of having `requests{host='a'}`, without any 19 | transformation, the metric would show up as `requests.host.a` 20 | 3. To address this, we leverage vmagent [graphite relabeling](https://docs.victoriametrics.com/vmagent.html#graphite-relabeling). A sample setup is added in [vmagent.yaml](vmagent.yaml), which converts a flattened metric like 21 | 22 | ``` 23 | "metric": { 24 | "__name__": "sample.service.jvmapp_4000.sun_management_MemoryImpl.HeapMemoryUsage_committed", 25 | }, 26 | ``` 27 | 28 | to 29 | 30 | ``` 31 | "metric": { 32 | "__name__": "HeapMemoryUsage_committed", 33 | "service": "sample_service", 34 | "instance": "jvmapp_4000", 35 | } 36 | ``` 37 | 4. This sample [vmagent.yaml](vmagent.yaml) can be modified for any other relabeling as required. 38 | -------------------------------------------------------------------------------- /levitate/remote-write/jmxtrans/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | # Java app and JVM config sourced from http://mintbeans.com/jvm-monitoring-docker/ 2 | version: '3.6' 3 | services: 4 | jvmapp: 5 | build: jvmapp 6 | container_name: jvmapp 7 | ports: 8 | - "4000:4000" 9 | 10 | jmxtrans: 11 | image: jmxtrans/jmxtrans 12 | container_name: jmxtrans 13 | environment: 14 | CONTINUE_ON_ERROR: "false" 15 | SECONDS_BETWEEN_RUNS: 5 16 | GRAPHITE_HOST: vmagent_levitate 17 | GRAPHITE_PORT: 2003 18 | volumes: 19 | - ./jmxtrans-config:/var/lib/jmxtrans 20 | depends_on: 21 | - jvmapp 22 | 23 | vmagent_levitate: 24 | image: victoriametrics/vmagent:v1.85.3 25 | ports: 26 | - 8430:8429 27 | - 2003:2003/tcp 28 | - 2003:2003/udp 29 | volumes: 30 | - vmagentdata:/vmagentdata 31 | - ./relabel.yaml:/etc/relabel.yaml 32 | - ./vmagent.yaml:/etc/vmagent.yaml 33 | command: 34 | - "--graphiteListenAddr=:2003" 35 | - "--remoteWrite.url=${LEVITATE_REMOTE_WRITE_URL}" 36 | - "--remoteWrite.basicAuth.username=${LEVITATE_REMOTE_WRITE_USERNAME}" 37 | - "--remoteWrite.basicAuth.password=${LEVITATE_REMOTE_WRITE_PASSWORD}" 38 | - "--remoteWrite.relabelConfig=/etc/relabel.yaml" 39 | - "--promscrape.config=/etc/vmagent.yaml" 40 | restart: always 41 | 42 | volumes: 43 | vmagentdata: {} 44 | -------------------------------------------------------------------------------- /levitate/remote-write/jmxtrans/jmxtrans-config/graphite.json: -------------------------------------------------------------------------------- 1 | { 2 | "servers": [ 3 | { 4 | "host": "jvmapp", 5 | "port": "4000", 6 | "queries": [ 7 | { 8 | "obj": "java.lang:type=Memory", 9 | "attr": [ 10 | "HeapMemoryUsage", 11 | "NonHeapMemoryUsage" 12 | ], 13 | "outputWriters": [ 14 | { 15 | "@class": "com.googlecode.jmxtrans.model.output.StdOutWriter" 16 | }, 17 | { 18 | "@class": "com.googlecode.jmxtrans.model.output.GraphiteWriterFactory", 19 | "host": "vmagent_levitate", 20 | "port": "2003", 21 | "rootPrefix": "sample.service" 22 | } 23 | ] 24 | } 25 | ] 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /levitate/remote-write/jmxtrans/jvmapp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8 2 | 3 | COPY SampleApp.java /SampleApp.java 4 | RUN javac SampleApp.java 5 | 6 | CMD java \ 7 | -Djava.rmi.server.hostname=jvmapp \ 8 | -Dcom.sun.management.jmxremote \ 9 | -Dcom.sun.management.jmxremote.port=4000 \ 10 | -Dcom.sun.management.jmxremote.rmi.port=4000 \ 11 | -Dcom.sun.management.jmxremote.local.only=false \ 12 | -Dcom.sun.management.jmxremote.authenticate=false \ 13 | -Dcom.sun.management.jmxremote.ssl=false \ 14 | SampleApp 15 | -------------------------------------------------------------------------------- /levitate/remote-write/jmxtrans/jvmapp/SampleApp.java: -------------------------------------------------------------------------------- 1 | public final class SampleApp { 2 | public static void main(String []args) throws Exception { 3 | final java.util.Random generator = new java.util.Random(); 4 | while (true) { 5 | System.out.println("test"); 6 | generator.ints(1000000, 0, 100).sorted(); 7 | Thread.sleep(5000L); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /levitate/remote-write/jmxtrans/relabel.yaml: -------------------------------------------------------------------------------- 1 | - action: graphite 2 | match: "*.*.*.*.*" 3 | labels: 4 | __name__: "${5}" 5 | service: "${1}_${2}" 6 | instance: "${3}" 7 | -------------------------------------------------------------------------------- /levitate/remote-write/jmxtrans/vmagent.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 1m 3 | scrape_configs: 4 | - job_name: "scrape_vmagent_self" 5 | static_configs: 6 | - targets: [ "localhost:8429" ] 7 | -------------------------------------------------------------------------------- /levitate/remote-write/opentelemetry-collector/opencensus-receiver/docker/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/last9/last9-integrations/8c9a66d98f253ff5e7afc0f9824c551b3f61f478/levitate/remote-write/opentelemetry-collector/opencensus-receiver/docker/README.md -------------------------------------------------------------------------------- /levitate/remote-write/opentelemetry-collector/prometheus-receiver/README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | This directory contains an example of a Prometheus receiver setup with OpenTelemetry collector which sends 4 | data to [Levitate](https://last9.io/products/levitate) 5 | 6 | Follow through the tutorial [here](https://docs.last9.io/docs/integration-opentelemetry) for a walk-through of the setup and the information flow, side by side. 7 | 8 | ### Running 9 | 10 | Replace the following variables in `otel-collector-config.yaml` with the actual values from your Levitate cluster. 11 | 12 | ```sh 13 | $levitate_username -> Cluster ID 14 | $levitate_password -> Write Token 15 | $levitate_write_endpoint -> Levitate Remote Write endpoint 16 | ``` 17 | 18 | Make sure that you have docker running and then perform: 19 | 20 | ```sh 21 | docker-compose up -d 22 | ``` 23 | 24 | After that, the Golang application will start on port 9000, and the Open Telemetry collector will start on port `4317`. 25 | Send a few HTTP requests on `http://localhost:9000/hello`. 26 | It will emit metrics relayed to Levitate via Open Telemetry collector. 27 | 28 | 29 | ### Verification 30 | 31 | Create a Read token for Levitate cluster and connect to [Grafana](https://docs.last9.io/docs/levitate-grafana-config) for verification. 32 | 33 | If all goes well, you should see the metrics as follows: 34 | 35 | ```json 36 | { 37 | "status": "success", 38 | "isPartial": false, 39 | "data": { 40 | "resultType": "matrix", 41 | "result": [ 42 | { 43 | "metric": { 44 | "__name__": "levitate_request_counts_total", 45 | "__l9cluster__": "ebce9978-80f0-4976-9103-d435a7a4adf6", 46 | "__l9lake__": "prometheus", 47 | "__tenant__": "omecs", 48 | "env": "production", 49 | "instance": "app:8000", 50 | "job": "otel-collector-01", 51 | "otel_scope_name": "levitate-otel-demo", 52 | "program": "levitate", 53 | "via_cluster": "cs-test-levitate-01" 54 | }, 55 | "values": [ 56 | [ 57 | 1672307336, 58 | "3" 59 | ], 60 | [ 61 | 1672307396, 62 | "5" 63 | ] 64 | ] 65 | } 66 | ] 67 | } 68 | } 69 | ``` 70 | 71 | ## Related Articles 72 | 73 | [What is OpenTelemetry](https://last9.io/blog/what-is-opentelemetry/) 74 | 75 | [What is OpenTelemetry Collector](https://last9.io/blog/what-is-opentelemetry-collector/) 76 | 77 | [Instrumenting Java applications using OpenTelemetry](https://last9.io/blog/how-to-instrument-java-applications-using-opentelemetry-tutorial-best-practices/) 78 | 79 | Read more about the difference between [Prometheus vs. Otel](https://last9.io/blog/opentelemetry-vs-prometheus/#metrics-in-opentelemetry-vs-prometheus). 80 | 81 | Here is a post on [How to filter metrics by labels using OpenTelemetry Collector](https://last9.io/blog/filtering-metrics-by-labels-in-opentelemetry-collector/). 82 | -------------------------------------------------------------------------------- /levitate/remote-write/opentelemetry-collector/prometheus-receiver/app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.18 as build 2 | WORKDIR /app/ 3 | COPY . . 4 | RUN CGO_ENABLED=0 go build -o main main.go 5 | FROM alpine:3.15 6 | COPY --from=build /app/main /app/main 7 | CMD ["/app/main"] 8 | -------------------------------------------------------------------------------- /levitate/remote-write/opentelemetry-collector/prometheus-receiver/app/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/last9-integrations/levitate/remote-write/opentelemetry-collector/prometheus-receiver/app 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/prometheus/client_golang v1.14.0 7 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0 8 | go.opentelemetry.io/otel v1.11.2 9 | go.opentelemetry.io/otel/exporters/prometheus v0.34.0 10 | go.opentelemetry.io/otel/metric v0.34.0 11 | go.opentelemetry.io/otel/sdk/metric v0.34.0 12 | ) 13 | 14 | require ( 15 | github.com/beorn7/perks v1.0.1 // indirect 16 | github.com/cespare/xxhash/v2 v2.1.2 // indirect 17 | github.com/felixge/httpsnoop v1.0.3 // indirect 18 | github.com/go-logr/logr v1.2.3 // indirect 19 | github.com/go-logr/stdr v1.2.2 // indirect 20 | github.com/golang/protobuf v1.5.2 // indirect 21 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 22 | github.com/prometheus/client_model v0.3.0 // indirect 23 | github.com/prometheus/common v0.37.0 // indirect 24 | github.com/prometheus/procfs v0.8.0 // indirect 25 | go.opentelemetry.io/otel/sdk v1.11.2 // indirect 26 | go.opentelemetry.io/otel/trace v1.11.2 // indirect 27 | golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect 28 | google.golang.org/protobuf v1.33.0 // indirect 29 | ) 30 | -------------------------------------------------------------------------------- /levitate/remote-write/opentelemetry-collector/prometheus-receiver/app/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 3 | cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 4 | cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= 5 | cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= 6 | cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= 7 | cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= 8 | cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= 9 | cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= 10 | cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= 11 | cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= 12 | cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= 13 | cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= 14 | cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= 15 | cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= 16 | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= 17 | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= 18 | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= 19 | cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= 20 | cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= 21 | cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= 22 | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= 23 | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= 24 | cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= 25 | cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= 26 | cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= 27 | cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= 28 | cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= 29 | cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= 30 | cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 31 | cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= 32 | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= 33 | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= 34 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 35 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 36 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 37 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 38 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 39 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 40 | github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= 41 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 42 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 43 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 44 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 45 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 46 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 47 | github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= 48 | github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 49 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 50 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 51 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 52 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 53 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 54 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 55 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 56 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 57 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 58 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 59 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 60 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 61 | github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= 62 | github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 63 | github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= 64 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 65 | github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 66 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 67 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 68 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 69 | github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= 70 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 71 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 72 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 73 | github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 74 | github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 75 | github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= 76 | github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 77 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 78 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 79 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 80 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 81 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 82 | github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 83 | github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 84 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 85 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 86 | github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 87 | github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 88 | github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 89 | github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 90 | github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 91 | github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= 92 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 93 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 94 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 95 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 96 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 97 | github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= 98 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 99 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 100 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 101 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 102 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 103 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 104 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 105 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 106 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 107 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 108 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 109 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 110 | github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 111 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 112 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 113 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 114 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 115 | github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 116 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 117 | github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 118 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 119 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 120 | github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 121 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 122 | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= 123 | github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 124 | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 125 | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= 126 | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 127 | github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 128 | github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 129 | github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 130 | github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= 131 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 132 | github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= 133 | github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 134 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 135 | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 136 | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 137 | github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= 138 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 139 | github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 140 | github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 141 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 142 | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= 143 | github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= 144 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 145 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 146 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 147 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 148 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 149 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 150 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 151 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 152 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 153 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 154 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 155 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 156 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 157 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 158 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 159 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 160 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 161 | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 162 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 163 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 164 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 165 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 166 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 167 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 168 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 169 | github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= 170 | github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= 171 | github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= 172 | github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= 173 | github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= 174 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 175 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 176 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 177 | github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 178 | github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= 179 | github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= 180 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 181 | github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= 182 | github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= 183 | github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= 184 | github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= 185 | github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= 186 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 187 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 188 | github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= 189 | github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 190 | github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 191 | github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= 192 | github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= 193 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 194 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 195 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 196 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 197 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 198 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 199 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 200 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 201 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 202 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 203 | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 204 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 205 | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 206 | go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 207 | go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 208 | go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 209 | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 210 | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= 211 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0 h1:yt2NKzK7Vyo6h0+X8BA4FpreZQTlVEIarnsBP/H5mzs= 212 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.37.0/go.mod h1:+ARmXlUlc51J7sZeCBkBJNdHGySrdOzgzxp6VWRWM1U= 213 | go.opentelemetry.io/otel v1.11.2 h1:YBZcQlsVekzFsFbjygXMOXSs6pialIZxcjfO/mBDmR0= 214 | go.opentelemetry.io/otel v1.11.2/go.mod h1:7p4EUV+AqgdlNV9gL97IgUZiVR3yrFXYo53f9BM3tRI= 215 | go.opentelemetry.io/otel/exporters/prometheus v0.34.0 h1:L5D+HxdaC/ORB47ribbTBbkXRZs9JzPjq0EoIOMWncM= 216 | go.opentelemetry.io/otel/exporters/prometheus v0.34.0/go.mod h1:6gUoJyfhoWqF0tOLaY0ZmKgkQRcvEQx6p5rVlKHp3s4= 217 | go.opentelemetry.io/otel/metric v0.34.0 h1:MCPoQxcg/26EuuJwpYN1mZTeCYAUGx8ABxfW07YkjP8= 218 | go.opentelemetry.io/otel/metric v0.34.0/go.mod h1:ZFuI4yQGNCupurTXCwkeD/zHBt+C2bR7bw5JqUm/AP8= 219 | go.opentelemetry.io/otel/sdk v1.11.2 h1:GF4JoaEx7iihdMFu30sOyRx52HDHOkl9xQ8SMqNXUiU= 220 | go.opentelemetry.io/otel/sdk v1.11.2/go.mod h1:wZ1WxImwpq+lVRo4vsmSOxdd+xwoUJ6rqyLc3SyX9aU= 221 | go.opentelemetry.io/otel/sdk/metric v0.34.0 h1:7ElxfQpXCFZlRTvVRTkcUvK8Gt5DC8QzmzsLsO2gdzo= 222 | go.opentelemetry.io/otel/sdk/metric v0.34.0/go.mod h1:l4r16BIqiqPy5rd14kkxllPy/fOI4tWo1jkpD9Z3ffQ= 223 | go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZM/+y0= 224 | go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA= 225 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 226 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 227 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 228 | golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 229 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 230 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 231 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 232 | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 233 | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 234 | golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= 235 | golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= 236 | golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 237 | golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 238 | golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= 239 | golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= 240 | golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 241 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 242 | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 243 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 244 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 245 | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 246 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 247 | golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 248 | golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 249 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 250 | golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= 251 | golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 252 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 253 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 254 | golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 255 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 256 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 257 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 258 | golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 259 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 260 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 261 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 262 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 263 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 264 | golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 265 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 266 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 267 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 268 | golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 269 | golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 270 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 271 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 272 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 273 | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 274 | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 275 | golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 276 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 277 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 278 | golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 279 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 280 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 281 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 282 | golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 283 | golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 284 | golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 285 | golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 286 | golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 287 | golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 288 | golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= 289 | golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 290 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 291 | golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 292 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 293 | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 294 | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 295 | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 296 | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= 297 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= 298 | golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= 299 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 300 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 301 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 302 | golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 303 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 304 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 305 | golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 306 | golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 307 | golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 308 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 309 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 310 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 311 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 312 | golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 313 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 314 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 315 | golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 316 | golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 317 | golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 318 | golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 319 | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 320 | golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 321 | golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 322 | golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 323 | golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 324 | golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 325 | golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 326 | golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 327 | golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 328 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 329 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 330 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 331 | golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 332 | golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 333 | golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 334 | golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 335 | golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 336 | golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 337 | golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 338 | golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 339 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 340 | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 341 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 342 | golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 343 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 344 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 345 | golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 346 | golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= 347 | golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 348 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 349 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 350 | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 351 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 352 | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 353 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 354 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 355 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 356 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 357 | golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 358 | golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 359 | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 360 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 361 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 362 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 363 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 364 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 365 | golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 366 | golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 367 | golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 368 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 369 | golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 370 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 371 | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 372 | golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 373 | golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 374 | golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 375 | golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 376 | golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 377 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 378 | golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 379 | golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 380 | golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 381 | golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 382 | golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 383 | golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 384 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 385 | golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 386 | golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 387 | golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 388 | golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 389 | golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 390 | golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 391 | golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= 392 | golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= 393 | golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 394 | golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 395 | golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 396 | golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 397 | golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 398 | golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 399 | golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= 400 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 401 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 402 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 403 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 404 | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= 405 | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 406 | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 407 | google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= 408 | google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 409 | google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 410 | google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= 411 | google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 412 | google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 413 | google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 414 | google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 415 | google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= 416 | google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 417 | google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= 418 | google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= 419 | google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= 420 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 421 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 422 | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 423 | google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= 424 | google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 425 | google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 426 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 427 | google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 428 | google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 429 | google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 430 | google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 431 | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 432 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 433 | google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= 434 | google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 435 | google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 436 | google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 437 | google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 438 | google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 439 | google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= 440 | google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= 441 | google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 442 | google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 443 | google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 444 | google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 445 | google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 446 | google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 447 | google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 448 | google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= 449 | google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= 450 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 451 | google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= 452 | google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 453 | google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 454 | google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 455 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 456 | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= 457 | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 458 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 459 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 460 | google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 461 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 462 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 463 | google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= 464 | google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= 465 | google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 466 | google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= 467 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 468 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 469 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 470 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 471 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 472 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 473 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 474 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 475 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 476 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 477 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 478 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 479 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= 480 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 481 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 482 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 483 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 484 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 485 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 486 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 487 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 488 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 489 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 490 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 491 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 492 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 493 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 494 | honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 495 | honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 496 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 497 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 498 | honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 499 | honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= 500 | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= 501 | rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 502 | rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= 503 | -------------------------------------------------------------------------------- /levitate/remote-write/opentelemetry-collector/prometheus-receiver/app/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "net/http" 6 | 7 | "github.com/prometheus/client_golang/prometheus/promhttp" 8 | "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" 9 | "go.opentelemetry.io/otel/attribute" 10 | "go.opentelemetry.io/otel/exporters/prometheus" 11 | "go.opentelemetry.io/otel/metric/instrument" 12 | "go.opentelemetry.io/otel/sdk/metric" 13 | ) 14 | 15 | func main() { 16 | exporter, err := prometheus.New() 17 | if err != nil { 18 | log.Fatal(err) 19 | } 20 | provider := metric.NewMeterProvider(metric.WithReader(exporter)) 21 | meter := provider.Meter("levitate-otel-demo") 22 | requestCount, _ := meter.SyncInt64().Counter( 23 | "levitate/request_counts", 24 | instrument.WithDescription("The number of requests received"), 25 | ) 26 | 27 | programLabel := attribute.String("program", "levitate") 28 | envLabel := attribute.String("env", "production") 29 | labels := []attribute.KeyValue{programLabel, envLabel} 30 | 31 | // Start the prometheus HTTP server and pass the exporter Collector to it 32 | go serveMetrics() 33 | 34 | handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 35 | ctx := req.Context() 36 | requestCount.Add(ctx, 1, labels...) 37 | 38 | if _, err := w.Write([]byte("Hello World")); err != nil { 39 | http.Error(w, "write operation failed.", http.StatusInternalServerError) 40 | return 41 | } 42 | 43 | }) 44 | 45 | mux := http.NewServeMux() 46 | mux.Handle("/hello", otelhttp.NewHandler(handler, "/hello")) 47 | server := &http.Server{ 48 | Addr: ":9000", 49 | Handler: mux, 50 | } 51 | if err := server.ListenAndServe(); err != http.ErrServerClosed { 52 | log.Fatalf("%v", err) 53 | } 54 | } 55 | 56 | func serveMetrics() { 57 | log.Printf("serving metrics") 58 | mux := http.NewServeMux() 59 | mux.Handle("/metrics", promhttp.Handler()) 60 | server := &http.Server{ 61 | Addr: ":8000", 62 | Handler: mux, 63 | } 64 | if err := server.ListenAndServe(); err != http.ErrServerClosed { 65 | log.Fatalf("%v", err) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /levitate/remote-write/opentelemetry-collector/prometheus-receiver/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | services: 3 | otel-collector: 4 | container_name: otel-collector-contrib 5 | image: otel/opentelemetry-collector-contrib:0.64.0 6 | restart: always 7 | command: ["--config=/etc/otel-collector-config.yaml"] 8 | volumes: 9 | - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml 10 | ports: 11 | - "8888:8888" # Prometheus metrics exposed by the collector 12 | - "4317:4317" # OTLP gRPC receiver 13 | - "4318:4318" # OTLP http receiver 14 | 15 | app: 16 | container_name: app 17 | build: 18 | dockerfile: Dockerfile 19 | context: ./app 20 | restart: always 21 | ports: 22 | - "8000:8000" # metrics 23 | - "9000:9000" # app 24 | depends_on: 25 | - otel-collector 26 | -------------------------------------------------------------------------------- /levitate/remote-write/opentelemetry-collector/prometheus-receiver/otel-collector-config.yaml: -------------------------------------------------------------------------------- 1 | extensions: 2 | basicauth/prw: 3 | client_auth: 4 | # Replace these variables by their actual values 5 | username: $levitate_username 6 | password: $levitate_password 7 | 8 | receivers: 9 | prometheus: 10 | config: 11 | scrape_configs: 12 | - job_name: 'otel-collector-01' 13 | scrape_interval: 60s 14 | static_configs: 15 | - targets: ['otel-collector:8888', 'app:8000'] 16 | 17 | exporters: 18 | prometheusremotewrite: 19 | auth: 20 | authenticator: basicauth/prw 21 | endpoint: "$levitate_write_endpoint" # Replace this variable by its actual value 22 | 23 | service: 24 | extensions: [basicauth/prw] 25 | pipelines: 26 | metrics: 27 | receivers: [prometheus] 28 | exporters: [prometheusremotewrite] 29 | -------------------------------------------------------------------------------- /levitate/remote-write/prometheus-agent/k8s/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/last9/last9-integrations/8c9a66d98f253ff5e7afc0f9824c551b3f61f478/levitate/remote-write/prometheus-agent/k8s/README.md -------------------------------------------------------------------------------- /levitate/remote-write/python/README.md: -------------------------------------------------------------------------------- 1 | ## Getting started 2 | 3 | Make sure that you have snappy installed as per instructions [here](https://github.com/andrix/python-snappy). 4 | 5 | ```sh 6 | pip install python-snappy 7 | pip install opentelemetry-exporter-prometheus-remote-write 8 | ``` 9 | 10 | This will install required dependencies. After that, pass the username and password of Prometheus backend. (It can be Levitate cluster). 11 | 12 | ```sh 13 | python app.py LEVITATE_REMOTE_WRITE_URL LEVITATE_CLUSTER_USERNAME LEVITATE_CLUSTER_PASSWORD 'my_metric' '{"environment": "staging", "label": "9999"}' 14 | ``` 15 | 16 | After this you can explore the metric in Grafana to make sure it is accessible. 17 | 18 | You can refer to complete tutorial [here](https://docs.last9.io/docs/using-open-telemetry-exporter-for-prometheus-remote-write). 19 | -------------------------------------------------------------------------------- /levitate/remote-write/python/app.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import logging 4 | import random 5 | import sys 6 | import time 7 | import json 8 | from logging import INFO 9 | 10 | from opentelemetry import metrics 11 | from opentelemetry.exporter.prometheus_remote_write import ( 12 | PrometheusRemoteWriteMetricsExporter, 13 | ) 14 | from opentelemetry.metrics import Observation 15 | from opentelemetry.sdk.metrics import MeterProvider 16 | from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader 17 | 18 | logging.basicConfig(stream=sys.stdout, level=logging.INFO) 19 | logger = logging.getLogger(__name__) 20 | 21 | 22 | exporter = PrometheusRemoteWriteMetricsExporter( 23 | endpoint=sys.argv[1], 24 | basic_auth={ 25 | "username": sys.argv[2], 26 | "password": sys.argv[3], 27 | }, 28 | headers={}, 29 | ) 30 | reader = PeriodicExportingMetricReader(exporter, 1000) 31 | provider = MeterProvider(metric_readers=[reader]) 32 | metrics.set_meter_provider(provider) 33 | meter = metrics.get_meter(__name__) 34 | 35 | requests_counter = meter.create_counter( 36 | name=sys.argv[4], 37 | description="number of requests", 38 | ) 39 | 40 | testing_labels = json.loads(sys.argv[5]) 41 | 42 | num = random.randint(0, 1000) 43 | requests_counter.add(num % 131 + 200, testing_labels) 44 | logger.log(level=INFO, msg="completed metrics collection cycle") 45 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/relay/.gitignore: -------------------------------------------------------------------------------- 1 | *.env 2 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/relay/README.md: -------------------------------------------------------------------------------- 1 | This folder contains demo code for statsd to Levitate remote write integration 2 | using stasd_exporter relay method. 3 | 4 | Read more about the flow [here](https://docs.last9.io/docs/levitate-integrations-statsd#relay-method) 5 | 6 | ### Steps 7 | 8 | 1. Update the following variables in [docker-compose.yaml](./docker-compose.yaml) or update export them as environment variables 9 | - $LEVITATE_REMOTE_WRITE_URL 10 | - $LEVITATE_REMOTE_WRITE_USERNAME 11 | - $LEVITATE_REMOTE_WRITE_PASSWORD 12 | 2. Run `docker-compose up --build --force-recreate --remove-orphans` 13 | 14 | ### Validate 15 | 16 | 1. Run a test app that sends metrics to statsd. 17 | ``` 18 | pip install -r requirements.txt 19 | python ./test/statsd-test.py 20 | ``` 21 | 2. After 5 minutes, query for a sample metric `performance_request_successful_count_value`. 22 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/relay/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | 4 | statsd: 5 | build: statsd 6 | ports: 7 | - 8125:8125/udp 8 | - 8126:8126/udp 9 | restart: always 10 | 11 | statsd_exporter: 12 | image: prom/statsd-exporter 13 | ports: 14 | - 9125:9125/udp 15 | - 9102:9102/tcp 16 | command: 17 | - "--statsd.relay.address=statsd:8125" 18 | - "--web.listen-address=:9102" 19 | restart: always 20 | 21 | vmagent_levitate: 22 | image: victoriametrics/vmagent:v1.85.3 23 | ports: 24 | - 8429:8429 25 | volumes: 26 | - vmagentdata:/vmagentdata 27 | - ./vmagent.yaml:/etc/prometheus/prometheus.yaml 28 | command: 29 | - "--promscrape.config=/etc/prometheus/prometheus.yaml" 30 | - "--remoteWrite.url=${LEVITATE_REMOTE_WRITE_URL}" 31 | - "--remoteWrite.basicAuth.username=${LEVITATE_REMOTE_WRITE_USERNAME}" 32 | - "--remoteWrite.basicAuth.password=${LEVITATE_REMOTE_WRITE_PASSWORD}" 33 | restart: always 34 | 35 | volumes: 36 | vmagentdata: {} 37 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/relay/statsd/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | 3 | RUN apt-get update && apt-get install -y --force-yes git 4 | RUN git clone https://github.com/etsy/statsd.git 5 | RUN cd /statsd 6 | 7 | ADD config.js /statsd/config.js 8 | 9 | EXPOSE 8125/udp 10 | EXPOSE 8126/udp 11 | EXPOSE 8125/tcp 12 | EXPOSE 8126/tcp 13 | 14 | CMD /usr/local/bin/node /statsd/stats.js /statsd/config.js 15 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/relay/statsd/config.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | return { 3 | port: 8125, 4 | debug: false, 5 | backends: ['./backends/console'], 6 | server: "./servers/udp", 7 | includeStatsdMetrics: false, 8 | includeInfluxdbMetrics: false, 9 | keyNameSanitize: false 10 | }; 11 | 12 | })(); 13 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/relay/test/requirements.txt: -------------------------------------------------------------------------------- 1 | statsd 2 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/relay/test/statsd-test.py: -------------------------------------------------------------------------------- 1 | import statsd 2 | from time import sleep 3 | from random import randint, choice 4 | 5 | c = statsd.StatsClient('localhost', 9125, prefix='performance') 6 | 7 | while True: 8 | incr = randint(1, 5) 9 | metric_type = choice(['A', 'B', 'C']) 10 | print(f"\radding metric: type: {metric_type}, incr: {incr}", end="") 11 | c.incr(f'request.successful.count,type={metric_type}', incr) 12 | sleep(1) 13 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/relay/vmagent.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 30s 3 | scrape_configs: 4 | - job_name: "scrape_statsd_exporter_relay_1" 5 | static_configs: 6 | - targets: [ "statsd_exporter:9102" ] 7 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/repeater/.gitignore: -------------------------------------------------------------------------------- 1 | *.env 2 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/repeater/README.md: -------------------------------------------------------------------------------- 1 | This directory contains demo code for statsd to Levitate remote write integration 2 | using stasd_exporter repeater method. 3 | 4 | Read more about the flow [here](https://docs.last9.io/docs/levitate-integrations-statsd#repeater-method) 5 | 6 | ### Steps 7 | 8 | 1. Update the following variables in [docker-compose.yaml](./docker-compose.yaml) or update export them as environment variables 9 | - $LEVITATE_REMOTE_WRITE_URL 10 | - $LEVITATE_REMOTE_WRITE_USERNAME 11 | - $LEVITATE_REMOTE_WRITE_PASSWORD 12 | 2. Run `docker-compose up --build --force-recreate --remove-orphans` 13 | 14 | ### Validate 15 | 16 | 1. Run a test app that sends metrics to statsd. 17 | ``` 18 | pip install -r requirements.txt 19 | python ./test/statsd-test.py 20 | ``` 21 | 2. After 5 minutes, query for a sample metric `performance_request_successful_count_value`. 22 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/repeater/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | 4 | statsd: 5 | build: statsd 6 | ports: 7 | - 8125:8125/udp 8 | - 8126:8126/udp 9 | restart: always 10 | 11 | statsd_exporter: 12 | image: prom/statsd-exporter 13 | ports: 14 | - 9102:9102/tcp 15 | command: 16 | - "--statsd.listen-udp=:9125" 17 | - "--web.listen-address=:9102" 18 | restart: always 19 | 20 | vmagent_levitate: 21 | image: victoriametrics/vmagent:v1.85.3 22 | ports: 23 | - 8429:8429 24 | volumes: 25 | - vmagentdata:/vmagentdata 26 | - ./vmagent.yaml:/etc/prometheus/prometheus.yaml 27 | command: 28 | - "--promscrape.config=/etc/prometheus/prometheus.yaml" 29 | - "--remoteWrite.url=${LEVITATE_REMOTE_WRITE_URL}" 30 | - "--remoteWrite.basicAuth.username=${LEVITATE_REMOTE_WRITE_USERNAME}" 31 | - "--remoteWrite.basicAuth.password=${LEVITATE_REMOTE_WRITE_PASSWORD}" 32 | restart: always 33 | 34 | volumes: 35 | vmagentdata: {} 36 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/repeater/statsd/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | 3 | RUN apt-get update && apt-get install -y --force-yes git 4 | RUN git clone https://github.com/etsy/statsd.git 5 | # Install generic-pool module as it is required by repeater backend 6 | RUN cd /statsd && npm install generic-pool@2.2.0 7 | 8 | ADD config.js /statsd/config.js 9 | 10 | EXPOSE 8125/udp 11 | EXPOSE 8126/udp 12 | EXPOSE 8125/tcp 13 | EXPOSE 8126/tcp 14 | 15 | CMD /usr/local/bin/node /statsd/stats.js /statsd/config.js 16 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/repeater/statsd/config.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | return { 3 | port: parseInt(process.env.STATSD_PORT) || 8125, 4 | debug: process.env.STATSD_DEBUG || false, 5 | backends: ['./backends/console', './backends/repeater'], 6 | repeater: [ { host: 'statsd_exporter', port: 9125 }], 7 | server: "./servers/udp", 8 | includeStatsdMetrics: false, 9 | includeInfluxdbMetrics: false, 10 | keyNameSanitize: false 11 | }; 12 | 13 | })(); 14 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/repeater/test/requirements.txt: -------------------------------------------------------------------------------- 1 | statsd 2 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/repeater/test/statsd-test.py: -------------------------------------------------------------------------------- 1 | import statsd 2 | from time import sleep 3 | from random import randint, choice 4 | 5 | c = statsd.StatsClient('localhost', 8125, prefix='performance') 6 | 7 | while True: 8 | incr = randint(1, 5) 9 | metric_type = choice(['A', 'B', 'C']) 10 | print(f"\radding metric: type: {metric_type}, incr: {incr}", end="") 11 | c.incr(f'request.successful.count,type={metric_type}', incr) 12 | sleep(1) 13 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/repeater/vmagent.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 30s 3 | scrape_configs: 4 | - job_name: "scrape_statsd_exporter_repeater_1" 5 | static_configs: 6 | - targets: [ "statsd_exporter:9102" ] 7 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/vmagent-graphite/.gitignore: -------------------------------------------------------------------------------- 1 | *.env 2 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/vmagent-graphite/README.md: -------------------------------------------------------------------------------- 1 | This folder contains demo code for statsd to Levitate remote write integration 2 | using vmagent. 3 | 4 | Read more about the flow [here]() 5 | 6 | ### Steps 7 | 8 | 1. Update the following variables in [docker-compose.yaml](./docker-compose.yaml) or update export them as environment variables 9 | - $LEVITATE_REMOTE_WRITE_URL 10 | - $LEVITATE_REMOTE_WRITE_USERNAME 11 | - $LEVITATE_REMOTE_WRITE_PASSWORD 12 | 2. Run `docker-compose up --build --force-recreate --remove-orphans` 13 | 14 | ### Validate 15 | 16 | 1. Run a test app that sends metrics to statsd. 17 | ``` 18 | pip install -r requirements.txt 19 | python ./test/statsd-test.py 20 | ``` 21 | 2. After 5 minutes, query for a sample metric `performance_request_successful_count_value`. 22 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/vmagent-graphite/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | statsd: 4 | build: statsd 5 | depends_on: 6 | - vmagent_levitate 7 | ports: 8 | - 8125:8125/udp 9 | - 8126:8126/udp 10 | restart: always 11 | 12 | vmagent_levitate: 13 | image: victoriametrics/vmagent:v1.85.3 14 | ports: 15 | - 8429:8429 16 | - 2003:2003/tcp 17 | - 2003:2003/udp 18 | volumes: 19 | - vmagentdata:/vmagentdata 20 | - ./vmagent.yaml:/etc/prometheus/prometheus.yaml 21 | command: 22 | - "--graphiteListenAddr=:2003" 23 | - "--promscrape.config=/etc/prometheus/prometheus.yaml" 24 | - "--remoteWrite.url=${LEVITATE_REMOTE_WRITE_URL}" 25 | - "--remoteWrite.basicAuth.username=${LEVITATE_REMOTE_WRITE_USERNAME}" 26 | - "--remoteWrite.basicAuth.password=${LEVITATE_REMOTE_WRITE_PASSWORD}" 27 | restart: always 28 | 29 | volumes: 30 | vmagentdata: {} 31 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/vmagent-graphite/statsd/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | 3 | RUN apt-get update && apt-get install -y --force-yes git 4 | RUN git clone https://github.com/etsy/statsd.git 5 | RUN cd /statsd 6 | 7 | ADD config.js /statsd/config.js 8 | 9 | EXPOSE 8125/udp 10 | EXPOSE 8126/udp 11 | EXPOSE 8125/tcp 12 | EXPOSE 8126/tcp 13 | 14 | CMD /usr/local/bin/node /statsd/stats.js /statsd/config.js 15 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/vmagent-graphite/statsd/config.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | return { 3 | port: 8125, 4 | debug: true, 5 | backends: ["./backends/console", "./backends/graphite"], 6 | graphiteHost: "vmagent_levitate", 7 | graphitePort: 2003, 8 | server: "./servers/udp", 9 | includeStatsdMetrics: false, 10 | includeInfluxdbMetrics: false, 11 | keyNameSanitize: false 12 | }; 13 | })(); 14 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/vmagent-graphite/test/requirements.txt: -------------------------------------------------------------------------------- 1 | statsd 2 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/vmagent-graphite/test/statsd-test.py: -------------------------------------------------------------------------------- 1 | import statsd 2 | from time import sleep 3 | from random import randint, choice 4 | 5 | c = statsd.StatsClient('localhost', 8125, prefix='performance2') 6 | 7 | while True: 8 | incr = randint(1, 5) 9 | metric_type = choice(['A', 'B', 'C']) 10 | print(f"\radding metric: type: {metric_type}, incr: {incr}", end="") 11 | c.incr(f'request.successful.count,type={metric_type}', incr) 12 | sleep(1) 13 | -------------------------------------------------------------------------------- /levitate/remote-write/statsd/vmagent-graphite/vmagent.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | # Sane default of 1 minute. Anything less than this is too frequent. 3 | scrape_interval: 1m 4 | scrape_configs: 5 | - job_name: "scrape_vmagent_self" 6 | static_configs: 7 | - targets: [ "localhost:8429" ] 8 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/http-prometheusremotewrite/.gitignore: -------------------------------------------------------------------------------- 1 | *.env 2 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/http-prometheusremotewrite/README.md: -------------------------------------------------------------------------------- 1 | This folder contains demo code for Telegraf to Levitate remote write integration 2 | using InfluxDB http output plugin with data_format as prometheusremotewrite. 3 | 4 | ### Steps 5 | 6 | 1. Update the following variables in [docker-compose.yaml](./docker-compose.yaml) or update export them as environment variables 7 | - $LEVITATE_REMOTE_WRITE_URL 8 | - $LEVITATE_REMOTE_WRITE_USERNAME 9 | - $LEVITATE_REMOTE_WRITE_PASSWORD 10 | 2. Run `docker-compose up --build --force-recreate --remove-orphans` 11 | 12 | ### Validate 13 | 14 | 1. Run a test app that sends metrics to Telegraf. 15 | ``` 16 | pip install -r requirements.txt 17 | python ./test/statsd-test.py 18 | ``` 19 | 2. After 5 minutes, query for a sample metric `performance_request_successful_count_value`. 20 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/http-prometheusremotewrite/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | telegraf: 4 | image: telegraf:1.24 5 | volumes: 6 | - ./telegraf/etc/telegraf.conf:/etc/telegraf/telegraf.conf:ro 7 | environment: 8 | - LEVITATE_REMOTE_WRITE_URL=${LEVITATE_REMOTE_WRITE_URL} 9 | - LEVITATE_REMOTE_WRITE_USERNAME=${LEVITATE_REMOTE_WRITE_USERNAME} 10 | - LEVITATE_REMOTE_WRITE_PASSWORD=${LEVITATE_REMOTE_WRITE_PASSWORD} 11 | ports: 12 | - '8125:8125/udp' 13 | restart: always 14 | 15 | volumes: 16 | vmagentdata: {} 17 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/http-prometheusremotewrite/telegraf/etc/telegraf.conf: -------------------------------------------------------------------------------- 1 | # Telegraf configuration 2 | 3 | # Telegraf is entirely plugin driven. All metrics are gathered from the 4 | # declared inputs, and sent to the declared outputs. 5 | 6 | # Plugins must be declared in here to be active. 7 | # To deactivate a plugin, comment out the name and any variables. 8 | 9 | # Use 'telegraf -config telegraf.conf -test' to see what metrics a config 10 | # file would generate. 11 | 12 | # Global tags can be specified here in key="value" format. 13 | [global_tags] 14 | # dc = "us-east-1" # will tag all metrics with dc=us-east-1 15 | # rack = "1a" 16 | 17 | # Configuration for telegraf agent 18 | [agent] 19 | ## Default data collection interval for all inputs 20 | interval = "5s" 21 | ## Rounds collection interval to 'interval' 22 | ## ie, if interval="10s" then always collect on :00, :10, :20, etc. 23 | round_interval = true 24 | 25 | ## Telegraf will cache metric_buffer_limit metrics for each output, and will 26 | ## flush this buffer on a successful write. 27 | metric_buffer_limit = 10000 28 | ## Flush the buffer whenever full, regardless of flush_interval. 29 | flush_buffer_when_full = true 30 | 31 | ## Collection jitter is used to jitter the collection by a random amount. 32 | ## Each plugin will sleep for a random time within jitter before collecting. 33 | ## This can be used to avoid many plugins querying things like sysfs at the 34 | ## same time, which can have a measurable effect on the system. 35 | collection_jitter = "0s" 36 | 37 | ## Default flushing interval for all outputs. You shouldn't set this below 38 | ## interval. Maximum flush_interval will be flush_interval + flush_jitter 39 | flush_interval = "1s" 40 | ## Jitter the flush interval by a random amount. This is primarily to avoid 41 | ## large write spikes for users running a large number of telegraf instances. 42 | ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s 43 | flush_jitter = "0s" 44 | 45 | ## Run telegraf in debug mode 46 | debug = false 47 | ## Run telegraf in quiet mode 48 | quiet = false 49 | ## Override default hostname, if empty use os.Hostname() 50 | hostname = "" 51 | 52 | 53 | ############################################################################### 54 | # OUTPUTS # 55 | ############################################################################### 56 | 57 | 58 | ######## read ########## 59 | # Warning: When generating histogram and summary types, output may not be correct if the metric spans multiple batches. 60 | # This issue can be somewhat, but not fully, mitigated by using outputs that support writing in "batch format". 61 | # When using histogram and summary types, it is recommended to use only the prometheus_client output. 62 | ######## read ########## 63 | # A plugin that can transmit metrics over HTTP 64 | [[outputs.http]] 65 | ## URL is the address to send metrics to 66 | url = "${LEVITATE_REMOTE_WRITE_URL}" 67 | 68 | ## HTTP Basic Auth credentials 69 | username = "${LEVITATE_REMOTE_WRITE_USERNAME}" 70 | password = "${LEVITATE_REMOTE_WRITE_PASSWORD}" 71 | 72 | ## Data format to output. 73 | data_format = "prometheusremotewrite" 74 | 75 | ## Additional HTTP headers 76 | [outputs.http.headers] 77 | Content-Type = "application/x-protobuf" 78 | Content-Encoding = "snappy" 79 | X-Prometheus-Remote-Write-Version = "0.1.0" 80 | 81 | # 82 | ############################################################################### 83 | # INPUTS # 84 | ############################################################################### 85 | # Statsd Server 86 | [[inputs.statsd]] 87 | ## Protocol, must be "tcp", "udp4", "udp6" or "udp" (default=udp) 88 | protocol = "udp" 89 | 90 | ## MaxTCPConnection - applicable when protocol is set to tcp (default=250) 91 | max_tcp_connections = 250 92 | 93 | ## Enable TCP keep alive probes (default=false) 94 | tcp_keep_alive = false 95 | 96 | ## Specifies the keep-alive period for an active network connection. 97 | ## Only applies to TCP sockets and will be ignored if tcp_keep_alive is false. 98 | ## Defaults to the OS configuration. 99 | # tcp_keep_alive_period = "2h" 100 | 101 | ## Address and port to host UDP listener on 102 | service_address = ":8125" 103 | 104 | ## The following configuration options control when telegraf clears it's cache 105 | ## of previous values. If set to false, then telegraf will only clear it's 106 | ## cache when the daemon is restarted. 107 | ## Reset gauges every interval (default=true) 108 | delete_gauges = true 109 | ## Reset counters every interval (default=true) 110 | delete_counters = true 111 | ## Reset sets every interval (default=true) 112 | delete_sets = true 113 | ## Reset timings & histograms every interval (default=true) 114 | delete_timings = true 115 | 116 | ## Percentiles to calculate for timing & histogram stats 117 | percentiles = [90] 118 | 119 | ## separator to use between elements of a statsd metric 120 | metric_separator = "_" 121 | 122 | ## Parses tags in the datadog statsd format 123 | ## http://docs.datadoghq.com/guides/dogstatsd/ 124 | parse_data_dog_tags = false 125 | 126 | ## Statsd data translation templates, more info can be read here: 127 | ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md#graphite 128 | # templates = [ 129 | # "cpu.* measurement*" 130 | # ] 131 | 132 | ## Number of UDP messages allowed to queue up, once filled, 133 | ## the statsd server will start dropping packets 134 | allowed_pending_messages = 10000 135 | 136 | ## Number of timing/histogram values to track per-measurement in the 137 | ## calculation of percentiles. Raising this limit increases the accuracy 138 | ## of percentiles but also increases the memory usage and cpu time. 139 | percentile_limit = 1000 140 | 141 | ## Maximum socket buffer size in bytes, once the buffer fills up, metrics 142 | ## will start dropping. Defaults to the OS default. 143 | # read_buffer_size = 65535 144 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/http-prometheusremotewrite/test/statsd-test.py: -------------------------------------------------------------------------------- 1 | import statsd 2 | from time import sleep 3 | from random import randint, choice 4 | 5 | c = statsd.StatsClient('localhost', 8125, prefix='performance') 6 | 7 | while True: 8 | incr = randint(1, 5) 9 | metric_type = choice(['A', 'B', 'C']) 10 | print(f"\radding metric: type: {metric_type}, incr: {incr}", end="") 11 | c.incr(f'request.successful.count,type={metric_type}', incr) 12 | sleep(1) 13 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/influxdb-to-vmagent/.gitignore: -------------------------------------------------------------------------------- 1 | *.env 2 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/influxdb-to-vmagent/README.md: -------------------------------------------------------------------------------- 1 | ### Overview 2 | 3 | This directory contains demo code for Telegraf to Levitate remote write integration 4 | using InfluxDB output plugin pointing to vmagent. 5 | 6 | Read more about the flow [here](https://docs.last9.io/docs/levitate-integrations-telegraf). 7 | 8 | 9 | ### Steps 10 | 11 | 1. Update the following variables in [docker-compose.yaml](./docker-compose.yaml) or update export them as environment variables 12 | - $LEVITATE_REMOTE_WRITE_URL 13 | - $LEVITATE_REMOTE_WRITE_USERNAME 14 | - $LEVITATE_REMOTE_WRITE_PASSWORD 15 | 2. Run `docker-compose up --build --force-recreate --remove-orphans` 16 | 17 | ### Validate 18 | 19 | 1. Run a test app that sends metrics to Telegraf. 20 | ``` 21 | pip install -r requirements.txt 22 | python ./test/statsd-test.py 23 | ``` 24 | 2. After few minutes, query for a sample metric `performance_request_successful_count_value` using Levitate read endpoint. 25 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/influxdb-to-vmagent/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | telegraf: 4 | image: telegraf:1.24 5 | volumes: 6 | - ./telegraf/etc/telegraf.conf:/etc/telegraf/telegraf.conf:ro 7 | ports: 8 | - '8125:8125/udp' 9 | restart: always 10 | 11 | vmagent_levitate: 12 | image: victoriametrics/vmagent:v1.85.3 13 | ports: 14 | - 8429:8429 15 | volumes: 16 | - vmagentdata:/vmagentdata 17 | - ./vmagent.yaml:/etc/prometheus/prometheus.yaml 18 | command: 19 | - "--promscrape.config=/etc/prometheus/prometheus.yaml" 20 | - "--remoteWrite.url=${LEVITATE_REMOTE_WRITE_URL}" 21 | - "--remoteWrite.basicAuth.username=${LEVITATE_REMOTE_WRITE_USERNAME}" 22 | - "--remoteWrite.basicAuth.password=${LEVITATE_REMOTE_WRITE_PASSWORD}" 23 | restart: always 24 | 25 | volumes: 26 | vmdata: {} 27 | vmagentdata: {} 28 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/influxdb-to-vmagent/telegraf/etc/telegraf.conf: -------------------------------------------------------------------------------- 1 | # Telegraf configuration 2 | 3 | # Telegraf is entirely plugin driven. All metrics are gathered from the 4 | # declared inputs, and sent to the declared outputs. 5 | 6 | # Plugins must be declared in here to be active. 7 | # To deactivate a plugin, comment out the name and any variables. 8 | 9 | # Use 'telegraf -config telegraf.conf -test' to see what metrics a config 10 | # file would generate. 11 | 12 | # Global tags can be specified here in key="value" format. 13 | [global_tags] 14 | # dc = "us-east-1" # will tag all metrics with dc=us-east-1 15 | # rack = "1a" 16 | 17 | # Configuration for telegraf agent 18 | [agent] 19 | ## Default data collection interval for all inputs 20 | interval = "5s" 21 | ## Rounds collection interval to 'interval' 22 | ## ie, if interval="10s" then always collect on :00, :10, :20, etc. 23 | round_interval = true 24 | 25 | ## Telegraf will cache metric_buffer_limit metrics for each output, and will 26 | ## flush this buffer on a successful write. 27 | metric_buffer_limit = 10000 28 | ## Flush the buffer whenever full, regardless of flush_interval. 29 | flush_buffer_when_full = true 30 | 31 | ## Collection jitter is used to jitter the collection by a random amount. 32 | ## Each plugin will sleep for a random time within jitter before collecting. 33 | ## This can be used to avoid many plugins querying things like sysfs at the 34 | ## same time, which can have a measurable effect on the system. 35 | collection_jitter = "0s" 36 | 37 | ## Default flushing interval for all outputs. You shouldn't set this below 38 | ## interval. Maximum flush_interval will be flush_interval + flush_jitter 39 | flush_interval = "1s" 40 | ## Jitter the flush interval by a random amount. This is primarily to avoid 41 | ## large write spikes for users running a large number of telegraf instances. 42 | ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s 43 | flush_jitter = "0s" 44 | 45 | ## Run telegraf in debug mode 46 | debug = false 47 | ## Run telegraf in quiet mode 48 | quiet = false 49 | ## Override default hostname, if empty use os.Hostname() 50 | hostname = "" 51 | 52 | 53 | ############################################################################### 54 | # OUTPUTS # 55 | ############################################################################### 56 | [[outputs.influxdb]] 57 | urls = ["http://vmagent_levitate:8429"] 58 | 59 | # 60 | ############################################################################### 61 | # INPUTS # 62 | ############################################################################### 63 | # Statsd Server 64 | [[inputs.statsd]] 65 | ## Protocol, must be "tcp", "udp4", "udp6" or "udp" (default=udp) 66 | protocol = "udp" 67 | 68 | ## MaxTCPConnection - applicable when protocol is set to tcp (default=250) 69 | max_tcp_connections = 250 70 | 71 | ## Enable TCP keep alive probes (default=false) 72 | tcp_keep_alive = false 73 | 74 | ## Specifies the keep-alive period for an active network connection. 75 | ## Only applies to TCP sockets and will be ignored if tcp_keep_alive is false. 76 | ## Defaults to the OS configuration. 77 | # tcp_keep_alive_period = "2h" 78 | 79 | ## Address and port to host UDP listener on 80 | service_address = ":8125" 81 | 82 | ## The following configuration options control when telegraf clears it's cache 83 | ## of previous values. If set to false, then telegraf will only clear it's 84 | ## cache when the daemon is restarted. 85 | ## Reset gauges every interval (default=true) 86 | delete_gauges = true 87 | ## Reset counters every interval (default=true) 88 | delete_counters = true 89 | ## Reset sets every interval (default=true) 90 | delete_sets = true 91 | ## Reset timings & histograms every interval (default=true) 92 | delete_timings = true 93 | 94 | ## Percentiles to calculate for timing & histogram stats 95 | percentiles = [90] 96 | 97 | ## separator to use between elements of a statsd metric 98 | metric_separator = "_" 99 | 100 | ## Parses tags in the datadog statsd format 101 | ## http://docs.datadoghq.com/guides/dogstatsd/ 102 | parse_data_dog_tags = false 103 | 104 | ## Statsd data translation templates, more info can be read here: 105 | ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md#graphite 106 | # templates = [ 107 | # "cpu.* measurement*" 108 | # ] 109 | 110 | ## Number of UDP messages allowed to queue up, once filled, 111 | ## the statsd server will start dropping packets 112 | allowed_pending_messages = 10000 113 | 114 | ## Number of timing/histogram values to track per-measurement in the 115 | ## calculation of percentiles. Raising this limit increases the accuracy 116 | ## of percentiles but also increases the memory usage and cpu time. 117 | percentile_limit = 1000 118 | 119 | ## Maximum socket buffer size in bytes, once the buffer fills up, metrics 120 | ## will start dropping. Defaults to the OS default. 121 | # read_buffer_size = 65535 122 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/influxdb-to-vmagent/test/statsd-test.py: -------------------------------------------------------------------------------- 1 | import statsd 2 | from time import sleep 3 | from random import randint, choice 4 | 5 | c = statsd.StatsClient('localhost', 8125, prefix='performance') 6 | 7 | while True: 8 | incr = randint(1, 5) 9 | metric_type = choice(['A', 'B', 'C']) 10 | print(f"\radding metric: type: {metric_type}, incr: {incr}", end="") 11 | c.incr(f'request.successful.count,type={metric_type}', incr) 12 | sleep(1) 13 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/influxdb-to-vmagent/vmagent.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 1m 3 | scrape_configs: 4 | - job_name: "scrape_vmagent_self" 5 | static_configs: 6 | - targets: [ "localhost:8429" ] 7 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/prometheus-client/.gitignore: -------------------------------------------------------------------------------- 1 | *.env 2 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/prometheus-client/README.md: -------------------------------------------------------------------------------- 1 | This folder contains demo code for Telegraf to Levitate remote write integration 2 | using InfluxDB prometheus_client output plugin. 3 | 4 | ### Steps 5 | 6 | 1. Update the following variables in [docker-compose.yaml](./docker-compose.yaml) or update export them as environment variables 7 | - $LEVITATE_REMOTE_WRITE_URL 8 | - $LEVITATE_REMOTE_WRITE_USERNAME 9 | - $LEVITATE_REMOTE_WRITE_PASSWORD 10 | 2. Run `docker-compose up --build --force-recreate --remove-orphans` 11 | 12 | ### Validate 13 | 14 | 1. Run a test app that sends metrics to Telegraf. 15 | ``` 16 | pip install -r requirements.txt 17 | python ./test/statsd-test.py 18 | ``` 19 | 2. After 5 minutes, query for a sample metric `performance_request_successful_count_value`. 20 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/prometheus-client/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | telegraf: 4 | image: telegraf:1.24 5 | volumes: 6 | - ./telegraf/etc/telegraf.conf:/etc/telegraf/telegraf.conf:ro 7 | ports: 8 | - '8125:8125/udp' 9 | - '9273:9273' 10 | restart: always 11 | 12 | vmagent_levitate: 13 | image: victoriametrics/vmagent:v1.85.3 14 | ports: 15 | - 8429:8429 16 | volumes: 17 | - vmagentdata:/vmagentdata 18 | - ./vmagent.yaml:/etc/prometheus/prometheus.yaml 19 | command: 20 | - "--promscrape.config=/etc/prometheus/prometheus.yaml" 21 | - "--remoteWrite.url=${LEVITATE_REMOTE_WRITE_URL}" 22 | - "--remoteWrite.basicAuth.username=${LEVITATE_REMOTE_WRITE_USERNAME}" 23 | - "--remoteWrite.basicAuth.password=${LEVITATE_REMOTE_WRITE_PASSWORD}" 24 | restart: always 25 | 26 | volumes: 27 | vmagentdata: {} 28 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/prometheus-client/telegraf/etc/telegraf.conf: -------------------------------------------------------------------------------- 1 | # Telegraf configuration 2 | 3 | # Telegraf is entirely plugin driven. All metrics are gathered from the 4 | # declared inputs, and sent to the declared outputs. 5 | 6 | # Plugins must be declared in here to be active. 7 | # To deactivate a plugin, comment out the name and any variables. 8 | 9 | # Use 'telegraf -config telegraf.conf -test' to see what metrics a config 10 | # file would generate. 11 | 12 | # Global tags can be specified here in key="value" format. 13 | [global_tags] 14 | # dc = "us-east-1" # will tag all metrics with dc=us-east-1 15 | # rack = "1a" 16 | 17 | # Configuration for telegraf agent 18 | [agent] 19 | ## Default data collection interval for all inputs 20 | interval = "5s" 21 | ## Rounds collection interval to 'interval' 22 | ## ie, if interval="10s" then always collect on :00, :10, :20, etc. 23 | round_interval = true 24 | 25 | ## Telegraf will cache metric_buffer_limit metrics for each output, and will 26 | ## flush this buffer on a successful write. 27 | metric_buffer_limit = 10000 28 | ## Flush the buffer whenever full, regardless of flush_interval. 29 | flush_buffer_when_full = true 30 | 31 | ## Collection jitter is used to jitter the collection by a random amount. 32 | ## Each plugin will sleep for a random time within jitter before collecting. 33 | ## This can be used to avoid many plugins querying things like sysfs at the 34 | ## same time, which can have a measurable effect on the system. 35 | collection_jitter = "0s" 36 | 37 | ## Default flushing interval for all outputs. You shouldn't set this below 38 | ## interval. Maximum flush_interval will be flush_interval + flush_jitter 39 | flush_interval = "1s" 40 | ## Jitter the flush interval by a random amount. This is primarily to avoid 41 | ## large write spikes for users running a large number of telegraf instances. 42 | ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s 43 | flush_jitter = "0s" 44 | 45 | ## Run telegraf in debug mode 46 | debug = false 47 | ## Run telegraf in quiet mode 48 | quiet = false 49 | ## Override default hostname, if empty use os.Hostname() 50 | hostname = "" 51 | 52 | 53 | ############################################################################### 54 | # OUTPUTS # 55 | ############################################################################### 56 | 57 | # Configuration for the Prometheus client to spawn 58 | [[outputs.prometheus_client]] 59 | ## Address to listen on. 60 | listen = ":9273" 61 | 62 | ## Metric version controls the mapping from Prometheus metrics into Telegraf metrics. 63 | ## See "Metric Format Configuration" in plugins/inputs/prometheus/README.md for details. 64 | ## Valid options: 1, 2 65 | # metric_version = 1 66 | 67 | ## Use HTTP Basic Authentication. 68 | # basic_username = "Foo" 69 | # basic_password = "Bar" 70 | 71 | ## If set, the IP Ranges which are allowed to access metrics. 72 | ## ex: ip_range = ["192.168.0.0/24", "192.168.1.0/30"] 73 | # ip_range = [] 74 | 75 | ## Path to publish the metrics on. 76 | # path = "/metrics" 77 | 78 | ## Expiration interval for each metric. 0 == no expiration 79 | # expiration_interval = "60s" 80 | 81 | ## Collectors to enable, valid entries are "gocollector" and "process". 82 | ## If unset, both are enabled. 83 | # collectors_exclude = ["gocollector", "process"] 84 | 85 | ## Send string metrics as Prometheus labels. 86 | ## Unless set to false all string metrics will be sent as labels. 87 | # string_as_label = true 88 | 89 | ## If set, enable TLS with the given certificate. 90 | # tls_cert = "/etc/ssl/telegraf.crt" 91 | # tls_key = "/etc/ssl/telegraf.key" 92 | 93 | ## Set one or more allowed client CA certificate file names to 94 | ## enable mutually authenticated TLS connections 95 | # tls_allowed_cacerts = ["/etc/telegraf/clientca.pem"] 96 | 97 | ## Export metric collection time. 98 | # export_timestamp = false 99 | 100 | # 101 | ############################################################################### 102 | # INPUTS # 103 | ############################################################################### 104 | # Statsd Server 105 | [[inputs.statsd]] 106 | ## Protocol, must be "tcp", "udp4", "udp6" or "udp" (default=udp) 107 | protocol = "udp" 108 | 109 | ## MaxTCPConnection - applicable when protocol is set to tcp (default=250) 110 | max_tcp_connections = 250 111 | 112 | ## Enable TCP keep alive probes (default=false) 113 | tcp_keep_alive = false 114 | 115 | ## Specifies the keep-alive period for an active network connection. 116 | ## Only applies to TCP sockets and will be ignored if tcp_keep_alive is false. 117 | ## Defaults to the OS configuration. 118 | # tcp_keep_alive_period = "2h" 119 | 120 | ## Address and port to host UDP listener on 121 | service_address = ":8125" 122 | 123 | ## The following configuration options control when telegraf clears it's cache 124 | ## of previous values. If set to false, then telegraf will only clear it's 125 | ## cache when the daemon is restarted. 126 | ## Reset gauges every interval (default=true) 127 | delete_gauges = true 128 | ## Reset counters every interval (default=true) 129 | delete_counters = true 130 | ## Reset sets every interval (default=true) 131 | delete_sets = true 132 | ## Reset timings & histograms every interval (default=true) 133 | delete_timings = true 134 | 135 | ## Percentiles to calculate for timing & histogram stats 136 | percentiles = [90] 137 | 138 | ## separator to use between elements of a statsd metric 139 | metric_separator = "_" 140 | 141 | ## Parses tags in the datadog statsd format 142 | ## http://docs.datadoghq.com/guides/dogstatsd/ 143 | parse_data_dog_tags = false 144 | 145 | ## Statsd data translation templates, more info can be read here: 146 | ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md#graphite 147 | # templates = [ 148 | # "cpu.* measurement*" 149 | # ] 150 | 151 | ## Number of UDP messages allowed to queue up, once filled, 152 | ## the statsd server will start dropping packets 153 | allowed_pending_messages = 10000 154 | 155 | ## Number of timing/histogram values to track per-measurement in the 156 | ## calculation of percentiles. Raising this limit increases the accuracy 157 | ## of percentiles but also increases the memory usage and cpu time. 158 | percentile_limit = 1000 159 | 160 | ## Maximum socket buffer size in bytes, once the buffer fills up, metrics 161 | ## will start dropping. Defaults to the OS default. 162 | # read_buffer_size = 65535 163 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/prometheus-client/test/statsd-test.py: -------------------------------------------------------------------------------- 1 | import statsd 2 | from time import sleep 3 | from random import randint, choice 4 | 5 | c = statsd.StatsClient('localhost', 8125, prefix='performance') 6 | 7 | while True: 8 | incr = randint(1, 5) 9 | metric_type = choice(['A', 'B', 'C']) 10 | print(f"\radding metric: type: {metric_type}, incr: {incr}", end="") 11 | c.incr(f'request.successful.count,type={metric_type}', incr) 12 | sleep(1) 13 | -------------------------------------------------------------------------------- /levitate/remote-write/telegraf/prometheus-client/vmagent.yaml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 1m 3 | scrape_configs: 4 | - job_name: "scrape_telegraf_prometheus_client" 5 | static_configs: 6 | - targets: [ "telegraf:9273" ] 7 | -------------------------------------------------------------------------------- /levitate/remote-write/vmagent/docker/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/last9/last9-integrations/8c9a66d98f253ff5e7afc0f9824c551b3f61f478/levitate/remote-write/vmagent/docker/README.md -------------------------------------------------------------------------------- /levitate/remote-write/vmagent/ecs/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/last9/last9-integrations/8c9a66d98f253ff5e7afc0f9824c551b3f61f478/levitate/remote-write/vmagent/ecs/README.md -------------------------------------------------------------------------------- /levitate/remote-write/vmagent/k8s/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/last9/last9-integrations/8c9a66d98f253ff5e7afc0f9824c551b3f61f478/levitate/remote-write/vmagent/k8s/README.md --------------------------------------------------------------------------------