Skip to content

Commit

Permalink
Merge branch 'main' into issues/586
Browse files Browse the repository at this point in the history
  • Loading branch information
julianocosta89 authored Nov 21, 2022
2 parents f889af9 + 9096420 commit 3615207
Show file tree
Hide file tree
Showing 22 changed files with 261 additions and 59 deletions.
19 changes: 14 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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/
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/)
Expand Down
70 changes: 70 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
@@ -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
11 changes: 6 additions & 5 deletions docs/manual_span_attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) |
25 changes: 16 additions & 9 deletions docs/services/shippingservice.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ fn init_tracer() -> Result<sdktrace::Tracer, TraceError> {
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(
Expand All @@ -43,7 +44,7 @@ fn init_tracer() -> Result<sdktrace::Tracer, TraceError> {
)
.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)
}
Expand All @@ -64,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) => {
Expand All @@ -91,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
Expand All @@ -118,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
Expand Down
73 changes: 73 additions & 0 deletions ide-gen-proto.sh
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion pb/demo.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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-----------------
Expand Down
11 changes: 9 additions & 2 deletions src/frontend/components/CartItems/CartItems.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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<Money>(
Expand Down
7 changes: 3 additions & 4 deletions src/frontend/components/CheckoutForm/CheckoutForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface IFormData {
city: string;
state: string;
country: string;
zipCode: number;
zipCode: string;
creditCardNumber: string;
creditCardCvv: number;
creditCardExpirationYear: number;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -99,13 +99,12 @@ const CheckoutForm = ({ onSubmit }: IProps) => {
/>
<Input
label="Zip Code"
type="number"
type="text"
name="zipCode"
id="zip_code"
value={zipCode}
onChange={handleChange}
required
pattern="\d{4,5}"
/>
<Input label="City" type="text" name="city" id="city" value={city} required onChange={handleChange} />

Expand Down
2 changes: 1 addition & 1 deletion src/frontend/components/CheckoutItem/CheckoutItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
5 changes: 3 additions & 2 deletions src/frontend/gateways/Api.gateway.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -36,12 +36,13 @@ const ApiGateway = () => ({
});
},

getShippingCost(itemList: IProductCartItem[], currencyCode: string) {
getShippingCost(itemList: IProductCartItem[], currencyCode: string, address: Address) {
return request<Money>({
url: `${basePath}/shipping`,
queryParams: {
itemList: JSON.stringify(itemList.map(({ productId, quantity }) => ({ productId, quantity }))),
currencyCode,
address: JSON.stringify(address),
},
});
},
Expand Down
6 changes: 3 additions & 3 deletions src/frontend/gateways/rpc/Shipping.gateway.ts
Original file line number Diff line number Diff line change
@@ -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<GetQuoteResponse>((resolve, reject) =>
client.getQuote({ items: itemList, address: undefined }, (error, response) =>
client.getQuote({ items: itemList, address: address }, (error, response) =>
error ? reject(error) : resolve(response)
)
);
Expand Down
Loading

0 comments on commit 3615207

Please sign in to comment.