Skip to content

Commit d391c37

Browse files
venjiangwoorui
andauthored
feat: trace (#575)
# Description Added the OpenTelemetry interface ## Usage Use Jaeger as the tracer exporter,configure the value of environment a for your [Jaeger](https://www.jaegertracing.io/) endpoint: ``` YOMO_TRACE_JAEGER_ENDPOINT=http://localhost:14268/api/traces ``` ### Source Tracing ```go // trace tp, shutdown, err := trace.NewTracerProviderWithJaeger("yomo-source") if err == nil { log.Println("[source] 🛰 trace enabled") } defer shutdown(context.Background()) // source source := yomo.NewSource( "source", "localhost:9000", yomo.WithTracerProvider(tp), // use tracer provider ) ... ``` ### SFN Tracing ```go // trace tp, shutdown, err := trace.NewTracerProviderWithJaeger("yomo-sfn") if err == nil { log.Println("[sfn] 🛰 trace enabled") } defer shutdown(context.Background()) // source sfn := yomo.NewStreamFunction( "sfn", "localhost:9000", yomo.WithSfnTracerProvider(tp), // use tracer provider ) ... ``` ### Zipper Tracing ```go // trace tp, shutdown, err := trace.NewTracerProviderWithJaeger("yomo-zipper") if err == nil { log.Println("[zipper] 🛰 trace enabled") } defer shutdown(context.Background()) // zipper conf, err := config.ParseConfigFile("config.yaml") if err != nil { log.Fatal(err) } zipper := yomo.NewZipper( conf.Name, conf.Functions, conf.Downstreams, yomo.WithZipperTracerProvider(tp), // use tracer provider ) ... ``` --------- Co-authored-by: woorui <rui1009479218@gmail.com>
1 parent 09352a8 commit d391c37

43 files changed

Lines changed: 798 additions & 133 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

core/client.go

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,29 @@ import (
66
"errors"
77
"fmt"
88
"io"
9+
"reflect"
910
"runtime"
1011
"time"
1112

1213
"github.com/yomorun/yomo/core/frame"
1314
"github.com/yomorun/yomo/pkg/frame-codec/y3codec"
1415
"github.com/yomorun/yomo/pkg/id"
16+
oteltrace "go.opentelemetry.io/otel/trace"
1517
"golang.org/x/exp/slog"
1618
)
1719

1820
// Client is the abstraction of a YoMo-Client. a YoMo-Client can be
1921
// Source, Upstream Zipper or StreamFunction.
2022
type Client struct {
21-
name string // name of the client
22-
clientID string // id of the client
23-
streamType StreamType // type of the dataStream
24-
processor func(*frame.DataFrame) // function to invoke when data arrived
25-
receiver func(*frame.BackflowFrame) // function to invoke when data is processed
26-
errorfn func(error) // function to invoke when error occured
27-
opts *clientOptions
28-
logger *slog.Logger
23+
name string // name of the client
24+
clientID string // id of the client
25+
streamType StreamType // type of the dataStream
26+
processor func(*frame.DataFrame) // function to invoke when data arrived
27+
receiver func(*frame.BackflowFrame) // function to invoke when data is processed
28+
errorfn func(error) // function to invoke when error occured
29+
opts *clientOptions
30+
logger *slog.Logger
31+
tracerProvider oteltrace.TracerProvider
2932

3033
// ctx and ctxCancel manage the lifecycle of client.
3134
ctx context.Context
@@ -57,6 +60,7 @@ func NewClient(appName string, connType ClientType, opts ...ClientOption) *Clien
5760
streamType: connType,
5861
opts: option,
5962
logger: logger,
63+
tracerProvider: option.tracerProvider,
6064
errorfn: func(err error) { logger.Error("client err", "err", err) },
6165
writeFrameChan: make(chan frame.Frame),
6266
ctx: ctx,
@@ -358,3 +362,14 @@ type FrameWriterConnection interface {
358362
Close() error
359363
Connect(context.Context, string) error
360364
}
365+
366+
// TracerProvider returns the tracer provider of client.
367+
func (c *Client) TracerProvider() oteltrace.TracerProvider {
368+
if c.tracerProvider == nil {
369+
return nil
370+
}
371+
if reflect.ValueOf(c.tracerProvider).IsNil() {
372+
return nil
373+
}
374+
return c.tracerProvider
375+
}

core/client_options.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/yomorun/yomo/core/frame"
1010
"github.com/yomorun/yomo/core/ylog"
1111
pkgtls "github.com/yomorun/yomo/pkg/tls"
12+
"go.opentelemetry.io/otel/trace"
1213
"golang.org/x/exp/slog"
1314
)
1415

@@ -24,6 +25,7 @@ type clientOptions struct {
2425
connectUntilSucceed bool
2526
nonBlockWrite bool
2627
logger *slog.Logger
28+
tracerProvider trace.TracerProvider
2729
}
2830

2931
func defaultClientOption() *clientOptions {
@@ -103,6 +105,12 @@ func WithLogger(logger *slog.Logger) ClientOption {
103105
}
104106
}
105107

108+
func WithTracerProvider(tp trace.TracerProvider) ClientOption {
109+
return func(o *clientOptions) {
110+
o.tracerProvider = tp
111+
}
112+
}
113+
106114
// ClientType is equal to StreamType.
107115
type ClientType = StreamType
108116

core/client_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func TestFrameRoundTrip(t *testing.T) {
131131
exited = checkClientExited(sameNameSfn, time.Second)
132132
assert.False(t, exited, "the new sfn stream should not exited")
133133

134-
mdBytes, _ := NewDefaultMetadata(source.clientID, true, "tid").Encode()
134+
mdBytes, _ := NewDefaultMetadata(source.clientID, true, "tid", "sid").Encode()
135135

136136
err = sameNameSfn.WriteFrame(&frame.DataFrame{Tag: backflowTag, Metadata: mdBytes, Payload: backflow})
137137
assert.NoError(t, err)
@@ -144,7 +144,7 @@ func TestFrameRoundTrip(t *testing.T) {
144144
assert.ElementsMatch(t, nameList, []string{"source", "sfn-1"})
145145

146146
md := metadata.New(
147-
NewDefaultMetadata(source.clientID, true, "tid"),
147+
NewDefaultMetadata(source.clientID, true, "tid", "sid"),
148148
metadata.M{
149149
"foo": "bar",
150150
},

core/metadata.go

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,39 +2,57 @@ package core
22

33
import "github.com/yomorun/yomo/core/metadata"
44

5-
var (
6-
metadataSourceIDKey = "yomo-source-id"
7-
metadataBroadcastKey = "yomo-broadcast"
8-
metadataTIDKey = "yomo-tid"
5+
const (
6+
MetadataSourceIDKey = "yomo-source-id"
7+
MetadataBroadcastKey = "yomo-broadcast"
8+
MetadataTIDKey = "yomo-tid"
9+
MetadataSIDKey = "yomo-sid"
910
)
1011

1112
// NewDefaultMetadata returns a default metadata.
12-
func NewDefaultMetadata(sourceID string, broadcast bool, tid string) metadata.M {
13+
func NewDefaultMetadata(sourceID string, broadcast bool, tid string, sid string) metadata.M {
1314
broadcastString := "false"
1415
if broadcast {
1516
broadcastString = "true"
1617
}
1718
return metadata.M{
18-
metadataSourceIDKey: sourceID,
19-
metadataBroadcastKey: broadcastString,
20-
metadataTIDKey: tid,
19+
MetadataSourceIDKey: sourceID,
20+
MetadataBroadcastKey: broadcastString,
21+
MetadataTIDKey: tid,
22+
MetadataSIDKey: sid,
2123
}
2224
}
2325

2426
// GetSourceIDFromMetadata gets sourceID from metadata.
2527
func GetSourceIDFromMetadata(m metadata.M) string {
26-
sourceID, _ := m.Get(metadataSourceIDKey)
28+
sourceID, _ := m.Get(MetadataSourceIDKey)
2729
return sourceID
2830
}
2931

3032
// GetBroadcastFromMetadata gets broadcast from metadata.
3133
func GetBroadcastFromMetadata(m metadata.M) bool {
32-
broadcast, _ := m.Get(metadataBroadcastKey)
34+
broadcast, _ := m.Get(MetadataBroadcastKey)
3335
return broadcast == "true"
3436
}
3537

3638
// GetTIDFromMetadata gets TID from metadata.
3739
func GetTIDFromMetadata(m metadata.M) string {
38-
tid, _ := m.Get(metadataTIDKey)
40+
tid, _ := m.Get(MetadataTIDKey)
3941
return tid
4042
}
43+
44+
// GetSIDFromMetadata gets SID from metadata.
45+
func GetSIDFromMetadata(m metadata.M) string {
46+
sid, _ := m.Get(MetadataSIDKey)
47+
return sid
48+
}
49+
50+
// SetTIDToMetadata sets tid to metadata.
51+
func SetTIDToMetadata(m metadata.M, tid string) {
52+
m.Set(MetadataTIDKey, tid)
53+
}
54+
55+
// SetSIDToMetadata sets sid to metadata.
56+
func SetSIDToMetadata(m metadata.M, sid string) {
57+
m.Set(MetadataSIDKey, sid)
58+
}

core/metadata_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,16 @@ import (
77
)
88

99
func TestMetadata(t *testing.T) {
10-
md := NewDefaultMetadata("source", true, "xxxxxxx")
10+
md := NewDefaultMetadata("source", true, "xxxxxxx", "sssssss")
1111

1212
assert.Equal(t, "source", GetSourceIDFromMetadata(md))
1313
assert.Equal(t, true, GetBroadcastFromMetadata(md))
1414
assert.Equal(t, "xxxxxxx", GetTIDFromMetadata(md))
15+
assert.Equal(t, "sssssss", GetSIDFromMetadata(md))
16+
17+
SetTIDToMetadata(md, "ccccccc")
18+
assert.Equal(t, "ccccccc", GetTIDFromMetadata(md))
19+
20+
SetSIDToMetadata(md, "aaaaaaa")
21+
assert.Equal(t, "aaaaaaa", GetSIDFromMetadata(md))
1522
}

core/server.go

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"io"
88
"net"
99
"os"
10+
"reflect"
1011
"sync"
1112
"sync/atomic"
1213

@@ -21,6 +22,9 @@ import (
2122
// authentication implements, Currently, only token authentication is implemented
2223
_ "github.com/yomorun/yomo/pkg/auth"
2324
"github.com/yomorun/yomo/pkg/frame-codec/y3codec"
25+
"github.com/yomorun/yomo/pkg/id"
26+
"github.com/yomorun/yomo/pkg/trace"
27+
oteltrace "go.opentelemetry.io/otel/trace"
2428
)
2529

2630
// ErrServerClosed is returned by the Server's Serve and ListenAndServe methods after a call to Shutdown or Close.
@@ -51,6 +55,7 @@ type Server struct {
5155
connectionCloseHandlers []ConnectionHandler
5256
listener Listener
5357
logger *slog.Logger
58+
tracerProvider oteltrace.TracerProvider
5459
}
5560

5661
// NewServer create a Server instance.
@@ -71,6 +76,7 @@ func NewServer(name string, opts ...ServerOption) *Server {
7176
name: name,
7277
downstreams: make(map[string]FrameWriterConnection),
7378
logger: logger,
79+
tracerProvider: options.tracerProvider,
7480
codec: y3codec.Codec(),
7581
packetReadWriter: y3codec.PacketReadWriter(),
7682
opts: options,
@@ -313,7 +319,40 @@ func (s *Server) handleDataFrame(c *Context) error {
313319
atomic.AddInt64(&s.counterOfDataFrame, 1)
314320

315321
from := c.DataStream
316-
322+
// trace
323+
tid := GetTIDFromMetadata(c.FrameMetadata)
324+
sid := GetSIDFromMetadata(c.FrameMetadata)
325+
tp := s.TracerProvider()
326+
if tp != nil {
327+
span, err := trace.NewSpan(tp, "zipper", "handle DataFrame", tid, sid)
328+
if err != nil {
329+
s.logger.Error("zipper trace error", "err", err)
330+
} else {
331+
defer span.End()
332+
tid = span.SpanContext().TraceID().String()
333+
sid = span.SpanContext().SpanID().String()
334+
}
335+
}
336+
if tid == "" {
337+
s.logger.Debug("zipper create new tid")
338+
tid = id.TID()
339+
}
340+
if sid == "" {
341+
s.logger.Debug("zipper create new sid")
342+
sid = id.SID()
343+
}
344+
// reallocate metadata with new TID and SID
345+
SetTIDToMetadata(c.FrameMetadata, tid)
346+
SetSIDToMetadata(c.FrameMetadata, sid)
347+
md, err := c.FrameMetadata.Encode()
348+
if err != nil {
349+
s.logger.Error("encode metadata error", "err", err)
350+
return err
351+
}
352+
c.Frame.Metadata = md
353+
if tp != nil {
354+
s.logger.Debug("zipper trace", "tid", tid, "sid", sid, "frome_stream_name", from.Name())
355+
}
317356
// route
318357
route := s.router.Route(c.FrameMetadata)
319358
if route == nil {
@@ -435,6 +474,7 @@ func (s *Server) dispatchToDownstreams(c *Context) {
435474
var (
436475
broadcast = GetBroadcastFromMetadata(c.FrameMetadata)
437476
tid = GetTIDFromMetadata(c.FrameMetadata)
477+
sid = GetSIDFromMetadata(c.FrameMetadata)
438478
)
439479
if broadcast {
440480
mdBytes, err := c.FrameMetadata.Encode()
@@ -445,7 +485,7 @@ func (s *Server) dispatchToDownstreams(c *Context) {
445485
c.Frame.Metadata = mdBytes
446486

447487
for streamID, ds := range s.downstreams {
448-
c.Logger.Info("dispatching to downstream", "dispatch_stream_id", streamID, "tid", tid)
488+
c.Logger.Info("dispatching to downstream", "dispatch_stream_id", streamID, "tid", tid, "sid", sid)
449489
ds.WriteFrame(c.Frame)
450490
}
451491
}
@@ -493,3 +533,14 @@ func (s *Server) authNames() []string {
493533

494534
// Name returns the name of server.
495535
func (s *Server) Name() string { return s.name }
536+
537+
// TracerProvider returns the tracer provider of server.
538+
func (s *Server) TracerProvider() oteltrace.TracerProvider {
539+
if s.tracerProvider == nil {
540+
return nil
541+
}
542+
if reflect.ValueOf(s.tracerProvider).IsNil() {
543+
return nil
544+
}
545+
return s.tracerProvider
546+
}

core/server_options.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/quic-go/quic-go"
77
"github.com/yomorun/yomo/core/auth"
88
"github.com/yomorun/yomo/core/ylog"
9+
oteltrace "go.opentelemetry.io/otel/trace"
910
"golang.org/x/exp/slog"
1011
)
1112

@@ -15,10 +16,11 @@ type ServerOption func(*serverOptions)
1516
// ServerOptions are the options for YoMo server.
1617
// TODO: quic alpn function.
1718
type serverOptions struct {
18-
quicConfig *quic.Config
19-
tlsConfig *tls.Config
20-
auths map[string]auth.Authentication
21-
logger *slog.Logger
19+
quicConfig *quic.Config
20+
tlsConfig *tls.Config
21+
auths map[string]auth.Authentication
22+
logger *slog.Logger
23+
tracerProvider oteltrace.TracerProvider
2224
}
2325

2426
func defaultServerOptions() *serverOptions {
@@ -66,3 +68,10 @@ func WithServerLogger(logger *slog.Logger) ServerOption {
6668
o.logger = logger
6769
}
6870
}
71+
72+
// WithServerTracerProvider sets tracer provider for the server.
73+
func WithServerTracerProvider(tp oteltrace.TracerProvider) ServerOption {
74+
return func(o *serverOptions) {
75+
o.tracerProvider = tp
76+
}
77+
}

core/serverless/context.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package serverless
22

3-
import "github.com/yomorun/yomo/core/frame"
3+
import (
4+
"github.com/yomorun/yomo/core/frame"
5+
)
46

57
// Context sfn handler context
68
type Context struct {

example/0-basic/Taskfile.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,19 @@ tasks:
2222
deps: [source-build, sfn-build]
2323
cmds:
2424
- echo 'building done'
25+
internal: true
2526

2627
source-build:
2728
desc: build source
2829
cmds:
2930
- "go build -o ./bin/source{{exeExt}} source/main.go"
31+
internal: true
3032

3133
sfn-build:
3234
desc: build sfn
3335
cmds:
3436
- "go build -o ./bin/sfn{{exeExt}} sfn/main.go"
37+
internal: true
3538

3639
source:
3740
desc: run source

example/0-basic/sfn/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ func main() {
3232
// start
3333
err := sfn.Connect()
3434
if err != nil {
35-
slog.Error("[sfn1] connect", err)
35+
slog.Error("[sfn] connect", err)
3636
os.Exit(1)
3737
}
3838
// set the error handler function when server error occurs
3939
sfn.SetErrorHandler(func(err error) {
40-
slog.Error("[sfn1] receive server error", "err", err)
40+
slog.Error("[sfn] receive server error", "err", err)
4141
sfn.Close()
4242
os.Exit(1)
4343
})

0 commit comments

Comments
 (0)