mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-14 06:57:31 +00:00
client/local,cmd/tailscale/cli,ipn/localapi: expose eventbus graph (#16597)
Make it possible to dump the eventbus graph as JSON or DOT to both debug and document what is communicated via the bus. Updates #15160 Signed-off-by: Claus Lensbøl <claus@tailscale.com>
This commit is contained in:
@@ -6,6 +6,7 @@ package cli
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"cmp"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
@@ -108,6 +109,17 @@ func debugCmd() *ffcli.Command {
|
||||
Exec: runDaemonBusEvents,
|
||||
ShortHelp: "Watch events on the tailscaled bus",
|
||||
},
|
||||
{
|
||||
Name: "daemon-bus-graph",
|
||||
ShortUsage: "tailscale debug daemon-bus-graph",
|
||||
Exec: runDaemonBusGraph,
|
||||
ShortHelp: "Print graph for the tailscaled bus",
|
||||
FlagSet: (func() *flag.FlagSet {
|
||||
fs := newFlagSet("debug-bus-graph")
|
||||
fs.StringVar(&daemonBusGraphArgs.format, "format", "json", "output format [json/dot]")
|
||||
return fs
|
||||
})(),
|
||||
},
|
||||
{
|
||||
Name: "metrics",
|
||||
ShortUsage: "tailscale debug metrics",
|
||||
@@ -807,6 +819,50 @@ func runDaemonBusEvents(ctx context.Context, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var daemonBusGraphArgs struct {
|
||||
format string
|
||||
}
|
||||
|
||||
func runDaemonBusGraph(ctx context.Context, args []string) error {
|
||||
graph, err := localClient.EventBusGraph(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if format := daemonBusGraphArgs.format; format != "json" && format != "dot" {
|
||||
return fmt.Errorf("unrecognized output format %q", format)
|
||||
}
|
||||
if daemonBusGraphArgs.format == "dot" {
|
||||
var topics eventbus.DebugTopics
|
||||
if err := json.Unmarshal(graph, &topics); err != nil {
|
||||
return fmt.Errorf("unable to parse json: %w", err)
|
||||
}
|
||||
fmt.Print(generateDOTGraph(topics.Topics))
|
||||
} else {
|
||||
fmt.Print(string(graph))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateDOTGraph generates the DOT graph format based on the events
|
||||
func generateDOTGraph(topics []eventbus.DebugTopic) string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString("digraph event_bus {\n")
|
||||
|
||||
for _, topic := range topics {
|
||||
// If no subscribers, still ensure the topic is drawn
|
||||
if len(topic.Subscribers) == 0 {
|
||||
topic.Subscribers = append(topic.Subscribers, "no-subscribers")
|
||||
}
|
||||
for _, subscriber := range topic.Subscribers {
|
||||
fmt.Fprintf(&sb, "\t%q -> %q [label=%q];\n",
|
||||
topic.Publisher, subscriber, cmp.Or(topic.Name, "???"))
|
||||
}
|
||||
}
|
||||
|
||||
sb.WriteString("}\n")
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
var metricsArgs struct {
|
||||
watch bool
|
||||
}
|
||||
|
Reference in New Issue
Block a user