From dc76c619fa1b158c9558e24a926d4820f8a67ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Thu, 21 Sep 2023 13:14:50 +0200 Subject: [PATCH 01/14] Add dice example --- .github/dependabot.yml | 9 ++++ .gitignore | 1 + CHANGELOG.md | 4 ++ example/dice/dice.go | 105 +++++++++++++++++++++++++++++++++++++ example/dice/go.mod | 35 +++++++++++++ example/dice/go.sum | 16 ++++++ example/dice/otel.go | 116 +++++++++++++++++++++++++++++++++++++++++ versions.yaml | 1 + 8 files changed, 287 insertions(+) create mode 100644 example/dice/dice.go create mode 100644 example/dice/go.mod create mode 100644 example/dice/go.sum create mode 100644 example/dice/otel.go diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 555decd4daf..f4c687ce090 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -64,6 +64,15 @@ updates: schedule: interval: weekly day: sunday + - package-ecosystem: gomod + directory: /example/dice + labels: + - dependencies + - go + - Skip Changelog + schedule: + interval: weekly + day: sunday - package-ecosystem: gomod directory: /example/fib labels: diff --git a/.gitignore b/.gitignore index aa699376225..f3355c852be 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ go.work.sum gen/ +/example/dice/dice /example/fib/fib /example/fib/traces.txt /example/jaeger/jaeger diff --git a/CHANGELOG.md b/CHANGELOG.md index dce5247f31b..1dfd1a01548 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ## [Unreleased] +### Added + +- Add the "Roll the dice" getting started application example in `go.opentelemetry.io/otel/example/dice`. (#????) + ## [1.19.0-rc.1/0.42.0-rc.1] 2023-09-14 This is a release candidate for the v1.19.0/v0.42.0 release. diff --git a/example/dice/dice.go b/example/dice/dice.go new file mode 100644 index 00000000000..3ad8d1b25a9 --- /dev/null +++ b/example/dice/dice.go @@ -0,0 +1,105 @@ +// Copyright The OpenTelemetry Authors +// +// 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. + +// dice is the "Roll the dice" getting started example application. +package main + +import ( + "context" + "errors" + "io" + "log" + "math/rand" + "net" + "net/http" + "os" + "os/signal" + "strconv" + "time" + + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" +) + +func main() { + if err := run(); err != nil { + log.Fatalln(err) + } +} + +func run() (err error) { + // Handle CTRL+C gracefully. + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) + defer stop() + + // Setup OpenTelemetry. + otelShutdown, err := setupOTelSDK(ctx) + if err != nil { + return + } + // Handle shutdown properly so nothing leaks. + defer func() { + err = errors.Join(err, otelShutdown(context.Background())) + }() + + // Create HTTP request multiplexer. + mux := http.NewServeMux() + registerHandleFunc(mux, "/rolldice", handle) + + // Create HTTP server with requests' base context canceled on server shutdown. + rCtx, cancel := context.WithCancel(context.Background()) + defer cancel() + srv := &http.Server{ + Addr: ":8080", + BaseContext: func(_ net.Listener) context.Context { return rCtx }, + ReadTimeout: time.Second, + WriteTimeout: 10 * time.Second, + // Add HTTP instrumentation for the whole server. + Handler: otelhttp.NewHandler(mux, "/"), + } + srv.RegisterOnShutdown(cancel) + + // Start the server. + srvErr := make(chan error, 1) + go func() { + srvErr <- srv.ListenAndServe() + }() + + // Wait for interruption. + select { + case err = <-srvErr: + // Error when starting HTTP server. + return + case <-ctx.Done(): + // Wait for first CTRL+C. + // Stop receiving signal notifications as soon as possible. + stop() + } + + // When Shutdown is called, ListenAndServe immediately returns ErrServerClosed. + return srv.Shutdown(context.Background()) +} + +func registerHandleFunc(mux *http.ServeMux, pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) { + // Configure the "http.route" for the HTTP instrumentation. + handler := otelhttp.WithRouteTag(pattern, http.HandlerFunc(handlerFunc)) + mux.Handle(pattern, handler) +} + +func handle(w http.ResponseWriter, r *http.Request) { + roll := 1 + rand.Intn(6) + resp := strconv.Itoa(roll) + "\n" + if _, err := io.WriteString(w, resp); err != nil { + log.Printf("Write failed: %v\n", err) + } +} diff --git a/example/dice/go.mod b/example/dice/go.mod new file mode 100644 index 00000000000..9224d7c95ac --- /dev/null +++ b/example/dice/go.mod @@ -0,0 +1,35 @@ +module go.opentelemetry.io/otel/example/dice + +go 1.20 + +require ( + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0 + go.opentelemetry.io/otel v1.19.0-rc.1 + go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.41.0 + go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.18.0 + go.opentelemetry.io/otel/sdk v1.19.0-rc.1 + go.opentelemetry.io/otel/sdk/metric v1.19.0-rc.1 +) + +require ( + github.com/felixge/httpsnoop v1.0.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + go.opentelemetry.io/otel/metric v1.19.0-rc.1 // indirect + go.opentelemetry.io/otel/trace v1.19.0-rc.1 // indirect + golang.org/x/sys v0.12.0 // indirect +) + +replace go.opentelemetry.io/otel/exporters/stdout/stdouttrace => ../../exporters/stdout/stdouttrace + +replace go.opentelemetry.io/otel/exporters/stdout/stdoutmetric => ../../exporters/stdout/stdoutmetric + +replace go.opentelemetry.io/otel => ../.. + +replace go.opentelemetry.io/otel/trace => ../../trace + +replace go.opentelemetry.io/otel/metric => ../../metric + +replace go.opentelemetry.io/otel/sdk/metric => ../../sdk/metric + +replace go.opentelemetry.io/otel/sdk => ../../sdk diff --git a/example/dice/go.sum b/example/dice/go.sum new file mode 100644 index 00000000000..b9534f5b329 --- /dev/null +++ b/example/dice/go.sum @@ -0,0 +1,16 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= +github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0 h1:KfYpVmrjI7JuToy5k8XV3nkapjWx48k4E4JOtVstzQI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0/go.mod h1:SeQhzAEccGVZVEy7aH87Nh0km+utSpo1pTv6eMMop48= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/example/dice/otel.go b/example/dice/otel.go new file mode 100644 index 00000000000..3cd077d93c1 --- /dev/null +++ b/example/dice/otel.go @@ -0,0 +1,116 @@ +// Copyright The OpenTelemetry Authors +// +// 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. + +package main + +import ( + "context" + "errors" + "time" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/stdout/stdoutmetric" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + "go.opentelemetry.io/otel/sdk/metric" + "go.opentelemetry.io/otel/sdk/resource" + "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.21.0" +) + +func setupOTelSDK(ctx context.Context) (shutdown func(context.Context) error, err error) { + var shutdownFuncs []func(context.Context) error + + // shutdown calls cleanup functions registered via shutdownFuncs. + // The errors from the calls are joined. + // Each registered cleanup will be invoked once. + shutdown = func(ctx context.Context) error { + var err error + for _, fn := range shutdownFuncs { + err = errors.Join(err, fn(ctx)) + } + shutdownFuncs = nil + return err + } + + // handleErr calls shutdown for cleanup and make sure that all errors are returned. + handleErr := func(inErr error) { + err = errors.Join(inErr, shutdown(ctx)) + } + + // Setup Resource. + res, err := newResource() + if err != nil { + handleErr(err) + return + } + + // Setup Trace Provider. + tracerProvider, err := newTraceProvider(res) + if err != nil { + handleErr(err) + return + } + shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown) + otel.SetTracerProvider(tracerProvider) + + // Setup Meter Provider. + meterProvider, err := newMeterProvider(res) + if err != nil { + handleErr(err) + return + } + shutdownFuncs = append(shutdownFuncs, meterProvider.Shutdown) + otel.SetMeterProvider(meterProvider) + + return +} + +func newResource() (*resource.Resource, error) { + return resource.Merge(resource.Default(), + resource.NewWithAttributes(semconv.SchemaURL, + semconv.ServiceName("dice"), + semconv.ServiceVersion("0.1.0"), + )) +} + +func newTraceProvider(res *resource.Resource) (*trace.TracerProvider, error) { + traceExporter, err := stdouttrace.New( + stdouttrace.WithPrettyPrint()) + if err != nil { + return nil, err + } + + traceProvider := trace.NewTracerProvider( + trace.WithBatcher(traceExporter, + // Default is 5s. Set to 1s for demonstrative purposes. + trace.WithBatchTimeout(time.Second)), + trace.WithResource(res), + ) + return traceProvider, nil +} + +func newMeterProvider(res *resource.Resource) (*metric.MeterProvider, error) { + metricExporter, err := stdoutmetric.New() + if err != nil { + return nil, err + } + + meterProvider := metric.NewMeterProvider( + metric.WithResource(res), + metric.WithReader(metric.NewPeriodicReader(metricExporter, + // Default is 1m. Set to 3s for demonstrative purposes. + metric.WithInterval(3*time.Second))), + ) + return meterProvider, nil +} diff --git a/versions.yaml b/versions.yaml index c34b100aa68..6492d09f1e8 100644 --- a/versions.yaml +++ b/versions.yaml @@ -19,6 +19,7 @@ module-sets: - go.opentelemetry.io/otel - go.opentelemetry.io/otel/bridge/opentracing - go.opentelemetry.io/otel/bridge/opentracing/test + - go.opentelemetry.io/otel/example/dice - go.opentelemetry.io/otel/example/fib - go.opentelemetry.io/otel/example/namedtracer - go.opentelemetry.io/otel/example/otel-collector From 984e7880cf210d4427190d0435f6bb1e7a82ed2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Thu, 21 Sep 2023 13:58:51 +0200 Subject: [PATCH 02/14] Add manual instrumentation --- example/dice/doc.go | 16 +++++++++ example/dice/go.mod | 2 +- example/dice/{dice.go => main.go} | 26 ++++---------- example/dice/otel.go | 10 +++--- example/dice/rolldice.go | 60 +++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 26 deletions(-) create mode 100644 example/dice/doc.go rename example/dice/{dice.go => main.go} (77%) create mode 100644 example/dice/rolldice.go diff --git a/example/dice/doc.go b/example/dice/doc.go new file mode 100644 index 00000000000..967d2fe2697 --- /dev/null +++ b/example/dice/doc.go @@ -0,0 +1,16 @@ +// Copyright The OpenTelemetry Authors +// +// 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. + +// dice is the "Roll the dice" getting started example application. +package main diff --git a/example/dice/go.mod b/example/dice/go.mod index 9224d7c95ac..79b391a4f79 100644 --- a/example/dice/go.mod +++ b/example/dice/go.mod @@ -7,6 +7,7 @@ require ( go.opentelemetry.io/otel v1.19.0-rc.1 go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v0.41.0 go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.18.0 + go.opentelemetry.io/otel/metric v1.19.0-rc.1 go.opentelemetry.io/otel/sdk v1.19.0-rc.1 go.opentelemetry.io/otel/sdk/metric v1.19.0-rc.1 ) @@ -15,7 +16,6 @@ require ( github.com/felixge/httpsnoop v1.0.3 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect - go.opentelemetry.io/otel/metric v1.19.0-rc.1 // indirect go.opentelemetry.io/otel/trace v1.19.0-rc.1 // indirect golang.org/x/sys v0.12.0 // indirect ) diff --git a/example/dice/dice.go b/example/dice/main.go similarity index 77% rename from example/dice/dice.go rename to example/dice/main.go index 3ad8d1b25a9..6dea7144fd6 100644 --- a/example/dice/dice.go +++ b/example/dice/main.go @@ -12,20 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -// dice is the "Roll the dice" getting started example application. package main import ( "context" "errors" - "io" "log" - "math/rand" "net" "net/http" "os" "os/signal" - "strconv" "time" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" @@ -43,7 +39,9 @@ func run() (err error) { defer stop() // Setup OpenTelemetry. - otelShutdown, err := setupOTelSDK(ctx) + serviceName := "dice" + serviceVersion := "0.1.0" + otelShutdown, err := setupOTelSDK(ctx, serviceName, serviceVersion) if err != nil { return } @@ -52,10 +50,6 @@ func run() (err error) { err = errors.Join(err, otelShutdown(context.Background())) }() - // Create HTTP request multiplexer. - mux := http.NewServeMux() - registerHandleFunc(mux, "/rolldice", handle) - // Create HTTP server with requests' base context canceled on server shutdown. rCtx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -65,7 +59,7 @@ func run() (err error) { ReadTimeout: time.Second, WriteTimeout: 10 * time.Second, // Add HTTP instrumentation for the whole server. - Handler: otelhttp.NewHandler(mux, "/"), + Handler: otelhttp.NewHandler(http.DefaultServeMux, "/"), } srv.RegisterOnShutdown(cancel) @@ -90,16 +84,8 @@ func run() (err error) { return srv.Shutdown(context.Background()) } -func registerHandleFunc(mux *http.ServeMux, pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) { +func handleFunc(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) { // Configure the "http.route" for the HTTP instrumentation. handler := otelhttp.WithRouteTag(pattern, http.HandlerFunc(handlerFunc)) - mux.Handle(pattern, handler) -} - -func handle(w http.ResponseWriter, r *http.Request) { - roll := 1 + rand.Intn(6) - resp := strconv.Itoa(roll) + "\n" - if _, err := io.WriteString(w, resp); err != nil { - log.Printf("Write failed: %v\n", err) - } + http.Handle(pattern, handler) } diff --git a/example/dice/otel.go b/example/dice/otel.go index 3cd077d93c1..619a5b7c4ef 100644 --- a/example/dice/otel.go +++ b/example/dice/otel.go @@ -28,7 +28,7 @@ import ( semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) -func setupOTelSDK(ctx context.Context) (shutdown func(context.Context) error, err error) { +func setupOTelSDK(ctx context.Context, serviceName, serviceVersion string) (shutdown func(context.Context) error, err error) { var shutdownFuncs []func(context.Context) error // shutdown calls cleanup functions registered via shutdownFuncs. @@ -49,7 +49,7 @@ func setupOTelSDK(ctx context.Context) (shutdown func(context.Context) error, er } // Setup Resource. - res, err := newResource() + res, err := newResource(serviceName, serviceVersion) if err != nil { handleErr(err) return @@ -76,11 +76,11 @@ func setupOTelSDK(ctx context.Context) (shutdown func(context.Context) error, er return } -func newResource() (*resource.Resource, error) { +func newResource(serviceName, serviceVersion string) (*resource.Resource, error) { return resource.Merge(resource.Default(), resource.NewWithAttributes(semconv.SchemaURL, - semconv.ServiceName("dice"), - semconv.ServiceVersion("0.1.0"), + semconv.ServiceName(serviceName), + semconv.ServiceVersion(serviceVersion), )) } diff --git a/example/dice/rolldice.go b/example/dice/rolldice.go new file mode 100644 index 00000000000..f1506f3d57a --- /dev/null +++ b/example/dice/rolldice.go @@ -0,0 +1,60 @@ +// Copyright The OpenTelemetry Authors +// +// 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. + +package main + +import ( + "io" + "log" + "math/rand" + "net/http" + "strconv" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/metric" +) + +var ( + tracer = otel.Tracer("rolldice") + meter = otel.Meter("rolldice") + rollCnt metric.Int64Counter +) + +func init() { + var err error + rollCnt, err = meter.Int64Counter("roll_counter", + metric.WithDescription("The number of rolls by roll value"), + metric.WithUnit("{roll}")) + if err != nil { + panic(err) + } + handleFunc("/rolldice", rolldice) +} + +func rolldice(w http.ResponseWriter, r *http.Request) { + ctx, span := tracer.Start(r.Context(), "do_roll") + defer span.End() + + roll := 1 + rand.Intn(6) + + rollValueAttr := attribute.Int("roll.value", roll) + span.SetAttributes(rollValueAttr) + rollCnt.Add(ctx, 1, metric.WithAttributes(rollValueAttr)) + + resp := strconv.Itoa(roll) + "\n" + if _, err := io.WriteString(w, resp); err != nil { + log.Printf("Write failed: %v\n", err) + } +} From 046d6a6eafa38fc7e135d4297df693fc48fe1433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Thu, 21 Sep 2023 14:05:18 +0200 Subject: [PATCH 03/14] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dfd1a01548..75e6a83b813 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Added -- Add the "Roll the dice" getting started application example in `go.opentelemetry.io/otel/example/dice`. (#????) +- Add the "Roll the dice" getting started application example in `go.opentelemetry.io/otel/example/dice`. (#4539) ## [1.19.0-rc.1/0.42.0-rc.1] 2023-09-14 From 637cd1f507d8bcc83d08abf3d8cc61f3916fecc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Thu, 21 Sep 2023 14:12:27 +0200 Subject: [PATCH 04/14] Add comments --- example/dice/main.go | 2 ++ example/dice/otel.go | 2 ++ 2 files changed, 4 insertions(+) diff --git a/example/dice/main.go b/example/dice/main.go index 6dea7144fd6..bfd67a02da9 100644 --- a/example/dice/main.go +++ b/example/dice/main.go @@ -84,6 +84,8 @@ func run() (err error) { return srv.Shutdown(context.Background()) } +// handleFunc is a replacement for [net/http.HandleFunc] +// which enriches the handler's HTTP instrumentation with the pattern as the http.route. func handleFunc(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) { // Configure the "http.route" for the HTTP instrumentation. handler := otelhttp.WithRouteTag(pattern, http.HandlerFunc(handlerFunc)) diff --git a/example/dice/otel.go b/example/dice/otel.go index 619a5b7c4ef..2f2e57cbcbc 100644 --- a/example/dice/otel.go +++ b/example/dice/otel.go @@ -28,6 +28,8 @@ import ( semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) +// setupOTelSDK bootstraps the OpenTelemetry piepeline. +// If it does not return an error, make sure to call shutdown for proper cleanup. func setupOTelSDK(ctx context.Context, serviceName, serviceVersion string) (shutdown func(context.Context) error, err error) { var shutdownFuncs []func(context.Context) error From d87f3431b52f5f404e2318c89e25dbe46736d227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Thu, 21 Sep 2023 15:08:29 +0200 Subject: [PATCH 05/14] Use naked return consistently --- example/dice/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/example/dice/main.go b/example/dice/main.go index bfd67a02da9..22797c91bc1 100644 --- a/example/dice/main.go +++ b/example/dice/main.go @@ -81,7 +81,8 @@ func run() (err error) { } // When Shutdown is called, ListenAndServe immediately returns ErrServerClosed. - return srv.Shutdown(context.Background()) + err = srv.Shutdown(context.Background()) + return } // handleFunc is a replacement for [net/http.HandleFunc] From 01a71c66e04b6277b422f949273e0131f227be12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Thu, 21 Sep 2023 15:24:49 +0200 Subject: [PATCH 06/14] Move handleFunc to main --- example/dice/main.go | 3 +++ example/dice/rolldice.go | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/example/dice/main.go b/example/dice/main.go index 22797c91bc1..e945817aa0d 100644 --- a/example/dice/main.go +++ b/example/dice/main.go @@ -50,6 +50,9 @@ func run() (err error) { err = errors.Join(err, otelShutdown(context.Background())) }() + // Register handlers. + handleFunc("/rolldice", rolldice) + // Create HTTP server with requests' base context canceled on server shutdown. rCtx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/example/dice/rolldice.go b/example/dice/rolldice.go index f1506f3d57a..9b6e700f2b4 100644 --- a/example/dice/rolldice.go +++ b/example/dice/rolldice.go @@ -40,7 +40,6 @@ func init() { if err != nil { panic(err) } - handleFunc("/rolldice", rolldice) } func rolldice(w http.ResponseWriter, r *http.Request) { From 26075173cf07d175482458c8fe7253560bbc6fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Thu, 21 Sep 2023 16:23:25 +0200 Subject: [PATCH 07/14] refactor: Extract newHTTPHandler --- example/dice/main.go | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/example/dice/main.go b/example/dice/main.go index e945817aa0d..945523e7519 100644 --- a/example/dice/main.go +++ b/example/dice/main.go @@ -50,9 +50,6 @@ func run() (err error) { err = errors.Join(err, otelShutdown(context.Background())) }() - // Register handlers. - handleFunc("/rolldice", rolldice) - // Create HTTP server with requests' base context canceled on server shutdown. rCtx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -61,8 +58,7 @@ func run() (err error) { BaseContext: func(_ net.Listener) context.Context { return rCtx }, ReadTimeout: time.Second, WriteTimeout: 10 * time.Second, - // Add HTTP instrumentation for the whole server. - Handler: otelhttp.NewHandler(http.DefaultServeMux, "/"), + Handler: newHTTPHandler(), } srv.RegisterOnShutdown(cancel) @@ -88,10 +84,21 @@ func run() (err error) { return } -// handleFunc is a replacement for [net/http.HandleFunc] -// which enriches the handler's HTTP instrumentation with the pattern as the http.route. -func handleFunc(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) { - // Configure the "http.route" for the HTTP instrumentation. - handler := otelhttp.WithRouteTag(pattern, http.HandlerFunc(handlerFunc)) - http.Handle(pattern, handler) +func newHTTPHandler() http.Handler { + mux := http.NewServeMux() + + // handleFunc is a replacement for mux.HandleFunc + // which enriches the handler's HTTP instrumentation with the pattern as the http.route. + handleFunc := func(pattern string, handlerFunc func(http.ResponseWriter, *http.Request)) { + // Configure the "http.route" for the HTTP instrumentation. + handler := otelhttp.WithRouteTag(pattern, http.HandlerFunc(handlerFunc)) + mux.Handle(pattern, handler) + } + + // Register handlers. + handleFunc("/rolldice", rolldice) + + // Add HTTP instrumentation for the whole server. + handler := otelhttp.NewHandler(mux, "/") + return handler } From 41ae17b2cef7b161bf3e295d1595e69d3a8b27b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Thu, 21 Sep 2023 16:42:26 +0200 Subject: [PATCH 08/14] Fix comment --- example/dice/otel.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/dice/otel.go b/example/dice/otel.go index 2f2e57cbcbc..820e9fe354d 100644 --- a/example/dice/otel.go +++ b/example/dice/otel.go @@ -29,7 +29,7 @@ import ( ) // setupOTelSDK bootstraps the OpenTelemetry piepeline. -// If it does not return an error, make sure to call shutdown for proper cleanup. +// If it does not return an error, ake sure to call shutdown for proper cleanup. func setupOTelSDK(ctx context.Context, serviceName, serviceVersion string) (shutdown func(context.Context) error, err error) { var shutdownFuncs []func(context.Context) error @@ -45,7 +45,7 @@ func setupOTelSDK(ctx context.Context, serviceName, serviceVersion string) (shut return err } - // handleErr calls shutdown for cleanup and make sure that all errors are returned. + // handleErr calls shutdown for cleanup and makes sure that all errors are returned. handleErr := func(inErr error) { err = errors.Join(inErr, shutdown(ctx)) } From 3d7eb0795b6aff414da4f2d0697caa15cada35fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Thu, 21 Sep 2023 17:05:44 +0200 Subject: [PATCH 09/14] Improve comments --- example/dice/main.go | 2 +- example/dice/otel.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/dice/main.go b/example/dice/main.go index 945523e7519..bdbdac296b6 100644 --- a/example/dice/main.go +++ b/example/dice/main.go @@ -34,7 +34,7 @@ func main() { } func run() (err error) { - // Handle CTRL+C gracefully. + // Handle SIGINT (CTRL+C) gracefully. ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) defer stop() diff --git a/example/dice/otel.go b/example/dice/otel.go index 820e9fe354d..092783bec54 100644 --- a/example/dice/otel.go +++ b/example/dice/otel.go @@ -28,7 +28,7 @@ import ( semconv "go.opentelemetry.io/otel/semconv/v1.21.0" ) -// setupOTelSDK bootstraps the OpenTelemetry piepeline. +// setupOTelSDK bootstraps the OpenTelemetry pipeline. // If it does not return an error, ake sure to call shutdown for proper cleanup. func setupOTelSDK(ctx context.Context, serviceName, serviceVersion string) (shutdown func(context.Context) error, err error) { var shutdownFuncs []func(context.Context) error @@ -50,14 +50,14 @@ func setupOTelSDK(ctx context.Context, serviceName, serviceVersion string) (shut err = errors.Join(inErr, shutdown(ctx)) } - // Setup Resource. + // Setup resource. res, err := newResource(serviceName, serviceVersion) if err != nil { handleErr(err) return } - // Setup Trace Provider. + // Setup trace provider. tracerProvider, err := newTraceProvider(res) if err != nil { handleErr(err) @@ -66,7 +66,7 @@ func setupOTelSDK(ctx context.Context, serviceName, serviceVersion string) (shut shutdownFuncs = append(shutdownFuncs, tracerProvider.Shutdown) otel.SetTracerProvider(tracerProvider) - // Setup Meter Provider. + // Setup meter provider. meterProvider, err := newMeterProvider(res) if err != nil { handleErr(err) From 99e448f22a7914ba57957c8dcbc92f369625319f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Thu, 21 Sep 2023 21:50:24 +0200 Subject: [PATCH 10/14] Update example/dice/otel.go Co-authored-by: Tyler Yahn --- example/dice/otel.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/dice/otel.go b/example/dice/otel.go index 092783bec54..8612352d959 100644 --- a/example/dice/otel.go +++ b/example/dice/otel.go @@ -29,7 +29,7 @@ import ( ) // setupOTelSDK bootstraps the OpenTelemetry pipeline. -// If it does not return an error, ake sure to call shutdown for proper cleanup. +// If it does not return an error, make sure to call shutdown for proper cleanup. func setupOTelSDK(ctx context.Context, serviceName, serviceVersion string) (shutdown func(context.Context) error, err error) { var shutdownFuncs []func(context.Context) error From bd65fec347966317e7b46825538b66d8b12f6816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Thu, 21 Sep 2023 21:57:33 +0200 Subject: [PATCH 11/14] Simplify BaseContext --- example/dice/main.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/example/dice/main.go b/example/dice/main.go index bdbdac296b6..4c72eb95a86 100644 --- a/example/dice/main.go +++ b/example/dice/main.go @@ -50,19 +50,14 @@ func run() (err error) { err = errors.Join(err, otelShutdown(context.Background())) }() - // Create HTTP server with requests' base context canceled on server shutdown. - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() + // Start HTTP server. srv := &http.Server{ Addr: ":8080", - BaseContext: func(_ net.Listener) context.Context { return rCtx }, + BaseContext: func(_ net.Listener) context.Context { return ctx }, ReadTimeout: time.Second, WriteTimeout: 10 * time.Second, Handler: newHTTPHandler(), } - srv.RegisterOnShutdown(cancel) - - // Start the server. srvErr := make(chan error, 1) go func() { srvErr <- srv.ListenAndServe() From 30cd9e8f9512ca885cc66b428dc8bda5f601ace9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Fri, 22 Sep 2023 15:50:45 +0200 Subject: [PATCH 12/14] Update doc.go --- example/dice/doc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/dice/doc.go b/example/dice/doc.go index 967d2fe2697..5fe156fb977 100644 --- a/example/dice/doc.go +++ b/example/dice/doc.go @@ -12,5 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -// dice is the "Roll the dice" getting started example application. +// Dice is the "Roll the dice" getting started example application. package main From 80f7e461b48538f2638086ab7ba3b1efb32d7e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Fri, 22 Sep 2023 19:32:33 +0200 Subject: [PATCH 13/14] Update example/dice/main.go Co-authored-by: Phillip Carter --- example/dice/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/dice/main.go b/example/dice/main.go index 4c72eb95a86..f7e0242906f 100644 --- a/example/dice/main.go +++ b/example/dice/main.go @@ -38,7 +38,7 @@ func run() (err error) { ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) defer stop() - // Setup OpenTelemetry. + // Set up OpenTelemetry. serviceName := "dice" serviceVersion := "0.1.0" otelShutdown, err := setupOTelSDK(ctx, serviceName, serviceVersion) From 93a69bc5261400e8b2f42edaa852e56e4eedb5ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Paj=C4=85k?= Date: Tue, 26 Sep 2023 08:24:36 +0200 Subject: [PATCH 14/14] Rename span and metric names --- example/dice/rolldice.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/dice/rolldice.go b/example/dice/rolldice.go index 9b6e700f2b4..10bd237c325 100644 --- a/example/dice/rolldice.go +++ b/example/dice/rolldice.go @@ -34,7 +34,7 @@ var ( func init() { var err error - rollCnt, err = meter.Int64Counter("roll_counter", + rollCnt, err = meter.Int64Counter("dice.rolls", metric.WithDescription("The number of rolls by roll value"), metric.WithUnit("{roll}")) if err != nil { @@ -43,7 +43,7 @@ func init() { } func rolldice(w http.ResponseWriter, r *http.Request) { - ctx, span := tracer.Start(r.Context(), "do_roll") + ctx, span := tracer.Start(r.Context(), "roll") defer span.End() roll := 1 + rand.Intn(6)