github.com/annwntech/go-micro/v2@v2.9.5/debug/service/handler/debug.go (about) 1 // Package handler implements service debug handler embedded in go-micro services 2 package handler 3 4 import ( 5 "context" 6 "time" 7 8 "github.com/annwntech/go-micro/v2/client" 9 "github.com/annwntech/go-micro/v2/debug/log" 10 proto "github.com/annwntech/go-micro/v2/debug/service/proto" 11 "github.com/annwntech/go-micro/v2/debug/stats" 12 "github.com/annwntech/go-micro/v2/debug/trace" 13 "github.com/annwntech/go-micro/v2/server" 14 ) 15 16 // NewHandler returns an instance of the Debug Handler 17 func NewHandler(c client.Client) *Debug { 18 return &Debug{ 19 log: log.DefaultLog, 20 stats: stats.DefaultStats, 21 trace: trace.DefaultTracer, 22 cache: c.Options().Cache, 23 } 24 } 25 26 type Debug struct { 27 // must honour the debug handler 28 proto.DebugHandler 29 // the logger for retrieving logs 30 log log.Log 31 // the stats collector 32 stats stats.Stats 33 // the tracer 34 trace trace.Tracer 35 // the cache 36 cache *client.Cache 37 } 38 39 func (d *Debug) Health(ctx context.Context, req *proto.HealthRequest, rsp *proto.HealthResponse) error { 40 rsp.Status = "ok" 41 return nil 42 } 43 44 func (d *Debug) Stats(ctx context.Context, req *proto.StatsRequest, rsp *proto.StatsResponse) error { 45 stats, err := d.stats.Read() 46 if err != nil { 47 return err 48 } 49 50 if len(stats) == 0 { 51 return nil 52 } 53 54 // write the response values 55 rsp.Timestamp = uint64(stats[0].Timestamp) 56 rsp.Started = uint64(stats[0].Started) 57 rsp.Uptime = uint64(stats[0].Uptime) 58 rsp.Memory = stats[0].Memory 59 rsp.Gc = stats[0].GC 60 rsp.Threads = stats[0].Threads 61 rsp.Requests = stats[0].Requests 62 rsp.Errors = stats[0].Errors 63 64 return nil 65 } 66 67 func (d *Debug) Trace(ctx context.Context, req *proto.TraceRequest, rsp *proto.TraceResponse) error { 68 traces, err := d.trace.Read(trace.ReadTrace(req.Id)) 69 if err != nil { 70 return err 71 } 72 73 for _, t := range traces { 74 var typ proto.SpanType 75 switch t.Type { 76 case trace.SpanTypeRequestInbound: 77 typ = proto.SpanType_INBOUND 78 case trace.SpanTypeRequestOutbound: 79 typ = proto.SpanType_OUTBOUND 80 } 81 rsp.Spans = append(rsp.Spans, &proto.Span{ 82 Trace: t.Trace, 83 Id: t.Id, 84 Parent: t.Parent, 85 Name: t.Name, 86 Started: uint64(t.Started.UnixNano()), 87 Duration: uint64(t.Duration.Nanoseconds()), 88 Type: typ, 89 Metadata: t.Metadata, 90 }) 91 } 92 93 return nil 94 } 95 96 func (d *Debug) Log(ctx context.Context, stream server.Stream) error { 97 req := new(proto.LogRequest) 98 if err := stream.Recv(req); err != nil { 99 return err 100 } 101 102 var options []log.ReadOption 103 104 since := time.Unix(req.Since, 0) 105 if !since.IsZero() { 106 options = append(options, log.Since(since)) 107 } 108 109 count := int(req.Count) 110 if count > 0 { 111 options = append(options, log.Count(count)) 112 } 113 114 if req.Stream { 115 // TODO: we need to figure out how to close the log stream 116 // It seems like when a client disconnects, 117 // the connection stays open until some timeout expires 118 // or something like that; that means the map of streams 119 // might end up leaking memory if not cleaned up properly 120 lgStream, err := d.log.Stream() 121 if err != nil { 122 return err 123 } 124 defer lgStream.Stop() 125 126 for record := range lgStream.Chan() { 127 // copy metadata 128 metadata := make(map[string]string) 129 for k, v := range record.Metadata { 130 metadata[k] = v 131 } 132 // send record 133 if err := stream.Send(&proto.Record{ 134 Timestamp: record.Timestamp.Unix(), 135 Message: record.Message.(string), 136 Metadata: metadata, 137 }); err != nil { 138 return err 139 } 140 } 141 142 // done streaming, return 143 return nil 144 } 145 146 // get the log records 147 records, err := d.log.Read(options...) 148 if err != nil { 149 return err 150 } 151 152 // send all the logs downstream 153 for _, record := range records { 154 // copy metadata 155 metadata := make(map[string]string) 156 for k, v := range record.Metadata { 157 metadata[k] = v 158 } 159 // send record 160 if err := stream.Send(&proto.Record{ 161 Timestamp: record.Timestamp.Unix(), 162 Message: record.Message.(string), 163 Metadata: metadata, 164 }); err != nil { 165 return err 166 } 167 } 168 169 return nil 170 } 171 172 // Cache returns all the key value pairs in the client cache 173 func (d *Debug) Cache(ctx context.Context, req *proto.CacheRequest, rsp *proto.CacheResponse) error { 174 rsp.Values = d.cache.List() 175 return nil 176 }