...
1 package server
2
3 import (
4 "context"
5 "flag"
6 "fmt"
7 "time"
8
9 el "golang.conradwood.net/apis/errorlogger"
10 fw "golang.conradwood.net/apis/framework"
11 ge "golang.conradwood.net/apis/goeasyops"
12 "golang.conradwood.net/go-easyops/auth"
13 "golang.conradwood.net/go-easyops/authremote"
14 "golang.conradwood.net/go-easyops/client"
15 "golang.conradwood.net/go-easyops/cmdline"
16 gctx "golang.conradwood.net/go-easyops/ctx"
17 "golang.conradwood.net/go-easyops/errors"
18 "golang.conradwood.net/go-easyops/utils"
19 "google.golang.org/grpc/status"
20 proto2 "google.golang.org/protobuf/proto"
21 "google.golang.org/protobuf/protoadapt"
22 )
23
24 var (
25 logChan = make(chan *le, 200)
26 els el.ErrorLoggerClient
27 error_looping = false
28 send_to_error_logger = flag.Bool("ge_use_errorlogger", true, "if false, do not send stuff to error logger")
29 debug_elog = flag.Bool("ge_debug_error_log", false, "if true debug what is being sent to the error logger")
30 )
31
32 type le struct {
33 ts time.Time
34 sd *serverDef
35 rc *rpccall
36 ctx context.Context
37 err error
38 }
39
40 func (sd *serverDef) logError(ctx context.Context, rc *rpccall, err error) {
41 if cmdline.IsStandalone() {
42 fmt.Printf("[go-easyops] ERROR: %s\n", err)
43 }
44 if len(logChan) > 100 {
45 fmt.Printf("[go-easyops] Dropping errorlog (not logging \"%s\")\n", errors.ErrorString(err))
46 return
47 }
48 l := &le{sd: sd, ctx: ctx, rc: rc, err: err, ts: time.Now()}
49 logChan <- l
50 }
51 func error_handler_startup() {
52 if cmdline.IsStandalone() {
53 return
54 }
55 if error_looping {
56 return
57 }
58 error_looping = true
59 if els == nil {
60 els = el.NewErrorLoggerClient(client.Connect("errorlogger.ErrorLogger"))
61 }
62 go logLoop()
63 }
64 func logLoop() {
65 for {
66 l := <-logChan
67 log(l)
68 }
69 }
70 func log(l *le) {
71 u := auth.GetUser(l.ctx)
72 uid := ""
73 if u != nil {
74 uid = u.ID
75 }
76 reqid := "norequestidinerrorhandler"
77 if l.ctx != nil {
78 reqid = gctx.GetRequestID(l.ctx)
79 }
80 svc := auth.GetService(l.ctx)
81 st := status.Convert(l.err)
82 e := &el.ErrorLogRequest{
83 UserID: uid,
84 ErrorCode: uint32(st.Code()),
85 ErrorMessage: fmt.Sprintf("%s", l.err),
86 LogMessage: utils.ErrorString(l.err),
87 ServiceName: l.rc.ServiceName,
88 MethodName: l.rc.MethodName,
89 Timestamp: uint32(l.ts.Unix()),
90 RequestID: reqid,
91 CallingService: svc,
92 Errors: &ge.GRPCErrorList{},
93 }
94
106 for _, a := range st.Details() {
107 if a == nil {
108 continue
109 }
110 fmd, ok := a.(*ge.GRPCError)
111 if !ok {
112 continue
113 }
114 e.Errors.Errors = append(e.Errors.Errors, fmd)
115 }
116 ctx := authremote.Context()
117 if *debug_elog {
118 fmt.Printf("[go-easyops] errorlog: %v\n", e)
119 }
120 if *send_to_error_logger {
121 els.Log(ctx, e)
122 }
123 }
124
125
126 func AddErrorDetail(st *status.Status, ct *ge.GRPCError) *status.Status {
127
128 odet := st.Details()
129 if cmdline.IsDebugRPCServer() {
130 fancyPrintf("errorhandler Error %s (%s) (%s)\n", st.Err(), st.Message(), errors.ErrorString(st.Err()))
131 }
132
133 var gel *ge.GRPCErrorList
134 for _, d := range odet {
135 mgel, ok := d.(*ge.GRPCErrorList)
136 if ok {
137 gel = mgel
138 break
139 }
140 proto2m, ok := d.(proto2.Message)
141 if ok {
142 msgname := proto2.MessageName(proto2m)
143
144 pv1 := protoadapt.MessageV1Of(proto2m)
145
146 if msgname == "goeasyops.GRPCErrorList" {
147 xgel, ok := pv1.(*ge.GRPCErrorList)
148 if ok {
149 gel = xgel
150 break
151 }
152 }
153 }
154 }
155
156 var stn *status.Status
157 if gel == nil {
158 gel = &ge.GRPCErrorList{}
159 }
160 gel.Errors = append(gel.Errors, ct)
161
162 stn, errx := st.WithDetails(gel)
163
164
165 if errx != nil {
166 if cmdline.IsDebugRPCServer() {
167 fancyPrintf("failed to get status with detail: %s", errx)
168 }
169 return st
170 }
171
176 return stn
177 }
178 func AddStatusDetail(st *status.Status, ct *fw.CallTrace) *status.Status {
179 return st
180
211 }
212
View as plain text