Skip to content

Commit 659c7d3

Browse files
committed
Otel for GCP
1 parent d542978 commit 659c7d3

File tree

4 files changed

+63
-21
lines changed

4 files changed

+63
-21
lines changed

backend/.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ OTEL_EXPORTER_ENDPOINT=localhost:4317
4343
OTEL_EXPORTER_INSECURE=true
4444
OTEL_SAMPLING_RATIO=1.0
4545

46+
# For Google Cloud Trace (Cloud Run), use:
47+
# OTEL_EXPORTER_ENDPOINT=cloudtrace.googleapis.com:443
48+
# OTEL_EXPORTER_INSECURE=false
49+
# GOOGLE_CLOUD_PROJECT is auto-set by Cloud Run
50+
4651
# Database Query Logging
4752
# Enable detailed SQL query logging (note: replaces OTEL database tracing when enabled)
4853
DB_LOG_QUERIES=false

backend/go.mod

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,15 @@ require (
3232
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0
3333
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0
3434
go.opentelemetry.io/otel/sdk v1.38.0
35+
go.opentelemetry.io/otel/trace v1.38.0
36+
golang.org/x/oauth2 v0.32.0
3537
golang.org/x/text v0.31.0
36-
google.golang.org/grpc v1.75.0
38+
google.golang.org/grpc v1.77.0
3739
)
3840

3941
require (
4042
cel.dev/expr v0.24.0 // indirect
43+
cloud.google.com/go/compute/metadata v0.9.0 // indirect
4144
filippo.io/edwards25519 v1.1.0 // indirect
4245
github.com/ClickHouse/ch-go v0.67.0 // indirect
4346
github.com/ClickHouse/clickhouse-go/v2 v2.40.1 // indirect
@@ -145,10 +148,9 @@ require (
145148
github.com/ydb-platform/ydb-go-genproto v0.0.0-20241112172322-ea1f63298f77 // indirect
146149
github.com/ydb-platform/ydb-go-sdk/v3 v3.108.1 // indirect
147150
github.com/ziutek/mymysql v1.5.4 // indirect
148-
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
151+
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
149152
go.opentelemetry.io/contrib v1.36.0 // indirect
150153
go.opentelemetry.io/otel/metric v1.38.0 // indirect
151-
go.opentelemetry.io/otel/trace v1.38.0 // indirect
152154
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
153155
go.uber.org/atomic v1.11.0 // indirect
154156
go.uber.org/multierr v1.11.0 // indirect
@@ -162,9 +164,9 @@ require (
162164
golang.org/x/sys v0.38.0 // indirect
163165
golang.org/x/time v0.12.0 // indirect
164166
golang.org/x/tools v0.38.0 // indirect
165-
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
166-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
167-
google.golang.org/protobuf v1.36.9 // indirect
167+
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect
168+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect
169+
google.golang.org/protobuf v1.36.10 // indirect
168170
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
169171
gopkg.in/yaml.v3 v3.0.1 // indirect
170172
howett.net/plist v1.0.1 // indirect

backend/go.sum

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
22
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
33
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
44
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
5+
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
6+
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
57
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
68
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
79
github.com/99designs/gqlgen v0.17.81 h1:kCkN/xVyRb5rEQpuwOHRTYq83i0IuTQg9vdIiwEerTs=
@@ -402,8 +404,8 @@ github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Br
402404
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
403405
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
404406
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
405-
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
406-
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
407+
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
408+
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
407409
go.opentelemetry.io/contrib v1.36.0 h1:ZeE8MRl6bAmxcjZeznBfqTe6syNvMKdxdBMzv6fDV94=
408410
go.opentelemetry.io/contrib v1.36.0/go.mod h1:V0PijCkYR5XurE5ytnNJuqWMXPW60jJTPXOiKj6nvhI=
409411
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.63.0 h1:5kSIJ0y8ckZZKoDhZHdVtcyjVi6rXyAwyaR8mp4zLbg=
@@ -480,6 +482,8 @@ golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
480482
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
481483
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
482484
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
485+
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
486+
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
483487
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
484488
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
485489
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -536,19 +540,19 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA
536540
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
537541
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
538542
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
539-
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
540-
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
541-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
542-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
543+
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4=
544+
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo=
545+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk=
546+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
543547
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
544548
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
545549
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
546550
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
547551
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
548552
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
549553
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
550-
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
551-
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
554+
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
555+
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
552556
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
553557
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
554558
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -563,8 +567,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
563567
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
564568
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
565569
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
566-
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
567-
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
570+
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
571+
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
568572
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
569573
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
570574
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=

backend/internal/otel/tracer.go

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"log/slog"
7+
"os"
78

89
"go.opentelemetry.io/otel"
910
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
@@ -12,7 +13,10 @@ import (
1213
"go.opentelemetry.io/otel/sdk/resource"
1314
sdktrace "go.opentelemetry.io/otel/sdk/trace"
1415
semconv "go.opentelemetry.io/otel/semconv/v1.21.0"
16+
"golang.org/x/oauth2/google"
1517
"google.golang.org/grpc"
18+
"google.golang.org/grpc/credentials"
19+
grpcoauth "google.golang.org/grpc/credentials/oauth"
1620
"google.golang.org/grpc/credentials/insecure"
1721
)
1822

@@ -39,13 +43,25 @@ func InitTracer(ctx context.Context, cfg Config) (*TracerProvider, error) {
3943
return nil, nil
4044
}
4145

42-
// Create resource with service information
43-
res, err := resource.New(ctx,
46+
// Build resource attributes
47+
resourceAttrs := []resource.Option{
4448
resource.WithAttributes(
4549
semconv.ServiceName(cfg.ServiceName),
4650
semconv.ServiceVersion(cfg.ServiceVersion),
4751
),
48-
)
52+
}
53+
54+
// Add GCP cloud attributes if project ID is available
55+
gcpProjectID := os.Getenv("GOOGLE_CLOUD_PROJECT")
56+
if gcpProjectID != "" {
57+
resourceAttrs = append(resourceAttrs, resource.WithAttributes(
58+
semconv.CloudProviderGCP,
59+
semconv.CloudAccountID(gcpProjectID),
60+
))
61+
}
62+
63+
// Create resource with service information
64+
res, err := resource.New(ctx, resourceAttrs...)
4965
if err != nil {
5066
return nil, fmt.Errorf("failed to create resource: %w", err)
5167
}
@@ -60,6 +76,17 @@ func InitTracer(ctx context.Context, cfg Config) (*TracerProvider, error) {
6076
otlptracegrpc.WithInsecure(),
6177
otlptracegrpc.WithDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
6278
)
79+
} else {
80+
// Use TLS with Google Application Default Credentials
81+
tokenSource, err := google.DefaultTokenSource(ctx, "https://www.googleapis.com/auth/trace.append")
82+
if err != nil {
83+
return nil, fmt.Errorf("failed to get Google default token source: %w", err)
84+
}
85+
opts = append(opts,
86+
otlptracegrpc.WithDialOption(grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, ""))),
87+
otlptracegrpc.WithDialOption(grpc.WithPerRPCCredentials(grpcoauth.TokenSource{TokenSource: tokenSource})),
88+
)
89+
slog.Info("OpenTelemetry: using Google Cloud credentials")
6390
}
6491

6592
exporter, err := otlptrace.New(ctx, otlptracegrpc.NewClient(opts...))
@@ -98,12 +125,16 @@ func InitTracer(ctx context.Context, cfg Config) (*TracerProvider, error) {
98125
propagation.Baggage{},
99126
))
100127

101-
slog.Info("OpenTelemetry tracer initialized successfully",
128+
logAttrs := []any{
102129
"service", cfg.ServiceName,
103130
"version", cfg.ServiceVersion,
104131
"endpoint", cfg.ExporterEndpoint,
105132
"insecure", cfg.ExporterInsecure,
106-
)
133+
}
134+
if gcpProjectID != "" {
135+
logAttrs = append(logAttrs, "gcp_project", gcpProjectID)
136+
}
137+
slog.Info("OpenTelemetry tracer initialized successfully", logAttrs...)
107138

108139
return &TracerProvider{
109140
provider: provider,

0 commit comments

Comments
 (0)