diff --git a/.pylintrc b/.pylintrc
index 866f003776..be29414dc3 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -7,7 +7,7 @@ extension-pkg-whitelist=
# Add list of files or directories to be excluded. They should be base names, not
# paths.
-ignore=CVS,gen
+ignore=CVS,gen,Dockerfile,docker-compose.yml,README.md,requirements.txt,cortex-config.yml
# Add files or directories matching the regex patterns to be excluded. The
# regex matches against base names, not paths.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 370b1303c1..a381043d87 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -29,6 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#216](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/216))
- `opentelemetry-instrumentation-grpc` Add tests for grpc span attributes, grpc `abort()` conditions
([#236](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/236))
+- Add README and example app for Prometheus Remote Write Exporter
+ ([#227](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/227]))
### Changed
- `opentelemetry-instrumentation-asgi`, `opentelemetry-instrumentation-wsgi` Return `None` for `CarrierGetter` if key not found
@@ -36,7 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `opentelemetry-instrumentation-grpc` Comply with updated spec, rework tests
([#236](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/236))
- `opentelemetry-instrumentation-asgi`, `opentelemetry-instrumentation-falcon`, `opentelemetry-instrumentation-flask`, `opentelemetry-instrumentation-pyramid`, `opentelemetry-instrumentation-wsgi` Renamed `host.port` attribute to `net.host.port`
- ([#242](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/242))
+ ([#242](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/242))
- `opentelemetry-instrumentation-flask` Do not emit a warning message for request contexts created with `app.test_request_context`
([#253](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/253))
- `opentelemetry-instrumentation-requests`, `opentelemetry-instrumentation-urllib` Fix span name callback parameters
diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/README.rst b/exporter/opentelemetry-exporter-prometheus-remote-write/README.rst
index 575af54fd5..94f4b61686 100644
--- a/exporter/opentelemetry-exporter-prometheus-remote-write/README.rst
+++ b/exporter/opentelemetry-exporter-prometheus-remote-write/README.rst
@@ -1,27 +1,322 @@
OpenTelemetry Prometheus Remote Write Exporter
-==============================================
+=========================================================
-This library allows exporting metric data to `Prometheus Remote Write Integrated Backends
-`_. Latest `types.proto
-` and `remote.proto
-` Protocol Buffers
-used to create WriteRequest objects were taken from Prometheus repository. Development is
-currently in progress.
+This package contains an exporter to send `OTLP`_ metrics from the
+`OpenTelemetry Python SDK`_ directly to a `Prometheus Remote Write integrated backend`_
+(such as Cortex or Thanos) without having to run an instance of the
+Prometheus server. The latest `types.proto`_ and `remote.proto`_
+protocol buffers are used to create the WriteRequest. The image below shows the
+two Prometheus exporters in the OpenTelemetry Python SDK.
+
+Pipeline 1 illustrates the setup required for a `Prometheus "pull" exporter`_.
+
+Pipeline 2 illustrates the setup required for the Prometheus Remote
+Write exporter.
+
+|Prometheus SDK pipelines|
+
+The Prometheus Remote Write Exporter is a "push" based exporter and only
+works with the OpenTelemetry `push controller`_. The controller
+periodically collects data and passes it to the exporter. This exporter
+then converts the data into `timeseries`_ and sends it to the Remote
+Write integrated backend through HTTP POST requests. The metrics
+collection datapath is shown below:
+
+
+See the ``examples`` folder for a demo usage of this exporter
+
+Table of Contents
+=================
+
+- `Summary`_
+- `Table of Contents`_
+
+ - `Installation`_
+ - `Quickstart`_
+ - `Examples`_
+ - `Configuring the Exporter`_
+ - `Securing the Exporter`_
+
+ - `Authentication`_
+ - `TLS`_
+
+ - `Supported Aggregators`_
+ - `Error Handling`_
+ - `Contributing`_
+
+ - `Design Doc`_
Installation
------------
+Prerequisites
+~~~~~~~~~~~~~
+1. Install the snappy c-library
+ **DEB**: ``sudo apt-get install libsnappy-dev``
-::
+ **RPM**: ``sudo yum install libsnappy-devel``
- pip install opentelemetry-exporter-prometheus-remote-write
+ **OSX/Brew**: ``brew install snappy``
+ **Windows**: ``pip install python_snappy-0.5-cp36-cp36m-win_amd64.whl``
-.. _Prometheus: https://prometheus.io/
-.. _OpenTelemetry: https://github.com/open-telemetry/opentelemetry-python/
+Exporter
+~~~~~~~~
+- To install from the latest PyPi release, run
+ ``pip install opentelemetry-exporter-prometheus-remote-write``
-References
+
+Quickstart
----------
-* `Prometheus `_
-* `OpenTelemetry Project `_
+.. code:: python
+
+ from opentelemetry import metrics
+ from opentelemetry.sdk.metrics import MeterProvider
+ from opentelemetry.exporter.prometheus_remote_write import (
+ PrometheusRemoteWriteMetricsExporter
+ )
+
+ # Sets the global MeterProvider instance
+ metrics.set_meter_provider(MeterProvider())
+
+ # The Meter is responsible for creating and recording metrics. Each meter has a unique name, which we set as the module's name here.
+ meter = metrics.get_meter(__name__)
+
+ exporter = PrometheusRemoteWriteMetricsExporter(endpoint="endpoint_here") # add other params as needed
+
+ metrics.get_meter_provider().start_pipeline(meter, exporter, 5)
+
+
+Examples
+--------
+
+This example uses `Docker Compose`_ to set up:
+
+1. A Python program that creates 5 instruments with 5 unique aggregators
+ and a randomized load generator
+2. An instance of `Cortex`_ to recieve the metrics data
+3. An instance of `Grafana`_ to visualizse the exported data
+
+Requirements
+~~~~~~~~~~~~
+
+- Have Docker Compose `installed`_
+
+*Users do not need to install Python as the app will be run in the
+Docker Container*
+
+Instructions
+~~~~~~~~~~~~
+
+1. Run ``docker-compose up -d`` in the the ``examples/`` directory
+
+The ``-d`` flag causes all services to run in detached mode and frees up
+your 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``
+
+2. Log into the Grafana instance at http://localhost:3000
+
+ - login credentials are ``username: admin`` and ``password: admin``
+ - There may be an additional screen on setting a new password. This
+ can be skipped and is optional
+
+3. Navigate to the ``Data Sources`` page
+
+ - Look for a gear icon on the left sidebar and select
+ ``Data Sources``
+
+4. Add a new Prometheus Data Source
+
+ - Use ``http://cortex:9009/api/prom`` as the URL
+ - Set the scrape interval to ``2s`` to make updates
+ appear quickly **(Optional)**
+ - click ``Save & Test``
+
+5. Go to ``Metrics Explore`` to query metrics
+
+ - Look for a compass icon on the left sidebar
+ - click ``Metrics`` for a dropdown list of all the available metrics
+ - Adjust time range by clicking the ``Last 6 hours``
+ button on the upper right side of the graph **(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 **(Optional)**
+ - Click the refresh button and data should show up on hte graph
+
+6. Shutdown the services when finished
+
+ - Run ``docker-compose down`` in the examples directory
+
+Configuring the Exporter
+------------------------
+
+The exporter can be configured through parameters passed to the
+constructor. Here are all the options:
+
+- ``endpoint``: url where data will be sent **(Required)**
+- ``basic_auth``: username and password for authentication
+ **(Optional)**
+- ``headers``: additional headers for remote write request as
+ determined by the remote write backend's API **(Optional)**
+- ``timeout``: timeout for requests to the remote write endpoint in
+ seconds **(Optional)**
+- ``proxies``: dict mapping request proxy protocols to proxy urls
+ **(Optional)**
+- ``tls_config``: configuration for remote write TLS settings
+ **(Optional)**
+
+Example with all the configuration options:
+
+.. code:: python
+
+ exporter = PrometheusRemoteWriteMetricsExporter(
+ endpoint="http://localhost:9009/api/prom/push",
+ timeout=30,
+ basic_auth={
+ "username": "user",
+ "password": "pass123",
+ },
+ headers={
+ "X-Scope-Org-ID": "5",
+ "Authorization": "Bearer mytoken123",
+ },
+ proxies={
+ "http": "http://10.10.1.10:3000",
+ "https": "http://10.10.1.10:1080",
+ },
+ tls_config={
+ "cert_file": "path/to/file",
+ "key_file": "path/to/file",
+ "ca_file": "path_to_file",
+ "insecure_skip_verify": true, # for developing purposes
+ }
+ )
+
+Securing the Exporter
+---------------------
+
+Authentication
+~~~~~~~~~~~~~~
+
+The exporter provides two forms of authentication which are shown below.
+Users can add their own custom authentication by setting the appropriate
+values in the ``headers`` dictionary
+
+1. Basic Authentication Basic authentication sets a HTTP Authorization
+ header containing a base64 encoded username/password pair. See `RFC
+ 7617`_ for more information. This
+
+.. code:: python
+
+ exporter = PrometheusRemoteWriteMetricsExporter(
+ basic_auth={"username": "base64user", "password": "base64pass"}
+ )
+
+2. Bearer Token Authentication This custom configuration can be achieved
+ by passing in a custom ``header`` to the constructor. See `RFC 6750`_
+ for more information.
+
+.. code:: python
+
+ header = {
+ "Authorization": "Bearer mytoken123"
+ }
+
+TLS
+~~~
+
+Users can add TLS to the exporter's HTTP Client by providing certificate
+and key files in the ``tls_config`` parameter.
+
+Supported Aggregators
+---------------------
+Behaviour of these aggregators is outlined in the `OpenTelemetry Specification `_.
+All aggregators are converted into the `timeseries`_ data format. However, method in
+which they are converted `differs `_ from aggregator to aggregator. A
+map of the conversion methods can be found `here `_.
+
++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+
+| **OpenTelemetry Aggregator** | **Equivalent Prometheus Data Type** | **Behaviour** |
++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+
+| Sum | Counter | Metric value can only go up or be reset to 0 |
++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+
+| MinMaxSumCount | Gauge | Metric value can arbitrarily increment or decrement |
++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+
+| Histogram | Histogram | Unlike the Prometheus histogram, the OpenTelemetry Histogram does not provide a sum of all observed values |
++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+
+| LastValue | N/A | Metric only contains the most recently observed value |
++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+
+| ValueObserver | N/A | Similar to MinMaxSumCount but also contains LastValue |
++------------------------------+-------------------------------------+------------------------------------------------------------------------------------------------------------+
+
+
+Error Handling
+--------------
+
+In general, errors are raised by the calling function. The exception is
+for failed requests where any error status code is logged as a warning
+instead.
+
+This is because the exporter does not implement any retry logic as data that
+failed to export will be dropped.
+
+For example, consider a situation where a user increments a Counter
+instrument 5 times and an export happens between each increment. If the
+exports happen like so:
+
+::
+
+ SUCCESS FAIL FAIL SUCCESS SUCCESS
+ 1 2 3 4 5
+
+Then the received data will be:
+
+::
+
+ 1 4 5
+
+Contributing
+------------
+
+If you would like to learn more about the exporter's structure and
+design decisions please view the design document below
+
+Design Doc
+~~~~~~~~~~
+
+`Design Document`_
+
+This document is stored elsewhere as it contains large images which will
+significantly increase the size of this repo.
+
+.. _Summary: #opentelemetry-python-sdk-prometheus-remote-write-exporter
+.. _Table of Contents: #table-of-contents
+.. _Installation: #installation
+.. _Quickstart: #quickstart
+.. _Examples: #examples
+.. _Configuring the Exporter: #configuring-the-exporter
+.. _Securing the Exporter: #securing-the-exporter
+.. _Authentication: #authentication
+.. _TLS: #tls
+.. _Supported Aggregators: #supported-aggregators
+.. _Error Handling: #error-handling
+.. _Contributing: #contributing
+.. _Design Doc: #design-doc
+.. |Prometheus SDK pipelines| image:: https://user-images.githubusercontent.com/20804975/100285430-e320fd80-2f3e-11eb-8217-a562c559153c.png
+.. _RFC 7617: https://tools.ietf.org/html/rfc7617
+.. _RFC 6750: https://tools.ietf.org/html/rfc6750
+.. _Design Document: https://github.com/open-o11y/docs/blob/master/python-prometheus-remote-write/design-doc.md
+.. _OTLP: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/protocol/otlp.md
+.. _OpenTelemetry Python SDK: https://github.com/open-telemetry/opentelemetry-python
+.. _Prometheus "pull" exporter: https://github.com/open-telemetry/opentelemetry-python/tree/master/exporter/opentelemetry-exporter-prometheus
+.. _Prometheus Remote Write integrated backend: https://prometheus.io/docs/operating/integrations/
+.. _types.proto: https://github.com/prometheus/prometheus/blob/master/prompb/types.proto
+.. _remote.proto: https://github.com/prometheus/prometheus/blob/master/prompb/remote.proto
+.. _push controller: https://github.com/open-telemetry/opentelemetry-python/blob/master/opentelemetry-sdk/src/opentelemetry/sdk/metrics/export/controller.py#L22
+.. _timeseries: https://prometheus.io/docs/concepts/data_model/
+.. _Docker Compose: https://docs.docker.com/compose/
+.. _Cortex: https://cortexmetrics.io/
+.. _Grafana: https://grafana.com/
+.. _installed: https://docs.docker.com/compose/install/
diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/examples/Dockerfile b/exporter/opentelemetry-exporter-prometheus-remote-write/examples/Dockerfile
new file mode 100644
index 0000000000..09ce8cc323
--- /dev/null
+++ b/exporter/opentelemetry-exporter-prometheus-remote-write/examples/Dockerfile
@@ -0,0 +1,8 @@
+FROM python:3.7
+WORKDIR /code
+
+COPY . .
+RUN apt-get update -y && apt-get install libsnappy-dev -y
+RUN pip install -e .
+RUN pip install -r ./examples/requirements.txt
+CMD ["python", "./examples/sampleapp.py"]
diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/examples/README.md b/exporter/opentelemetry-exporter-prometheus-remote-write/examples/README.md
new file mode 100644
index 0000000000..91f7ead578
--- /dev/null
+++ b/exporter/opentelemetry-exporter-prometheus-remote-write/examples/README.md
@@ -0,0 +1,42 @@
+# Prometheus Remote Write Exporter Example
+This example uses [Docker Compose](https://docs.docker.com/compose/) to set up:
+
+1. A Python program that creates 5 instruments with 5 unique
+aggregators and a randomized load generator
+2. An instance of [Cortex](https://cortexmetrics.io/) to recieve the metrics
+data
+3. An instance of [Grafana](https://grafana.com/) to visualizse the exported
+data
+
+## Requirements
+* Have Docker Compose [installed](https://docs.docker.com/compose/install/)
+
+*Users do not need to install Python as the app will be run in the Docker Container*
+
+## Instructions
+1. Run `docker-compose up -d` in the the `examples/` directory
+
+The `-d` flag causes all services to run in detached mode and frees up your
+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`
+
+2. Log into the Grafana instance at [http://localhost:3000](http://localhost:3000)
+ * login credentials are `username: admin` and `password: admin`
+ * There may be an additional screen on setting a new password. This can be skipped and is optional
+
+3. Navigate to the `Data Sources` page
+ * Look for a gear icon on the left sidebar and select `Data Sources`
+
+4. Add a new Prometheus Data Source
+ * Use `http://cortex:9009/api/prom` as the URL
+ * (OPTIONAl) set the scrape interval to `2s` to make updates appear quickly
+ * click `Save & Test`
+
+5. Go to `Metrics Explore` to query metrics
+ * Look for a compass icon on the left sidebar
+ * click `Metrics` for a dropdown list of all the available metrics
+ * (OPTIONAL) Adjust time range by clicking the `Last 6 hours` button on the upper right side of the graph
+ * (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
+ * Click the refresh button and data should show up on hte graph
+
+6. Shutdown the services when finished
+ * Run `docker-compose down` in the examples directory
\ No newline at end of file
diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/examples/cortex-config.yml b/exporter/opentelemetry-exporter-prometheus-remote-write/examples/cortex-config.yml
new file mode 100644
index 0000000000..37bd6473d6
--- /dev/null
+++ b/exporter/opentelemetry-exporter-prometheus-remote-write/examples/cortex-config.yml
@@ -0,0 +1,100 @@
+# This Cortex Config is copied from the Cortex Project documentation
+# Source: https://github.com/cortexproject/cortex/blob/master/docs/configuration/single-process-config.yaml
+
+# Configuration for running Cortex in single-process mode.
+# This configuration should not be used in production.
+# It is only for getting started and development.
+
+# Disable the requirement that every request to Cortex has a
+# X-Scope-OrgID header. `fake` will be substituted in instead.
+auth_enabled: false
+
+server:
+ http_listen_port: 9009
+
+ # Configure the server to allow messages up to 100MB.
+ grpc_server_max_recv_msg_size: 104857600
+ grpc_server_max_send_msg_size: 104857600
+ grpc_server_max_concurrent_streams: 1000
+
+distributor:
+ shard_by_all_labels: true
+ pool:
+ health_check_ingesters: true
+
+ingester_client:
+ grpc_client_config:
+ # Configure the client to allow messages up to 100MB.
+ max_recv_msg_size: 104857600
+ max_send_msg_size: 104857600
+ use_gzip_compression: true
+
+ingester:
+ # We want our ingesters to flush chunks at the same time to optimise
+ # deduplication opportunities.
+ spread_flushes: true
+ chunk_age_jitter: 0
+
+ walconfig:
+ wal_enabled: true
+ recover_from_wal: true
+ wal_dir: /tmp/cortex/wal
+
+ lifecycler:
+ # The address to advertise for this ingester. Will be autodiscovered by
+ # looking up address on eth0 or en0; can be specified if this fails.
+ # address: 127.0.0.1
+
+ # We want to start immediately and flush on shutdown.
+ join_after: 0
+ min_ready_duration: 0s
+ final_sleep: 0s
+ num_tokens: 512
+ tokens_file_path: /tmp/cortex/wal/tokens
+
+ # Use an in memory ring store, so we don't need to launch a Consul.
+ ring:
+ kvstore:
+ store: inmemory
+ replication_factor: 1
+
+# Use local storage - BoltDB for the index, and the filesystem
+# for the chunks.
+schema:
+ configs:
+ - from: 2019-07-29
+ store: boltdb
+ object_store: filesystem
+ schema: v10
+ index:
+ prefix: index_
+ period: 1w
+
+storage:
+ boltdb:
+ directory: /tmp/cortex/index
+
+ filesystem:
+ directory: /tmp/cortex/chunks
+
+ delete_store:
+ store: boltdb
+
+purger:
+ object_store_type: filesystem
+
+frontend_worker:
+ # Configure the frontend worker in the querier to match worker count
+ # to max_concurrent on the queriers.
+ match_max_concurrent: true
+
+# Configure the ruler to scan the /tmp/cortex/rules directory for prometheus
+# rules: https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/#recording-rules
+ruler:
+ enable_api: true
+ enable_sharding: false
+ storage:
+ type: local
+ local:
+ directory: /tmp/cortex/rules
+
diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/examples/docker-compose.yml b/exporter/opentelemetry-exporter-prometheus-remote-write/examples/docker-compose.yml
new file mode 100644
index 0000000000..61e6f4981e
--- /dev/null
+++ b/exporter/opentelemetry-exporter-prometheus-remote-write/examples/docker-compose.yml
@@ -0,0 +1,33 @@
+# Copyright The OpenTelemetry Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+version: "3.8"
+
+services:
+ cortex:
+ image: quay.io/cortexproject/cortex:v1.5.0
+ command:
+ - -config.file=./config/cortex-config.yml
+ volumes:
+ - ./cortex-config.yml:/config/cortex-config.yml:ro
+ ports:
+ - 9009:9009
+ grafana:
+ image: grafana/grafana:latest
+ ports:
+ - 3000:3000
+ sample_app:
+ build:
+ context: ../
+ dockerfile: ./examples/Dockerfile
diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/examples/requirements.txt b/exporter/opentelemetry-exporter-prometheus-remote-write/examples/requirements.txt
new file mode 100644
index 0000000000..ee4803d7d0
--- /dev/null
+++ b/exporter/opentelemetry-exporter-prometheus-remote-write/examples/requirements.txt
@@ -0,0 +1,7 @@
+psutil
+protobuf>=3.13.0
+requests>=2.25.0
+python-snappy
+opentelemetry-api
+opentelemetry-sdk
+opentelemetry-proto
diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/examples/sampleapp.py b/exporter/opentelemetry-exporter-prometheus-remote-write/examples/sampleapp.py
new file mode 100644
index 0000000000..69f7a068ea
--- /dev/null
+++ b/exporter/opentelemetry-exporter-prometheus-remote-write/examples/sampleapp.py
@@ -0,0 +1,153 @@
+import logging
+import random
+import sys
+import time
+from logging import INFO
+
+import psutil
+
+from opentelemetry import metrics
+from opentelemetry.exporter.prometheus_remote_write import (
+ PrometheusRemoteWriteMetricsExporter,
+)
+from opentelemetry.sdk.metrics import MeterProvider
+from opentelemetry.sdk.metrics.export.aggregate import (
+ HistogramAggregator,
+ LastValueAggregator,
+ MinMaxSumCountAggregator,
+ SumAggregator,
+)
+from opentelemetry.sdk.metrics.view import View, ViewConfig
+
+logging.basicConfig(stream=sys.stdout, level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+metrics.set_meter_provider(MeterProvider())
+meter = metrics.get_meter(__name__)
+exporter = PrometheusRemoteWriteMetricsExporter(
+ endpoint="http://cortex:9009/api/prom/push",
+ headers={"X-Scope-Org-ID": "5"},
+)
+metrics.get_meter_provider().start_pipeline(meter, exporter, 1)
+testing_labels = {"environment": "testing"}
+
+
+# Callback to gather cpu usage
+def get_cpu_usage_callback(observer):
+ for (number, percent) in enumerate(psutil.cpu_percent(percpu=True)):
+ labels = {"cpu_number": str(number)}
+ observer.observe(percent, labels)
+
+
+# Callback to gather RAM usage
+def get_ram_usage_callback(observer):
+ ram_percent = psutil.virtual_memory().percent
+ observer.observe(ram_percent, {})
+
+
+requests_counter = meter.create_counter(
+ name="requests",
+ description="number of requests",
+ unit="1",
+ value_type=int,
+)
+
+request_min_max = meter.create_counter(
+ name="requests_min_max",
+ description="min max sum count of requests",
+ unit="1",
+ value_type=int,
+)
+
+request_last_value = meter.create_counter(
+ name="requests_last_value",
+ description="last value number of requests",
+ unit="1",
+ value_type=int,
+)
+
+requests_size = meter.create_valuerecorder(
+ name="requests_size",
+ description="size of requests",
+ unit="1",
+ value_type=int,
+)
+
+requests_size_histogram = meter.create_valuerecorder(
+ name="requests_size_histogram",
+ description="histogram of request_size",
+ unit="1",
+ value_type=int,
+)
+requests_active = meter.create_updowncounter(
+ name="requests_active",
+ description="number of active requests",
+ unit="1",
+ value_type=int,
+)
+
+meter.register_sumobserver(
+ callback=get_ram_usage_callback,
+ name="ram_usage",
+ description="ram usage",
+ unit="1",
+ value_type=float,
+)
+
+meter.register_valueobserver(
+ callback=get_cpu_usage_callback,
+ name="cpu_percent",
+ description="per-cpu usage",
+ unit="1",
+ value_type=float,
+)
+
+
+counter_view1 = View(
+ requests_counter,
+ SumAggregator,
+ label_keys=["environment"],
+ view_config=ViewConfig.LABEL_KEYS,
+)
+counter_view2 = View(
+ request_min_max,
+ MinMaxSumCountAggregator,
+ label_keys=["os_type"],
+ view_config=ViewConfig.LABEL_KEYS,
+)
+
+counter_view3 = View(
+ request_last_value,
+ LastValueAggregator,
+ label_keys=["environment"],
+ view_config=ViewConfig.UNGROUPED,
+)
+size_view = View(
+ requests_size_histogram,
+ HistogramAggregator,
+ label_keys=["environment"],
+ aggregator_config={"bounds": [20, 40, 60, 80, 100]},
+ view_config=ViewConfig.UNGROUPED,
+)
+meter.register_view(counter_view1)
+meter.register_view(counter_view2)
+meter.register_view(counter_view3)
+meter.register_view(size_view)
+
+# Load generator
+num = random.randint(0, 1000)
+while True:
+ # counters
+ requests_counter.add(num % 131 + 200, testing_labels)
+ request_min_max.add(num % 181 + 200, testing_labels)
+ request_last_value.add(num % 101 + 200, testing_labels)
+
+ # updown counter
+ requests_active.add(num % 7231 + 200, testing_labels)
+
+ # value observers
+ requests_size.record(num % 6101 + 100, testing_labels)
+ requests_size_histogram.record(num % 113, testing_labels)
+ logger.log(level=INFO, msg="completed metrics collection cycle")
+ time.sleep(1)
+ num += 9791
diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/setup.cfg b/exporter/opentelemetry-exporter-prometheus-remote-write/setup.cfg
index 0908b8827f..ab54a42afe 100644
--- a/exporter/opentelemetry-exporter-prometheus-remote-write/setup.cfg
+++ b/exporter/opentelemetry-exporter-prometheus-remote-write/setup.cfg
@@ -43,7 +43,7 @@ install_requires =
requests == 2.25.0
opentelemetry-api == 0.17.dev0
opentelemetry-sdk == 0.17.dev0
-
+ python-snappy >= 0.5.4
[options.packages.find]
where = src
diff --git a/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/__init__.py b/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/__init__.py
index be1292f764..4a09bf3e9f 100644
--- a/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/__init__.py
+++ b/exporter/opentelemetry-exporter-prometheus-remote-write/src/opentelemetry/exporter/prometheus_remote_write/__init__.py
@@ -17,8 +17,8 @@
from typing import Dict, Sequence
import requests
-
import snappy
+
from opentelemetry.exporter.prometheus_remote_write.gen.remote_pb2 import (
WriteRequest,
)
diff --git a/tox.ini b/tox.ini
index 6ceb4a8c2c..9265b68a09 100644
--- a/tox.ini
+++ b/tox.ini
@@ -296,6 +296,8 @@ deps =
httpretty
commands_pre =
+ sudo apt-get install libsnappy-dev
+ pip install python-snappy
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-api
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-instrumentation
python -m pip install {toxinidir}/opentelemetry-python-core/opentelemetry-sdk
@@ -356,6 +358,8 @@ changedir =
tests/opentelemetry-docker-tests/tests
commands_pre =
+ sudo apt-get install libsnappy-dev
+ pip install python-snappy
pip install -e {toxinidir}/opentelemetry-python-core/opentelemetry-api \
-e {toxinidir}/opentelemetry-python-core/opentelemetry-instrumentation \
-e {toxinidir}/opentelemetry-python-core/opentelemetry-sdk \
@@ -373,8 +377,6 @@ commands_pre =
-e {toxinidir}/instrumentation/opentelemetry-instrumentation-system-metrics \
-e {toxinidir}/opentelemetry-python-core/exporter/opentelemetry-exporter-opencensus \
-e {toxinidir}/exporter/opentelemetry-exporter-prometheus-remote-write
- sudo apt-get install libsnappy-dev
- pip install python-snappy
docker-compose up -d
python check_availability.py
commands =