diff --git a/CHANGELOG.md b/CHANGELOG.md index b57750b850..a312731d8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ tls_certificate_check and bump to OTP-25 ([#756](https://github.com/open-telemetry/opentelemetry-demo/pull/756)) * Bump up OTEL Java Agent version to 1.23.0 ([#757](https://github.com/open-telemetry/opentelemetry-demo/pull/757)) +* Add counter metric to currency service (C++) +([#759](https://github.com/open-telemetry/opentelemetry-demo/issues/759)) * Use browserDetector to populate browser info to frontend-web telemetry ([#760](https://github.com/open-telemetry/opentelemetry-demo/pull/760)) diff --git a/src/currencyservice/.dockerignore b/src/currencyservice/.dockerignore index 4d92be1501..5957e52fe4 100644 --- a/src/currencyservice/.dockerignore +++ b/src/currencyservice/.dockerignore @@ -1,2 +1,4 @@ client.js node_modules/ +build/ +out/ diff --git a/src/currencyservice/CMakeLists.txt b/src/currencyservice/CMakeLists.txt index 5ab5120c10..5b672559f8 100644 --- a/src/currencyservice/CMakeLists.txt +++ b/src/currencyservice/CMakeLists.txt @@ -1,8 +1,9 @@ cmake_minimum_required(VERSION 3.1) project(currency-service) -find_package(Protobuf) -find_package(gRPC) +find_package(Protobuf REQUIRED) +find_package(gRPC CONFIG REQUIRED) +find_package(opentelemetry-cpp CONFIG REQUIRED) set(PROTO_PATH "${CMAKE_CURRENT_SOURCE_DIR}/proto") set(GENERATED_PROTOBUF_PATH "${CMAKE_BINARY_DIR}/generated/proto") @@ -56,12 +57,15 @@ add_library(demo-proto ${DEMO_PB_H_FILE} ${HEALTH_GRPC_PB_H_FILE}) target_link_libraries(demo-proto gRPC::grpc++ protobuf::libprotobuf) -include_directories("${GENERATED_PROTOBUF_PATH}") +include_directories("${GENERATED_PROTOBUF_PATH}" "${OPENTELEMETRY_CPP_INCLUDE_DIRS}") add_executable(currencyservice src/server.cpp) add_dependencies(currencyservice demo-proto) target_link_libraries( currencyservice demo-proto protobuf::libprotobuf - opentelemetry_trace opentelemetry_common opentelemetry_exporter_otlp_grpc opentelemetry_exporter_otlp_grpc_client opentelemetry_proto opentelemetry_otlp_recordable opentelemetry_resources gRPC::grpc++) + ${OPENTELEMETRY_CPP_LIBRARIES} opentelemetry_trace opentelemetry_common + opentelemetry_exporter_otlp_grpc opentelemetry_exporter_otlp_grpc_client + opentelemetry_proto opentelemetry_otlp_recordable opentelemetry_resources + opentelemetry_metrics opentelemetry_exporter_otlp_grpc_metrics gRPC::grpc++) install(TARGETS currencyservice DESTINATION bin) diff --git a/src/currencyservice/Dockerfile b/src/currencyservice/Dockerfile index 935f20327c..bce1f101dc 100644 --- a/src/currencyservice/Dockerfile +++ b/src/currencyservice/Dockerfile @@ -17,14 +17,14 @@ FROM alpine as builder RUN apk update RUN apk add git cmake make g++ grpc-dev re2-dev protobuf-dev c-ares-dev -ARG OPENTELEMETRY_CPP_VERSION=1.8.1 +ARG OPENTELEMETRY_CPP_VERSION=1.8.2 RUN git clone https://github.com/open-telemetry/opentelemetry-cpp \ && cd opentelemetry-cpp/ \ && git checkout tags/v${OPENTELEMETRY_CPP_VERSION} -b v${OPENTELEMETRY_CPP_VERSION} \ && mkdir build \ && cd build \ - && cmake .. -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -DWITH_EXAMPLES=OFF -DWITH_OTLP=ON \ + && cmake .. -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -DWITH_EXAMPLES=OFF -DWITH_OTLP=ON -DWITH_OTLP_GRPC=ON \ && make -j$(nproc || sysctl -n hw.ncpu || echo 1) install && cd ../.. && rm -rf opentelemetry-cpp COPY . /currencyservice diff --git a/src/currencyservice/src/meter_common.h b/src/currencyservice/src/meter_common.h new file mode 100644 index 0000000000..24fad7255d --- /dev/null +++ b/src/currencyservice/src/meter_common.h @@ -0,0 +1,64 @@ +// 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. + +#include "opentelemetry/exporters/otlp/otlp_grpc_metric_exporter_factory.h" +#include "opentelemetry/metrics/provider.h" +#include "opentelemetry/sdk/metrics/export/periodic_exporting_metric_reader.h" +#include "opentelemetry/sdk/metrics/meter.h" +#include "opentelemetry/sdk/metrics/meter_provider.h" + +// namespaces +namespace common = opentelemetry::common; +namespace metrics_api = opentelemetry::metrics; +namespace metric_sdk = opentelemetry::sdk::metrics; +namespace nostd = opentelemetry::nostd; +namespace otlp_exporter = opentelemetry::exporter::otlp; + +namespace +{ + std::string version{ "1.3.0" }; + std::string name{ "app_currency" }; + std::string schema{ "https://opentelemetry.io/schemas/1.2.0" }; + + void initMeter() + { + // Build MetricExporter + otlp_exporter::OtlpGrpcMetricExporterOptions otlpOptions; + + // Configuration via environment variable not supported yet + otlpOptions.endpoint = "otelcol:4317"; + otlpOptions.aggregation_temporality = metric_sdk::AggregationTemporality::kDelta; + auto exporter = otlp_exporter::OtlpGrpcMetricExporterFactory::Create(otlpOptions); + + // Build MeterProvider and Reader + metric_sdk::PeriodicExportingMetricReaderOptions options; + options.export_interval_millis = std::chrono::milliseconds(1000); + options.export_timeout_millis = std::chrono::milliseconds(500); + std::unique_ptr reader{ + new metric_sdk::PeriodicExportingMetricReader(std::move(exporter), options) }; + auto provider = std::shared_ptr(new metric_sdk::MeterProvider()); + auto p = std::static_pointer_cast(provider); + p->AddMetricReader(std::move(reader)); + metrics_api::Provider::SetMeterProvider(provider); + } + + nostd::unique_ptr> initIntCounter() + { + std::string counter_name = name + "_counter"; + auto provider = metrics_api::Provider::GetMeterProvider(); + nostd::shared_ptr meter = provider->GetMeter(name, version); + auto int_counter = meter->CreateUInt64Counter(counter_name); + return int_counter; + } +} diff --git a/src/currencyservice/src/server.cpp b/src/currencyservice/src/server.cpp index 605bee31c2..88a2817dfe 100644 --- a/src/currencyservice/src/server.cpp +++ b/src/currencyservice/src/server.cpp @@ -22,6 +22,7 @@ #include "opentelemetry/trace/span_context_kv_iterable_view.h" #include "opentelemetry/baggage/baggage.h" #include "opentelemetry/nostd/string_view.h" +#include "meter_common.h" #include "tracer_common.h" #include @@ -48,9 +49,13 @@ using namespace opentelemetry::trace; using namespace opentelemetry::baggage; namespace context = opentelemetry::context; +namespace metrics_api = opentelemetry::metrics; +namespace nostd = opentelemetry::nostd; + namespace { - std::unordered_map currency_conversion{ + std::unordered_map currency_conversion + { {"EUR", 1.0}, {"USD", 1.1305}, {"JPY", 126.40}, @@ -84,7 +89,9 @@ namespace {"SGD", 1.5349}, {"THB", 36.012}, {"ZAR", 16.0583}, -}; + }; + + nostd::unique_ptr> currency_counter; class HealthServer final : public grpc::health::v1::Health::Service { @@ -202,6 +209,8 @@ class CurrencyService final : public oteldemo::CurrencyService::Service span->SetAttribute("app.currency.conversion.from", from_code); span->SetAttribute("app.currency.conversion.to", to_code); + CurrencyCounter(to_code); + // End the span span->AddEvent("Conversion successful, response sent back"); span->SetStatus(StatusCode::kOk); @@ -218,6 +227,13 @@ class CurrencyService final : public oteldemo::CurrencyService::Service } return Status::OK; } + + void CurrencyCounter(const std::string& currency_code) + { + std::map labels = { {"currency_code", currency_code} }; + auto labelkv = common::KeyValueIterableView{ labels }; + currency_counter->Add(1, labelkv); + } }; void RunServer(uint16_t port) @@ -250,7 +266,9 @@ int main(int argc, char **argv) { std::cout << "Port: " << port << "\n"; initTracer(); + initMeter(); + currency_counter = initIntCounter(); RunServer(port); return 0; -} \ No newline at end of file +}