github.com/go-spring/spring-base@v1.1.3/log/log_inject.go (about)

     1  /*
     2   * Copyright 2012-2019 the original author or authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *      https://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package log
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"reflect"
    23  	"strconv"
    24  	"strings"
    25  
    26  	"github.com/go-spring/spring-base/code"
    27  	"github.com/go-spring/spring-base/util"
    28  )
    29  
    30  var converters = map[reflect.Type]util.Converter{}
    31  
    32  func init() {
    33  	RegisterConverter(ParseLevel)
    34  	RegisterConverter(ParseColorStyle)
    35  }
    36  
    37  // RegisterConverter registers Converter for non-primitive type such as
    38  // time.Time, time.Duration, or other user-defined value type.
    39  func RegisterConverter(fn util.Converter) {
    40  	t := reflect.TypeOf(fn)
    41  	if !util.IsConverter(t) {
    42  		panic(errors.New("fn must be func(string)(type,error)"))
    43  	}
    44  	converters[t.Out(0)] = fn
    45  }
    46  
    47  func newPlugin(t reflect.Type, node *Node) (reflect.Value, error) {
    48  	v := reflect.New(t)
    49  	err := inject(v.Elem(), v.Type().Elem(), node)
    50  	if err != nil {
    51  		return reflect.Value{}, err
    52  	}
    53  	i, ok := v.Interface().(Initializer)
    54  	if ok {
    55  		if err = i.Init(); err != nil {
    56  			return reflect.Value{}, err
    57  		}
    58  	}
    59  	return v, nil
    60  }
    61  
    62  // inject handles the struct field with the PluginAttribute or PluginElement tag.
    63  func inject(v reflect.Value, t reflect.Type, node *Node) error {
    64  	for i := 0; i < v.NumField(); i++ {
    65  		ft := t.Field(i)
    66  		fv := v.Field(i)
    67  		if tag, ok := ft.Tag.Lookup("PluginAttribute"); ok {
    68  			if err := injectAttribute(tag, fv, ft, node); err != nil {
    69  				return err
    70  			}
    71  			continue
    72  		}
    73  		if tag, ok := ft.Tag.Lookup("PluginElement"); ok {
    74  			if err := injectElement(tag, fv, ft, node); err != nil {
    75  				return err
    76  			}
    77  			continue
    78  		}
    79  		if ft.Anonymous && ft.Type.Kind() == reflect.Struct {
    80  			if err := inject(fv, fv.Type(), node); err != nil {
    81  				return err
    82  			}
    83  		}
    84  	}
    85  	return nil
    86  }
    87  
    88  type PluginTag string
    89  
    90  func (tag PluginTag) Get(key string) string {
    91  	v, _ := tag.Lookup(key)
    92  	return v
    93  }
    94  
    95  func (tag PluginTag) Lookup(key string) (value string, ok bool) {
    96  	kvs := strings.Split(string(tag), ",")
    97  	if key == "" {
    98  		return kvs[0], true
    99  	}
   100  	for i := 1; i < len(kvs); i++ {
   101  		ss := strings.Split(kvs[i], "=")
   102  		if ss[0] == key {
   103  			if len(ss) > 1 {
   104  				return ss[1], true
   105  			}
   106  			return "", true
   107  		}
   108  	}
   109  	return "", false
   110  }
   111  
   112  // injectAttribute handles the struct field with the PluginAttribute tag.
   113  func injectAttribute(tag string, fv reflect.Value, ft reflect.StructField, node *Node) error {
   114  
   115  	attrTag := PluginTag(tag)
   116  	attrName := attrTag.Get("")
   117  	val, ok := node.Attributes[attrName]
   118  	if !ok {
   119  		val, ok = attrTag.Lookup("default")
   120  		if !ok {
   121  			return fmt.Errorf("found no attribute for %s", attrName)
   122  		}
   123  	}
   124  
   125  	if fn := converters[ft.Type]; fn != nil {
   126  		fnValue := reflect.ValueOf(fn)
   127  		out := fnValue.Call([]reflect.Value{reflect.ValueOf(val)})
   128  		if !out[1].IsNil() {
   129  			err := out[1].Interface().(error)
   130  			return util.Wrapf(err, code.FileLine(), "inject error")
   131  		}
   132  		fv.Set(out[0])
   133  		return nil
   134  	}
   135  
   136  	switch fv.Kind() {
   137  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   138  		u, err := strconv.ParseUint(val, 0, 0)
   139  		if err == nil {
   140  			fv.SetUint(u)
   141  			return nil
   142  		}
   143  		return util.Wrapf(err, code.FileLine(), "inject %s error", ft.Name)
   144  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   145  		i, err := strconv.ParseInt(val, 0, 0)
   146  		if err == nil {
   147  			fv.SetInt(i)
   148  			return nil
   149  		}
   150  		return util.Wrapf(err, code.FileLine(), "inject %s error", ft.Name)
   151  	case reflect.Float32, reflect.Float64:
   152  		f, err := strconv.ParseFloat(val, 64)
   153  		if err == nil {
   154  			fv.SetFloat(f)
   155  			return nil
   156  		}
   157  		return util.Wrapf(err, code.FileLine(), "inject %s error", ft.Name)
   158  	case reflect.Bool:
   159  		b, err := strconv.ParseBool(val)
   160  		if err == nil {
   161  			fv.SetBool(b)
   162  			return nil
   163  		}
   164  		return util.Wrapf(err, code.FileLine(), "inject %s error", ft.Name)
   165  	case reflect.String:
   166  		fv.SetString(val)
   167  		return nil
   168  	}
   169  	return fmt.Errorf("unsupported inject type %s for struct field %s", ft.Type.String(), ft.Name)
   170  }
   171  
   172  // injectElement handles the struct field with the PluginElement tag.
   173  func injectElement(tag string, fv reflect.Value, ft reflect.StructField, node *Node) error {
   174  
   175  	elemTag := PluginTag(tag)
   176  	elemType := elemTag.Get("")
   177  
   178  	var children []reflect.Value
   179  	for _, c := range node.Children {
   180  		p, ok := plugins[c.Label]
   181  		if !ok {
   182  			err := fmt.Errorf("plugin %s not found", c.Label)
   183  			return util.Wrap(err, code.FileLine(), "inject element")
   184  		}
   185  		if p.Type != elemType {
   186  			continue
   187  		}
   188  		v, err := newPlugin(p.Class, c)
   189  		if err != nil {
   190  			return err
   191  		}
   192  		children = append(children, v)
   193  	}
   194  
   195  	if len(children) == 0 {
   196  		elemLabel, ok := elemTag.Lookup("default")
   197  		if !ok {
   198  			return nil
   199  		}
   200  		p, ok := plugins[elemLabel]
   201  		if !ok {
   202  			err := fmt.Errorf("plugin %s not found", elemLabel)
   203  			return util.Wrap(err, code.FileLine(), "inject element")
   204  		}
   205  		v, err := newPlugin(p.Class, &Node{Label: elemLabel})
   206  		if err != nil {
   207  			return err
   208  		}
   209  		children = append(children, v)
   210  	}
   211  
   212  	switch fv.Kind() {
   213  	case reflect.Slice:
   214  		slice := reflect.MakeSlice(ft.Type, 0, len(children))
   215  		for j := 0; j < len(children); j++ {
   216  			slice = reflect.Append(slice, children[j])
   217  		}
   218  		fv.Set(slice)
   219  	case reflect.Interface:
   220  		if len(children) > 1 {
   221  			return fmt.Errorf("found %d plugin elements for struct field %s", len(children), ft.Name)
   222  		}
   223  		fv.Set(children[0])
   224  	default:
   225  		return fmt.Errorf("unsupported inject type %s for struct field %s", ft.Type.String(), ft.Name)
   226  	}
   227  	return nil
   228  }