forked from open-telemetry/opentelemetry-demo
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
39 Moving the Front end application from Go to Next.js (open-telemetr…
- Loading branch information
Showing
171 changed files
with
10,272 additions
and
4,318 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"extends": ["plugin:react/recommended", "plugin:@typescript-eslint/recommended", "next/core-web-vitals"], | ||
"plugins": ["@typescript-eslint"], | ||
"root": true, | ||
"globals": {}, | ||
"rules": { | ||
"@typescript-eslint/no-non-null-assertion": "off", | ||
"react-hooks/exhaustive-deps": "warn", | ||
"no-unused-vars": "off", | ||
"@typescript-eslint/no-unused-vars": "error", | ||
"max-len": [ | ||
"error", | ||
{ | ||
"code": 150, | ||
"ignoreComments": true, | ||
"ignoreTrailingComments": true, | ||
"ignoreUrls": true, | ||
"ignoreStrings": true, | ||
"ignoreTemplateLiterals": true | ||
} | ||
] | ||
}, | ||
"parser": "@typescript-eslint/parser", | ||
"env": {}, | ||
"overrides": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.idea | ||
.git | ||
build | ||
dist | ||
.husky | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"importOrderSeparation": true, | ||
"importOrderSortSpecifiers": true, | ||
"singleQuote": true, | ||
"arrowParens": "avoid", | ||
"bracketSpacing": true, | ||
"semi": true, | ||
"trailingComma": "es5", | ||
"printWidth": 120, | ||
"jsxBracketSameLine": false, | ||
"proseWrap": "always", | ||
"quoteProps": "as-needed", | ||
"tabWidth": 2, | ||
"useTabs": false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,40 @@ | ||
# Copyright 2020 Google LLC | ||
# | ||
# 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. | ||
|
||
FROM golang:1.17.7-alpine AS builder | ||
|
||
RUN apk add build-base protoc | ||
|
||
WORKDIR /usr/src/app/ | ||
|
||
# Restore dependencies | ||
COPY ./src/frontend/ ./ | ||
COPY ./pb/ ./proto/ | ||
RUN go mod download | ||
RUN go get google.golang.org/protobuf/cmd/protoc-gen-go | ||
RUN go get google.golang.org/grpc/cmd/protoc-gen-go-grpc | ||
|
||
# Build executable | ||
RUN protoc -I ./proto/ ./proto/demo.proto --go_out=./ --go-grpc_out=./ | ||
RUN go build -o /go/bin/frontend/ ./ | ||
|
||
# ----------------------------------------------------------------------------- | ||
|
||
FROM alpine | ||
|
||
RUN apk add busybox-extras net-tools bind-tools | ||
WORKDIR /usr/src/app/ | ||
|
||
COPY --from=builder /go/bin/frontend/ ./ | ||
COPY ./src/frontend/templates/ ./templates/ | ||
COPY ./src/frontend/static/ ./static/ | ||
|
||
EXPOSE ${FRONTEND_PORT} | ||
ENTRYPOINT [ "./frontend" ] | ||
FROM node:16-alpine AS deps | ||
RUN apk add --no-cache libc6-compat | ||
|
||
WORKDIR /app | ||
|
||
COPY ./src/frontend/package*.json ./ | ||
RUN npm ci | ||
|
||
FROM node:16-alpine AS builder | ||
RUN apk add --no-cache libc6-compat protoc | ||
WORKDIR /app | ||
COPY --from=deps /app/node_modules ./node_modules | ||
COPY ./pb ./pb | ||
COPY ./src/frontend . | ||
|
||
RUN npm run grpc:generate | ||
RUN npm run build | ||
|
||
FROM node:16-alpine AS runner | ||
WORKDIR /app | ||
RUN apk add --no-cache protoc | ||
|
||
ENV NODE_ENV=production | ||
|
||
RUN addgroup -g 1001 -S nodejs | ||
RUN adduser -S nextjs -u 1001 | ||
|
||
COPY --from=builder /app/next.config.js ./ | ||
COPY --from=builder /app/public ./public | ||
COPY --from=builder /app/package.json ./package.json | ||
|
||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ | ||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static | ||
|
||
USER nextjs | ||
|
||
ENV PORT 8080 | ||
EXPOSE ${PORT} | ||
|
||
CMD ["node", "server.js"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,131 +1,27 @@ | ||
# Frontend service | ||
|
||
The **frontend** service is responsible for rendering the UI for the store's website. | ||
It serves as the main entry point for the application routing requests to their | ||
appropriate backend services. | ||
The application uses Server Side Rendering (SSR) to generate HTML consumed by | ||
the clients, which could be web browsers, web crawlers, mobile clients or something | ||
else. | ||
The frontend is a [Next.js](https://nextjs.org/) application that is composed | ||
by two layers. | ||
|
||
## OpenTelemetry instrumentation | ||
1. Client side application. Which renders the components for the OTEL webstore. | ||
2. API layer. Connects the client to the backend services by exposing REST endpoints. | ||
|
||
### Initialization | ||
## Build Locally | ||
|
||
The OpenTelemetry SDK is initialized in `main` using the `InitTraceProvider` function. | ||
By running `docker compose up` at the root of the project you'll have access to the | ||
frontend client by going to <http://localhost:8080/>. | ||
|
||
```go | ||
func InitTracerProvider() *sdktrace.TracerProvider { | ||
ctx := context.Background() | ||
## Local development | ||
|
||
exporter, err := otlptracegrpc.New(ctx) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
tp := sdktrace.NewTracerProvider( | ||
sdktrace.WithSampler(sdktrace.AlwaysSample()), | ||
sdktrace.WithBatcher(exporter), | ||
) | ||
otel.SetTracerProvider(tp) | ||
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{})) | ||
return tp | ||
} | ||
``` | ||
|
||
Services should call `TraceProvider.Shutdown()` when the service is shutdown to | ||
ensure all spans are exported. | ||
This service makes that call as part of a deferred function in `main`. | ||
|
||
```go | ||
// Initialize OpenTelemetry Tracing | ||
tp := InitTracerProvider() | ||
defer func() { | ||
if err := tp.Shutdown(context.Background()); err != nil { | ||
log.Printf("Error shutting down tracer provider: %v", err) | ||
} | ||
}() | ||
``` | ||
|
||
### HTTP instrumentation | ||
|
||
This service receives HTTP requests, controlled by the gorilla/mux Router. | ||
The following routes are defined by the frontend: | ||
|
||
| Path | Method | Use | | ||
|-------------------|--------|-----------------------------------| | ||
| `/` | GET | Main index page | | ||
| `/cart` | GET | View Cart | | ||
| `/cart` | POST | Add to Cart | | ||
| `/cart/checkout` | POST | Place Order | | ||
| `/cart/empty` | POST | Empty Cart | | ||
| `/logout` | GET | Logout | | ||
| `/product/{id}` | GET | View Product | | ||
| `/setCurrency` | POST | Set Currency | | ||
| `/static/` | * | Static resources | | ||
| `/robots.txt` | * | Search engine response (disallow) | | ||
| `/_healthz` | * | Health check (ok) | | ||
|
||
These requests are instrumented in the main function as part of the router's definition. | ||
|
||
```go | ||
// Add OpenTelemetry instrumentation to incoming HTTP requests controlled by the gorilla/mux Router. | ||
r.Use(otelmux.Middleware("server")) | ||
``` | ||
Currently, the easiest way to run the frontend for local development is to execute | ||
|
||
### gRPC instrumentation | ||
|
||
This service will issue several outgoing gRPC calls, which have instrumentation | ||
hooks added in the `mustConnGRPC` function. | ||
|
||
```go | ||
func mustConnGRPC(ctx context.Context, conn **grpc.ClientConn, addr string) { | ||
// Add OpenTelemetry instrumentation to outgoing gRPC requests | ||
var err error | ||
ctx, cancel := context.WithTimeout(ctx, time.Second*3) | ||
defer cancel() | ||
*conn, err = grpc.DialContext(ctx, addr, | ||
grpc.WithTransportCredentials(insecure.NewCredentials()), | ||
grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), | ||
grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), | ||
) | ||
if err != nil { | ||
panic(errors.Wrapf(err, "grpc: failed to connect %s", addr)) | ||
} | ||
} | ||
``` | ||
|
||
### Service specific instrumentation attributes | ||
|
||
All requests incoming to the frontend service will receive the following attributes: | ||
|
||
- `app.session.id` | ||
- `app.request.id` | ||
- `app.currency` | ||
- `app.user.id` (when the user is present) | ||
|
||
These attributes are added in the `instrumentHandler` function (defined in the | ||
middleware.go file) which wraps all HTTP routes specified within the | ||
gorilla/mux router. | ||
Additional attributes are added within each handler's function as appropriate | ||
(ie: `app.cart.size`, `app.cart.total.price`). | ||
|
||
Adding attributes to existing auto-instrumented spans can be accomplished by | ||
getting the current span from context, then adding attributes to it. | ||
|
||
```go | ||
span := trace.SpanFromContext(r.Context()) | ||
span.SetAttributes( | ||
attribute.Int(instr.AppPrefix+"cart.size", cartSize(cart)), | ||
attribute.Int(instr.AppPrefix+"cart.items.count", len(items)), | ||
attribute.Float64(instr.AppPrefix+"cart.shipping.cost", shippingCostFloat), | ||
attribute.Float64(instr.AppPrefix+"cart.total.price", totalPriceFloat), | ||
) | ||
```shell | ||
docker compose run --service-ports -e NODE_ENV=development | ||
--volume $(pwd)/src/frontend:/app --volume $(pwd)/pb:/app/pb frontend sh | ||
``` | ||
|
||
When an error is encountered, the current span's status code and error message | ||
are set. | ||
from the root folder. | ||
|
||
```go | ||
// set span status on error | ||
span := trace.SpanFromContext(r.Context()) | ||
span.SetStatus(codes.Error, errMsg) | ||
``` | ||
It will start all of the required backend services | ||
and within the container simply run `npm run dev`. | ||
After that the app should be available at <http://localhost:8080/>. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import styled from 'styled-components'; | ||
import RouterLink from 'next/link'; | ||
|
||
export const Ad = styled.section` | ||
position: relative; | ||
background-color: ${({ theme }) => theme.colors.otelYellow}; | ||
font-size: ${({ theme }) => theme.sizes.dMedium}; | ||
text-align: center; | ||
padding: 48px; | ||
* { | ||
color: ${({ theme }) => theme.colors.white}; | ||
margin: 0; | ||
cursor: pointer; | ||
} | ||
`; | ||
|
||
export const Link = styled(RouterLink)` | ||
color: black; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { useAd } from '../../providers/Ad.provider'; | ||
import * as S from './Ad.styled'; | ||
|
||
const Ad = () => { | ||
const { | ||
adList: [{ text, redirectUrl } = { text: '', redirectUrl: '' }], | ||
} = useAd(); | ||
|
||
return ( | ||
<S.Ad> | ||
<S.Link href={redirectUrl}> | ||
<p>{text}</p> | ||
</S.Link> | ||
</S.Ad> | ||
); | ||
}; | ||
|
||
export default Ad; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from './Ad'; |
Oops, something went wrong.