Skip to content

Commit

Permalink
docs: Reorganize examples and improve ext packages documentation (#483)
Browse files Browse the repository at this point in the history
This commit moves the text on the readmes of the external packages to their
source code as a docstring. This improves the generated documentation and helps
to consolidate the documentation in a single place.

Also unify the readmes present on each package to include a 1 line description, installation instructions and a link to the online documentation. This small readme will be the one shown on Github and on PyPI.

Also change the examples structure to have the following examples:
- basic meter & tracer
- http integration
- jaeger, prometheus, otcollector{tracer, metrics}
- opentracing shim

Co-authored-by: alrex <alrex.boten@gmail.com>
Co-authored-by: Diego Hurtado <ocelotl@users.noreply.github.com>
  • Loading branch information
3 people authored Mar 24, 2020
1 parent fbfafa4 commit 04a9533
Show file tree
Hide file tree
Showing 62 changed files with 945 additions and 680 deletions.
1 change: 1 addition & 0 deletions docs-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ flask~=1.0
mysql-connector-python ~= 8.0
wrapt >= 1.0.0, < 2.0.0
psycopg2-binary >= 2.7.3.1
prometheus_client >= 0.5.0, < 1.0.0
42 changes: 42 additions & 0 deletions docs/examples/basic_meter/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Basic Meter
===========

These examples show how to use OpenTelemetry to capture and report metrics.

There are three different examples:

* basic_metrics: Shows to how create a metric instrument, how to configure an
exporter and a controller and also how to capture data by using the direct
calling convention.

* calling_conventions: Shows how to use the direct, bound and batch calling conventions.

* observer: Shows how to use the observer instrument.

The source files of these examples are available :scm_web:`here <docs/examples/metrics/>`.

Installation
------------

.. code-block:: sh
pip install opentelemetry-api
pip install opentelemetry-sdk
pip install psutil # needed to get ram and cpu usage in the observer example
Run the Example
---------------

.. code-block:: sh
python <example_name>.py
The output will be shown in the console after few seconds.

Useful links
------------

- OpenTelemetry_
- :doc:`../../api/metrics`

.. _OpenTelemetry: https://github.com/open-telemetry/opentelemetry-python/
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
# limitations under the License.
#
"""
This module serves as an example for a simple application using metrics
This module serves as an example for a simple application using metrics.
It shows:
- How to configure a meter passing a sateful or stateless.
- How to configure an exporter and how to create a controller.
Expand All @@ -27,7 +28,7 @@
from opentelemetry.sdk.metrics.export import ConsoleMetricsExporter
from opentelemetry.sdk.metrics.export.controller import PushController

batcher_mode = "stateful"
stateful = True


def usage(argv):
Expand All @@ -42,6 +43,11 @@ def usage(argv):
print("bad mode specified.")
usage(sys.argv)
sys.exit(1)
stateful = batcher_mode == "stateful"

print(
"Starting example, values will be printed to the console every 5 seconds."
)


# The Meter is responsible for creating and recording metrics. Each meter has a
Expand All @@ -57,7 +63,7 @@ def usage(argv):

# A PushController collects metrics created from meter and exports it via the
# exporter every interval
controller = PushController(meter, exporter, 5)
controller = PushController(meter=meter, exporter=exporter, interval=5)

# Metric instruments allow to capture measurements
requests_counter = meter.create_metric(
Expand All @@ -69,15 +75,6 @@ def usage(argv):
label_keys=("environment",),
)

clicks_counter = meter.create_metric(
name="clicks",
description="number of clicks",
unit="1",
value_type=int,
metric_type=Counter,
label_keys=("environment",),
)

requests_size = meter.create_metric(
name="requests_size",
description="size of requests",
Expand All @@ -94,17 +91,14 @@ def usage(argv):
testing_label_set = meter.get_label_set({"environment": "testing"})

# Update the metric instruments using the direct calling convention
requests_size.record(100, staging_label_set)
requests_counter.add(25, staging_label_set)
requests_size.record(100, staging_label_set)
time.sleep(5)

requests_size.record(5000, staging_label_set)
requests_counter.add(50, staging_label_set)
requests_size.record(5000, staging_label_set)
time.sleep(5)

requests_size.record(2, testing_label_set)
requests_counter.add(35, testing_label_set)
time.sleep(5)

clicks_counter.add(5, staging_label_set)
requests_size.record(2, testing_label_set)
time.sleep(5)
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,23 @@
# limitations under the License.
#
"""
This module serves as an example for a simple application using metrics.
It demonstrates the different ways you can record metrics via the meter.
This example shows how to use the different modes to capture metrics.
It shows the usage of the direct, bound and batch calling conventions.
"""
import time

from opentelemetry import metrics
from opentelemetry.sdk.metrics import Counter, MeterProvider
from opentelemetry.sdk.metrics import Counter, Measure, MeterProvider
from opentelemetry.sdk.metrics.export import ConsoleMetricsExporter
from opentelemetry.sdk.metrics.export.controller import PushController

# Use the meter type provided by the SDK package
metrics.set_meter_provider(MeterProvider())
# Meter is responsible for creating and recording metrics
meter = metrics.get_meter(__name__)
# exporter to export metrics to the console
exporter = ConsoleMetricsExporter()
# controller collects metrics created from meter and exports it via the
# exporter every interval
controller = PushController(meter=meter, exporter=exporter, interval=5)

# Example to show how to record using the meter
counter = meter.create_metric(
requests_counter = meter.create_metric(
name="requests",
description="number of requests",
unit="1",
Expand All @@ -43,7 +38,16 @@
label_keys=("environment",),
)

counter2 = meter.create_metric(
requests_size = meter.create_metric(
name="requests_size",
description="size of requests",
unit="1",
value_type=int,
metric_type=Measure,
label_keys=("environment",),
)

clicks_counter = meter.create_metric(
name="clicks",
description="number of clicks",
unit="1",
Expand All @@ -52,36 +56,27 @@
label_keys=("environment",),
)

# Labelsets are used to identify key-values that are associated with a specific
# metric that you want to record. These are useful for pre-aggregation and can
# be used to store custom dimensions pertaining to a metric

# The meter takes a dictionary of key value pairs
label_set = meter.get_label_set({"environment": "staging"})

# Bound instrument usage
print("Updating using direct calling convention...")
# You can record metrics directly using the metric instrument. You pass in a
# labelset that you would like to record for.
requests_counter.add(25, label_set)
time.sleep(5)

print("Updating using a bound instrument...")
# You can record metrics with bound metric instruments. Bound metric
# instruments are created by passing in a labelset. A bound metric instrument
# is essentially metric data that corresponds to a specific set of labels.
# Therefore, getting a bound metric instrument using the same set of labels
# will yield the same bound metric instrument.
bound_counter = counter.bind(label_set)
for i in range(1000):
bound_counter.add(i)

# You can release the bound instrument we you are done
bound_counter.release()

# Direct metric usage
# You can record metrics directly using the metric instrument. You pass in a
# labelset that you would like to record for.
counter.add(25, label_set)
bound_requests_counter = requests_counter.bind(label_set)
bound_requests_counter.add(100)
time.sleep(5)

# Record batch usage
print("Updating using batch calling convention...")
# You can record metrics in a batch by passing in a labelset and a sequence of
# (metric, value) pairs. The value would be recorded for each metric using the
# specified labelset for each.
meter.record_batch(label_set, [(counter, 50), (counter2, 70)])

time.sleep(10)
meter.record_batch(label_set, ((requests_counter, 50), (clicks_counter, 70)))
time.sleep(5)
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,9 @@

# Configure a stateful batcher
batcher = UngroupedBatcher(stateful=True)

metrics.set_meter_provider(MeterProvider())
meter = metrics.get_meter(__name__)

# Exporter to export metrics to the console
exporter = ConsoleMetricsExporter()

# Configure a push controller
controller = PushController(meter=meter, exporter=exporter, interval=2)


Expand Down Expand Up @@ -69,4 +64,4 @@ def get_ram_usage_callback(observer):
label_keys=(),
)

input("Press a key to finish...\n")
input("Metrics will be printed soon. Press a key to finish...\n")
61 changes: 12 additions & 49 deletions docs/examples/basic_tracer/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,25 @@ Basic Tracer
============

This example shows how to use OpenTelemetry to instrument a Python application - e.g. a batch job.
It supports exporting spans either to the console or to Jaeger_.

The source files required to run this example are available :scm_web:`here <docs/examples/basic_tracer/>`.
The source files of this example are available :scm_web:`here <docs/examples/basic_tracer/>`.

Installation
------------

Run the application
-------------------
.. code-block:: sh
Console
*******
pip install opentelemetry-api
pip install opentelemetry-sdk
* Run the sample
Run the Example
---------------

.. code-block:: sh
$ python tracer.py
python tracer.py
The output will be displayed at the console
The output will be displayed in the console:

::

Expand All @@ -29,48 +30,10 @@ The output will be displayed at the console
Span(name="foo", context=SpanContext(trace_id=0xf906f80f64d57c71ea8da4dfbbd2ddf2, span_id=0x1d5d87441ec2f410, trace_state={}), kind=SpanKind.INTERNAL, parent=None, start_time=2019-11-07T21:26:45.934369Z, end_time=2019-11-07T21:26:45.934580Z)


Jaeger
******

Setup `Jaeger Tracing <https://www.jaegertracing.io/docs/latest/getting-started/#all-in-one>`_.

* Run the sample

.. code-block:: sh
$ pip install opentelemetry-ext-jaeger
$ EXPORTER=jaeger python tracer.py
The traces should be available in the Jaeger UI at `<http://localhost:16686>`_


Collector
*********

* Start Collector

.. code-block:: sh
$ pip install docker-compose
$ cd docker
$ docker-compose up
* Run the sample

.. code-block:: sh
$ pip install opentelemetry-ext-otcollector
$ EXPORTER=collector python tracer.py
Collector is configured to export to Jaeger, follow Jaeger UI instructions to find the traces.

Useful links
------------

- For more information on OpenTelemetry, visit OpenTelemetry_.
- For more information on tracing in Python, visit Jaeger_.
- OpenTelemetry_
- :doc:`../../api/trace`

.. _Jaeger: https://www.jaegertracing.io/
.. _OpenTelemetry: https://github.com/open-telemetry/opentelemetry-python/
26 changes: 4 additions & 22 deletions docs/examples/basic_tracer/tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,17 @@
ConsoleSpanExporter,
)

if os.getenv("EXPORTER") == "jaeger":
from opentelemetry.ext.jaeger import JaegerSpanExporter

print("Using JaegerSpanExporter")
exporter = JaegerSpanExporter(
service_name="basic-service",
agent_host_name="localhost",
agent_port=6831,
)
elif os.getenv("EXPORTER") == "collector":
from opentelemetry.ext.otcollector.trace_exporter import (
CollectorSpanExporter,
)

print("Using CollectorSpanExporter")
exporter = CollectorSpanExporter(
service_name="basic-service", endpoint="localhost:55678"
)
else:
print("Using ConsoleSpanExporter")
exporter = ConsoleSpanExporter()

# The preferred tracer implementation must be set, as the opentelemetry-api
# defines the interface with a no-op implementation.
trace.set_tracer_provider(TracerProvider())

# We tell OpenTelemetry who it is that is creating spans. In this case, we have
# no real name (no setup.py), so we make one up. If we had a version, we would
# also specify it here.
tracer = trace.get_tracer(__name__)

# SpanExporter receives the spans and send them to the target location.
exporter = ConsoleSpanExporter()
span_processor = BatchExportSpanProcessor(exporter)
trace.get_tracer_provider().add_span_processor(span_processor)

Expand Down
Loading

0 comments on commit 04a9533

Please sign in to comment.