|
1 | 1 | OpenTelemetry Prometheus Remote Write Exporter
|
2 |
| -============================================== |
| 2 | +========================================================= |
3 | 3 |
|
4 |
| -This library allows exporting metric data to `Prometheus Remote Write Integrated Backends |
5 |
| -<https://prometheus.io/docs/operating/integrations/>`_. Latest `types.proto |
6 |
| -<https://github.com/prometheus/prometheus/blob/master/prompb/types.proto>` and `remote.proto |
7 |
| -<https://github.com/prometheus/prometheus/blob/master/prompb/remote.proto>` Protocol Buffers |
8 |
| -used to create WriteRequest objects were taken from Prometheus repository. Development is |
9 |
| -currently in progress. |
| 4 | +This package contains an exporter to send `OTLP`_ metrics from the |
| 5 | +`OpenTelemetry Python SDK`_ directly to a `Prometheus Remote Write integrated backend`_ |
| 6 | +(such as Cortex or Thanos) without having to run an instance of the |
| 7 | +Prometheus server. The latest `types.proto`_ and `remote.proto`_ |
| 8 | +protocol buffers are used to create the WriteRequest. The image below shows the |
| 9 | +two Prometheus exporters in the OpenTelemetry Python SDK. |
| 10 | + |
| 11 | +Pipeline 1 illustrates the setup required for a `Prometheus "pull" exporter`_. |
| 12 | + |
| 13 | +Pipeline 2 illustrates the setup required for the Prometheus Remote |
| 14 | +Write exporter. |
| 15 | + |
| 16 | +|Prometheus SDK pipelines| |
| 17 | + |
| 18 | +The Prometheus Remote Write Exporter is a "push" based exporter and only |
| 19 | +works with the OpenTelemetry `push controller`_. The controller |
| 20 | +periodically collects data and passes it to the exporter. This exporter |
| 21 | +then converts the data into `timeseries`_ and sends it to the Remote |
| 22 | +Write integrated backend through HTTP POST requests. The metrics |
| 23 | +collection datapath is shown below: |
| 24 | + |
| 25 | + |
| 26 | +See the ``examples`` folder for a demo usage of this exporter |
| 27 | + |
| 28 | +Table of Contents |
| 29 | +================= |
| 30 | + |
| 31 | +- `Summary`_ |
| 32 | +- `Table of Contents`_ |
| 33 | + |
| 34 | + - `Installation`_ |
| 35 | + - `Quickstart`_ |
| 36 | + - `Examples`_ |
| 37 | + - `Configuring the Exporter`_ |
| 38 | + - `Securing the Exporter`_ |
| 39 | + |
| 40 | + - `Authentication`_ |
| 41 | + - `TLS`_ |
| 42 | + |
| 43 | + - `Supported Aggregators`_ |
| 44 | + - `Error Handling`_ |
| 45 | + - `Contributing`_ |
| 46 | + |
| 47 | + - `Design Doc`_ |
10 | 48 |
|
11 | 49 | Installation
|
12 | 50 | ------------
|
| 51 | +Prerequisites |
| 52 | +~~~~~~~~~~~~~ |
| 53 | +1. Install the snappy c-library |
| 54 | + **DEB**: ``sudo apt-get install libsnappy-dev`` |
13 | 55 |
|
14 |
| -:: |
| 56 | + **RPM**: ``sudo yum install libsnappy-devel`` |
15 | 57 |
|
16 |
| - pip install opentelemetry-exporter-prometheus-remote-write |
| 58 | + **OSX/Brew**: ``brew install snappy`` |
17 | 59 |
|
| 60 | + **Windows**: ``pip install python_snappy-0.5-cp36-cp36m-win_amd64.whl`` |
18 | 61 |
|
19 |
| -.. _Prometheus: https://prometheus.io/ |
20 |
| -.. _OpenTelemetry: https://github.com/open-telemetry/opentelemetry-python/ |
| 62 | +Exporter |
| 63 | +~~~~~~~~ |
21 | 64 |
|
| 65 | +- To install from the latest PyPi release, run |
| 66 | + ``pip install opentelemetry-exporter-prometheus-remote-write`` |
22 | 67 |
|
23 |
| -References |
| 68 | + |
| 69 | +Quickstart |
24 | 70 | ----------
|
25 | 71 |
|
26 |
| -* `Prometheus <https://prometheus.io/>`_ |
27 |
| -* `OpenTelemetry Project <https://opentelemetry.io/>`_ |
| 72 | +.. code:: python |
| 73 | +
|
| 74 | + from opentelemetry import metrics |
| 75 | + from opentelemetry.sdk.metrics import MeterProvider |
| 76 | + from opentelemetry.exporter.prometheus_remote_write import ( |
| 77 | + PrometheusRemoteWriteMetricsExporter |
| 78 | + ) |
| 79 | +
|
| 80 | + # Sets the global MeterProvider instance |
| 81 | + metrics.set_meter_provider(MeterProvider()) |
| 82 | +
|
| 83 | + # The Meter is responsible for creating and recording metrics. Each meter has a unique name, which we set as the module's name here. |
| 84 | + meter = metrics.get_meter(__name__) |
| 85 | +
|
| 86 | + exporter = PrometheusRemoteWriteMetricsExporter(endpoint="endpoint_here") # add other params as needed |
| 87 | +
|
| 88 | + metrics.get_meter_provider().start_pipeline(meter, exporter, 5) |
| 89 | +
|
| 90 | +
|
| 91 | +Examples |
| 92 | +-------- |
| 93 | + |
| 94 | +This example uses `Docker Compose`_ to set up: |
| 95 | + |
| 96 | +1. A Python program that creates 5 instruments with 5 unique aggregators |
| 97 | + and a randomized load generator |
| 98 | +2. An instance of `Cortex`_ to recieve the metrics data |
| 99 | +3. An instance of `Grafana`_ to visualizse the exported data |
| 100 | + |
| 101 | +Requirements |
| 102 | +~~~~~~~~~~~~ |
| 103 | + |
| 104 | +- Have Docker Compose `installed`_ |
| 105 | + |
| 106 | +*Users do not need to install Python as the app will be run in the |
| 107 | +Docker Container* |
| 108 | + |
| 109 | +Instructions |
| 110 | +~~~~~~~~~~~~ |
| 111 | + |
| 112 | +1. Run ``docker-compose up -d`` in the the ``examples/`` directory |
| 113 | + |
| 114 | +The ``-d`` flag causes all services to run in detached mode and frees up |
| 115 | +your terminal session. This also causes no logs to show up. Users can |
| 116 | +attach themselves to the service’s logs manually using |
| 117 | +``docker logs ${CONTAINER_ID} --follow`` |
| 118 | + |
| 119 | +2. Log into the Grafana instance at http://localhost:3000 |
| 120 | + |
| 121 | + - login credentials are ``username: admin`` and ``password: admin`` |
| 122 | + - There may be an additional screen on setting a new password. This |
| 123 | + can be skipped and is optional |
| 124 | + |
| 125 | +3. Navigate to the ``Data Sources`` page |
| 126 | + |
| 127 | + - Look for a gear icon on the left sidebar and select |
| 128 | + ``Data Sources`` |
| 129 | + |
| 130 | +4. Add a new Prometheus Data Source |
| 131 | + |
| 132 | + - Use ``http://cortex:9009/api/prom`` as the URL |
| 133 | + - Set the scrape interval to ``2s`` to make updates |
| 134 | + appear quickly **(Optional)** |
| 135 | + - click ``Save & Test`` |
| 136 | + |
| 137 | +5. Go to ``Metrics Explore`` to query metrics |
| 138 | + |
| 139 | + - Look for a compass icon on the left sidebar |
| 140 | + - click ``Metrics`` for a dropdown list of all the available metrics |
| 141 | + - Adjust time range by clicking the ``Last 6 hours`` |
| 142 | + button on the upper right side of the graph **(Optional)** |
| 143 | + - Set up auto-refresh by selecting an option under the |
| 144 | + dropdown next to the refresh button on the upper right side of the |
| 145 | + graph **(Optional)** |
| 146 | + - Click the refresh button and data should show up on hte graph |
| 147 | + |
| 148 | +6. Shutdown the services when finished |
| 149 | + |
| 150 | + - Run ``docker-compose down`` in the examples directory |
| 151 | + |
| 152 | +Configuring the Exporter |
| 153 | +------------------------ |
| 154 | + |
| 155 | +The exporter can be configured through parameters passed to the |
| 156 | +constructor. Here are all the options: |
| 157 | + |
| 158 | +- ``endpoint``: url where data will be sent **(Required)** |
| 159 | +- ``basic_auth``: username and password for authentication |
| 160 | + **(Optional)** |
| 161 | +- ``headers``: additional headers for remote write request as |
| 162 | + determined by the remote write backend's API **(Optional)** |
| 163 | +- ``timeout``: timeout for requests to the remote write endpoint in |
| 164 | + seconds **(Optional)** |
| 165 | +- ``proxies``: dict mapping request proxy protocols to proxy urls |
| 166 | + **(Optional)** |
| 167 | +- ``tls_config``: configuration for remote write TLS settings |
| 168 | + **(Optional)** |
| 169 | + |
| 170 | +Example with all the configuration options: |
| 171 | + |
| 172 | +.. code:: python |
| 173 | +
|
| 174 | + exporter = PrometheusRemoteWriteMetricsExporter( |
| 175 | + endpoint="http://localhost:9009/api/prom/push", |
| 176 | + timeout=30, |
| 177 | + basic_auth={ |
| 178 | + "username": "user", |
| 179 | + "password": "pass123", |
| 180 | + }, |
| 181 | + headers={ |
| 182 | + "X-Scope-Org-ID": "5", |
| 183 | + "Authorization": "Bearer mytoken123", |
| 184 | + }, |
| 185 | + proxies={ |
| 186 | + "http": "http://10.10.1.10:3000", |
| 187 | + "https": "http://10.10.1.10:1080", |
| 188 | + }, |
| 189 | + tls_config={ |
| 190 | + "cert_file": "path/to/file", |
| 191 | + "key_file": "path/to/file", |
| 192 | + "ca_file": "path_to_file", |
| 193 | + "insecure_skip_verify": true, # for developing purposes |
| 194 | + } |
| 195 | + ) |
| 196 | +
|
| 197 | +Securing the Exporter |
| 198 | +--------------------- |
| 199 | + |
| 200 | +Authentication |
| 201 | +~~~~~~~~~~~~~~ |
| 202 | + |
| 203 | +The exporter provides two forms of authentication which are shown below. |
| 204 | +Users can add their own custom authentication by setting the appropriate |
| 205 | +values in the ``headers`` dictionary |
| 206 | + |
| 207 | +1. Basic Authentication Basic authentication sets a HTTP Authorization |
| 208 | + header containing a base64 encoded username/password pair. See `RFC |
| 209 | + 7617`_ for more information. This |
| 210 | + |
| 211 | +.. code:: python |
| 212 | +
|
| 213 | + exporter = PrometheusRemoteWriteMetricsExporter( |
| 214 | + basic_auth={"username": "base64user", "password": "base64pass"} |
| 215 | + ) |
| 216 | +
|
| 217 | +2. Bearer Token Authentication This custom configuration can be achieved |
| 218 | + by passing in a custom ``header`` to the constructor. See `RFC 6750`_ |
| 219 | + for more information. |
| 220 | + |
| 221 | +.. code:: python |
| 222 | +
|
| 223 | + header = { |
| 224 | + "Authorization": "Bearer mytoken123" |
| 225 | + } |
| 226 | +
|
| 227 | +TLS |
| 228 | +~~~ |
| 229 | + |
| 230 | +Users can add TLS to the exporter's HTTP Client by providing certificate |
| 231 | +and key files in the ``tls_config`` parameter. |
| 232 | + |
| 233 | +Supported Aggregators |
| 234 | +--------------------- |
| 235 | +Behaviour of these aggregators is outlined in the `OpenTelemetry Specification <https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/metrics/api.md#aggregations>`_. |
| 236 | +All aggregators are converted into the `timeseries`_ data format. However, method in |
| 237 | +which they are converted `differs <https://github.com/open-telemetry/opentelemetry-python-contrib/blob/master/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/__init__.py#L196>`_ from aggregator to aggregator. A |
| 238 | +map of the conversion methods can be found `here <https://github.com/open-telemetry/opentelemetry-python-contrib/blob/master/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/__init__.py#L75>`_. |
| 239 | + |
| 240 | ++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+ |
| 241 | +| **OpenTelemetry Aggregator** | **Equivalent Prometheus Data Type** | **Behaviour** | |
| 242 | ++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+ |
| 243 | +| Sum | Counter | Metric value can only go up or be reset to 0 | |
| 244 | ++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+ |
| 245 | +| MinMaxSumCount | Gauge | Metric value can arbitrarily increment or decrement | |
| 246 | ++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+ |
| 247 | +| Histogram | Histogram | Unlike the Prometheus histogram, the OpenTelemetry Histogram does not provide a sum of all observed values | |
| 248 | ++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+ |
| 249 | +| LastValue | N/A | Metric only contains the most recently observed value | |
| 250 | ++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+ |
| 251 | +| ValueObserver | N/A | Similar to MinMaxSumCount but also contains LastValue | |
| 252 | ++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+ |
| 253 | + |
| 254 | + |
| 255 | +Error Handling |
| 256 | +-------------- |
| 257 | + |
| 258 | +In general, errors are raised by the calling function. The exception is |
| 259 | +for failed requests where any error status code is logged as a warning |
| 260 | +instead. |
| 261 | + |
| 262 | +This is because the exporter does not implement any retry logic as data that |
| 263 | +failed to export will be dropped. |
| 264 | + |
| 265 | +For example, consider a situation where a user increments a Counter |
| 266 | +instrument 5 times and an export happens between each increment. If the |
| 267 | +exports happen like so: |
| 268 | + |
| 269 | +:: |
| 270 | + |
| 271 | + SUCCESS FAIL FAIL SUCCESS SUCCESS |
| 272 | + 1 2 3 4 5 |
| 273 | + |
| 274 | +Then the received data will be: |
| 275 | + |
| 276 | +:: |
| 277 | + |
| 278 | + 1 4 5 |
| 279 | + |
| 280 | +Contributing |
| 281 | +------------ |
| 282 | + |
| 283 | +If you would like to learn more about the exporter's structure and |
| 284 | +design decisions please view the design document below |
| 285 | + |
| 286 | +Design Doc |
| 287 | +~~~~~~~~~~ |
| 288 | + |
| 289 | +`Design Document`_ |
| 290 | + |
| 291 | +This document is stored elsewhere as it contains large images which will |
| 292 | +significantly increase the size of this repo. |
| 293 | + |
| 294 | +.. _Summary: #opentelemetry-python-sdk-prometheus-remote-write-exporter |
| 295 | +.. _Table of Contents: #table-of-contents |
| 296 | +.. _Installation: #installation |
| 297 | +.. _Quickstart: #quickstart |
| 298 | +.. _Examples: #examples |
| 299 | +.. _Configuring the Exporter: #configuring-the-exporter |
| 300 | +.. _Securing the Exporter: #securing-the-exporter |
| 301 | +.. _Authentication: #authentication |
| 302 | +.. _TLS: #tls |
| 303 | +.. _Supported Aggregators: #supported-aggregators |
| 304 | +.. _Error Handling: #error-handling |
| 305 | +.. _Contributing: #contributing |
| 306 | +.. _Design Doc: #design-doc |
| 307 | +.. |Prometheus SDK pipelines| image:: https://user-images.githubusercontent.com/20804975/100285430-e320fd80-2f3e-11eb-8217-a562c559153c.png |
| 308 | +.. _RFC 7617: https://tools.ietf.org/html/rfc7617 |
| 309 | +.. _RFC 6750: https://tools.ietf.org/html/rfc6750 |
| 310 | +.. _Design Document: https://github.com/open-o11y/docs/blob/master/python-prometheus-remote-write/design-doc.md |
| 311 | +.. _OTLP: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/protocol/otlp.md |
| 312 | +.. _OpenTelemetry Python SDK: https://github.com/open-telemetry/opentelemetry-python |
| 313 | +.. _Prometheus "pull" exporter: https://github.com/open-telemetry/opentelemetry-python/tree/master/exporter/opentelemetry-exporter-prometheus |
| 314 | +.. _Prometheus Remote Write integrated backend: https://prometheus.io/docs/operating/integrations/ |
| 315 | +.. _types.proto: https://github.com/prometheus/prometheus/blob/master/prompb/types.proto |
| 316 | +.. _remote.proto: https://github.com/prometheus/prometheus/blob/master/prompb/remote.proto |
| 317 | +.. _push controller: https://github.com/open-telemetry/opentelemetry-python/blob/master/opentelemetry-sdk/src/opentelemetry/sdk/metrics/export/controller.py#L22 |
| 318 | +.. _timeseries: https://prometheus.io/docs/concepts/data_model/ |
| 319 | +.. _Docker Compose: https://docs.docker.com/compose/ |
| 320 | +.. _Cortex: https://cortexmetrics.io/ |
| 321 | +.. _Grafana: https://grafana.com/ |
| 322 | +.. _installed: https://docs.docker.com/compose/install/ |
0 commit comments