diff --git a/Dockerfile b/Dockerfile index de15a6f..e38b4d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,24 +1,40 @@ -FROM golang:1.17.6-alpine - -MAINTAINER Zaid Albirawi - -WORKDIR /go/src/github.com/zalbiraw/go-api-test-service - -COPY go.mod go.mod -COPY helpers/ helpers/ -COPY services/ services/ - -RUN go mod tidy -RUN go mod vendor -RUN CGO_ENABLED=0 GO111MODULE=on go build -o services/rest/rest services/rest/rest/server.go -RUN CGO_ENABLED=0 GO111MODULE=on go build -o services/rest/users services/rest/users/server.go -RUN CGO_ENABLED=0 GO111MODULE=on go build -o services/rest/posts services/rest/posts/server.go -RUN CGO_ENABLED=0 GO111MODULE=on go build -o services/rest/comments services/rest/comments/server.go -RUN CGO_ENABLED=0 GO111MODULE=on go build -o services/graphql/users services/graphql/users/server.go -RUN CGO_ENABLED=0 GO111MODULE=on go build -o services/graphql/posts services/graphql/posts/server.go -RUN CGO_ENABLED=0 GO111MODULE=on go build -o services/graphql/comments services/graphql/comments/server.go -RUN CGO_ENABLED=0 GO111MODULE=on go build -o services/graphql/notifications services/graphql/notifications/server.go -RUN CGO_ENABLED=0 GO111MODULE=on go build -o services/graphql-subgraphs/users services/graphql-subgraphs/users/server.go -RUN CGO_ENABLED=0 GO111MODULE=on go build -o services/graphql-subgraphs/posts services/graphql-subgraphs/posts/server.go -RUN CGO_ENABLED=0 GO111MODULE=on go build -o services/graphql-subgraphs/comments services/graphql-subgraphs/comments/server.go -RUN CGO_ENABLED=0 GO111MODULE=on go build -o services/graphql-subgraphs/notifications services/graphql-subgraphs/notifications/server.go +# Stage 1: Build all Go binaries +FROM golang:1.23-alpine AS builder + +LABEL maintainer="Zaid Albirawi" + +# Set the working directory inside the container +WORKDIR /go/src/github.com/zalbiraw/go-api-test-service + +# Copy the go.mod and go.sum files for dependency caching +COPY go.mod go.sum ./ + +# Download dependencies +RUN go mod download + +# Copy the rest of the source code +COPY helpers/ helpers/ +COPY services/ services/ + +# Build all the Go binaries +RUN CGO_ENABLED=0 GO111MODULE=on go build -o /go/bin/rest-rest services/rest/rest/server.go +RUN CGO_ENABLED=0 GO111MODULE=on go build -o /go/bin/rest-users services/rest/users/server.go +RUN CGO_ENABLED=0 GO111MODULE=on go build -o /go/bin/rest-posts services/rest/posts/server.go +RUN CGO_ENABLED=0 GO111MODULE=on go build -o /go/bin/rest-comments services/rest/comments/server.go +RUN CGO_ENABLED=0 GO111MODULE=on go build -o /go/bin/graphql-users services/graphql/users/server.go +RUN CGO_ENABLED=0 GO111MODULE=on go build -o /go/bin/graphql-posts services/graphql/posts/server.go +RUN CGO_ENABLED=0 GO111MODULE=on go build -o /go/bin/graphql-comments services/graphql/comments/server.go +RUN CGO_ENABLED=0 GO111MODULE=on go build -o /go/bin/graphql-notifications services/graphql/notifications/server.go +RUN CGO_ENABLED=0 GO111MODULE=on go build -o /go/bin/graphql-subgraphs-users services/graphql-subgraphs/users/server.go +RUN CGO_ENABLED=0 GO111MODULE=on go build -o /go/bin/graphql-subgraphs-posts services/graphql-subgraphs/posts/server.go +RUN CGO_ENABLED=0 GO111MODULE=on go build -o /go/bin/graphql-subgraphs-comments services/graphql-subgraphs/comments/server.go +RUN CGO_ENABLED=0 GO111MODULE=on go build -o /go/bin/graphql-subgraphs-notifications services/graphql-subgraphs/notifications/server.go + +# Stage 2: Create the final lightweight image +FROM alpine:latest + +# Set the working directory +WORKDIR /root/ + +# Copy all the built binaries from the builder stage +COPY --from=builder /go/bin/* /usr/local/bin/ diff --git a/docker-compose.yml b/docker-compose.yml index c65deaf..2cced3c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3.9' services: rest: - image: zalbiraw/go-api-test-service:v3.0 + image: zalbiraw/go-api-test-service:v3.0.1 container_name: rest entrypoint: ./services/rest/rest/server @@ -12,7 +12,7 @@ services: - "3100:3100" users-rest: - image: zalbiraw/go-api-test-service:v3.0 + image: zalbiraw/go-api-test-service:v3.0.1 container_name: users-rest entrypoint: ./services/rest/users/server @@ -23,7 +23,7 @@ services: - "3101:3101" posts-rest: - image: zalbiraw/go-api-test-service:v3.0 + image: zalbiraw/go-api-test-service:v3.0.1 container_name: posts-rest entrypoint: ./services/rest/posts/server @@ -34,7 +34,7 @@ services: - "3102:3102" comments-rest: - image: zalbiraw/go-api-test-service:v3.0 + image: zalbiraw/go-api-test-service:v3.0.1 container_name: comments-rest entrypoint: ./services/rest/comments/server @@ -45,7 +45,7 @@ services: - "3103:3103" users-graph: - image: zalbiraw/go-api-test-service:v3.0 + image: zalbiraw/go-api-test-service:v3.0.1 container_name: users-graph entrypoint: ./services/graphql/users/server @@ -56,7 +56,7 @@ services: - "4101:4101" posts-graph: - image: zalbiraw/go-api-test-service:v3.0 + image: zalbiraw/go-api-test-service:v3.0.1 container_name: posts-graph entrypoint: ./services/graphql/posts/server @@ -67,7 +67,7 @@ services: - "4102:4102" comments-graph: - image: zalbiraw/go-api-test-service:v3.0 + image: zalbiraw/go-api-test-service:v3.0.1 container_name: comments-graph entrypoint: ./services/graphql/comments/server @@ -78,7 +78,7 @@ services: - "4103:4103" notifications-graph: - image: zalbiraw/go-api-test-service:v3.0 + image: zalbiraw/go-api-test-service:v3.0.1 container_name: notifications-graph entrypoint: ./services/graphql/notifications/server @@ -89,7 +89,7 @@ services: - "4104:4104" users-subgraph: - image: zalbiraw/go-api-test-service:v3.0 + image: zalbiraw/go-api-test-service:v3.0.1 container_name: users-subgraph entrypoint: ./services/graphql-subgraphs/users/server @@ -100,7 +100,7 @@ services: - "4201:4201" posts-subgraph: - image: zalbiraw/go-api-test-service:v3.0 + image: zalbiraw/go-api-test-service:v3.0.1 container_name: posts-subgraph entrypoint: ./services/graphql-subgraphs/posts/server @@ -111,7 +111,7 @@ services: - "4202:4202" comments-subgraph: - image: zalbiraw/go-api-test-service:v3.0 + image: zalbiraw/go-api-test-service:v3.0.1 container_name: comments-subgraph entrypoint: ./services/graphql-subgraphs/comments/server @@ -122,7 +122,7 @@ services: - "4203:4203" notifications-subgraph: - image: zalbiraw/go-api-test-service:v3.0 + image: zalbiraw/go-api-test-service:v3.0.1 container_name: notifications-subgraph entrypoint: ./services/graphql-subgraphs/notifications/server diff --git a/go.mod b/go.mod index c334fb8..fb74309 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/zalbiraw/go-api-test-service -go 1.17 +go 1.23 require ( github.com/99designs/gqlgen v0.17.13 @@ -12,11 +12,31 @@ require ( require ( github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/logrusorgru/aurora/v3 v3.0.0 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect - golang.org/x/sys v0.0.0-20220412071739-889880a91fd5 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect + go.opentelemetry.io/otel/sdk v1.29.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/text v0.17.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 8e01106..7c57c0e 100644 --- a/go.sum +++ b/go.sum @@ -8,18 +8,31 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNg github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs= github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM= @@ -50,6 +63,22 @@ github.com/vektah/gqlparser/v2 v2.4.6 h1:Yjzp66g6oVq93Jihbi0qhGnf/6zIWjcm8H6gA27 github.com/vektah/gqlparser/v2 v2.4.6/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 h1:dIIDULZJpgdiHz5tXrTgKIMLkus6jEFa7x5SOKcyR7E= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 h1:JAv0Jwtl01UFiyWZEMiJZBiTlv5A50zNs8lsthXqIio= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0/go.mod h1:QNKLmUEAq2QUbPQUfvw4fmv0bgbK7UlOSFCnXyfvSNc= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= +go.opentelemetry.io/otel/sdk v1.29.0 h1:vkqKjk7gwhS8VaWb0POZKmIEDimRCMsopNYnriHyryo= +go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -59,6 +88,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -71,11 +102,15 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412071739-889880a91fd5 h1:NubxfvTRuNb4RVzWrIDAUzUvREH1HkCD4JjyQTSG9As= golang.org/x/sys v0.0.0-20220412071739-889880a91fd5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= @@ -84,8 +119,16 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= +google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/loremipsum.v1 v1.1.0 h1:j6TAjs6Db5AMfLwTzs51Kq4Qx7dCufw/IJ0hpMbjU8U= @@ -98,3 +141,4 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/services/graphql/comments/graph/schema.resolvers.go b/services/graphql/comments/graph/schema.resolvers.go index 5f51acb..f63e7ff 100644 --- a/services/graphql/comments/graph/schema.resolvers.go +++ b/services/graphql/comments/graph/schema.resolvers.go @@ -5,27 +5,50 @@ package graph import ( "context" + "fmt" "strconv" "github.com/zalbiraw/go-api-test-service/services/graphql/comments/graph/model" "github.com/zalbiraw/go-api-test-service/services/graphql/comments/helpers" + + "go.opentelemetry.io/otel" ) // Comment is the resolver for the comment field. func (r *queryResolver) Comment(ctx context.Context, id string) (*model.Comment, error) { + tracer := otel.Tracer("graphql-api") + ctx, span := tracer.Start(ctx, "CommentResolver") + defer span.End() + commentId, err := strconv.Atoi(id) if nil != err { + span.RecordError(err) return nil, err } comments := helpers.GetComments() + if commentId <= 0 || commentId > len(comments) { + err := fmt.Errorf("comment not found") + span.RecordError(err) + return nil, err + } + + span.AddEvent(fmt.Sprintf("Fetched comment successfully, (%s, %s)", comments[commentId].Name, comments[commentId].Email)) return comments[commentId-1], nil } // Comments is the resolver for the comments field. func (r *queryResolver) Comments(ctx context.Context) ([]*model.Comment, error) { - return helpers.GetComments(), nil + // Create a new span for tracing + tracer := otel.Tracer("graphql-api") + ctx, span := tracer.Start(ctx, "CommentsResolver") + defer span.End() + + comments := helpers.GetComments() + + span.AddEvent("Fetched comments successfully") + return comments, nil } // Query returns QueryResolver implementation. diff --git a/services/graphql/comments/server.go b/services/graphql/comments/server.go index 415f68a..95949e0 100644 --- a/services/graphql/comments/server.go +++ b/services/graphql/comments/server.go @@ -2,18 +2,55 @@ package main import ( - "github.com/99designs/gqlgen/graphql/handler" + "context" "log" "net/http" "os" + "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/playground" "github.com/zalbiraw/go-api-test-service/services/graphql/comments/graph" "github.com/zalbiraw/go-api-test-service/services/graphql/comments/helpers" + + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "go.opentelemetry.io/otel/sdk/resource" + "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) -const defaultPort = "4103" +const defaultPort = "4101" + +func initTracer() func() { + ctx := context.Background() + + // Set up OTLP HTTP exporter + exporter, err := otlptracehttp.New(ctx) + if err != nil { + log.Fatalf("failed to create OTLP trace exporter: %v", err) + } + + // Create a new trace provider + tp := trace.NewTracerProvider( + trace.WithBatcher(exporter), + trace.WithResource(resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("comments-graphql-service"), + )), + ) + + // Register as global trace provider + otel.SetTracerProvider(tp) + + return func() { + err := tp.Shutdown(ctx) + if err != nil { + log.Fatalf("failed to shutdown TracerProvider: %v", err) + } + } +} func main() { port := os.Getenv("PORT") @@ -21,14 +58,17 @@ func main() { port = defaultPort } - err := helpers.LoadComments() + shutdown := initTracer() + defer shutdown() + err := helpers.LoadComments() if nil != err { panic("Unable to load comments.") } - http.Handle("/", playground.Handler("GraphQL playground", "/query")) - http.Handle("/query", handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))) + // Wrap HTTP handlers with OpenTelemetry instrumentation + http.Handle("/", otelhttp.NewHandler(playground.Handler("GraphQL playground", "/query"), "Playground")) + http.Handle("/query", otelhttp.NewHandler(handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}})), "GraphQL Query")) log.Printf("connect to http://localhost:%s/ for GraphQL playground", port) log.Fatal(http.ListenAndServe(":"+port, nil)) diff --git a/services/graphql/posts/graph/schema.resolvers.go b/services/graphql/posts/graph/schema.resolvers.go index 574ab41..a9fda33 100644 --- a/services/graphql/posts/graph/schema.resolvers.go +++ b/services/graphql/posts/graph/schema.resolvers.go @@ -5,27 +5,50 @@ package graph import ( "context" + "fmt" "strconv" "github.com/zalbiraw/go-api-test-service/services/graphql/posts/graph/model" "github.com/zalbiraw/go-api-test-service/services/graphql/posts/helpers" + + "go.opentelemetry.io/otel" ) // Post is the resolver for the post field. func (r *queryResolver) Post(ctx context.Context, id string) (*model.Post, error) { + tracer := otel.Tracer("graphql-api") + ctx, span := tracer.Start(ctx, "PostResolver") + defer span.End() + postId, err := strconv.Atoi(id) if nil != err { + span.RecordError(err) return nil, err } posts := helpers.GetPosts() + if postId <= 0 || postId > len(posts) { + err := fmt.Errorf("post not found") + span.RecordError(err) + return nil, err + } + + span.AddEvent(fmt.Sprintf("Fetched post successfully, (%s, %s)", posts[postId].ID, posts[postId].UserID)) return posts[postId-1], nil } // Posts is the resolver for the posts field. func (r *queryResolver) Posts(ctx context.Context) ([]*model.Post, error) { - return helpers.GetPosts(), nil + // Create a new span for tracing + tracer := otel.Tracer("graphql-api") + ctx, span := tracer.Start(ctx, "PostsResolver") + defer span.End() + + posts := helpers.GetPosts() + + span.AddEvent("Fetched posts successfully") + return posts, nil } // Query returns QueryResolver implementation. diff --git a/services/graphql/posts/server.go b/services/graphql/posts/server.go index cfcf592..31c4872 100644 --- a/services/graphql/posts/server.go +++ b/services/graphql/posts/server.go @@ -2,18 +2,55 @@ package main import ( - "github.com/99designs/gqlgen/graphql/handler" + "context" "log" "net/http" "os" + "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/playground" "github.com/zalbiraw/go-api-test-service/services/graphql/posts/graph" "github.com/zalbiraw/go-api-test-service/services/graphql/posts/helpers" + + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "go.opentelemetry.io/otel/sdk/resource" + "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) -const defaultPort = "4102" +const defaultPort = "4101" + +func initTracer() func() { + ctx := context.Background() + + // Set up OTLP HTTP exporter + exporter, err := otlptracehttp.New(ctx) + if err != nil { + log.Fatalf("failed to create OTLP trace exporter: %v", err) + } + + // Create a new trace provider + tp := trace.NewTracerProvider( + trace.WithBatcher(exporter), + trace.WithResource(resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("posts-graphql-service"), + )), + ) + + // Register as global trace provider + otel.SetTracerProvider(tp) + + return func() { + err := tp.Shutdown(ctx) + if err != nil { + log.Fatalf("failed to shutdown TracerProvider: %v", err) + } + } +} func main() { port := os.Getenv("PORT") @@ -21,14 +58,17 @@ func main() { port = defaultPort } - err := helpers.LoadPosts() + shutdown := initTracer() + defer shutdown() + err := helpers.LoadPosts() if nil != err { panic("Unable to load posts.") } - http.Handle("/", playground.Handler("GraphQL playground", "/query")) - http.Handle("/query", handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))) + // Wrap HTTP handlers with OpenTelemetry instrumentation + http.Handle("/", otelhttp.NewHandler(playground.Handler("GraphQL playground", "/query"), "Playground")) + http.Handle("/query", otelhttp.NewHandler(handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}})), "GraphQL Query")) log.Printf("connect to http://localhost:%s/ for GraphQL playground", port) log.Fatal(http.ListenAndServe(":"+port, nil)) diff --git a/services/graphql/users/graph/schema.resolvers.go b/services/graphql/users/graph/schema.resolvers.go index 52b618d..00a00d9 100644 --- a/services/graphql/users/graph/schema.resolvers.go +++ b/services/graphql/users/graph/schema.resolvers.go @@ -5,27 +5,50 @@ package graph import ( "context" + "fmt" "strconv" "github.com/zalbiraw/go-api-test-service/services/graphql/users/graph/model" "github.com/zalbiraw/go-api-test-service/services/graphql/users/helpers" + + "go.opentelemetry.io/otel" ) // User is the resolver for the user field. func (r *queryResolver) User(ctx context.Context, id string) (*model.User, error) { + tracer := otel.Tracer("graphql-api") + ctx, span := tracer.Start(ctx, "UserResolver") + defer span.End() + userId, err := strconv.Atoi(id) if nil != err { + span.RecordError(err) return nil, err } users := helpers.GetUsers() + if userId <= 0 || userId > len(users) { + err := fmt.Errorf("user not found") + span.RecordError(err) + return nil, err + } + + span.AddEvent(fmt.Sprintf("Fetched user successfully, (%s, %s)", users[userId].Name, users[userId].Email)) return users[userId-1], nil } // Users is the resolver for the users field. func (r *queryResolver) Users(ctx context.Context) ([]*model.User, error) { - return helpers.GetUsers(), nil + // Create a new span for tracing + tracer := otel.Tracer("graphql-api") + ctx, span := tracer.Start(ctx, "UsersResolver") + defer span.End() + + users := helpers.GetUsers() + + span.AddEvent("Fetched users successfully") + return users, nil } // Query returns QueryResolver implementation. diff --git a/services/graphql/users/server.go b/services/graphql/users/server.go index 0855439..c5b8a84 100644 --- a/services/graphql/users/server.go +++ b/services/graphql/users/server.go @@ -2,32 +2,74 @@ package main import ( - "github.com/99designs/gqlgen/graphql/handler" + "context" "log" "net/http" "os" + "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/playground" + "github.com/zalbiraw/go-api-test-service/services/graphql/users/graph" "github.com/zalbiraw/go-api-test-service/services/graphql/users/helpers" + + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "go.opentelemetry.io/otel/sdk/resource" + "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) const defaultPort = "4101" +func initTracer() func() { + ctx := context.Background() + + // Set up OTLP HTTP exporter + exporter, err := otlptracehttp.New(ctx) + if err != nil { + log.Fatalf("failed to create OTLP trace exporter: %v", err) + } + + // Create a new trace provider + tp := trace.NewTracerProvider( + trace.WithBatcher(exporter), + trace.WithResource(resource.NewWithAttributes( + semconv.SchemaURL, + semconv.ServiceNameKey.String("users-graphql-service"), + )), + ) + + // Register as global trace provider + otel.SetTracerProvider(tp) + + return func() { + err := tp.Shutdown(ctx) + if err != nil { + log.Fatalf("failed to shutdown TracerProvider: %v", err) + } + } +} + func main() { port := os.Getenv("PORT") if port == "" { port = defaultPort } - err := helpers.LoadUsers() + shutdown := initTracer() + defer shutdown() + err := helpers.LoadUsers() if nil != err { panic("Unable to load users.") } - http.Handle("/", playground.Handler("GraphQL playground", "/query")) - http.Handle("/query", handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))) + // Wrap HTTP handlers with OpenTelemetry instrumentation + http.Handle("/", otelhttp.NewHandler(playground.Handler("GraphQL playground", "/query"), "Playground")) + http.Handle("/query", otelhttp.NewHandler(handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}})), "GraphQL Query")) + log.Printf("connect to http://localhost:%s/ for GraphQL playground", port) log.Fatal(http.ListenAndServe(":"+port, nil)) }