From 133d089a6d7e082a277a0c4ed134b62ca08b4c7e Mon Sep 17 00:00:00 2001 From: Pierre Tessier Date: Mon, 21 Nov 2022 08:44:47 -0500 Subject: [PATCH 1/4] [protobuf] - encode zipcode as a string (#587) * encode zipcode as a string * encode zipcode as a string * encode zipcode as a string * add zip_code attribute * update zipCode to string type * update zipCode to string type * add address to shipping api call * add address to shipping api call * zipcode as string --- CHANGELOG.md | 2 ++ docs/manual_span_attributes.md | 11 ++++++----- pb/demo.proto | 2 +- .../components/CartItems/CartItems.tsx | 11 +++++++++-- .../components/CheckoutForm/CheckoutForm.tsx | 7 +++---- .../components/CheckoutItem/CheckoutItem.tsx | 2 +- src/frontend/gateways/Api.gateway.ts | 5 +++-- src/frontend/gateways/rpc/Shipping.gateway.ts | 6 +++--- src/frontend/pages/api/shipping.ts | 7 ++++--- src/loadgenerator/locustfile.py | 18 +++++++++--------- src/paymentservice/package-lock.json | 5 +++-- src/shippingservice/src/shipping_service.rs | 7 ++++--- test/data.json | 6 +++--- 13 files changed, 51 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f9d3e4353..865de2a372 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -140,3 +140,5 @@ significant modifications will be credited to OpenTelemetry Authors. ([#536](https://github.com/open-telemetry/opentelemetry-demo/pull/536)) * Add basic metrics support for payment service ([#583](https://github.com/open-telemetry/opentelemetry-demo/pull/583)) +* Change ZipCode data type from int to string +([#587](https://github.com/open-telemetry/opentelemetry-demo/pull/587)) diff --git a/docs/manual_span_attributes.md b/docs/manual_span_attributes.md index 31c5828802..bb8fe232bd 100644 --- a/docs/manual_span_attributes.md +++ b/docs/manual_span_attributes.md @@ -116,8 +116,9 @@ This document contains the list of manual Span Attributes used throughout the de ## ShippingService -| Name | Type | Description | -|----------------------------|--------|----------------------| -| `app.shipping.cost.total` | number | Total shipping cost | -| `app.shipping.items.count` | number | Total items to ship | -| `app.shipping.tracking.id` | string | Shipping tracking Id | +| Name | Type | Description | +|----------------------------|--------|-------------------------------| +| `app.shipping.cost.total` | number | Total shipping cost | +| `app.shipping.items.count` | number | Total items to ship | +| `app.shipping.tracking.id` | string | Shipping tracking Id | +| `app.shipping.zip_code` | string | Zip code used to ship item(s) | diff --git a/pb/demo.proto b/pb/demo.proto index 882752e9e2..fef5cb6383 100644 --- a/pb/demo.proto +++ b/pb/demo.proto @@ -134,7 +134,7 @@ message Address { string city = 2; string state = 3; string country = 4; - int32 zip_code = 5; + string zip_code = 5; } // -----------------Currency service----------------- diff --git a/src/frontend/components/CartItems/CartItems.tsx b/src/frontend/components/CartItems/CartItems.tsx index aee57995ab..b192ff245d 100644 --- a/src/frontend/components/CartItems/CartItems.tsx +++ b/src/frontend/components/CartItems/CartItems.tsx @@ -1,7 +1,7 @@ import { useMemo } from 'react'; import { useQuery } from 'react-query'; import ApiGateway from '../../gateways/Api.gateway'; -import { Money } from '../../protos/demo'; +import { Address, Money } from '../../protos/demo'; import { useCurrency } from '../../providers/Currency.provider'; import { IProductCartItem } from '../../types/Cart'; import ProductPrice from '../ProductPrice'; @@ -15,8 +15,15 @@ interface IProps { const CartItems = ({ productList, shouldShowPrice = true }: IProps) => { const { selectedCurrency } = useCurrency(); + const address: Address = { + streetAddress: '1600 Amphitheatre Parkway', + city: 'Mountain View', + state: 'CA', + country: 'United States', + zipCode: "94043", + }; const { data: shippingConst = { units: 0, currencyCode: 'USD', nanos: 0 } } = useQuery('shipping', () => - ApiGateway.getShippingCost(productList, selectedCurrency) + ApiGateway.getShippingCost(productList, selectedCurrency, address) ); const total = useMemo( diff --git a/src/frontend/components/CheckoutForm/CheckoutForm.tsx b/src/frontend/components/CheckoutForm/CheckoutForm.tsx index 88f6465c89..a259521a7e 100644 --- a/src/frontend/components/CheckoutForm/CheckoutForm.tsx +++ b/src/frontend/components/CheckoutForm/CheckoutForm.tsx @@ -13,7 +13,7 @@ export interface IFormData { city: string; state: string; country: string; - zipCode: number; + zipCode: string; creditCardNumber: string; creditCardCvv: number; creditCardExpirationYear: number; @@ -45,7 +45,7 @@ const CheckoutForm = ({ onSubmit }: IProps) => { city: 'Mountain View', state: 'CA', country: 'United States', - zipCode: 94043, + zipCode: "94043", creditCardNumber: '4432-8015-6152-0454', creditCardCvv: 672, creditCardExpirationYear: 2030, @@ -99,13 +99,12 @@ const CheckoutForm = ({ onSubmit }: IProps) => { /> diff --git a/src/frontend/components/CheckoutItem/CheckoutItem.tsx b/src/frontend/components/CheckoutItem/CheckoutItem.tsx index fba9adf6b8..05c7a3525b 100644 --- a/src/frontend/components/CheckoutItem/CheckoutItem.tsx +++ b/src/frontend/components/CheckoutItem/CheckoutItem.tsx @@ -19,7 +19,7 @@ const CheckoutItem = ({ }, cost = { currencyCode: 'USD', units: 0, nanos: 0 }, }, - address: { streetAddress = '', city = '', state = '', zipCode = 0, country = '' }, + address: { streetAddress = '', city = '', state = '', zipCode = '', country = '' }, }: IProps) => { const [isCollapsed, setIsCollapsed] = useState(false); diff --git a/src/frontend/gateways/Api.gateway.ts b/src/frontend/gateways/Api.gateway.ts index 5d495d4b8e..1b754084d3 100644 --- a/src/frontend/gateways/Api.gateway.ts +++ b/src/frontend/gateways/Api.gateway.ts @@ -1,4 +1,4 @@ -import { Ad, Cart, CartItem, Money, PlaceOrderRequest, Product } from '../protos/demo'; +import { Ad, Address, Cart, CartItem, Money, PlaceOrderRequest, Product } from '../protos/demo'; import { IProductCart, IProductCartItem, IProductCheckout } from '../types/Cart'; import request from '../utils/Request'; import SessionGateway from './Session.gateway'; @@ -36,12 +36,13 @@ const ApiGateway = () => ({ }); }, - getShippingCost(itemList: IProductCartItem[], currencyCode: string) { + getShippingCost(itemList: IProductCartItem[], currencyCode: string, address: Address) { return request({ url: `${basePath}/shipping`, queryParams: { itemList: JSON.stringify(itemList.map(({ productId, quantity }) => ({ productId, quantity }))), currencyCode, + address: JSON.stringify(address), }, }); }, diff --git a/src/frontend/gateways/rpc/Shipping.gateway.ts b/src/frontend/gateways/rpc/Shipping.gateway.ts index b64c266fe3..14ebcb3acf 100644 --- a/src/frontend/gateways/rpc/Shipping.gateway.ts +++ b/src/frontend/gateways/rpc/Shipping.gateway.ts @@ -1,14 +1,14 @@ import { ChannelCredentials } from '@grpc/grpc-js'; -import { CartItem, GetQuoteResponse, ShippingServiceClient } from '../../protos/demo'; +import { Address, CartItem, GetQuoteResponse, ShippingServiceClient } from '../../protos/demo'; const { SHIPPING_SERVICE_ADDR = '' } = process.env; const client = new ShippingServiceClient(SHIPPING_SERVICE_ADDR, ChannelCredentials.createInsecure()); const AdGateway = () => ({ - getShippingCost(itemList: CartItem[]) { + getShippingCost(itemList: CartItem[], address: Address) { return new Promise((resolve, reject) => - client.getQuote({ items: itemList, address: undefined }, (error, response) => + client.getQuote({ items: itemList, address: address }, (error, response) => error ? reject(error) : resolve(response) ) ); diff --git a/src/frontend/pages/api/shipping.ts b/src/frontend/pages/api/shipping.ts index 280d666f88..9a1cf2520c 100644 --- a/src/frontend/pages/api/shipping.ts +++ b/src/frontend/pages/api/shipping.ts @@ -1,7 +1,7 @@ import type { NextApiRequest, NextApiResponse } from 'next'; import InstrumentationMiddleware from '../../utils/telemetry/InstrumentationMiddleware'; import ShippingGateway from '../../gateways/rpc/Shipping.gateway'; -import { CartItem, Empty, Money } from '../../protos/demo'; +import { Address, CartItem, Empty, Money } from '../../protos/demo'; import CurrencyGateway from '../../gateways/rpc/Currency.gateway'; type TResponse = Money | Empty; @@ -9,8 +9,9 @@ type TResponse = Money | Empty; const handler = async ({ method, query }: NextApiRequest, res: NextApiResponse) => { switch (method) { case 'GET': { - const { itemList = '', currencyCode = 'USD' } = query; - const { costUsd } = await ShippingGateway.getShippingCost(JSON.parse(itemList as string) as CartItem[]); + const { itemList = '', currencyCode = 'USD', address = '' } = query; + const { costUsd } = await ShippingGateway.getShippingCost(JSON.parse(itemList as string) as CartItem[], + JSON.parse(address as string) as Address); const cost = await CurrencyGateway.convert(costUsd!, currencyCode as string); return res.status(200).json(cost!); diff --git a/src/loadgenerator/locustfile.py b/src/loadgenerator/locustfile.py index 4dd90a9352..afcf29cb78 100644 --- a/src/loadgenerator/locustfile.py +++ b/src/loadgenerator/locustfile.py @@ -50,7 +50,7 @@ "email": "larry_sergei@example.com", "address": { "streetAddress": "1600 Amphitheatre Parkway", - "zipCode": 94043, + "zipCode": "94043", "city": "Mountain View", "state": "CA", "country": "United States", @@ -67,7 +67,7 @@ "email": "bill@example.com", "address": { "streetAddress": "One Microsoft Way", - "zipCode": 98052, + "zipCode": "98052", "city": "Redmond", "state": "WA", "country": "United States", @@ -84,7 +84,7 @@ "email": "steve@example.com", "address": { "streetAddress": "One Apple Park Way", - "zipCode": 95014, + "zipCode": "95014", "city": "Cupertino", "state": "CA", "country": "United States", @@ -101,7 +101,7 @@ "email": "mark@example.com", "address": { "streetAddress": "1 Hacker Way", - "zipCode": 94025, + "zipCode": "94025", "city": "Menlo Park", "state": "CA", "country": "United States", @@ -118,7 +118,7 @@ "email": "jeff@example.com", "address": { "streetAddress": "410 Terry Ave N", - "zipCode": 98109, + "zipCode": "98109", "city": "Seattle", "state": "WA", "country": "United States", @@ -135,7 +135,7 @@ "email": "reed@example.com", "address": { "streetAddress": "100 Winchester Circle", - "zipCode": 95032, + "zipCode": "95032", "city": "Los Gatos", "state": "CA", "country": "United States", @@ -152,7 +152,7 @@ "email": "tobias@example.com", "address": { "streetAddress": "150 Elgin St", - "zipCode": 214, + "zipCode": "K2P1L4", "city": "Ottawa", "state": "ON", "country": "Canada", @@ -169,7 +169,7 @@ "email": "jack@example.com", "address": { "streetAddress": "1355 Market St", - "zipCode": 94103, + "zipCode": "94103", "city": "San Francisco", "state": "CA", "country": "United States", @@ -186,7 +186,7 @@ "email": "moore@example.com", "address": { "streetAddress": "2200 Mission College Blvd", - "zipCode": 95054, + "zipCode": "95054", "city": "Santa Clara", "state": "CA", "country": "United States", diff --git a/src/paymentservice/package-lock.json b/src/paymentservice/package-lock.json index 23858ae5d9..64e3aafec9 100644 --- a/src/paymentservice/package-lock.json +++ b/src/paymentservice/package-lock.json @@ -12,11 +12,12 @@ "@grpc/grpc-js": "1.7.3", "@grpc/proto-loader": "^0.7.3", "@opentelemetry/api": "^1.2.0", - "@opentelemetry/api-metrics": "^0.33.0", + "@opentelemetry/api-metrics": "0.33.0", "@opentelemetry/auto-instrumentations-node": "0.33.1", "@opentelemetry/core": "1.7.0", - "@opentelemetry/exporter-metrics-otlp-grpc": "^0.33.0", + "@opentelemetry/exporter-metrics-otlp-grpc": "0.33.0", "@opentelemetry/exporter-trace-otlp-grpc": "0.33.0", + "@opentelemetry/sdk-metrics": "0.33.0", "@opentelemetry/sdk-node": "0.33.0", "grpc-js-health-check": "^1.0.2", "pino": "8.7.0", diff --git a/src/shippingservice/src/shipping_service.rs b/src/shippingservice/src/shipping_service.rs index 94a14a30d5..38142f25e2 100644 --- a/src/shippingservice/src/shipping_service.rs +++ b/src/shippingservice/src/shipping_service.rs @@ -51,8 +51,9 @@ impl ShippingService for ShippingServer { let parent_cx = global::get_text_map_propagator(|prop| prop.extract(&MetadataMap(request.metadata()))); - let itemct: u32 = request - .into_inner() + let request_message = request.into_inner(); + + let itemct: u32 = request_message .items .into_iter() .fold(0, |accum, cart_item| accum + (cart_item.quantity as u32)); @@ -62,8 +63,8 @@ impl ShippingService for ShippingServer { // check out the create_quote_from_count method to see how we use the span created here let tracer = global::tracer("shippingservice/get-quote"); let mut span = tracer.start_with_context("get-quote", &parent_cx); - span.add_event("Processing get quote request".to_string(), vec![]); + span.set_attribute(KeyValue::new("app.shipping.zip_code", request_message.address.unwrap().zip_code)); let q = match create_quote_from_count(itemct) .with_context(Context::current_with_span(span)) diff --git a/test/data.json b/test/data.json index 85db134e2c..e575f2b314 100644 --- a/test/data.json +++ b/test/data.json @@ -17,7 +17,7 @@ "city": "Seattle", "state": "Washington", "country": "United States", - "zipCode": 98109 + "zipCode": "98109" }, "email": "amazon@example.com", "creditCard": { @@ -50,7 +50,7 @@ "city": "Mountain View", "state": "California", "country": "United States", - "zipCode": 94043 + "zipCode": "94043" }, "items": [ { @@ -90,7 +90,7 @@ "city": "Redmond", "state": "Washington", "country": "United States", - "zipCode": 98052 + "zipCode": "98052" }, "items": [ { From 265aefe47a639baed615c4ad662ef0a3aa1551c1 Mon Sep 17 00:00:00 2001 From: Ty Bekiares <107002404+ty-elastic@users.noreply.github.com> Date: Mon, 21 Nov 2022 10:19:25 -0600 Subject: [PATCH 2/4] [shippingservice] apply OTEL_RESOURCE_ATTRIBUTES (#594) Co-authored-by: Austin Parker --- docs/services/shippingservice.md | 3 ++- src/shippingservice/src/main.rs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/services/shippingservice.md b/docs/services/shippingservice.md index bf50a5efbc..ada111b862 100644 --- a/docs/services/shippingservice.md +++ b/docs/services/shippingservice.md @@ -28,6 +28,7 @@ fn init_tracer() -> Result { let os_resource = OsResourceDetector.detect(Duration::from_secs(0)); let process_resource = ProcessResourceDetector.detect(Duration::from_secs(0)); let sdk_resource = SdkProvidedResourceDetector.detect(Duration::from_secs(0)); + let env_resource = EnvResourceDetector::new().detect(Duration::from_secs(0)); opentelemetry_otlp::new_pipeline() .tracing() .with_exporter( @@ -43,7 +44,7 @@ fn init_tracer() -> Result { ) .with_trace_config( sdktrace::config() - .with_resource(os_resource.merge(&process_resource).merge(&sdk_resource)), + .with_resource(os_resource.merge(&process_resource).merge(&sdk_resource).merge(&env_resource)), ) .install_batch(opentelemetry::runtime::Tokio) } diff --git a/src/shippingservice/src/main.rs b/src/shippingservice/src/main.rs index d9a561ff78..f4c0087008 100644 --- a/src/shippingservice/src/main.rs +++ b/src/shippingservice/src/main.rs @@ -19,6 +19,7 @@ use opentelemetry::{ propagation::TraceContextPropagator, resource::{ OsResourceDetector, ProcessResourceDetector, ResourceDetector, + EnvResourceDetector, SdkProvidedResourceDetector, }, trace as sdktrace, @@ -52,6 +53,7 @@ fn init_tracer() -> Result { let os_resource = OsResourceDetector.detect(Duration::from_secs(0)); let process_resource = ProcessResourceDetector.detect(Duration::from_secs(0)); let sdk_resource = SdkProvidedResourceDetector.detect(Duration::from_secs(0)); + let env_resource = EnvResourceDetector::new().detect(Duration::from_secs(0)); opentelemetry_otlp::new_pipeline() .tracing() .with_exporter( @@ -67,7 +69,7 @@ fn init_tracer() -> Result { ) .with_trace_config( sdktrace::config() - .with_resource(os_resource.merge(&process_resource).merge(&sdk_resource)), + .with_resource(os_resource.merge(&process_resource).merge(&sdk_resource).merge(&env_resource)), ) .install_batch(opentelemetry::runtime::Tokio) } From 7d4b9d9e784988bc70c026473aa6a22f5fb6e807 Mon Sep 17 00:00:00 2001 From: Ty Bekiares <107002404+ty-elastic@users.noreply.github.com> Date: Mon, 21 Nov 2022 10:23:42 -0600 Subject: [PATCH 3/4] [shippingservice] add grpc conventions (#597) Co-authored-by: Austin Parker --- docs/services/shippingservice.md | 22 ++++++++++------- src/shippingservice/Cargo.lock | 10 ++++++++ src/shippingservice/Cargo.toml | 1 + src/shippingservice/src/shipping_service.rs | 26 +++++++++++++++------ 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/docs/services/shippingservice.md b/docs/services/shippingservice.md index ada111b862..2b6e538e60 100644 --- a/docs/services/shippingservice.md +++ b/docs/services/shippingservice.md @@ -65,15 +65,17 @@ The root span is started and passed down as reference in the same thread to another closure where we call `quoteservice`. ```rust - let tracer = global::tracer("shippingservice/get-quote"); - let mut span = tracer.start_with_context("get-quote", &parent_cx); + let tracer = global::tracer("shippingservice"); + let mut span = tracer.span_builder("hipstershop.ShippingService/GetQuote").with_kind(SpanKind::Server).start_with_context(&tracer, &parent_cx); + span.set_attribute(semcov::trace::RPC_SYSTEM.string(RPC_SYSTEM_GRPC)); span.add_event("Processing get quote request".to_string(), vec![]); + let cx = Context::current_with_span(span); let q = match create_quote_from_count(itemct) - .with_context(Context::current_with_span(span)) + .with_context(cx.clone()) .await -//...create_quote_from_count... +//-> create_quote_from_count()... let f = match request_quote(count).await { Ok(float) => float, Err(err) => { @@ -92,10 +94,13 @@ to another closure where we call `quoteservice`. span.set_attribute(KeyValue::new("app.shipping.cost.total", format!("{}", q))); q })) +//<- create_quote_from_count()... + cx.span().set_attribute(semcov::trace::RPC_GRPC_STATUS_CODE.i64(RPC_GRPC_STATUS_CODE_OK)); ``` -Note that the span cannot be used after calling an async method in the -originating function. +Note that we create a context around the root span and send a clone to the +async function create_quote_from_count(). After create_quote_from_count() +completes, we can add additional attributes to the root span as appropriate. You may also notice the `attributes` set on the span in this example, and `events` propogated similarly. With any valid `span` pointer (attached to @@ -119,8 +124,9 @@ This is appropriate in our case of a sync runtime. global::get_text_map_propagator(|prop| prop.extract(&MetadataMap(request.metadata()))); // in this case, generating a tracking ID is trivial // we'll create a span and associated events all in this function. - let mut span = global::tracer("shippingservice/ship-order") - .start_with_context("ship-order", &parent_cx); + let tracer = global::tracer("shippingservice"); + let mut span = tracer + .span_builder("hipstershop.ShippingService/ShipOrder").with_kind(SpanKind::Server).start_with_context(&tracer, &parent_cx); ``` You must add attributes to a span in context with `set_attribute`, followed by a diff --git a/src/shippingservice/Cargo.lock b/src/shippingservice/Cargo.lock index 5328ab2f28..5cb67153a9 100644 --- a/src/shippingservice/Cargo.lock +++ b/src/shippingservice/Cargo.lock @@ -618,6 +618,15 @@ dependencies = [ "tonic-build", ] +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b02e0230abb0ab6636d18e2ba8fa02903ea63772281340ccac18e0af3ec9eeb" +dependencies = [ + "opentelemetry", +] + [[package]] name = "opentelemetry_api" version = "0.18.0" @@ -952,6 +961,7 @@ dependencies = [ "opentelemetry", "opentelemetry-http", "opentelemetry-otlp", + "opentelemetry-semantic-conventions", "opentelemetry_api", "prost", "prost-types", diff --git a/src/shippingservice/Cargo.toml b/src/shippingservice/Cargo.toml index 97def98776..f1d59601fd 100644 --- a/src/shippingservice/Cargo.toml +++ b/src/shippingservice/Cargo.toml @@ -18,6 +18,7 @@ prost = "0.11" prost-types = "0.11" tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } opentelemetry = { version = "0.18", features = ["rt-tokio", "trace"] } +opentelemetry-semantic-conventions = "0.10.0" opentelemetry_api = { version = "0.18" } opentelemetry-http = "0.7.0" opentelemetry-otlp = "0.11.0" diff --git a/src/shippingservice/src/shipping_service.rs b/src/shippingservice/src/shipping_service.rs index 38142f25e2..67c3481494 100644 --- a/src/shippingservice/src/shipping_service.rs +++ b/src/shippingservice/src/shipping_service.rs @@ -1,5 +1,6 @@ use opentelemetry::{global, propagation::Extractor, trace::Span, Context, KeyValue}; -use opentelemetry_api::trace::{FutureExt, TraceContextExt, Tracer}; +use opentelemetry_api::trace::{FutureExt, TraceContextExt, SpanKind, Tracer}; +use opentelemetry_semantic_conventions as semcov; use shop::shipping_service_server::ShippingService; use shop::{GetQuoteRequest, GetQuoteResponse, Money, ShipOrderRequest, ShipOrderResponse}; use tonic::{Request, Response, Status}; @@ -14,6 +15,10 @@ use tracking::create_tracking_id; const NANOS_MULTIPLE: i32 = 10000000i32; +const RPC_SYSTEM_GRPC: &'static str = "grpc"; +const RPC_GRPC_STATUS_CODE_OK: i64 = 0; +const RPC_GRPC_STATUS_CODE_UNKNOWN: i64 = 2; + pub mod shop { tonic::include_proto!("hipstershop"); // The string specified here must match the proto package name } @@ -61,17 +66,20 @@ impl ShippingService for ShippingServer { // We may want to ask another service for product pricing / info // (although now everything is assumed to be the same price) // check out the create_quote_from_count method to see how we use the span created here - let tracer = global::tracer("shippingservice/get-quote"); - let mut span = tracer.start_with_context("get-quote", &parent_cx); + let tracer = global::tracer("shippingservice"); + let mut span = tracer.span_builder("hipstershop.ShippingService/GetQuote").with_kind(SpanKind::Server).start_with_context(&tracer, &parent_cx); + span.set_attribute(semcov::trace::RPC_SYSTEM.string(RPC_SYSTEM_GRPC)); + span.add_event("Processing get quote request".to_string(), vec![]); span.set_attribute(KeyValue::new("app.shipping.zip_code", request_message.address.unwrap().zip_code)); + let cx = Context::current_with_span(span); let q = match create_quote_from_count(itemct) - .with_context(Context::current_with_span(span)) + .with_context(cx.clone()) .await { Ok(quote) => quote, - Err(status) => return Err(status), + Err(status) => {cx.span().set_attribute(semcov::trace::RPC_GRPC_STATUS_CODE.i64(RPC_GRPC_STATUS_CODE_UNKNOWN)); return Err(status)}, }; let reply = GetQuoteResponse { @@ -83,6 +91,7 @@ impl ShippingService for ShippingServer { }; info!("Sending Quote: {}", q); + cx.span().set_attribute(semcov::trace::RPC_GRPC_STATUS_CODE.i64(RPC_GRPC_STATUS_CODE_OK)); Ok(Response::new(reply)) } async fn ship_order( @@ -95,8 +104,10 @@ impl ShippingService for ShippingServer { global::get_text_map_propagator(|prop| prop.extract(&MetadataMap(request.metadata()))); // in this case, generating a tracking ID is trivial // we'll create a span and associated events all in this function. - let mut span = global::tracer("shippingservice/ship-order") - .start_with_context("ship-order", &parent_cx); + let tracer = global::tracer("shippingservice"); + let mut span = tracer + .span_builder("hipstershop.ShippingService/ShipOrder").with_kind(SpanKind::Server).start_with_context(&tracer, &parent_cx); + span.set_attribute(semcov::trace::RPC_SYSTEM.string(RPC_SYSTEM_GRPC)); span.add_event("Processing shipping order request".to_string(), vec![]); @@ -109,6 +120,7 @@ impl ShippingService for ShippingServer { vec![], ); + span.set_attribute(semcov::trace::RPC_GRPC_STATUS_CODE.i64(RPC_GRPC_STATUS_CODE_OK)); Ok(Response::new(ShipOrderResponse { tracking_id: tid })) } } From 90964205fd37a3dbd8d36b9d7362590ced4bc818 Mon Sep 17 00:00:00 2001 From: Pierre Tessier Date: Mon, 21 Nov 2022 11:27:03 -0500 Subject: [PATCH 4/4] Better dev environment (#598) * local dev protobuf gen script * remove gen_proto_java * fix cargo build * add docs * add development docs * add development docs * fix linter * Update docs/development.md Co-authored-by: Reiley Yang * Update docs/development.md Co-authored-by: Reiley Yang * Update docs/development.md Co-authored-by: Reiley Yang * Update docs/development.md Co-authored-by: Reiley Yang * Update docs/development.md Co-authored-by: Reiley Yang * alpha order c++ pre-requisites * use python3 * add protoc-gen-go / grpc Co-authored-by: Reiley Yang --- .gitignore | 19 ++++++++---- Makefile | 4 +++ docs/README.md | 1 + docs/development.md | 70 +++++++++++++++++++++++++++++++++++++++++++ ide-gen-proto.sh | 73 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 162 insertions(+), 5 deletions(-) create mode 100644 docs/development.md create mode 100755 ide-gen-proto.sh diff --git a/.gitignore b/.gitignore index 846a49a06e..cbd8f5fd8e 100644 --- a/.gitignore +++ b/.gitignore @@ -22,16 +22,25 @@ obj/ .idea/ build/ node_modules/ -src/shippingservice/target/ - coverage .next/ out/ build -src/frontend/protos next-env.d.ts -src/frontend/cypress/videos -src/frontend/cypress/screenshots vendor/ composer.lock .venv + +src/frontend/cypress/videos +src/frontend/cypress/screenshots +src/shippingservice/target/ + +# Ignore copied/generated protobuf files +/src/cartservice/src/protos/ +/src/checkoutservice/genproto/ +/src/frontend/pb/ +/src/frontend/protos/ +/src/paymentservice/demo.proto +/src/productcatalogservice/genproto/ +/src/recommendationservice/demo_pb2*.py +/src/shippingservice/proto/ diff --git a/Makefile b/Makefile index 69bb761760..738103a2fc 100644 --- a/Makefile +++ b/Makefile @@ -80,3 +80,7 @@ build-env-file: run-tests: docker compose run frontendTests docker compose run integrationTests + +.PHONY: generate-protobuf +generate-protobuf: + ./ide-gen-proto.sh diff --git a/docs/README.md b/docs/README.md index 10289b2aae..b725bbaae6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -72,6 +72,7 @@ We'll be adding more scenarios over time. Project reference documentation, like requirements and feature matrices. - [Architecture](./current_architecture.md) +- [Development](./development.md) - [Feature Flags Reference](./feature_flags.md) - [Metric Feature Matrix](./metric_service_features.md) - [Requirements](./requirements/) diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000000..5d1b8b430f --- /dev/null +++ b/docs/development.md @@ -0,0 +1,70 @@ +# Development + +Development for this demo requires tooling in several programming languages. +Minimum required versions will be noted where possible, but it is recommended +to update to the latest version for all tooling. The OpenTelemetry demo team +will attempt the services in this repository up to date with the latest version +for dependencies and tooling when possible. + +## Generate Protobuf files + +The `make generate-protobuf` command is provided to generate protobuf files for +all services. This can be used to compile code locally (without Docker) and +receive hints from IDEs such as IntelliJ or VS Code. + +## Development tooling requirements + +### .NET + +- .NET 6.0+ + +### C++ + +- build-essential +- cmake +- libcurl4-openssl-dev +- libprotobuf-dev +- nlohmann-json3-dev +- pkg-config +- protobuf-compiler + +### Elixir + +- Erlang/OTP 23+ +- Elixir 1.13+ +- Rebar3 3.20+ + +### Go + +- Go 1.19+ +- protoc-gen-go +- protoc-gen-go-grpc + +### Java + +- JDK 17+ +- Gradle 7+ + +### JavaScript + +- Node.js 16+ + +### PHP + +- PHP 8.1+ +- Composer 2.4+ + +### Python + +- Python 3.10 +- grpcio-tools 1.48+ + +### Ruby + +- Ruby 3.1+ + +### Rust + +- Rust 1.61+ +- protoc 3.21+ +- protobuf-dev diff --git a/ide-gen-proto.sh b/ide-gen-proto.sh new file mode 100755 index 0000000000..d37978c52d --- /dev/null +++ b/ide-gen-proto.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +# This script is used to generate protobuf files for all services. +# Useful to ensure code can compile without Docker, and provide hints for IDEs. +# Several dev tools including: cargo, protoc, python grpc_tools.protoc, and rebar3 may be required to run this script. + +base_dir=$(pwd) + +gen_proto_dotnet() { + echo "Generating .NET protobuf files for $1" + cd "$base_dir"/src/"$1" || return + mkdir -p ./src/protos/ + cp -r "$base_dir"/pb/ ./src/protos/ + cd "$base_dir" || return +} + +gen_proto_elixir() { + echo "Generating Elixir protobuf files for $1" + cd "$base_dir"/src/"$1" || return + cp "$base_dir"/pb/demo.proto ./proto/demo.proto + rebar3 grpc gen + cd "$base_dir" || return +} + +gen_proto_go() { + echo "Generating Go protobuf files for $1" + cd "$base_dir"/src/"$1" || return + protoc -I ../../pb ./../../pb/demo.proto --go_out=./ --go-grpc_out=./ + cd "$base_dir" || return +} + +gen_proto_js() { + echo "Generating Javascript protobuf files for $1" + cd "$base_dir"/src/"$1" || return + cp "$base_dir"/pb/demo.proto . + cd "$base_dir" || return +} + +gen_proto_python() { + echo "Generating Python protobuf files for $1" + cd "$base_dir"/src/"$1" || return + python3 -m grpc_tools.protoc -I=../../pb --python_out=./ --grpc_python_out=./ ./../../pb/demo.proto + cd "$base_dir" || return +} + +gen_proto_rust() { + echo "Generating Rust protobuf files for $1" + cd "$base_dir"/src/"$1" || return + mkdir -p proto + cp "$base_dir"/pb/demo.proto proto/demo.proto + cargo build + cd "$base_dir" || return +} + +gen_proto_ts() { + echo "Generating Typescript protobuf files for $1" + cd "$base_dir"/src/"$1" || return + cp -r "$base_dir"/pb . + cd "$base_dir" || return +} + +# gen_proto_java adservice +gen_proto_dotnet cartservice +gen_proto_go checkoutservice +# gen_proto_cpp currencyservice +# gen_proto_ruby emailservice +# gen_proto_elixir featureflagservice +gen_proto_ts frontend +gen_proto_js paymentservice +gen_proto_go productcatalogservice +# gen_proto_php quoteservice +gen_proto_python recommendationservice +gen_proto_rust shippingservice