...

Source file src/golang.conradwood.net/go-easyops/errors/shared/strings.go

Documentation: golang.conradwood.net/go-easyops/errors/shared

     1  package shared
     2  
     3  import (
     4  	goerrors "errors"
     5  	"fmt"
     6  	"reflect"
     7  	"strings"
     8  
     9  	"github.com/golang/protobuf/proto"
    10  	"golang.conradwood.net/apis/common"
    11  	fw "golang.conradwood.net/apis/framework"
    12  	"golang.conradwood.net/apis/goeasyops"
    13  	goe "golang.conradwood.net/apis/goeasyops"
    14  	"google.golang.org/grpc/status"
    15  	proto2 "google.golang.org/protobuf/proto"
    16  	"google.golang.org/protobuf/protoadapt"
    17  )
    18  
    19  // extracts the PRIVATE and possibly SENSITIVE debug error message from a string
    20  // the reason this is so convoluted with different types, is that different versions of grpc
    21  // encapsulate status details in different messages.
    22  // also note the message between "google.golang.org/protobuf/proto" and	"github.com/golang/protobuf/proto"
    23  
    24  func ErrorString(err error) string {
    25  	st := status.Convert(err)
    26  	s := "[STATUS] "
    27  	deli := ""
    28  	var cstatus *common.Status
    29  	var gel *goe.GRPCErrorList
    30  	for _, a := range st.Details() {
    31  		unknown := true
    32  
    33  		st, ok := a.(*common.Status)
    34  		if ok {
    35  			cstatus = st
    36  			continue
    37  		}
    38  		lgel, ok := a.(*goeasyops.GRPCErrorList)
    39  		if ok {
    40  			gel = lgel
    41  			s = s + deli + ge2string(lgel)
    42  			continue
    43  		}
    44  
    45  		// check newer proto messages now
    46  		proto2m, okconv := a.(proto2.Message)
    47  		if !okconv {
    48  			z := fmt.Sprintf("[type=%v]", reflect.TypeOf(a))
    49  			fmt.Printf("[go-easyops] Failed to convert error message (%v %v)\n", a, z)
    50  			s = s + fmt.Sprintf(" =%v= ", a)
    51  			continue
    52  		}
    53  		msgname := proto2.MessageName(proto2m)
    54  		//	msg := proto2m.ProtoReflect()
    55  		pv1 := protoadapt.MessageV1Of(proto2m)
    56  		//	fmt.Printf("Proto2 (%s): %#v %v \n", msgname, proto2m, pv1)
    57  		if msgname == "goeasyops.GRPCErrorList" {
    58  			xgel, ok := pv1.(*goe.GRPCErrorList)
    59  			if ok {
    60  				gel = xgel
    61  				s = s + deli + ge2string(xgel)
    62  				continue
    63  			}
    64  		} else if msgname == "common.Status" {
    65  			st, ok := pv1.(*common.Status)
    66  			if ok {
    67  				cstatus = st
    68  				continue
    69  			}
    70  		}
    71  
    72  		fmd, ok := a.(*fw.FrameworkMessageDetail)
    73  		if ok {
    74  			unknown = false
    75  			s = s + deli + fmd2string(fmd)
    76  		}
    77  
    78  		ge, ok := a.(*goe.GRPCErrorList)
    79  		if unknown && ok {
    80  			unknown = false
    81  			s = s + deli + ge2string(ge)
    82  		}
    83  
    84  		ge2, ok := a.(goe.GRPCErrorList)
    85  		if unknown && ok {
    86  			unknown = false
    87  			s = s + deli + ge2string(&ge2)
    88  		}
    89  
    90  		x, ok := a.(goe.GRPCError)
    91  		if unknown && ok {
    92  			unknown = false
    93  			s = s + deli + fmt.Sprintf("CALLTRACE: %v", x)
    94  		}
    95  
    96  		x2, ok := a.(*fw.CallTrace)
    97  		if unknown && ok {
    98  			unknown = false
    99  			s = s + deli + fmt.Sprintf("CALLTRACE: %v", x2)
   100  		}
   101  
   102  		proto, ok := a.(proto.Message)
   103  		if unknown && ok {
   104  			unknown = false
   105  			s = s + deli + "proto:" + proto.String()
   106  		}
   107  
   108  		deli = "->"
   109  
   110  	}
   111  	s = s + ": " + st.Message() + " [/STATUS]"
   112  	//	fmt.Printf("cstatus=%v\n", cstatus)
   113  	if cstatus == nil && gel == nil {
   114  		return s
   115  	}
   116  	gel_s := ""
   117  	if gel != nil {
   118  		gel_s = ge2string(gel)
   119  	}
   120  	cs_s := ""
   121  	if cstatus != nil {
   122  		cs_s = fmt.Sprintf("code=%d(%s)", cstatus.ErrorCode, cstatus.ErrorDescription)
   123  	}
   124  	// THIS IS THE NORMAL NEW wayy of doing it...
   125  	s = fmt.Sprintf("(N) %s %s", cs_s, gel_s)
   126  	return s
   127  
   128  }
   129  
   130  func fmd2string(fmd *fw.FrameworkMessageDetail) string {
   131  	s := ""
   132  	for _, ct := range fmd.CallTraces {
   133  		if ct.Service != "" {
   134  			spl := strings.SplitN(ct.Service, ".", 2)
   135  			sn := ct.Service
   136  			if len(spl) == 2 {
   137  				sn = spl[1]
   138  			}
   139  			s = fmt.Sprintf("(1 %s.%s)", sn, ct.Method)
   140  		} else {
   141  			s = fmt.Sprintf("(2 %s)", ct.Message)
   142  		}
   143  	}
   144  	return s
   145  }
   146  
   147  func ge2string(fmd *goe.GRPCErrorList) string {
   148  	s := ""
   149  	for _, ct := range fmd.Errors {
   150  		if ct.ServiceName != "" {
   151  			spl := strings.SplitN(ct.ServiceName, ".", 2)
   152  			sn := ct.ServiceName
   153  			if len(spl) == 2 {
   154  				sn = spl[1]
   155  			}
   156  			s = fmt.Sprintf("(3 %s.%s)", sn, ct.MethodName)
   157  		} else {
   158  			s = fmt.Sprintf("(4 %s)", ct.LogMessage)
   159  		}
   160  	}
   161  	return s
   162  }
   163  
   164  func ErrorStringWithStackTrace(err error) string {
   165  	// given some error, first find those with stack traces
   166  	var stacks []StackError
   167  	e := err
   168  	for {
   169  		if e == nil {
   170  			break
   171  		}
   172  		est, ok := e.(*MyError)
   173  		if ok {
   174  			stacks = append(stacks, est)
   175  			e = est.err
   176  			continue
   177  		}
   178  		wst, ok := e.(*WrappedError)
   179  		if ok {
   180  			stacks = append(stacks, wst)
   181  			e = wst.err
   182  			continue
   183  		}
   184  		e = goerrors.Unwrap(e)
   185  	}
   186  	has_stacktrace := false
   187  	st := "(no stacktrace)"
   188  	if len(stacks) > 0 {
   189  		has_stacktrace = true
   190  		stack := stacks[len(stacks)-1]
   191  		st = stackToString(stack.Stack())
   192  	}
   193  
   194  	s := fmt.Sprintf("Error (no stacktrace): \"%s\", Log: \"%s\"", err, ErrorString(err))
   195  	if has_stacktrace {
   196  		s = fmt.Sprintf("Error: \"%s\", Log: \"%s\"\nStackTrace:\n%s", err, ErrorString(err), st)
   197  	}
   198  	return s
   199  }
   200  
   201  func stackToString(stack ErrorStackTrace) string {
   202  	res := ""
   203  	starting := true
   204  	for _, pos := range stack.Positions() {
   205  		if starting {
   206  			if pos.IsFiltered() {
   207  				continue
   208  			}
   209  		}
   210  		starting = false
   211  		res = res + fmt.Sprintf("%s:%d\n", pos.Filename, pos.Line)
   212  		if pos.Function == "main.main" {
   213  			break
   214  		}
   215  	}
   216  	return res
   217  
   218  }
   219  
   220  func ShortMessage(err error) string {
   221  	e1, ok := err.(*MyError)
   222  	if ok {
   223  		return fmt.Sprintf("%s", e1.err)
   224  	}
   225  	e2, ok := err.(*WrappedError)
   226  	if ok {
   227  		// cannot do recursion here, beacuse of potential infinity
   228  		unwrap := e2
   229  		for i := 0; i < 10; i++ {
   230  			fmt.Printf("UNWRAP: %s\n", unwrap)
   231  			x, ok := unwrap.err.(*WrappedError)
   232  			if !ok {
   233  				return ShortMessage(unwrap.err)
   234  			}
   235  			unwrap = x
   236  		}
   237  		return fmt.Sprintf("%s", e2.err)
   238  	}
   239  
   240  	return fmt.Sprintf("%s", err)
   241  }
   242  

View as plain text