opentelemetry-collector/examples/demo/server/main.go

172 lines
5.0 KiB
Go

// 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.
// Sample contains a simple http server that exports to the OpenTelemetry agent.
package main
import (
"context"
"log"
"math/rand"
"net/http"
"os"
"time"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/metric/global"
"go.opentelemetry.io/otel/propagation"
controller "go.opentelemetry.io/otel/sdk/metric/controller/basic"
processor "go.opentelemetry.io/otel/sdk/metric/processor/basic"
"go.opentelemetry.io/otel/sdk/metric/selector/simple"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc"
)
var rng = rand.New(rand.NewSource(time.Now().UnixNano()))
// Initializes an OTLP exporter, and configures the corresponding trace and
// metric providers.
func initProvider() func() {
ctx := context.Background()
otelAgentAddr, ok := os.LookupEnv("OTEL_EXPORTER_OTLP_ENDPOINT")
if !ok {
otelAgentAddr = "0.0.0.0:4317"
}
metricClient := otlpmetricgrpc.NewClient(
otlpmetricgrpc.WithInsecure(),
otlpmetricgrpc.WithEndpoint(otelAgentAddr))
metricExp, err := otlpmetric.New(ctx, metricClient)
handleErr(err, "Failed to create the collector metric exporter")
pusher := controller.New(
processor.New(
simple.NewWithExactDistribution(),
metricExp,
),
controller.WithExporter(metricExp),
controller.WithCollectPeriod(2*time.Second),
)
global.SetMeterProvider(pusher.MeterProvider())
err = pusher.Start(ctx)
handleErr(err, "Failed to start metric pusher")
traceClient := otlptracegrpc.NewClient(
otlptracegrpc.WithInsecure(),
otlptracegrpc.WithEndpoint(otelAgentAddr),
otlptracegrpc.WithDialOption(grpc.WithBlock()))
traceExp, err := otlptrace.New(ctx, traceClient)
handleErr(err, "Failed to create the collector trace exporter")
res, err := resource.New(ctx,
resource.WithFromEnv(),
resource.WithProcess(),
resource.WithTelemetrySDK(),
resource.WithHost(),
resource.WithAttributes(
// the service name used to display traces in backends
semconv.ServiceNameKey.String("demo-server"),
),
)
handleErr(err, "failed to create resource")
bsp := sdktrace.NewBatchSpanProcessor(traceExp)
tracerProvider := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithResource(res),
sdktrace.WithSpanProcessor(bsp),
)
// set global propagator to tracecontext (the default is no-op).
otel.SetTextMapPropagator(propagation.TraceContext{})
otel.SetTracerProvider(tracerProvider)
return func() {
cxt, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()
if err := traceExp.Shutdown(cxt); err != nil {
otel.Handle(err)
}
// pushes any last exports to the receiver
if err := pusher.Stop(cxt); err != nil {
otel.Handle(err)
}
}
}
func handleErr(err error, message string) {
if err != nil {
log.Fatalf("%s: %v", message, err)
}
}
func main() {
shutdown := initProvider()
defer shutdown()
meter := global.Meter("demo-server-meter")
serverAttribute := attribute.String("server-attribute", "foo")
commonLabels := []attribute.KeyValue{serverAttribute}
requestCount := metric.Must(meter).NewInt64Counter(
"demo_server/request_counts",
metric.WithDescription("The number of requests received"),
)
// create a handler wrapped in OpenTelemetry instrumentation
handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
// random sleep to simulate latency
var sleep int64
switch modulus := time.Now().Unix() % 5; modulus {
case 0:
sleep = rng.Int63n(2000)
case 1:
sleep = rng.Int63n(15)
case 2:
sleep = rng.Int63n(917)
case 3:
sleep = rng.Int63n(87)
case 4:
sleep = rng.Int63n(1173)
}
time.Sleep(time.Duration(sleep) * time.Millisecond)
ctx := req.Context()
meter.RecordBatch(
ctx,
commonLabels,
requestCount.Measurement(1),
)
span := trace.SpanFromContext(ctx)
span.SetAttributes(serverAttribute)
w.Write([]byte("Hello World"))
})
wrappedHandler := otelhttp.NewHandler(handler, "/hello")
// serve up the wrapped handler
http.Handle("/hello", wrappedHandler)
http.ListenAndServe(":7080", nil)
}