func newValidator()

in confgenerator/config.go [181:305]


func newValidator() *validator.Validate {
	v := validator.New()
	v.RegisterTagNameFunc(func(fld reflect.StructField) string {
		name := strings.SplitN(fld.Tag.Get("yaml"), ",", 2)[0]
		if name == "-" {
			return ""
		}
		return name
	})
	// duration validates that the value is a valid duration and >= the parameter
	v.RegisterValidation("duration", func(fl validator.FieldLevel) bool {
		fieldStr := fl.Field().String()
		if fieldStr == "" {
			// Ignore the case where this field is not actually specified or is left empty.
			return true
		}
		t, err := time.ParseDuration(fl.Field().String())
		if err != nil {
			return false
		}
		tmin, err := time.ParseDuration(fl.Param())
		if err != nil {
			panic(err)
		}
		return t >= tmin
	})
	v.RegisterStructValidation(validatePrometheusConfig, &promconfig.Config{})
	// filter validates that a Cloud Logging filter condition is valid
	v.RegisterValidation("filter", func(fl validator.FieldLevel) bool {
		_, err := filter.NewFilter(fl.Field().String())
		return err == nil
	})
	// field validates that a Cloud Logging field expression is valid
	v.RegisterValidation("field", func(fl validator.FieldLevel) bool {
		_, err := filter.NewMember(fl.Field().String())
		// TODO: Disallow specific target fields?
		return err == nil
	})
	v.RegisterValidation("fieldlegacy", func(fl validator.FieldLevel) bool {
		_, err := filter.NewMemberLegacy(fl.Field().String())
		// TODO: Disallow specific target fields?
		return err == nil
	})
	// distinctfield validates that a key in a map refers to different fields from the other keys in the map.
	// Use this as keys,distinctfield,endkeys
	v.RegisterValidation("distinctfield", func(fl validator.FieldLevel) bool {
		// Get the map that contains this key.
		parent, parentkind, found := fl.GetStructFieldOKAdvanced(fl.Parent(), fl.StructFieldName()[:strings.Index(fl.StructFieldName(), "[")])
		if !found {
			return false
		}
		if parentkind != reflect.Map {
			fmt.Printf("not map\n")
			return false
		}
		k1 := fl.Field().String()
		field, err := filter.NewMember(k1)
		if err != nil {
			fmt.Printf("newmember %q: %v", fl.Field().String(), err)
			return false
		}
		for _, key := range parent.MapKeys() {
			k2 := key.String()
			if k1 == k2 {
				// Skip itself
				continue
			}
			field2, err := filter.NewMember(k2)
			if err != nil {
				continue
			}
			if field2.Equals(*field) {
				return false
			}
		}
		return true
	})
	// writablefield checks to make sure the field is writable
	v.RegisterValidation("writablefield", func(fl validator.FieldLevel) bool {
		m1, err := filter.NewMember(fl.Field().String())
		if err != nil {
			// The "field" validator will handle this better.
			return true
		}
		// Currently, instrumentation_source is the only field that is not writable.
		m2, err := filter.NewMember(InstrumentationSourceLabel)
		if err != nil {
			panic(err)
		}
		return !m2.Equals(*m1)
	})
	// multipleof_time validates that the value duration is a multiple of the parameter
	v.RegisterValidation("multipleof_time", func(fl validator.FieldLevel) bool {
		t, ok := fl.Field().Interface().(time.Duration)
		if !ok {
			panic(fmt.Sprintf("multipleof_time: could not convert %s to time duration", fl.Field().String()))
		}
		tfactor, err := time.ParseDuration(fl.Param())
		if err != nil {
			panic(fmt.Sprintf("multipleof_time: could not convert %s to time duration", fl.Param()))
		}
		return t%tfactor == 0
	})
	// winlogchannels wraps validateWinlogChannels when receiver_version > 1 and validateWinlogV1Channels when receiver_version = 1
	// TODO: relax the "receiver_version > 1" constraint and replace validateWinlogChannels with built-in validator primitives
	v.RegisterValidationCtx("winlogchannels", func(ctx context.Context, fl validator.FieldLevel) bool {
		receiver, ok := fl.Parent().Interface().(LoggingReceiverWindowsEventLog)
		if !ok {
			panic(fmt.Sprintf("winlogchannels: could not convert %s's parent to LoggingReceiverWindowsEventLog", fl.Field().String()))
		}
		if receiver.IsDefaultVersion() {
			if err := validateWinlogV1Channels(ctx, receiver.Channels); err != nil {
				// Only emit a soft failure (warning) here, because:
				// 1) we want this to be backwards compatible, and
				// 2) the implementation of the validation is not officially documented to be the "correct" way to do it
				log.Print(err)
			}
			return true
		}
		return validateWinlogChannels(receiver.Channels) == nil
	})
	// Validates that experimental config components are enabled via EXPERIMENTAL_FEATURES
	registerExperimentalValidations(v)
	return v
}