Skip to content

Commit

Permalink
Integrate with existing metrics code (#432)
Browse files Browse the repository at this point in the history
  • Loading branch information
avillela authored Oct 14, 2022
1 parent c9a3018 commit 672387c
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 51 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,8 @@ significant modifications will be credited to OpenTelemetry Authors.
([#339](https://github.com/open-telemetry/opentelemetry-demo/pull/339))
* Added basic metrics support for recommendation service (Python)
([#416](https://github.com/open-telemetry/opentelemetry-demo/pull/416))
* Added metrics auto-instrumentation + minor metrics refactor for recommendation
service (Python)
[#432](https://github.com/open-telemetry/opentelemetry-demo/pull/432)
* Replaced the Jaeger exporter to the OTLP exporter in the OTel Collector
([#435](https://github.com/open-telemetry/opentelemetry-demo/pull/435))
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,8 @@ services:
- RECOMMENDATION_SERVICE_PORT
- PRODUCT_CATALOG_SERVICE_ADDR
- OTEL_PYTHON_LOG_CORRELATION=true
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
# OTEL_EXPORTER_OTLP_METRICS_ENDPOINT # Not working for Python OTLP exporter
- OTEL_TRACES_EXPORTER=otlp
- OTEL_METRICS_EXPORTER=otlp
- OTEL_EXPORTER_OTLP_ENDPOINT
- OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE
- OTEL_SERVICE_NAME=recommendationservice
Expand Down
2 changes: 1 addition & 1 deletion docs/metric_service_features.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ Emoji Legend
| Frontend | JavaScript | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: |
| Payment | JavaScript | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: |
| Product Catalog | Go | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: |
| Recommendation | Python | :construction: | :100: | :construction: | :construction: | :construction: | :construction: |
| Recommendation | Python | :100: | :100: | :construction: | :construction: | :construction: | :construction: |
| Shipping | Rust | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: |
33 changes: 28 additions & 5 deletions docs/services/recommendationservice.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,7 @@ endpoints, resource attributes, and service name are automatically set by the
OpenTelemetry auto instrumentor based on environment variables.

```python
tracer_provider = TracerProvider()
trace.set_tracer_provider(tracer_provider)
tracer_provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
tracer = trace.get_tracer("recommendationservice")
tracer = trace.get_tracer_provider().get_tracer("recommendationservice")
```

### Add attributes to auto-instrumented spans
Expand Down Expand Up @@ -61,7 +58,33 @@ block ends execution. This is done in the `get_product_list` function.

## Metrics

TBD
### Initialize meter provider

The OpenTelemetry SDK is initialized in the `__main__` code block. This code
will create a meter provider. Export
endpoints, resource attributes, and service name are automatically set by the
OpenTelemetry auto instrumentor based on environment variables.

```python
meter = metrics.get_meter_provider().get_meter("recommendationservice")
```

### Custom metrics

The following custom metrics are currently available:

* `app_recommendations_counter`: Cumulative count of # recommended
products per service call

### Auto-instrumented metrics

The following metrics are available through auto-instrumentation, courtesy of
the `opentelemetry-instrumentation-system-metrics`, which is installed as part
of `opentelemetry-bootstrap` on building the recommendationservice Docker image:

* `runtime.cpython.cpu_time`
* `runtime.cpython.memory`
* `runtime.cpython.gc_count`

## Logs

Expand Down
4 changes: 3 additions & 1 deletion src/recommendationservice/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ COPY ./pb/ ./proto/
RUN pip install --upgrade pip
RUN pip install -r ./requirements.txt

RUN opentelemetry-bootstrap -a install

# add files into working directory
RUN python -m pip install grpcio-tools
RUN python -m pip install grpcio-tools==1.48.2
RUN python -m grpc_tools.protoc -I=./proto/ --python_out=./ --grpc_python_out=./ ./proto/demo.proto

EXPOSE ${RECOMMENDATION_SERVICE_PORT}
Expand Down
14 changes: 14 additions & 0 deletions src/recommendationservice/metrics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/python

def init_metrics(meter):

# Recommendations counter
app_recommendations_counter = meter.create_counter(
'app_recommendations_counter', unit='recommendations', description="Counts the total number of given recommendations"
)

rec_svc_metrics = {
"app_recommendations_counter": app_recommendations_counter,
}

return rec_svc_metrics
51 changes: 18 additions & 33 deletions src/recommendationservice/recommendation_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,12 @@
# Python
import os
import random
import time
from concurrent import futures

# Pip
import grpc
from opentelemetry import trace, metrics

# Traces
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import (BatchSpanProcessor)
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

# Metrics
from opentelemetry import metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import (PeriodicExportingMetricReader)
from opentelemetry.exporter.otlp.proto.grpc.metric_exporter import OTLPMetricExporter

# Local
import demo_pb2
Expand All @@ -42,18 +31,23 @@
from grpc_health.v1 import health_pb2_grpc
from logger import getJSONLogger

from metrics import (
init_metrics
)

class RecommendationService(demo_pb2_grpc.RecommendationServiceServicer):
def ListRecommendations(self, request, context):
prod_list = get_product_list(request.product_ids)
span = trace.get_current_span()
span.set_attribute("app.products_recommended.count", len(prod_list))
logger.info("[Recv ListRecommendations] product_ids={}".format(prod_list))
app_recommendations_counter.add(len(prod_list), {'recommendation.type': 'catalog'})

logger.info(f"[Recv ListRecommendations] product_ids={prod_list}")
# build and return response
response = demo_pb2.ListRecommendationsResponse()
response.product_ids.extend(prod_list)

# Collect metrics for this service
rec_svc_metrics["app_recommendations_counter"].add(len(prod_list), {'recommendation.type': 'catalog'})

return response

def Check(self, request, context):
Expand Down Expand Up @@ -88,6 +82,9 @@ def get_product_list(request_product_ids):
indices = random.sample(range(num_products), num_return)
# Fetch product ids from indices
prod_list = [filtered_products[i] for i in indices]

span.set_attribute("app.filtered_products.list", prod_list)

return prod_list


Expand All @@ -98,22 +95,10 @@ def must_map_env(key: str):
return value

if __name__ == "__main__":
# Initialize tracer provider
tracer_provider = TracerProvider()
trace.set_tracer_provider(tracer_provider)
tracer_provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
tracer = trace.get_tracer("recommendationservice")

# Initialize meter provider
metric_reader = PeriodicExportingMetricReader(OTLPMetricExporter())
provider = MeterProvider(metric_readers=[metric_reader])
metrics.set_meter_provider(provider)
meter = metrics.get_meter(__name__)

# Create counters
app_recommendations_counter = meter.create_counter(
'app.recommendations.counter', unit='recommendations', description="Counts the total number of given recommendations"
)
# Initialize Traces and Metrics
tracer = trace.get_tracer_provider().get_tracer("recommendationservice")
meter = metrics.get_meter_provider().get_meter("recommendationservice")
rec_svc_metrics = init_metrics(meter)

port = must_map_env('RECOMMENDATION_SERVICE_PORT')
catalog_addr = must_map_env('PRODUCT_CATALOG_SERVICE_ADDR')
Expand All @@ -131,9 +116,9 @@ def must_map_env(key: str):

# Start logger
logger = getJSONLogger('recommendationservice-server')
logger.info("RecommendationService listening on port: " + port)
logger.info(f"RecommendationService listening on port: {port}")

# Start server
server.add_insecure_port('[::]:' + port)
server.add_insecure_port(f'[::]:{port}')
server.start()
server.wait_for_termination()
13 changes: 4 additions & 9 deletions src/recommendationservice/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
google-api-core==2.4.0
grpcio-health-checking==1.43.0
grpcio==1.43.0
opentelemetry-api==1.13.0
opentelemetry-distro==0.34b0
opentelemetry-exporter-otlp-proto-grpc==1.13.0
opentelemetry-instrumentation==0.34b0
opentelemetry-instrumentation-grpc==0.34b0
opentelemetry-instrumentation-urllib3==0.34b0
opentelemetry-sdk==1.13.0
python-dotenv==0.20.0
python-json-logger==2.0.2
requests==2.27.1
urllib3==1.26.8
python-dotenv==0.21.0
python-json-logger==2.0.4
psutil==5.9.2 # Importing this will also import opentelemetry-instrumentation-system-metrics when running opentelemetry-bootstrap

0 comments on commit 672387c

Please sign in to comment.