From 813df954cd0bdc4f3d6b0ab45956e93e7292ab64 Mon Sep 17 00:00:00 2001 From: Mikko Viitanen Date: Sat, 8 Oct 2022 16:02:00 +0300 Subject: [PATCH 1/2] Adding basic metrics support for recommendation service (Python) - First part of metrics support, manual metrics creation for recommendation service (Python) - Bump versions for opentelemetry api, sdk, exporter, and instrumentation libraries (to enable metrics). --- CHANGELOG.md | 2 ++ docker-compose.yml | 3 ++ docs/metric_service_features.md | 2 +- .../recommendation_server.py | 32 ++++++++++++++++--- src/recommendationservice/requirements.txt | 12 +++---- 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44ecb6bb4a..9a15bd76b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -111,3 +111,5 @@ significant modifications will be credited to OpenTelemetry Authors. ([#409](https://github.com/open-telemetry/opentelemetry-demo/pull/409)) * Added hero scenario metric to Checkout Service on cache leak ([#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)) diff --git a/docker-compose.yml b/docker-compose.yml index 3f233f2256..141cf1883e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -329,6 +329,9 @@ services: - 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_EXPORTER_OTLP_ENDPOINT + - OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE - OTEL_SERVICE_NAME=recommendationservice - PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python logging: *logging diff --git a/docs/metric_service_features.md b/docs/metric_service_features.md index 3b3946c012..887d9af6a7 100644 --- a/docs/metric_service_features.md +++ b/docs/metric_service_features.md @@ -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: | :construction: | :construction: | :construction: | :construction: | :construction: | +| Recommendation | Python | :construction: | :100: | :construction: | :construction: | :construction: | :construction: | | Shipping | Rust | :construction: | :construction: | :construction: | :construction: | :construction: | :construction: | diff --git a/src/recommendationservice/recommendation_server.py b/src/recommendationservice/recommendation_server.py index efef9b3ae9..21ecf57ce9 100644 --- a/src/recommendationservice/recommendation_server.py +++ b/src/recommendationservice/recommendation_server.py @@ -22,11 +22,19 @@ # Pip import grpc + +# 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 import demo_pb2_grpc @@ -41,6 +49,8 @@ def ListRecommendations(self, request, context): span = trace.get_current_span() span.set_attribute("app.products_recommended.count", len(prod_list)) logger.info("[Recv ListRecommendations] product_ids={}".format(prod_list)) + recommendations_counter.add(len(prod_list), {'recommendation.type': 'catalog'}) + # build and return response response = demo_pb2.ListRecommendationsResponse() response.product_ids.extend(prod_list) @@ -82,28 +92,42 @@ def must_map_env(key: str): return value if __name__ == "__main__": - logger = getJSONLogger('recommendationservice-server') + # 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 + recommendations_counter = meter.create_counter( + 'recommendations.counter', unit='recommendations', description="Counts the total number of given recommendations" + ) + port = must_map_env('RECOMMENDATION_SERVICE_PORT') catalog_addr = must_map_env('PRODUCT_CATALOG_SERVICE_ADDR') channel = grpc.insecure_channel(catalog_addr) product_catalog_stub = demo_pb2_grpc.ProductCatalogServiceStub(channel) - # create gRPC server + # Create gRPC server server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) - # add class to gRPC server + # Add class to gRPC server service = RecommendationService() demo_pb2_grpc.add_RecommendationServiceServicer_to_server(service, server) health_pb2_grpc.add_HealthServicer_to_server(service, server) - # start server + # Start logger + logger = getJSONLogger('recommendationservice-server') logger.info("RecommendationService listening on port: " + port) + + # Start server server.add_insecure_port('[::]:' + port) server.start() server.wait_for_termination() diff --git a/src/recommendationservice/requirements.txt b/src/recommendationservice/requirements.txt index 0bd544764d..1065829c37 100644 --- a/src/recommendationservice/requirements.txt +++ b/src/recommendationservice/requirements.txt @@ -1,12 +1,12 @@ google-api-core==2.4.0 grpcio-health-checking==1.43.0 grpcio==1.43.0 -opentelemetry-api==1.9.1 -opentelemetry-exporter-otlp-proto-grpc==1.9.1 -opentelemetry-instrumentation==0.28b1 -opentelemetry-instrumentation-grpc==0.28b1 -opentelemetry-instrumentation-urllib3==0.28b1 -opentelemetry-sdk==1.9.1 +opentelemetry-api==1.13.0 +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 From 2eb986ae924ae00d676f61f09314f1166b8839c7 Mon Sep 17 00:00:00 2001 From: Mikko Viitanen Date: Mon, 10 Oct 2022 20:35:27 +0300 Subject: [PATCH 2/2] Update to counter name. --- src/recommendationservice/recommendation_server.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/recommendationservice/recommendation_server.py b/src/recommendationservice/recommendation_server.py index 21ecf57ce9..b981f316be 100644 --- a/src/recommendationservice/recommendation_server.py +++ b/src/recommendationservice/recommendation_server.py @@ -49,7 +49,7 @@ def ListRecommendations(self, request, context): span = trace.get_current_span() span.set_attribute("app.products_recommended.count", len(prod_list)) logger.info("[Recv ListRecommendations] product_ids={}".format(prod_list)) - recommendations_counter.add(len(prod_list), {'recommendation.type': 'catalog'}) + app_recommendations_counter.add(len(prod_list), {'recommendation.type': 'catalog'}) # build and return response response = demo_pb2.ListRecommendationsResponse() @@ -105,8 +105,8 @@ def must_map_env(key: str): meter = metrics.get_meter(__name__) # Create counters - recommendations_counter = meter.create_counter( - 'recommendations.counter', unit='recommendations', description="Counts the total number of given recommendations" + app_recommendations_counter = meter.create_counter( + 'app.recommendations.counter', unit='recommendations', description="Counts the total number of given recommendations" ) port = must_map_env('RECOMMENDATION_SERVICE_PORT')