1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-15 04:42:04 +00:00
srs/trunk/research/srs-apm-http-raw/main.go

197 lines
6 KiB
Go

package main
import (
"bytes"
"context"
"fmt"
"github.com/golang/protobuf/proto"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
coltracepb "go.opentelemetry.io/proto/otlp/collector/trace/v1"
tracepb "go.opentelemetry.io/proto/otlp/trace/v1"
"net/http"
"os"
"time"
)
type httpRawClientForAPM struct {
endpoint, urlPath string
}
func (v *httpRawClientForAPM) Start(ctx context.Context) error {
fmt.Println("http1: Transport start")
return nil
}
func (v *httpRawClientForAPM) Stop(ctx context.Context) error {
fmt.Println("http1: Transport stop")
return nil
}
func (v *httpRawClientForAPM) UploadTraces(ctx context.Context, protoSpans []*tracepb.ResourceSpans) error {
// Wrap with request message.
m := &coltracepb.ExportTraceServiceRequest{
ResourceSpans: protoSpans,
}
// Marshal to bytes.
b, err := proto.Marshal(m)
if err != nil {
return err
}
// Upload by HTTP/1
url := fmt.Sprintf("http://%v%v", v.endpoint, v.urlPath)
r, err := http.NewRequest("POST", url, bytes.NewReader(b))
if err != nil {
return err
}
r.Header.Set("Content-Type", "application/x-protobuf") // For http
res, err := http.DefaultClient.Do(r)
if err != nil {
return err
}
defer res.Body.Close()
var nn int
for _, span := range protoSpans {
for _, span2 := range span.ScopeSpans {
nn += len(span2.Spans)
}
}
fmt.Println(fmt.Sprintf("http1: Upload %v/%v spans to %v%v, response is %v", len(protoSpans), nn, v.endpoint, v.urlPath, res.Status))
return nil
}
func main() {
if os.Getenv("TOKEN") == "" {
panic("no env TOKEN, see https://console.cloud.tencent.com/apm/monitor/access")
}
// The gRPC client defaults to https://localhost:4317 and the HTTP client https://localhost:4318.
// See https://github.com/open-telemetry/opentelemetry-go/tree/main/exporters/otlp/otlptrace
endpoint := "ap-guangzhou.apm.tencentcs.com:55681"
urlPath := "/v1/traces"
service := "srs-server"
fmt.Println(fmt.Sprintf("main: APM endpoint=%v, urlPath=%v, token=%vB, service=%v", endpoint, urlPath, len(os.Getenv("TOKEN")), service))
// Create exporter to upload spans over HTTP/1.1
ctx := context.Background()
exporter, err := otlptrace.New(ctx, &httpRawClientForAPM{endpoint, urlPath})
if err != nil {
panic(err)
}
// Create resource for tracer provider.
r, err := resource.New(ctx, []resource.Option{
resource.WithAttributes(attribute.KeyValue{
Key: "token", Value: attribute.StringValue(os.Getenv("TOKEN")),
}),
resource.WithAttributes(attribute.KeyValue{
Key: "service.name", Value: attribute.StringValue(service),
}),
}...)
if err != nil {
panic(err)
}
// Create tracer provider for tracing.
tp := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(r),
)
defer tp.Shutdown(ctx)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
fmt.Println("main: Init ok")
// Create global tracer.
tracer := otel.GetTracerProvider().Tracer("app")
ctx, span := tracer.Start(context.Background(), "main", trace.WithSpanKind(trace.SpanKindServer))
time.Sleep(100 * time.Millisecond)
defer span.End()
ctx, span2 := tracer.Start(ctx, "sub", trace.WithSpanKind(trace.SpanKindInternal))
time.Sleep(70 * time.Millisecond)
span2.End()
sc := span.SpanContext()
fmt.Println(fmt.Sprintf("main: Done, trace=%v, span=%v", sc.TraceID().String(), sc.SpanID().String()))
foo := func() {
_, span5 := tracer.Start(ctx, "failed")
span5.RecordError(fmt.Errorf("default err service=%v", service), trace.WithStackTrace(true))
span5.SetStatus(codes.Error, fmt.Sprintf("failed span endpoint=%v", endpoint))
span5.End()
}
foo()
// Link for span.
_, span6 := tracer.Start(context.Background(), "linker", trace.WithSpanKind(trace.SpanKindServer),
trace.WithNewRoot(), trace.WithLinks(trace.LinkFromContext(ctx)))
defer span6.End()
// Propagator over HTTP header, start a client span and inject HTTP header.
ctx, span3 := tracer.Start(ctx, "call", trace.WithSpanKind(trace.SpanKindClient))
defer span3.End()
header := make(http.Header)
propagators := otel.GetTextMapPropagator()
propagators.Inject(ctx, propagation.HeaderCarrier(header))
fmt.Println(fmt.Sprintf("main: Save to header %v, span=%v", header, span3.SpanContext().SpanID().String()))
// Mock another service.
mockServer(endpoint, urlPath, "origin", header)
}
func mockServer(endpoint, urlPath, service string, header http.Header) {
// Create exporter to upload spans over HTTP/1.1
ctx := context.Background()
exporter, err := otlptrace.New(ctx, &httpRawClientForAPM{endpoint, urlPath})
if err != nil {
panic(err)
}
// Create resource for tracer provider.
r, err := resource.New(ctx, []resource.Option{
resource.WithAttributes(attribute.KeyValue{
Key: "token", Value: attribute.StringValue(os.Getenv("TOKEN")),
}),
resource.WithAttributes(attribute.KeyValue{
Key: "service.name", Value: attribute.StringValue(service),
}),
}...)
if err != nil {
panic(err)
}
// Create tracer provider for tracing.
tp := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithBatcher(exporter),
sdktrace.WithResource(r),
)
defer tp.Shutdown(ctx)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
fmt.Println("main: Init ok")
tracer := otel.GetTracerProvider().Tracer("app")
propagators := otel.GetTextMapPropagator()
ctx = propagators.Extract(context.Background(), propagation.HeaderCarrier(header))
ctx, span4 := tracer.Start(ctx, "callee", trace.WithSpanKind(trace.SpanKindServer))
defer span4.End()
fmt.Println(fmt.Sprintf("main: Restore from header %v, span=%v", header, span4.SpanContext().SpanID().String()))
}