diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..37d6738 Binary files /dev/null and b/.DS_Store differ diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7661253 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +**/node_modules/ +**/dist/ +k8s/ diff --git a/Dockerfile b/Dockerfile index 14461f9..006ef57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,25 @@ -# Build stage -FROM golang:1.25-alpine AS builder +# UI build stage +FROM node:alpine AS ui-builder + +WORKDIR /app + +COPY otel-ui/ . + +RUN npm install && npm run build + +# Go build stage +FROM golang:1.25-alpine AS go-builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download -COPY . . +COPY cmd/ ./cmd +COPY internal/ ./internal + +# Copy built UI dist +COPY --from=ui-builder /app/dist ./otel-ui/dist RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -o /go-otel ./cmd/server @@ -17,9 +30,9 @@ RUN apk --no-cache add ca-certificates WORKDIR /root/ -COPY --from=builder /go-otel . -COPY --from=builder /app/index.html . +COPY --from=go-builder /go-otel . +COPY --from=go-builder /app/otel-ui/dist ./dist EXPOSE 8080 -CMD ["./go-otel"] \ No newline at end of file +CMD ["./go-otel"] diff --git a/cmd/server/main.go b/cmd/server/main.go index 1eafae0..3ff694d 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -7,6 +7,7 @@ import ( "log" "net" "net/http" + "strings" "git.tornberg.me/go-otel/internal/collector" "git.tornberg.me/go-otel/internal/websocket" @@ -150,10 +151,9 @@ func main() { // WebSocket server for visualization http.HandleFunc("/ws", wsServer.HandleConnections) - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write([]byte("OTel Debug Receiver is running")) - }) + + // Serve static files with SPA fallback + http.Handle("/", spaHandler(http.Dir("./dist"))) log.Printf("Starting HTTP server on port 8080") log.Printf("OTLP HTTP endpoints:") @@ -345,3 +345,18 @@ func handleHistoryByType(coll *collector.Collector, dataType string) http.Handle } } } + +func spaHandler(root http.FileSystem) http.Handler { + fileServer := http.FileServer(root) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + path := r.URL.Path + // Skip API, WebSocket, and OTLP endpoints + if !strings.HasPrefix(path, "/api") && !strings.HasPrefix(path, "/ws") && !strings.HasPrefix(path, "/v1") { + if _, err := root.Open(path); err != nil { + // File does not exist, serve index.html + r.URL.Path = "/" + } + } + fileServer.ServeHTTP(w, r) + }) +} diff --git a/internal/collector/collector.go b/internal/collector/collector.go index 8aba6d2..c318c8a 100644 --- a/internal/collector/collector.go +++ b/internal/collector/collector.go @@ -133,7 +133,6 @@ func (c *Collector) ConsumeLogs(ctx context.Context, ld plog.Logs) error { c.broadcaster.Broadcast(&entry) - //c.broadcaster.Broadcast(buf) return nil } diff --git a/test-client/go.mod b/test-client/go.mod deleted file mode 100644 index 795188a..0000000 --- a/test-client/go.mod +++ /dev/null @@ -1,37 +0,0 @@ -module test-client - -go 1.25.1 - -require ( - go.opentelemetry.io/collector/pdata v1.45.0 - go.opentelemetry.io/otel v1.38.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 - go.opentelemetry.io/otel/sdk v1.38.0 - go.opentelemetry.io/otel/trace v1.38.0 -) - -require ( - github.com/cenkalti/backoff/v5 v5.0.3 // indirect - github.com/go-logr/logr v1.4.3 // 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.27.2 // indirect - github.com/hashicorp/go-version v1.7.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/collector/featuregate v1.45.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/proto/otlp v1.7.1 // indirect - go.uber.org/multierr v1.11.0 // indirect - golang.org/x/net v0.43.0 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/text v0.28.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect - google.golang.org/grpc v1.76.0 // indirect - google.golang.org/protobuf v1.36.10 // indirect -) diff --git a/test-client/go.sum b/test-client/go.sum deleted file mode 100644 index 42acc43..0000000 --- a/test-client/go.sum +++ /dev/null @@ -1,87 +0,0 @@ -github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= -github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= -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/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= -github.com/go-logr/logr v1.4.3/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.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -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/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= -github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= -github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= -github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/collector/featuregate v1.45.0 h1:D06hpf1F2KzKC+qXLmVv5e8IZpgCyZVeVVC8iOQxVmw= -go.opentelemetry.io/collector/featuregate v1.45.0/go.mod h1:d0tiRzVYrytB6LkcYgz2ESFTv7OktRPQe0QEQcPt1L4= -go.opentelemetry.io/collector/pdata v1.45.0 h1:q4XaISpeX640BcwXwb2mKOVw/gb67r22HjGWl8sbWsk= -go.opentelemetry.io/collector/pdata v1.45.0/go.mod h1:5q2f001YhwMQO8QvpFhCOa4Cq/vtwX9W4HRMsXkU/nE= -go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= -go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= -go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= -go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= -go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= -go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= -go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= -go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= -go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= -go.opentelemetry.io/proto/slim/otlp v1.8.0 h1:afcLwp2XOeCbGrjufT1qWyruFt+6C9g5SOuymrSPUXQ= -go.opentelemetry.io/proto/slim/otlp v1.8.0/go.mod h1:Yaa5fjYm1SMCq0hG0x/87wV1MP9H5xDuG/1+AhvBcsI= -go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.1.0 h1:Uc+elixz922LHx5colXGi1ORbsW8DTIGM+gg+D9V7HE= -go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.1.0/go.mod h1:VyU6dTWBWv6h9w/+DYgSZAPMabWbPTFTuxp25sM8+s0= -go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.1.0 h1:i8YpvWGm/Uq1koL//bnbJ/26eV3OrKWm09+rDYo7keU= -go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.1.0/go.mod h1:pQ70xHY/ZVxNUBPn+qUWPl8nwai87eWdqL3M37lNi9A= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= -gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= -gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY= -google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc= -google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A= -google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/test-client/main.go b/test-client/main.go deleted file mode 100644 index bb52575..0000000 --- a/test-client/main.go +++ /dev/null @@ -1,224 +0,0 @@ -package main - -import ( - "bytes" - "context" - "fmt" - "log" - "net/http" - "time" - - "go.opentelemetry.io/collector/pdata/pcommon" - "go.opentelemetry.io/collector/pdata/plog" - "go.opentelemetry.io/collector/pdata/pmetric" - "go.opentelemetry.io/otel" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" - "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" - "go.opentelemetry.io/otel/sdk/resource" - sdktrace "go.opentelemetry.io/otel/sdk/trace" - semconv "go.opentelemetry.io/otel/semconv/v1.17.0" - "go.opentelemetry.io/otel/trace" -) - -func main() { - ctx := context.Background() - - fmt.Println("Testing OTLP Debug Receiver...") - fmt.Println("Make sure the receiver is running on ports 8080 (HTTP) and 4317 (gRPC)") - fmt.Println() - - // Test HTTP endpoint - fmt.Println("Testing HTTP endpoint...") - testHTTPTraces(ctx) - - time.Sleep(1 * time.Second) - - // Test gRPC endpoint - fmt.Println("Testing gRPC endpoint...") - testGRPCTraces(ctx) - - time.Sleep(1 * time.Second) - - // Test HTTP metrics - fmt.Println("Testing HTTP metrics...") - testHTTPMetrics() - - time.Sleep(1 * time.Second) - - // Test HTTP logs - fmt.Println("Testing HTTP logs...") - testHTTPLogs() - - fmt.Println() - fmt.Println("Test completed! Check the receiver logs and web interface at http://localhost:8080") - fmt.Println("You should see traces, metrics, and logs from both HTTP and gRPC clients.") -} - -func testHTTPTraces(ctx context.Context) { - // Create OTLP HTTP exporter - exporter, err := otlptracehttp.New(ctx, - otlptracehttp.WithEndpoint("localhost:8080"), - otlptracehttp.WithInsecure(), - ) - if err != nil { - log.Fatalf("failed to create HTTP exporter: %v", err) - } - - // Create tracer provider - tp := sdktrace.NewTracerProvider( - sdktrace.WithBatcher(exporter), - sdktrace.WithResource(resource.NewWithAttributes( - semconv.SchemaURL, - semconv.ServiceNameKey.String("test-client-http"), - semconv.ServiceVersionKey.String("1.0.0"), - )), - ) - defer func() { - if err := tp.Shutdown(ctx); err != nil { - log.Printf("failed to shutdown tracer provider: %v", err) - } - }() - - otel.SetTracerProvider(tp) - - // Create tracer - tracer := tp.Tracer("test-tracer") - - // Create some sample spans - for i := 0; i < 3; i++ { - _, span := tracer.Start(ctx, fmt.Sprintf("http-test-span-%d", i), - trace.WithAttributes( - attribute.String("test.key", fmt.Sprintf("test-value-%d", i)), - attribute.Int("test.number", i), - ), - ) - - // Add an event - span.AddEvent("test event", trace.WithAttributes( - attribute.String("event.key", "event.value"), - )) - - // Simulate some work - time.Sleep(10 * time.Millisecond) - - span.End() - } - - // Force flush - if err := tp.ForceFlush(ctx); err != nil { - log.Printf("failed to flush: %v", err) - } - - fmt.Println("HTTP traces sent successfully") -} - -func testGRPCTraces(ctx context.Context) { - // Create OTLP gRPC exporter - exporter, err := otlptracegrpc.New(ctx, - otlptracegrpc.WithEndpoint("localhost:4317"), - otlptracegrpc.WithInsecure(), - ) - if err != nil { - log.Fatalf("failed to create gRPC exporter: %v", err) - } - - // Create tracer provider - tp := sdktrace.NewTracerProvider( - sdktrace.WithBatcher(exporter), - sdktrace.WithResource(resource.NewWithAttributes( - semconv.SchemaURL, - semconv.ServiceNameKey.String("test-client-grpc"), - semconv.ServiceVersionKey.String("1.0.0"), - )), - ) - defer func() { - if err := tp.Shutdown(ctx); err != nil { - log.Printf("failed to shutdown tracer provider: %v", err) - } - }() - - otel.SetTracerProvider(tp) - - // Create tracer - tracer := tp.Tracer("test-tracer-grpc") - - // Create some sample spans - for i := 0; i < 3; i++ { - _, span := tracer.Start(ctx, fmt.Sprintf("grpc-test-span-%d", i), - trace.WithAttributes( - attribute.String("test.key", fmt.Sprintf("grpc-test-value-%d", i)), - attribute.Int("test.number", i*10), - ), - ) - - // Add an event - span.AddEvent("grpc test event", trace.WithAttributes( - attribute.String("grpc.event.key", "grpc.event.value"), - )) - - // Simulate some work - time.Sleep(10 * time.Millisecond) - - span.End() - } - - // Force flush - if err := tp.ForceFlush(ctx); err != nil { - log.Printf("failed to flush: %v", err) - } - - fmt.Println("gRPC traces sent successfully") -} - -func testHTTPMetrics() { - md := pmetric.NewMetrics() - resourceMetrics := md.ResourceMetrics().AppendEmpty() - resourceMetrics.Resource().Attributes().PutStr("service.name", "test-client-metric") - scopeMetrics := resourceMetrics.ScopeMetrics().AppendEmpty() - scopeMetrics.Scope().SetName("test-meter") - metric := scopeMetrics.Metrics().AppendEmpty() - metric.SetName("test_counter") - gauge := metric.SetEmptyGauge() - dataPoint := gauge.DataPoints().AppendEmpty() - dataPoint.SetIntValue(42) - dataPoint.Attributes().PutStr("test.key", "test-value") - marshaler := &pmetric.ProtoMarshaler{} - buf, err := marshaler.MarshalMetrics(md) - if err != nil { - log.Printf("failed to marshal metrics: %v", err) - return - } - resp, err := http.Post("http://localhost:8080/v1/metrics", "application/x-protobuf", bytes.NewReader(buf)) - if err != nil { - log.Printf("failed to post metrics: %v", err) - return - } - resp.Body.Close() - fmt.Println("HTTP metrics sent successfully") -} - -func testHTTPLogs() { - ld := plog.NewLogs() - resourceLogs := ld.ResourceLogs().AppendEmpty() - resourceLogs.Resource().Attributes().PutStr("service.name", "test-client-log") - scopeLogs := resourceLogs.ScopeLogs().AppendEmpty() - scopeLogs.Scope().SetName("test-logger") - logRecord := scopeLogs.LogRecords().AppendEmpty() - logRecord.Body().SetStr("test log message") - logRecord.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) - logRecord.Attributes().PutStr("test.key", "test-value") - marshaler := &plog.ProtoMarshaler{} - buf, err := marshaler.MarshalLogs(ld) - if err != nil { - log.Printf("failed to marshal logs: %v", err) - return - } - resp, err := http.Post("http://localhost:8080/v1/logs", "application/x-protobuf", bytes.NewReader(buf)) - if err != nil { - log.Printf("failed to post logs: %v", err) - return - } - resp.Body.Close() - fmt.Println("HTTP logs sent successfully") -}