├── .codecov.yml ├── .coveralls.yml ├── .gitignore ├── .rubocop.yml ├── .rubocop_todo.yml ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE ├── MAINTAINERS.md ├── README.md ├── Rakefile ├── SECURITY.md ├── examples ├── authentication_proxy.rb ├── get_labels.rb ├── get_metrics.rb └── low_level.rb ├── lib ├── prometheus.rb └── prometheus │ ├── api_client.rb │ └── api_client │ ├── client.rb │ └── version.rb ├── prometheus-api-client.gemspec └── spec ├── prometheus ├── api_client │ └── client_spec.rb └── api_client_spec.rb ├── spec_helper.rb └── vcr_cassettes └── prometheus └── api_client └── client.yml /.codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | branch: master 3 | -------------------------------------------------------------------------------- /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | Gemfile.lock 3 | pkg/ 4 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | inherit_from: .rubocop_todo.yml 2 | 3 | AllCops: 4 | TargetRubyVersion: 3.0 5 | Exclude: 6 | - lib/prometheus/api_client/version.rb 7 | NewCops: disable 8 | SuggestExtensions: false 9 | 10 | Layout/HashAlignment: 11 | EnforcedHashRocketStyle: table 12 | 13 | Style/TrailingCommaInArguments: 14 | EnforcedStyleForMultiline: comma 15 | 16 | Style/TrailingCommaInArrayLiteral: 17 | EnforcedStyleForMultiline: comma 18 | 19 | Style/TrailingCommaInHashLiteral: 20 | EnforcedStyleForMultiline: comma 21 | 22 | Metrics/AbcSize: 23 | Max: 18 24 | 25 | Metrics/MethodLength: 26 | Max: 23 27 | 28 | Metrics/BlockLength: 29 | Exclude: 30 | - 'spec/**/*.rb' 31 | 32 | Layout/LineLength: 33 | Exclude: 34 | - 'spec/**/*.rb' 35 | -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config` 3 | # on 2023-02-20 17:39:35 UTC using RuboCop version 1.45.1. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | # Offense count: 1 10 | # This cop supports safe autocorrection (--autocorrect). 11 | Layout/EmptyLineAfterMagicComment: 12 | Exclude: 13 | - 'prometheus-api-client.gemspec' 14 | 15 | # Offense count: 8 16 | # This cop supports safe autocorrection (--autocorrect). 17 | # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. 18 | # SupportedHashRocketStyles: key, separator, table 19 | # SupportedColonStyles: key, separator, table 20 | # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit 21 | Layout/HashAlignment: 22 | Exclude: 23 | - 'examples/get_metrics.rb' 24 | - 'examples/low_level.rb' 25 | - 'spec/prometheus/api_client/client_spec.rb' 26 | 27 | # Offense count: 1 28 | # This cop supports safe autocorrection (--autocorrect). 29 | # Configuration parameters: PreferredName. 30 | Naming/RescuedExceptionsVariableName: 31 | Exclude: 32 | - 'lib/prometheus/api_client/client.rb' 33 | 34 | # Offense count: 8 35 | # This cop supports safe autocorrection (--autocorrect). 36 | Style/Encoding: 37 | Exclude: 38 | - 'Rakefile' 39 | - 'lib/prometheus.rb' 40 | - 'lib/prometheus/api_client.rb' 41 | - 'lib/prometheus/api_client/client.rb' 42 | - 'prometheus-api-client.gemspec' 43 | - 'spec/prometheus/api_client/client_spec.rb' 44 | - 'spec/prometheus/api_client_spec.rb' 45 | - 'spec/spec_helper.rb' 46 | 47 | # Offense count: 1 48 | # This cop supports safe autocorrection (--autocorrect). 49 | Style/ExpandPathArguments: 50 | Exclude: 51 | - 'prometheus-api-client.gemspec' 52 | 53 | # Offense count: 13 54 | # This cop supports unsafe autocorrection (--autocorrect-all). 55 | # Configuration parameters: EnforcedStyle. 56 | # SupportedStyles: always, always_true, never 57 | Style/FrozenStringLiteralComment: 58 | Exclude: 59 | - 'Gemfile' 60 | - 'Rakefile' 61 | - 'examples/authentication_proxy.rb' 62 | - 'examples/get_labels.rb' 63 | - 'examples/get_metrics.rb' 64 | - 'examples/low_level.rb' 65 | - 'lib/prometheus.rb' 66 | - 'lib/prometheus/api_client.rb' 67 | - 'lib/prometheus/api_client/client.rb' 68 | - 'prometheus-api-client.gemspec' 69 | - 'spec/prometheus/api_client/client_spec.rb' 70 | - 'spec/prometheus/api_client_spec.rb' 71 | - 'spec/spec_helper.rb' 72 | 73 | # Offense count: 1 74 | # This cop supports safe autocorrection (--autocorrect). 75 | # Configuration parameters: PreferredDelimiters. 76 | Style/PercentLiteralDelimiters: 77 | Exclude: 78 | - 'prometheus-api-client.gemspec' 79 | 80 | # Offense count: 1 81 | # This cop supports safe autocorrection (--autocorrect). 82 | Style/RedundantCondition: 83 | Exclude: 84 | - 'lib/prometheus/api_client/client.rb' 85 | 86 | # Offense count: 1 87 | # This cop supports unsafe autocorrection (--autocorrect-all). 88 | # Configuration parameters: Mode. 89 | Style/StringConcatenation: 90 | Exclude: 91 | - 'lib/prometheus/api_client/client.rb' 92 | 93 | # Offense count: 1 94 | # This cop supports safe autocorrection (--autocorrect). 95 | # Configuration parameters: MinSize. 96 | # SupportedStyles: percent, brackets 97 | Style/SymbolArray: 98 | EnforcedStyle: brackets 99 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: ruby 3 | # Needed for rainbow 2.2.1 / rubygems issues. 4 | before_install: 5 | - | 6 | if [[ "$(ruby -e 'puts RUBY_VERSION')" != 1.* ]]; then gem update --system; fi 7 | rvm: 8 | - 3.0.5 9 | - 3.1.3 10 | - 3.2.1 11 | - jruby-9.4.1.0 12 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Prometheus Community Code of Conduct 2 | 3 | Prometheus follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md). 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Prometheus uses GitHub to manage reviews of pull requests. 4 | 5 | * If you have a trivial fix or improvement, go ahead and create a pull request, 6 | addressing (with `@...`) the maintainer of this repository (see 7 | [MAINTAINERS.md](MAINTAINERS.md)) in the description of the pull request. 8 | 9 | * If you plan to do something more involved, first discuss your ideas 10 | on our [mailing list](https://groups.google.com/forum/?fromgroups#!forum/prometheus-developers). 11 | This will avoid unnecessary work and surely give you and us a good deal 12 | of inspiration. 13 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | gem 'faraday' 6 | 7 | group :test do 8 | gem 'coveralls' 9 | gem 'rake' 10 | gem 'rspec' 11 | gem 'rubocop' 12 | gem 'vcr' 13 | gem 'webmock' 14 | end 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | * Yaacov Zamir 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Prometheus API Ruby Client 2 | 3 | [![Gem Version][1]](http://badge.fury.io/rb/prometheus-api-client) 4 | [![Build Status][3]](https://codeclimate.com/github/prometheus/prometheus_api_client_ruby) 5 | [![Coverage Status][4]](https://coveralls.io/github/prometheus/prometheus_api_client_ruby?branch=master) 6 | 7 | A Ruby library for reading metrics stored on a Prometheus server. 8 | 9 | ## Install 10 | 11 | ``` 12 | gem install prometheus-api-client 13 | ``` 14 | 15 | ## Usage 16 | 17 | ### Overview 18 | 19 | ```ruby 20 | require 'prometheus/api_client' 21 | 22 | # return a client for host http://localhost:9090/api/v1/ 23 | prometheus = Prometheus::ApiClient.client 24 | ``` 25 | 26 | #### Changing server hostname 27 | 28 | ```ruby 29 | # return a client for host http://example.com:9090/api/v1/ 30 | prometheus = Prometheus::ApiClient.client(url: 'http://example.com:9090') 31 | ``` 32 | 33 | #### Authentication proxy 34 | 35 | If an authentication proxy ( e.g. oauth2 ) is used in a layer above the 36 | prometheus REST server, this client can use ssl and authentication headears. 37 | 38 | ```ruby 39 | # return a client for host https://example.com/api/v1/ using a Bearer token "TopSecret" 40 | prometheus = Prometheus::ApiClient.client(url: 'https://example.com:443', 41 | credentials: { token: 'TopSecret' }) 42 | ``` 43 | 44 | #### Low level calls 45 | 46 | ###### query 47 | 48 | ```ruby 49 | 50 | # send a low level get request to server 51 | prometheus.get( 52 | 'query_range', 53 | query: 'sum(container_cpu_usage_seconds_total' \ 54 | '{container_name="prometheus-hgv4s",job="kubernetes-nodes"})', 55 | start: '2015-07-01T20:10:30.781Z', 56 | end: '2015-07-02T20:10:30.781Z', 57 | step: '120s', 58 | ) 59 | ``` 60 | ``` 61 | # response from server is a low level response struct including 62 | # fields like: method, body and request_headers 63 | # usually users will not need to use this low level calls 64 | ... 65 | method=:get, 66 | body="{\"status\":\"success\", 67 | ... 68 | ``` 69 | #### High level calls 70 | 71 | ###### query 72 | 73 | ```ruby 74 | 75 | # send a query request to server 76 | prometheus.query( 77 | query: 'sum(container_cpu_usage_seconds_total' \ 78 | '{container_name="prometheus-hgv4s",job="kubernetes-nodes"})', 79 | time: '2015-07-01T20:10:30.781Z', 80 | ) 81 | ``` 82 | ``` 83 | # response from server: 84 | {"resultType"=>"vector", "result"=>[{"metric"=>{}, "value"=>[1502350741.161, "6606.310387038"]}]} 85 | ``` 86 | ###### query_range 87 | 88 | ```ruby 89 | # send a query_range request to server 90 | prometheus.query_range( 91 | query: 'sum(container_cpu_usage_seconds_total' \ 92 | '{container_name="prometheus-hgv4s",job="kubernetes-nodes"})', 93 | start: '2015-07-01T20:10:30.781Z', 94 | end: '2015-07-02T20:10:30.781Z', 95 | step: '120s', 96 | ) 97 | ``` 98 | ``` 99 | # response from server: 100 | {"resultType"=>"matrix", 101 | "result"=> 102 | [{"metric"=> 103 | {"__name__"=>"container_cpu_usage_seconds_total", 104 | "beta_kubernetes_io_arch"=>"amd64", 105 | "beta_kubernetes_io_os"=>"linux", 106 | "cpu"=>"cpu00", 107 | "id"=>"/", 108 | "instance"=>"example.com", 109 | "job"=>"kubernetes-cadvisor", 110 | "kubernetes_io_hostname"=>"example.com", 111 | "region"=>"infra", 112 | "zone"=>"default"}, 113 | "values"=>[[1502086230.781, "51264.830099022"], 114 | [1502086470.781, "51277.367732154"]]}, 115 | {"metric"=> 116 | {"__name__"=>"container_cpu_usage_seconds_total", 117 | "beta_kubernetes_io_arch"=>"amd64", 118 | "beta_kubernetes_io_os"=>"linux", 119 | "cpu"=>"cpu01", 120 | "id"=>"/", 121 | "instance"=>"example.com", 122 | "job"=>"kubernetes-cadvisor", 123 | "kubernetes_io_hostname"=>"example.com", 124 | "region"=>"infra", 125 | "zone"=>"default"}, 126 | "values"=>[[1502086230.781, "53879.644934689"], 127 | [1502086470.781, "53892.665282065"]]}]} 128 | ``` 129 | 130 | ###### label 131 | 132 | ```ruby 133 | # send a label request to server 134 | prometheus.label('__name__') 135 | ``` 136 | ``` 137 | # response from server: 138 | ["APIServiceRegistrationController_adds", 139 | "APIServiceRegistrationController_depth", 140 | ... 141 | 142 | ``` 143 | 144 | ###### targets 145 | 146 | ```ruby 147 | # send a targets request to server 148 | prometheus.targets() 149 | ``` 150 | ``` 151 | # response from server: 152 | {"activeTargets"=> 153 | [{"discoveredLabels"=> 154 | {"__address__"=>"10.35.19.248:8443", 155 | "__meta_kubernetes_endpoint_port_name"=>"https", 156 | "__meta_kubernetes_endpoint_port_protocol"=>"TCP", 157 | "__meta_kubernetes_endpoint_ready"=>"true", 158 | "__meta_kubernetes_endpoints_name"=>"kubernetes", 159 | "__meta_kubernetes_namespace"=>"default", 160 | "__meta_kubernetes_service_label_component"=>"apiserver", 161 | "__meta_kubernetes_service_label_provider"=>"kubernetes", 162 | "__meta_kubernetes_service_name"=>"kubernetes", 163 | "__metrics_path__"=>"/metrics", 164 | "__scheme__"=>"https", 165 | "job"=>"kubernetes-apiservers"}, 166 | "labels"=>{"instance"=>"10.35.19.248:8443", "job"=>"kubernetes-apiservers"}, 167 | "scrapeUrl"=>"https://10.35.19.248:8443/metrics", 168 | "lastError"=>"", 169 | "lastScrape"=>"2017-08-10T07:35:40.919376413Z", 170 | "health"=>"up"}, 171 | ... 172 | 173 | ``` 174 | 175 | ## Tests 176 | 177 | Install necessary development gems with `bundle install` and run tests with 178 | rspec: 179 | 180 | ```bash 181 | rake 182 | ``` 183 | 184 | [1]: https://badge.fury.io/rb/prometheus-api-client.svg 185 | [2]: https://secure.travis-ci.org/yaacov/prometheus_api_client_ruby.svg 186 | [3]: https://codeclimate.com/github/yaacov/prometheus_api_client_ruby.svg 187 | [4]: https://coveralls.io/repos/github/yaacov/prometheus_api_client_ruby/badge.svg 188 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | require 'bundler' 4 | require 'rspec/core/rake_task' 5 | require 'rubocop/rake_task' 6 | 7 | desc 'Default: run specs' 8 | task default: [:spec, :rubocop] 9 | 10 | # test alias 11 | task test: :spec 12 | 13 | desc 'Run specs' 14 | RSpec::Core::RakeTask.new do |t| 15 | t.rspec_opts = '--require ./spec/spec_helper.rb' 16 | end 17 | 18 | desc 'Lint code' 19 | RuboCop::RakeTask.new 20 | 21 | Bundler::GemHelper.install_tasks 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting a security issue 2 | 3 | The Prometheus security policy, including how to report vulnerabilities, can be 4 | found here: 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/authentication_proxy.rb: -------------------------------------------------------------------------------- 1 | require 'prometheus/api_client' 2 | 3 | # returns a client, with authentication proxy support 4 | prometheus = Prometheus::ApiClient.client(url: 'https://example.com:443', 5 | credentials: { token: 'TopSecret' }) 6 | 7 | prometheus.query( 8 | query: 'container_cpu_usage_seconds_total{id="/"}', 9 | time: '2017-08-07T06:10:30.781Z', 10 | ) 11 | 12 | # will result in a hash containing the results data struct: 13 | # 14 | # {"resultType"=>"vector", 15 | # "result"=> 16 | # [{"metric"=> 17 | # {"__name__"=>"container_cpu_usage_seconds_total", 18 | # "beta_kubernetes_io_arch"=>"amd64", 19 | # "beta_kubernetes_io_os"=>"linux", 20 | # "cpu"=>"cpu00", 21 | # "id"=>"/", 22 | # "instance"=>"example.com", 23 | # "job"=>"kubernetes-cadvisor", 24 | # "kubernetes_io_hostname"=>"example.com", 25 | # "region"=>"infra", 26 | # "zone"=>"default"}, 27 | # "value"=>[1502089057.125, "51412.007276689"]}, 28 | # {"metric"=> 29 | # {"__name__"=>"container_cpu_usage_seconds_total", 30 | # "beta_kubernetes_io_arch"=>"amd64", 31 | # "beta_kubernetes_io_os"=>"linux", 32 | # "cpu"=>"cpu01", 33 | # "id"=>"/", 34 | # "instance"=>"example.com", 35 | # "job"=>"kubernetes-cadvisor", 36 | # "kubernetes_io_hostname"=>"example.com", 37 | # "region"=>"infra", 38 | # "zone"=>"default"}, 39 | # "value"=>[1502089057.125, "54034.698666487"]}]} 40 | -------------------------------------------------------------------------------- /examples/get_labels.rb: -------------------------------------------------------------------------------- 1 | require 'prometheus/api_client' 2 | 3 | # returns a client 4 | prometheus = Prometheus::ApiClient.client(url: 'http://example.com:8080') 5 | 6 | prometheus.label('job') 7 | 8 | # will result in an array containing the results data struct: 9 | # 10 | # ["kubernetes-apiservers", "kubernetes-cadvisor", "kubernetes-nodes", 11 | # "kubernetes-service-endpoints"] 12 | -------------------------------------------------------------------------------- /examples/get_metrics.rb: -------------------------------------------------------------------------------- 1 | require 'prometheus/api_client' 2 | 3 | # returns a client 4 | prometheus = Prometheus::ApiClient.client(url: 'http://example.com:8080') 5 | 6 | prometheus.query_range( 7 | query: 'container_cpu_usage_seconds_total{id="/"}', 8 | start: '2017-08-07T06:10:30.781Z', 9 | end: '2017-08-07T06:14:30.781Z', 10 | step: '120s', 11 | ) 12 | 13 | # will result in a hash containing the results data struct: 14 | # 15 | # {"resultType"=>"matrix", 16 | # "result"=> 17 | # [{"metric"=> 18 | # {"__name__"=>"container_cpu_usage_seconds_total", 19 | # "beta_kubernetes_io_arch"=>"amd64", 20 | # "beta_kubernetes_io_os"=>"linux", 21 | # "cpu"=>"cpu00", 22 | # "id"=>"/", 23 | # "instance"=>"example.com", 24 | # "job"=>"kubernetes-cadvisor", 25 | # "kubernetes_io_hostname"=>"example.com", 26 | # "region"=>"infra", 27 | # "zone"=>"default"}, 28 | # "values"=>[[1502086230.781, "51264.830099022"], 29 | # [1502086470.781, "51277.367732154"]]}, 30 | # {"metric"=> 31 | # {"__name__"=>"container_cpu_usage_seconds_total", 32 | # "beta_kubernetes_io_arch"=>"amd64", 33 | # "beta_kubernetes_io_os"=>"linux", 34 | # "cpu"=>"cpu01", 35 | # "id"=>"/", 36 | # "instance"=>"example.com", 37 | # "job"=>"kubernetes-cadvisor", 38 | # "kubernetes_io_hostname"=>"example.com", 39 | # "region"=>"infra", 40 | # "zone"=>"default"}, 41 | # "values"=>[[1502086230.781, "53879.644934689"], 42 | # [1502086470.781, "53892.665282065"]]}]} 43 | -------------------------------------------------------------------------------- /examples/low_level.rb: -------------------------------------------------------------------------------- 1 | require 'prometheus/api_client' 2 | 3 | # returns a default client 4 | prometheus = Prometheus::ApiClient.client 5 | 6 | prometheus.get( 7 | 'query_range', 8 | query: 'sum(container_cpu_usage_seconds_total{job="kubernetes-cadvisor"})', 9 | start: '2015-07-01T20:10:30.781Z', 10 | end: '2015-07-02T20:10:30.781Z', 11 | step: '120s', 12 | ) 13 | 14 | # will result in a low level Response object: 15 | # 16 | # Evaluation 52 | # timestamp. Optional. 53 | # @option options [String] :timeout Evaluation timeout. Optional. 54 | # Defaults to and is capped by the value of the -query.timeout flag. 55 | # 56 | # The current server time is used if the time parameter is omitted. 57 | def query(options) 58 | run_command('query', options) 59 | end 60 | 61 | # Evaluates an expression query over a range of time: 62 | # 63 | # @param [Hash] options 64 | # @option options [String] :query Prometheus expression query string. 65 | # @option options [String] :start Start 66 | # timestamp. 67 | # @option options [String] :end End timestamp. 68 | # @option options [String] :step Query resolution step width. 69 | # @option options [String] :timeout Evaluation timeout. Optional. 70 | # Defaults to and is capped by the value of the -query.timeout flag. 71 | # 72 | # The current server time is used if the time parameter is omitted. 73 | def query_range(options) 74 | run_command('query_range', options) 75 | end 76 | 77 | # Returns an overview of the current state of the Prometheus target 78 | # discovery: 79 | # 80 | # @param [Hash] options 81 | # 82 | # No options used. 83 | def targets(options = {}) 84 | run_command('targets', options) 85 | end 86 | 87 | # Returns a list of label values for a provided label name: 88 | # 89 | # @param [String] label Label name 90 | # @param [Hash] options 91 | # 92 | # No options used. 93 | def label(label, options = {}) 94 | run_command("label/#{label}/values", options) 95 | end 96 | 97 | # Issues a get request to the low level client. 98 | def get(command, options) 99 | @client.get(command, options) 100 | end 101 | 102 | # Issues a get request to the low level client, and evalueate the 103 | # response JSON. 104 | def run_command(command, options) 105 | response = get(command, options) 106 | 107 | body = JSON.parse(response.body) 108 | raise RequestError, body['error'] if body['status'] != 'success' 109 | 110 | body['data'] 111 | rescue StandardError => err 112 | raise RequestError, err.message 113 | end 114 | 115 | # Helper function to evalueate the low level proxy option 116 | def faraday_proxy(options) 117 | return options[:proxy] if options[:proxy] 118 | 119 | proxy = options[:options] 120 | proxy[:http_proxy_uri] if proxy[:http_proxy_uri] 121 | end 122 | 123 | # Helper function to evalueate the low level ssl option 124 | def faraday_ssl(options) 125 | return options[:ssl] if options[:ssl] 126 | 127 | ssl = options[:options] 128 | return unless ssl[:verify_ssl] || ssl[:ssl_cert_store] 129 | 130 | { 131 | verify: ssl[:verify_ssl] != OpenSSL::SSL::VERIFY_NONE, 132 | cert_store: ssl[:ssl_cert_store], 133 | } 134 | end 135 | 136 | # Helper function to evalueate the low level headers option 137 | def faraday_headers(options) 138 | return options[:headers] if options[:headers] 139 | 140 | headers = options[:credentials] 141 | return unless headers && headers[:token] 142 | 143 | { 144 | Authorization: 'Bearer ' + headers[:token].to_s, 145 | } 146 | end 147 | 148 | # Helper function to evalueate the low level headers option 149 | def faraday_request(options) 150 | return options[:request] if options[:request] 151 | 152 | request = options[:options] 153 | return unless request[:open_timeout] || request[:timeout] 154 | 155 | { 156 | open_timeout: request[:open_timeout], 157 | timeout: request[:timeout], 158 | } 159 | end 160 | 161 | # Helper function to create the args for the low level client 162 | def faraday_options(options) 163 | { 164 | url: options[:url] + options[:path], 165 | proxy: faraday_proxy(options), 166 | ssl: faraday_ssl(options), 167 | headers: faraday_headers(options), 168 | request: faraday_request(options), 169 | } 170 | end 171 | end 172 | end 173 | end 174 | -------------------------------------------------------------------------------- /lib/prometheus/api_client/version.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | module Prometheus 4 | module ApiClient 5 | VERSION = '0.6.4' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /prometheus-api-client.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $LOAD_PATH.push File.expand_path('../lib', __FILE__) 3 | require 'prometheus/api_client/version' 4 | 5 | Gem::Specification.new do |s| 6 | s.name = 'prometheus-api-client' 7 | s.version = Prometheus::ApiClient::VERSION 8 | s.summary = 'A suite of reading metrics stored on ' \ 9 | 'a Prometheus server.' 10 | s.authors = ['Yaacov Zamir'] 11 | s.email = ['kobi.zamir@gmail.com'] 12 | s.homepage = 'https://github.com/yaacov/prometheus_api_client_ruby' 13 | s.license = 'Apache-2.0' 14 | s.required_ruby_version = '>= 3.0.0' 15 | 16 | s.files = %w(README.md) + Dir.glob('{lib/**/*}') 17 | s.require_paths = ['lib'] 18 | 19 | s.add_dependency 'faraday', '>= 2.0.0', '< 3.0.0' 20 | end 21 | -------------------------------------------------------------------------------- /spec/prometheus/api_client/client_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | require 'prometheus/api_client' 4 | require 'webmock' 5 | require 'vcr' 6 | 7 | VCR.configure do |c| 8 | c.cassette_library_dir = 'spec/vcr_cassettes' 9 | c.hook_into :webmock 10 | end 11 | 12 | describe Prometheus::ApiClient::Client do 13 | token = 'toSecret' 14 | url = 'https://prometheus.example.com:443' 15 | 16 | describe '.label' do 17 | it 'reads labels' do 18 | VCR.use_cassette('prometheus/api_client/client') do # , record: :new_episodes) do 19 | prometheus = Prometheus::ApiClient::Client.new( 20 | url: url, 21 | credentials: { token: token }, 22 | options: { verify_ssl: OpenSSL::SSL::VERIFY_NONE }, 23 | ) 24 | 25 | response = prometheus.label('job') 26 | 27 | expect(response).to be_a(Array) 28 | end 29 | end 30 | end 31 | 32 | describe '.targets' do 33 | it 'reads targets' do 34 | VCR.use_cassette('prometheus/api_client/client') do # , record: :new_episodes) do 35 | prometheus = Prometheus::ApiClient::Client.new( 36 | url: url, 37 | credentials: { token: token }, 38 | options: { verify_ssl: OpenSSL::SSL::VERIFY_NONE }, 39 | ) 40 | 41 | response = prometheus.targets 42 | 43 | expect(response).to be_a(Hash) 44 | end 45 | end 46 | end 47 | 48 | describe '.run_command' do 49 | it 'returns a hash' do 50 | VCR.use_cassette('prometheus/api_client/client') do # , record: :new_episodes) do 51 | prometheus = Prometheus::ApiClient::Client.new( 52 | url: url, 53 | credentials: { token: token }, 54 | options: { verify_ssl: OpenSSL::SSL::VERIFY_NONE }, 55 | ) 56 | 57 | response = prometheus.run_command( 58 | "query_range", 59 | { query: "up", start: "2015-07-01T20:10:30.781Z", end: "2015-07-01T20:11:00.781Z", step: "15s"} 60 | ) 61 | 62 | expect(response).to eq({ "resultType"=>"matrix", "result"=>[], "explanation" => nil }) 63 | end 64 | end 65 | 66 | it 'raises on error' do 67 | VCR.use_cassette('prometheus/api_client/client') do # , record: :new_episodes) do 68 | prometheus = Prometheus::ApiClient::Client.new( 69 | url: url, 70 | credentials: { token: token }, 71 | options: { verify_ssl: OpenSSL::SSL::VERIFY_NONE }, 72 | ) 73 | 74 | expect { prometheus.run_command("query_ranage", { query: "(not a valid command"}) } .to raise_error(Prometheus::ApiClient::Client::RequestError) 75 | end 76 | end 77 | end 78 | end 79 | -------------------------------------------------------------------------------- /spec/prometheus/api_client_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | require 'prometheus/api_client' 4 | 5 | describe Prometheus::ApiClient do 6 | describe '.client' do 7 | it 'returne a client object' do 8 | client = Prometheus::ApiClient.client 9 | 10 | expect(client).to be_a(Prometheus::ApiClient::Client) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | require 'simplecov' 4 | require 'coveralls' 5 | 6 | SimpleCov.formatter = 7 | if ENV['CI'] 8 | Coveralls::SimpleCov::Formatter 9 | else 10 | SimpleCov::Formatter::HTMLFormatter 11 | end 12 | 13 | SimpleCov.start 14 | -------------------------------------------------------------------------------- /spec/vcr_cassettes/prometheus/api_client/client.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: get 5 | uri: https://prometheus.example.com/api/v1/label/job/values 6 | body: 7 | encoding: US-ASCII 8 | string: '' 9 | headers: 10 | Authorization: 11 | - Bearer toSecret 12 | User-Agent: 13 | - Faraday v0.12.2 14 | Accept-Encoding: 15 | - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 16 | Accept: 17 | - "*/*" 18 | response: 19 | status: 20 | code: 200 21 | message: OK 22 | headers: 23 | Access-Control-Allow-Headers: 24 | - Accept, Authorization, Content-Type, Origin 25 | Access-Control-Allow-Methods: 26 | - GET, OPTIONS 27 | Access-Control-Allow-Origin: 28 | - "*" 29 | Access-Control-Expose-Headers: 30 | - Date 31 | Content-Length: 32 | - '125' 33 | Content-Type: 34 | - application/json 35 | Date: 36 | - Tue, 08 Aug 2017 09:24:01 GMT 37 | Set-Cookie: 38 | - bd337c9bdedd23361d6a22bfc4876b73=44e5e3f1c41ffda8509c6f9fbf8b9402; path=/; 39 | HttpOnly; Secure 40 | Cache-Control: 41 | - private 42 | body: 43 | encoding: UTF-8 44 | string: '{"status":"success","data":["kubernetes-apiservers","kubernetes-cadvisor","kubernetes-nodes","kubernetes-service-endpoints"]}' 45 | http_version: 46 | recorded_at: Tue, 08 Aug 2017 09:24:01 GMT 47 | - request: 48 | method: get 49 | uri: https://prometheus.example.com/api/v1/targets 50 | body: 51 | encoding: US-ASCII 52 | string: '' 53 | headers: 54 | Authorization: 55 | - Bearer toSecret 56 | User-Agent: 57 | - Faraday v0.12.2 58 | Accept-Encoding: 59 | - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 60 | Accept: 61 | - "*/*" 62 | response: 63 | status: 64 | code: 200 65 | message: OK 66 | headers: 67 | Access-Control-Allow-Headers: 68 | - Accept, Authorization, Content-Type, Origin 69 | Access-Control-Allow-Methods: 70 | - GET, OPTIONS 71 | Access-Control-Allow-Origin: 72 | - "*" 73 | Access-Control-Expose-Headers: 74 | - Date 75 | Content-Type: 76 | - application/json 77 | Date: 78 | - Tue, 08 Aug 2017 09:24:01 GMT 79 | Transfer-Encoding: 80 | - chunked 81 | Set-Cookie: 82 | - bd337c9bdedd23361d6a22bfc4876b73=44e5e3f1c41ffda8509c6f9fbf8b9402; path=/; 83 | HttpOnly; Secure 84 | Cache-Control: 85 | - private 86 | body: 87 | encoding: UTF-8 88 | string: '{"status":"success","data":{"activeTargets":[{"discoveredLabels":{"__address__":"10.35.19.248:8443","__meta_kubernetes_endpoint_port_name":"https","__meta_kubernetes_endpoint_port_protocol":"TCP","__meta_kubernetes_endpoint_ready":"true","__meta_kubernetes_endpoints_name":"kubernetes","__meta_kubernetes_namespace":"default","__meta_kubernetes_service_label_component":"apiserver","__meta_kubernetes_service_label_provider":"kubernetes","__meta_kubernetes_service_name":"kubernetes","__metrics_path__":"/metrics","__scheme__":"https","job":"kubernetes-apiservers"},"labels":{"instance":"10.35.19.248:8443","job":"kubernetes-apiservers"},"scrapeUrl":"https://10.35.19.248:8443/metrics","lastError":"","lastScrape":"2017-08-08T09:23:40.919424567Z","health":"up"},{"discoveredLabels":{"__address__":"10.35.19.248:10250","__meta_kubernetes_node_address_Hostname":"example.com","__meta_kubernetes_node_address_InternalIP":"10.35.19.248","__meta_kubernetes_node_annotation_volumes_kubernetes_io_controller_managed_attach_detach":"true","__meta_kubernetes_node_label_beta_kubernetes_io_arch":"amd64","__meta_kubernetes_node_label_beta_kubernetes_io_os":"linux","__meta_kubernetes_node_label_kubernetes_io_hostname":"example.com","__meta_kubernetes_node_label_region":"infra","__meta_kubernetes_node_label_zone":"default","__meta_kubernetes_node_name":"example.com","__metrics_path__":"/metrics","__scheme__":"https","instance":"example.com","job":"kubernetes-nodes"},"labels":{"beta_kubernetes_io_arch":"amd64","beta_kubernetes_io_os":"linux","instance":"example.com","job":"kubernetes-nodes","kubernetes_io_hostname":"example.com","region":"infra","zone":"default"},"scrapeUrl":"https://10.35.19.248:10250/metrics","lastError":"","lastScrape":"2017-08-08T09:23:41.832027061Z","health":"up"},{"discoveredLabels":{"__address__":"10.35.19.248:10250","__meta_kubernetes_node_address_Hostname":"example.com","__meta_kubernetes_node_address_InternalIP":"10.35.19.248","__meta_kubernetes_node_annotation_volumes_kubernetes_io_controller_managed_attach_detach":"true","__meta_kubernetes_node_label_beta_kubernetes_io_arch":"amd64","__meta_kubernetes_node_label_beta_kubernetes_io_os":"linux","__meta_kubernetes_node_label_kubernetes_io_hostname":"example.com","__meta_kubernetes_node_label_region":"infra","__meta_kubernetes_node_label_zone":"default","__meta_kubernetes_node_name":"example.com","__metrics_path__":"/metrics/cadvisor","__scheme__":"https","instance":"example.com","job":"kubernetes-cadvisor"},"labels":{"beta_kubernetes_io_arch":"amd64","beta_kubernetes_io_os":"linux","instance":"example.com","job":"kubernetes-cadvisor","kubernetes_io_hostname":"example.com","region":"infra","zone":"default"},"scrapeUrl":"https://10.35.19.248:10250/metrics/cadvisor","lastError":"","lastScrape":"2017-08-08T09:24:00.587199854Z","health":"up"},{"discoveredLabels":{"__address__":"10.35.19.248:443","__meta_kubernetes_endpoint_port_name":"443-tcp","__meta_kubernetes_endpoint_port_protocol":"TCP","__meta_kubernetes_endpoint_ready":"true","__meta_kubernetes_endpoints_name":"router","__meta_kubernetes_namespace":"default","__meta_kubernetes_pod_annotation_kubernetes_io_created_by":"{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"ReplicationController\",\"namespace\":\"default\",\"name\":\"router-1\",\"uid\":\"872bac6a-7299-11e7-8221-001a4a2314d7\",\"apiVersion\":\"v1\",\"resourceVersion\":\"1206\"}}\n","__meta_kubernetes_pod_annotation_openshift_io_deployment_config_latest_version":"1","__meta_kubernetes_pod_annotation_openshift_io_deployment_config_name":"router","__meta_kubernetes_pod_annotation_openshift_io_deployment_name":"router-1","__meta_kubernetes_pod_annotation_openshift_io_scc":"hostnetwork","__meta_kubernetes_pod_container_name":"router","__meta_kubernetes_pod_container_port_name":"","__meta_kubernetes_pod_container_port_number":"443","__meta_kubernetes_pod_container_port_protocol":"TCP","__meta_kubernetes_pod_host_ip":"10.35.19.248","__meta_kubernetes_pod_ip":"10.35.19.248","__meta_kubernetes_pod_label_deployment":"router-1","__meta_kubernetes_pod_label_deploymentconfig":"router","__meta_kubernetes_pod_label_router":"router","__meta_kubernetes_pod_name":"router-1-ct5bh","__meta_kubernetes_pod_node_name":"example.com","__meta_kubernetes_pod_ready":"true","__meta_kubernetes_service_annotation_prometheus_io_port":"1936","__meta_kubernetes_service_annotation_prometheus_io_scrape":"true","__meta_kubernetes_service_annotation_prometheus_openshift_io_password":"5fCg06IOyO","__meta_kubernetes_service_annotation_prometheus_openshift_io_username":"admin","__meta_kubernetes_service_label_router":"router","__meta_kubernetes_service_name":"router","__metrics_path__":"/metrics","__scheme__":"http","job":"kubernetes-service-endpoints"},"labels":{"instance":"10.35.19.248:1936","job":"kubernetes-service-endpoints","kubernetes_name":"router","kubernetes_namespace":"default","router":"router"},"scrapeUrl":"http://10.35.19.248:1936/metrics","lastError":"server 89 | returned HTTP status 403 Forbidden","lastScrape":"2017-08-08T09:23:29.647620005Z","health":"down"},{"discoveredLabels":{"__address__":"10.128.0.7:8443","__meta_kubernetes_endpoint_port_name":"prometheus","__meta_kubernetes_endpoint_port_protocol":"TCP","__meta_kubernetes_endpoint_ready":"true","__meta_kubernetes_endpoints_name":"prometheus","__meta_kubernetes_namespace":"kube-system","__meta_kubernetes_pod_annotation_kubernetes_io_created_by":"{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"ReplicaSet\",\"namespace\":\"kube-system\",\"name\":\"prometheus-1552260379\",\"uid\":\"dada58d9-72aa-11e7-8221-001a4a2314d7\",\"apiVersion\":\"extensions\",\"resourceVersion\":\"3185\"}}\n","__meta_kubernetes_pod_annotation_openshift_io_scc":"restricted","__meta_kubernetes_pod_container_name":"oauth-proxy","__meta_kubernetes_pod_container_port_name":"web","__meta_kubernetes_pod_container_port_number":"8443","__meta_kubernetes_pod_container_port_protocol":"TCP","__meta_kubernetes_pod_host_ip":"10.35.19.248","__meta_kubernetes_pod_ip":"10.128.0.7","__meta_kubernetes_pod_label_app":"prometheus","__meta_kubernetes_pod_label_pod_template_hash":"1552260379","__meta_kubernetes_pod_name":"prometheus-1552260379-fq410","__meta_kubernetes_pod_node_name":"example.com","__meta_kubernetes_pod_ready":"true","__meta_kubernetes_service_annotation_openshift_io_generated_by":"OpenShiftNewApp","__meta_kubernetes_service_annotation_prometheus_io_scheme":"https","__meta_kubernetes_service_annotation_prometheus_io_scrape":"true","__meta_kubernetes_service_annotation_service_alpha_openshift_io_serving_cert_secret_name":"prometheus-tls","__meta_kubernetes_service_annotation_service_alpha_openshift_io_serving_cert_signed_by":"openshift-service-serving-signer@1501138614","__meta_kubernetes_service_label_name":"prometheus","__meta_kubernetes_service_name":"prometheus","__metrics_path__":"/metrics","__scheme__":"http","job":"kubernetes-service-endpoints"},"labels":{"instance":"10.128.0.7:8443","job":"kubernetes-service-endpoints","kubernetes_name":"prometheus","kubernetes_namespace":"kube-system","name":"prometheus"},"scrapeUrl":"https://10.128.0.7:8443/metrics","lastError":"","lastScrape":"2017-08-08T09:23:35.197491923Z","health":"up"}]}}' 90 | http_version: 91 | recorded_at: Tue, 08 Aug 2017 09:24:01 GMT 92 | - request: 93 | method: get 94 | uri: https://prometheus.example.com/api/v1/query_range?end=2015-07-01T20:11:00.781Z&query=up&start=2015-07-01T20:10:30.781Z&step=15s 95 | body: 96 | encoding: US-ASCII 97 | string: '' 98 | headers: 99 | Authorization: 100 | - Bearer toSecret 101 | User-Agent: 102 | - Faraday v0.12.2 103 | Accept-Encoding: 104 | - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 105 | Accept: 106 | - "*/*" 107 | response: 108 | status: 109 | code: 200 110 | message: OK 111 | headers: 112 | Access-Control-Allow-Headers: 113 | - Accept, Authorization, Content-Type, Origin 114 | Access-Control-Allow-Methods: 115 | - GET, OPTIONS 116 | Access-Control-Allow-Origin: 117 | - "*" 118 | Access-Control-Expose-Headers: 119 | - Date 120 | Content-Type: 121 | - application/json 122 | Date: 123 | - Tue, 08 Aug 2017 09:24:01 GMT 124 | Transfer-Encoding: 125 | - chunked 126 | Set-Cookie: 127 | - bd337c9bdedd23361d6a22bfc4876b73=44e5e3f1c41ffda8509c6f9fbf8b9402; path=/; 128 | HttpOnly; Secure 129 | Cache-Control: 130 | - private 131 | body: 132 | encoding: UTF-8 133 | string: '{"status":"success","data":{"resultType":"matrix","result":[],"explanation":null}}' 134 | http_version: 135 | recorded_at: Tue, 08 Aug 2017 09:24:01 GMT 136 | - request: 137 | method: get 138 | uri: https://prometheus.example.com/api/v1/query_ranage?query=(not%20a%20valid%20command 139 | body: 140 | encoding: US-ASCII 141 | string: '' 142 | headers: 143 | Authorization: 144 | - Bearer toSecret 145 | User-Agent: 146 | - Faraday v0.12.2 147 | Accept-Encoding: 148 | - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 149 | Accept: 150 | - "*/*" 151 | response: 152 | status: 153 | code: 200 154 | message: OK 155 | headers: 156 | Access-Control-Allow-Headers: 157 | - Accept, Authorization, Content-Type, Origin 158 | Access-Control-Allow-Methods: 159 | - GET, OPTIONS 160 | Access-Control-Allow-Origin: 161 | - "*" 162 | Access-Control-Expose-Headers: 163 | - Date 164 | Content-Type: 165 | - application/json 166 | Date: 167 | - Tue, 08 Aug 2017 09:24:01 GMT 168 | Transfer-Encoding: 169 | - chunked 170 | Set-Cookie: 171 | - bd337c9bdedd23361d6a22bfc4876b73=44e5e3f1c41ffda8509c6f9fbf8b9402; path=/; 172 | HttpOnly; Secure 173 | Cache-Control: 174 | - private 175 | body: 176 | encoding: UTF-8 177 | string: '{"status": "error", "error": "1:6: parse error: unexpected identifier \"a\""}' 178 | http_version: 179 | recorded_at: Tue, 08 Aug 2017 09:24:01 GMT 180 | recorded_with: VCR 3.0.3 181 | --------------------------------------------------------------------------------