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