Browse Source

Use errors.Trace in protobufConverter helpers

Rod Hynes 2 months ago
parent
commit
be3bac6a50
1 changed files with 56 additions and 120 deletions
  1. 56 120
      psiphon/server/protobufConverter.go

+ 56 - 120
psiphon/server/protobufConverter.go

@@ -447,7 +447,7 @@ func protobufPopulateMessageFromFields(logFields LogFields, msg proto.Message) {
 
 		// Handle special field names that might be mapped differently.
 		if err := setProtobufFieldValue(field, fieldType, logValue); err != nil {
-			panic(fmt.Errorf("failed to set field value: %w", err))
+			panic(errors.Tracef("failed to set field value: %w", err))
 		}
 	}
 }
@@ -490,32 +490,32 @@ func getProtobufFieldName(protoTag string) string {
 	return ""
 }
 
-// protobufConversionError represents an error during type conversion
-type protobufConversionError struct {
-	fieldName string
-	fromType  string
-	toType    string
-	value     any
-	err       error
-}
-
-func (e *protobufConversionError) Error() string {
-	return fmt.Sprintf("failed to convert field %s from %s to %s (value: %v): %v",
-		e.fieldName, e.fromType, e.toType, e.value, e.err)
-}
-
 // setProtobufFieldValue sets a protobuf field value from a LogFields value.
 func setProtobufFieldValue(field reflect.Value, fieldType reflect.StructField, logValue any) error {
 	if logValue == nil {
 		return nil // Don't set anything for nil values
 	}
 
+	var err error
+
 	// Handle pointers by creating a new instance and setting recursively
 	if field.Kind() == reflect.Ptr {
-		return setProtobufPointerField(field, fieldType, logValue)
+		err = setProtobufPointerField(field, fieldType, logValue)
+	} else {
+		err = setProtobufPrimitiveField(field, fieldType, logValue)
 	}
 
-	return setProtobufPrimitiveField(field, fieldType, logValue)
+	if err != nil {
+		err = errors.Tracef(
+			"failed to convert field %s value `%v` type %T to %s : %w",
+			fieldType.Name,
+			logValue,
+			logValue,
+			fieldType.Type.String(),
+			errors.Trace(err))
+	}
+
+	return nil
 }
 
 // setProtobufPointerField handles pointer fields by creating new instances
@@ -526,7 +526,7 @@ func setProtobufPointerField(field reflect.Value, fieldType reflect.StructField,
 	if elemType == reflect.TypeOf(timestamppb.Timestamp{}) {
 		ts, err := protobufConvertToTimestamp(logValue)
 		if err != nil {
-			return err
+			return errors.Trace(err)
 		}
 
 		if ts != nil {
@@ -540,7 +540,7 @@ func setProtobufPointerField(field reflect.Value, fieldType reflect.StructField,
 	newVal := reflect.New(elemType)
 	err := setProtobufPrimitiveField(newVal.Elem(), fieldType, logValue)
 	if err != nil {
-		return err
+		return errors.Trace(err)
 	}
 
 	field.Set(newVal)
@@ -550,42 +550,32 @@ func setProtobufPointerField(field reflect.Value, fieldType reflect.StructField,
 
 // setProtobufPrimitiveField handles non-pointer fields
 func setProtobufPrimitiveField(field reflect.Value, fieldType reflect.StructField, logValue any) error {
+	var err error
 	switch field.Kind() {
 	case reflect.String:
-		return setProtobufStringField(field, fieldType, logValue)
+		err = setProtobufStringField(field, fieldType, logValue)
 	case reflect.Int, reflect.Int32, reflect.Int64:
-		return setProtobufIntField(field, fieldType, logValue)
+		err = setProtobufIntField(field, fieldType, logValue)
 	case reflect.Uint, reflect.Uint32, reflect.Uint64:
-		return setProtobufUintField(field, fieldType, logValue)
+		err = setProtobufUintField(field, fieldType, logValue)
 	case reflect.Float64:
-		return setProtobufFloat64Field(field, fieldType, logValue)
+		err = setProtobufFloat64Field(field, fieldType, logValue)
 	case reflect.Bool:
-		return setProtobufBoolField(field, fieldType, logValue)
+		err = setProtobufBoolField(field, fieldType, logValue)
 	case reflect.Map:
-		return setProtobufMapField(field, fieldType, logValue)
+		err = setProtobufMapField(field, fieldType, logValue)
 	case reflect.Slice:
-		return setProtobufSliceField(field, fieldType, logValue)
+		err = setProtobufSliceField(field, fieldType, logValue)
 	default:
-		return &protobufConversionError{
-			fieldName: fieldType.Name,
-			fromType:  fmt.Sprintf("%T", logValue),
-			toType:    field.Kind().String(),
-			value:     logValue,
-			err:       fmt.Errorf("unsupported field kind"),
-		}
+		err = errors.TraceNew("unsupported field kind")
 	}
+	return errors.Trace(err)
 }
 
 func setProtobufStringField(field reflect.Value, fieldType reflect.StructField, logValue any) error {
 	str, err := protobufConvertToString(logValue)
 	if err != nil {
-		return &protobufConversionError{
-			fieldName: fieldType.Name,
-			fromType:  fmt.Sprintf("%T", logValue),
-			toType:    "string",
-			value:     logValue,
-			err:       err,
-		}
+		return errors.Trace(err)
 	}
 
 	// Handle special cases for string fields
@@ -600,26 +590,14 @@ func setProtobufStringField(field reflect.Value, fieldType reflect.StructField,
 }
 
 func setProtobufIntField(field reflect.Value, fieldType reflect.StructField, logValue any) error {
-	convErr := &protobufConversionError{
-		fieldName: fieldType.Name,
-		fromType:  fmt.Sprintf("%T", logValue),
-		value:     logValue,
-	}
 
-	switch field.Kind() {
-	case reflect.Int, reflect.Int64:
-		// Because we extensively run on 64-bit architectures and protobuf
-		// doesn't have the architecture switching int type, for consistency,
-		// we always use int64 in our protos to represent int in go.
-		convErr.toType = "int64"
-	case reflect.Int32:
-		convErr.toType = "int32"
-	}
+	// Because we extensively run on 64-bit architectures and protobuf
+	// doesn't have the architecture switching int type, for consistency,
+	// we always use int64 in our protos to represent int in go.
 
 	val, err := protobufConvertToInt64(logValue)
 	if err != nil {
-		convErr.err = err
-		return convErr
+		return errors.Trace(err)
 	}
 
 	field.SetInt(val)
@@ -627,26 +605,14 @@ func setProtobufIntField(field reflect.Value, fieldType reflect.StructField, log
 }
 
 func setProtobufUintField(field reflect.Value, fieldType reflect.StructField, logValue any) error {
-	convErr := &protobufConversionError{
-		fieldName: fieldType.Name,
-		fromType:  fmt.Sprintf("%T", logValue),
-		value:     logValue,
-	}
 
-	switch field.Kind() {
-	case reflect.Uint, reflect.Uint64:
-		// Because we extensively run on 64-bit architectures and protobuf
-		// doesn't have the architecture switching int type, for consistency,
-		// we always use uint64 in our protos to represent uint in go.
-		convErr.toType = "uint64"
-	case reflect.Uint32:
-		convErr.toType = "uint32"
-	}
+	// Because we extensively run on 64-bit architectures and protobuf
+	// doesn't have the architecture switching int type, for consistency,
+	// we always use uint64 in our protos to represent uint in go.
 
 	val, err := protobufConvertToUint64(logValue)
 	if err != nil {
-		convErr.err = err
-		return convErr
+		return errors.Trace(err)
 	}
 
 	field.SetUint(val)
@@ -656,13 +622,7 @@ func setProtobufUintField(field reflect.Value, fieldType reflect.StructField, lo
 func setProtobufFloat64Field(field reflect.Value, fieldType reflect.StructField, logValue any) error {
 	val, err := protobufConvertToFloat64(logValue)
 	if err != nil {
-		return &protobufConversionError{
-			fieldName: fieldType.Name,
-			fromType:  fmt.Sprintf("%T", logValue),
-			toType:    "float64",
-			value:     logValue,
-			err:       err,
-		}
+		return errors.Trace(err)
 	}
 
 	field.SetFloat(val)
@@ -672,13 +632,7 @@ func setProtobufFloat64Field(field reflect.Value, fieldType reflect.StructField,
 func setProtobufBoolField(field reflect.Value, fieldType reflect.StructField, logValue any) error {
 	val, err := protobufConvertToBool(logValue)
 	if err != nil {
-		return &protobufConversionError{
-			fieldName: fieldType.Name,
-			fromType:  fmt.Sprintf("%T", logValue),
-			toType:    "bool",
-			value:     logValue,
-			err:       err,
-		}
+		return errors.Trace(err)
 	}
 
 	field.SetBool(val)
@@ -688,13 +642,7 @@ func setProtobufBoolField(field reflect.Value, fieldType reflect.StructField, lo
 func setProtobufMapField(field reflect.Value, fieldType reflect.StructField, logValue any) error {
 	mapValue, ok := logValue.(map[string]int64)
 	if !ok {
-		return &protobufConversionError{
-			fieldName: fieldType.Name,
-			fromType:  fmt.Sprintf("%T", logValue),
-			toType:    "map[string]int64",
-			value:     logValue,
-			err:       fmt.Errorf("expected map[string]int64"),
-		}
+		return errors.TraceNew("expected map[string]int64")
 	}
 
 	newMap := reflect.MakeMap(field.Type())
@@ -714,13 +662,7 @@ func setProtobufSliceField(field reflect.Value, fieldType reflect.StructField, l
 		for i, elem := range sliceValue {
 			str, ok := elem.(string)
 			if !ok {
-				return &protobufConversionError{
-					fieldName: fieldType.Name,
-					fromType:  fmt.Sprintf("%T", elem),
-					toType:    "string",
-					value:     elem,
-					err:       fmt.Errorf("slice element at index %d is not a string", i),
-				}
+				return errors.Tracef("slice element at index %d is not a string", i)
 			}
 			newSlice = append(newSlice, str)
 		}
@@ -747,13 +689,7 @@ func setProtobufSliceField(field reflect.Value, fieldType reflect.StructField, l
 		field.Set(reflect.ValueOf(newSlice))
 
 	default:
-		return &protobufConversionError{
-			fieldName: fieldType.Name,
-			fromType:  fmt.Sprintf("%T", logValue),
-			toType:    "[]string",
-			value:     logValue,
-			err:       fmt.Errorf("expected []any or []string"),
-		}
+		return errors.TraceNew("unexpected slice type")
 	}
 
 	return nil
@@ -768,7 +704,7 @@ func protobufConvertToString(value any) (string, error) {
 		return v.String(), nil
 
 	default:
-		return "", fmt.Errorf("cannot convert %T to string", value)
+		return "", errors.Tracef("cannot convert %T to string", value)
 	}
 }
 
@@ -785,7 +721,7 @@ func protobufConvertToInt64(value any) (int64, error) {
 
 	case string:
 		if v == "" {
-			return 0, fmt.Errorf("cannot convert empty string to int64")
+			return 0, errors.TraceNew("cannot convert empty string to int64")
 		}
 
 		return strconv.ParseInt(v, 10, 64)
@@ -796,13 +732,13 @@ func protobufConvertToInt64(value any) (int64, error) {
 			return int64(v), nil
 		}
 
-		return 0, fmt.Errorf("float64 %f is not a whole number", v)
+		return 0, errors.Tracef("float64 %f is not a whole number", v)
 
 	case time.Duration:
 		return int64(v), nil
 
 	default:
-		return 0, fmt.Errorf("cannot convert %T to int64", value)
+		return 0, errors.Tracef("cannot convert %T to int64", value)
 	}
 }
 
@@ -819,27 +755,27 @@ func protobufConvertToUint64(value any) (uint64, error) {
 
 	case int:
 		if v < 0 {
-			return 0, fmt.Errorf("cannot convert negative int %d to uint64", v)
+			return 0, errors.Tracef("cannot convert negative int %d to uint64", v)
 		}
 
 		return uint64(v), nil
 
 	case int64:
 		if v < 0 {
-			return 0, fmt.Errorf("cannot convert negative int64 %d to uint64", v)
+			return 0, errors.Tracef("cannot convert negative int64 %d to uint64", v)
 		}
 
 		return uint64(v), nil
 
 	case string:
 		if v == "" {
-			return 0, fmt.Errorf("cannot convert empty string to uint64")
+			return 0, errors.TraceNew("cannot convert empty string to uint64")
 		}
 
 		return strconv.ParseUint(v, 10, 64)
 
 	default:
-		return 0, fmt.Errorf("cannot convert %T to uint64", value)
+		return 0, errors.Tracef("cannot convert %T to uint64", value)
 	}
 }
 
@@ -859,13 +795,13 @@ func protobufConvertToFloat64(value any) (float64, error) {
 
 	case string:
 		if v == "" {
-			return 0, fmt.Errorf("cannot convert empty string to float64")
+			return 0, errors.TraceNew("cannot convert empty string to float64")
 		}
 
 		return strconv.ParseFloat(v, 64)
 
 	default:
-		return 0, fmt.Errorf("cannot convert %T to float64", value)
+		return 0, errors.Tracef("cannot convert %T to float64", value)
 	}
 }
 
@@ -883,7 +819,7 @@ func protobufConvertToBool(value any) (bool, error) {
 			return false, nil
 
 		default:
-			return false, fmt.Errorf("cannot convert string %q to bool", v)
+			return false, errors.Tracef("cannot convert string %q to bool", v)
 		}
 	case int:
 		return v != 0, nil
@@ -914,7 +850,7 @@ func protobufConvertToTimestamp(value any) (*timestamppb.Timestamp, error) {
 			}
 		}
 		if err != nil {
-			return nil, fmt.Errorf("cannot parse timestamp string %q", v)
+			return nil, errors.Tracef("cannot parse timestamp string %q", v)
 		}
 
 		return timestamppb.New(t), nil
@@ -934,6 +870,6 @@ func protobufConvertToTimestamp(value any) (*timestamppb.Timestamp, error) {
 		return timestamppb.New(*v), nil
 
 	default:
-		return nil, fmt.Errorf("cannot convert %T to timestamp", value)
+		return nil, errors.Tracef("cannot convert %T to timestamp", value)
 	}
 }