devops/otel-col-cloud-run-multicontainer/recursive/main.go (112 lines of code) (raw):
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"context"
"fmt"
"log"
"math/rand"
"net/http"
"os"
"strconv"
"time"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.11.0"
)
const (
spanInterval = 50 * time.Millisecond
genInterval = 10 * time.Second
)
var (
OTLPEndpoint = "localhost:4317"
ServiceName = "default-service"
)
func initTracer() (*sdktrace.TracerProvider, error) {
e := os.Getenv("OTLP_ENDPOINT")
if e == "" {
e = OTLPEndpoint
}
// OTLP exporter config for Collector (using default config)
exporter, err := otlptracegrpc.New(
context.Background(),
otlptracegrpc.WithEndpoint(e),
otlptracegrpc.WithInsecure(),
)
if err != nil {
return nil, err
}
sname := os.Getenv("SERVICE_NAME")
if sname == "" {
sname = ServiceName
}
res, err := resource.New(
context.Background(),
resource.WithAttributes(
semconv.ServiceNameKey.String(sname),
semconv.ServiceVersionKey.String("1.0.0"),
semconv.DeploymentEnvironmentKey.String("production"),
semconv.TelemetrySDKNameKey.String("opentelemetry"),
semconv.TelemetrySDKLanguageKey.String("go"),
semconv.TelemetrySDKVersionKey.String("0.13.0"),
),
)
if err != nil {
return nil, err
}
tp := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(res),
)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.TraceContext{})
return tp, nil
}
func main() {
log.Print("starting tracer provider")
tp, err := initTracer()
if err != nil {
log.Fatalf("failed to start OpenTelemetry Trace config: %v", err)
}
defer func() {
if err := tp.Shutdown(context.Background()); err != nil {
log.Fatalf("failed to shutdown TraceProvider: %v", err)
}
}()
log.Print("launch trace generator")
http.HandleFunc("/_hello", func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
})
otelHandler := otelhttp.NewHandler(http.HandlerFunc(root), "client.handler")
http.Handle("/root", otelHandler)
http.ListenAndServe(":8080", nil)
}
func root(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
q := r.URL.Query()
n := rand.Intn(10) + 1
nstr := q.Get("n")
if nstr != "" {
n, _ = strconv.Atoi(nstr)
}
ctx, span := otel.Tracer("handler").Start(ctx, "sample.root")
foo(ctx, n)
span.End()
fmt.Fprintf(w, "run %vth fib", n)
}
func foo(ctx context.Context, n int) {
if n == 0 {
return
}
ctx, span := otel.Tracer("handler").Start(ctx, "sample.foo")
span.SetAttributes(attribute.Key("iteration").Int(n))
time.Sleep(spanInterval)
span.AddEvent(fmt.Sprintf("mid-interval-%v", n))
time.Sleep(spanInterval)
foo(ctx, n-1)
span.End()
}