Skip to content

Commit 30ecfab

Browse files
committed
Proto & Tox updates
- add Tox commands to setup & test the exporter - add the Prometheus Remote Write Proto files & update them. - added a mini-script that wraps the protoc command to regen. them
1 parent fc98f08 commit 30ecfab

File tree

21 files changed

+2146
-0
lines changed

21 files changed

+2146
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
OpenTelemetry Prometheus Remote Write Exporter
2+
=========================================================
3+
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`_
48+
49+
Installation
50+
------------
51+
Prerequisites
52+
~~~~~~~~~~~~~
53+
1. Install the snappy c-library
54+
**DEB**: ``sudo apt-get install libsnappy-dev``
55+
56+
**RPM**: ``sudo yum install libsnappy-devel``
57+
58+
**OSX/Brew**: ``brew install snappy``
59+
60+
**Windows**: ``pip install python_snappy-0.5-cp36-cp36m-win_amd64.whl``
61+
62+
Exporter
63+
~~~~~~~~
64+
65+
- To install from the latest PyPi release, run
66+
``pip install opentelemetry-exporter-prometheus-remote-write``
67+
68+
69+
Quickstart
70+
----------
71+
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/main/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/main/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/main/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/main/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/main/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/main/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/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM python:3.7
2+
WORKDIR /code
3+
4+
COPY . .
5+
RUN apt-get update -y && apt-get install libsnappy-dev -y
6+
RUN pip install -e .
7+
RUN pip install -r ./examples/requirements.txt
8+
CMD ["python", "./examples/sampleapp.py"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Prometheus Remote Write Exporter Example
2+
This example uses [Docker Compose](https://docs.docker.com/compose/) to set up:
3+
4+
1. A Python program that creates 5 instruments with 5 unique
5+
aggregators and a randomized load generator
6+
2. An instance of [Cortex](https://cortexmetrics.io/) to recieve the metrics
7+
data
8+
3. An instance of [Grafana](https://grafana.com/) to visualizse the exported
9+
data
10+
11+
## Requirements
12+
* Have Docker Compose [installed](https://docs.docker.com/compose/install/)
13+
14+
*Users do not need to install Python as the app will be run in the Docker Container*
15+
16+
## Instructions
17+
1. Run `docker-compose up -d` in the the `examples/` directory
18+
19+
The `-d` flag causes all services to run in detached mode and frees up your
20+
terminal session. This also causes no logs to show up. Users can attach themselves to the service's logs manually using `docker logs ${CONTAINER_ID} --follow`
21+
22+
2. Log into the Grafana instance at [http://localhost:3000](http://localhost:3000)
23+
* login credentials are `username: admin` and `password: admin`
24+
* There may be an additional screen on setting a new password. This can be skipped and is optional
25+
26+
3. Navigate to the `Data Sources` page
27+
* Look for a gear icon on the left sidebar and select `Data Sources`
28+
29+
4. Add a new Prometheus Data Source
30+
* Use `http://cortex:9009/api/prom` as the URL
31+
* (OPTIONAl) set the scrape interval to `2s` to make updates appear quickly
32+
* click `Save & Test`
33+
34+
5. Go to `Metrics Explore` to query metrics
35+
* Look for a compass icon on the left sidebar
36+
* click `Metrics` for a dropdown list of all the available metrics
37+
* (OPTIONAL) Adjust time range by clicking the `Last 6 hours` button on the upper right side of the graph
38+
* (OPTIONAL) Set up auto-refresh by selecting an option under the dropdown next to the refresh button on the upper right side of the graph
39+
* Click the refresh button and data should show up on hte graph
40+
41+
6. Shutdown the services when finished
42+
* Run `docker-compose down` in the examples directory

0 commit comments

Comments
 (0)