1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-11 05:55:57 +00:00

mvc: struct field and method dependency logs on debug level. Read HISTORY.md

- remove Party.GetReporter

- Read HISTORY.md
This commit is contained in:
Gerasimos (Makis) Maropoulos
2020-08-24 21:44:29 +03:00
parent ef5685bf7e
commit 5e82fa5b89
24 changed files with 435 additions and 167 deletions

View File

@@ -16,8 +16,9 @@ type binding struct {
// Input contains the input reference of which a dependency is binded to.
type Input struct {
Index int // for func inputs
StructFieldIndex []int // for struct fields in order to support embedded ones.
Index int // for func inputs
StructFieldIndex []int // for struct fields in order to support embedded ones.
StructFieldName string // the struct field's name.
Type reflect.Type
selfValue reflect.Value // reflect.ValueOf(*Input) cache.
@@ -34,6 +35,12 @@ func newInput(typ reflect.Type, index int, structFieldIndex []int) *Input {
return in
}
func newStructFieldInput(f reflect.StructField) *Input {
input := newInput(f.Type, f.Index[0], f.Index)
input.StructFieldName = f.Name
return input
}
// String returns the string representation of a binding.
func (b *binding) String() string {
index := fmt.Sprintf("%d", b.Input.Index)
@@ -261,7 +268,7 @@ func getBindingsForStruct(v reflect.Value, dependencies []*Dependency, paramsCou
// fmt.Printf("Controller [%s] | NonZero | Field Index: %v | Field Type: %s\n", typ, f.Index, f.Type)
bindings = append(bindings, &binding{
Dependency: NewDependency(elem.FieldByIndex(f.Index).Interface()),
Input: newInput(f.Type, f.Index[0], f.Index),
Input: newStructFieldInput(f),
})
}
@@ -299,9 +306,10 @@ func getBindingsForStruct(v reflect.Value, dependencies []*Dependency, paramsCou
// fmt.Printf(""Controller [%s] | Binding: %s\n", typ, binding.String())
if len(binding.Input.StructFieldIndex) == 0 {
// set correctly the input's field index.
structFieldIndex := fields[binding.Input.Index].Index
binding.Input.StructFieldIndex = structFieldIndex
// set correctly the input's field index and name.
f := fields[binding.Input.Index]
binding.Input.StructFieldIndex = f.Index
binding.Input.StructFieldName = f.Name
}
// fmt.Printf("Controller [%s] | binding Index: %v | binding Type: %s\n", typ, binding.Input.StructFieldIndex, binding.Input.Type)

View File

@@ -6,6 +6,7 @@ import (
"net"
"net/http"
"reflect"
"strings"
"time"
"github.com/kataras/iris/v12/context"
@@ -15,7 +16,7 @@ import (
)
// Default is the default container value which can be used for dependencies share.
var Default = New()
var Default = New().WithLogger(golog.Default)
// Container contains and delivers the Dependencies that will be binded
// to the controller(s) or handler(s) that can be created
@@ -28,6 +29,10 @@ var Default = New()
//
// For a more high-level structure please take a look at the "mvc.go#Application".
type Container struct {
// Optional Logger to report dependencies and matched bindings
// per struct, function and method.
// By default it is set by the Party creator of this Container.
Logger *golog.Logger
// Sorter specifies how the inputs should be sorted before binded.
// Defaults to sort by "thinnest" target empty interface.
Sorter Sorter
@@ -36,12 +41,83 @@ type Container struct {
// GetErrorHandler should return a valid `ErrorHandler` to handle bindings AND handler dispatch errors.
// Defaults to a functon which returns the `DefaultErrorHandler`.
GetErrorHandler func(*context.Context) ErrorHandler // cannot be nil.
// Reports contains an ordered list of information about bindings for further analysys and testing.
Reports []*Report
// resultHandlers is a list of functions that serve the return struct value of a function handler.
// Defaults to "defaultResultHandler" but it can be overridden.
resultHandlers []func(next ResultHandler) ResultHandler
}
// A Report holds meta information about dependency sources and target values per package,
// struct, struct's fields, struct's method, package-level function or closure.
// E.g. main -> (*UserController) -> HandleHTTPError.
type Report struct {
// The name is the last part of the name of a struct or its methods or a function.
// Each name is splited by its package.struct.field or package.funcName or package.func.inlineFunc.
Name string
// If it's a struct or package or function
// then it contains children reports of each one of its methods or input parameters
// respectfully.
Reports []*Report
Parent *Report
Entries []ReportEntry
}
// A ReportEntry holds the information about a binding.
type ReportEntry struct {
InputPosition int // struct field position or parameter position.
InputFieldName string // if it's a struct field, then this is its type name (we can't get param names).
InputFieldType reflect.Type // the input's type.
DependencyValue interface{} // the dependency value binded to that InputPosition of Name.
DependencyFile string // the file
DependencyLine int // and line number of the dependency's value.
}
func (r *Report) fill(bindings []*binding) {
for _, b := range bindings {
inputFieldName := b.Input.StructFieldName
if inputFieldName == "" {
// it's not a struct field, then type.
inputFieldName = b.Input.Type.String()
}
// remove only the main one prefix.
inputFieldName = strings.TrimPrefix(inputFieldName, "main.")
fieldName := inputFieldName
switch fieldName {
case "*context.Context":
inputFieldName = strings.Replace(inputFieldName, "*context", "iris", 1)
case "hero.Code", "hero.Result", "hero.View", "hero.Response":
inputFieldName = strings.Replace(inputFieldName, "hero", "mvc", 1)
}
entry := ReportEntry{
InputPosition: b.Input.Index,
InputFieldName: inputFieldName,
InputFieldType: b.Input.Type,
DependencyValue: b.Dependency.OriginalValue,
DependencyFile: b.Dependency.Source.File,
DependencyLine: b.Dependency.Source.Line,
}
r.Entries = append(r.Entries, entry)
}
}
// fillReport adds a report to the Reports field.
func (c *Container) fillReport(fullName string, bindings []*binding) {
// r := c.getReport(fullName)
r := &Report{
Name: fullName,
}
r.fill(bindings)
c.Reports = append(c.Reports, r)
}
// BuiltinDependencies is a list of builtin dependencies that are added on Container's initilization.
// Contains the iris context, standard context, iris sessions and time dependencies.
var BuiltinDependencies = []*Dependency{
@@ -113,16 +189,24 @@ func New(dependencies ...interface{}) *Container {
return c
}
// WithLogger injects a logger to use to debug dependencies and bindings.
func (c *Container) WithLogger(logger *golog.Logger) *Container {
c.Logger = logger
return c
}
// Clone returns a new cloned container.
// It copies the ErrorHandler, Dependencies and all Options from "c" receiver.
func (c *Container) Clone() *Container {
cloned := New()
cloned.Logger = c.Logger
cloned.GetErrorHandler = c.GetErrorHandler
cloned.Sorter = c.Sorter
clonedDeps := make([]*Dependency, len(c.Dependencies))
copy(clonedDeps, c.Dependencies)
cloned.Dependencies = clonedDeps
cloned.resultHandlers = c.resultHandlers
// Reports are not cloned.
return cloned
}

View File

@@ -48,7 +48,7 @@ func newSource(fn reflect.Value) Source {
}
return Source{
File: callerFileName,
File: filepath.ToSlash(callerFileName),
Line: callerLineNumber,
Caller: callerName,
}

View File

@@ -82,6 +82,7 @@ func makeHandler(fn interface{}, c *Container, paramsCount int) context.Handler
numIn := typ.NumIn()
bindings := getBindingsForFunc(v, c.Dependencies, paramsCount)
c.fillReport(context.HandlerName(fn), bindings)
resultHandler := defaultResultHandler
for i, lidx := 0, len(c.resultHandlers)-1; i <= lidx; i++ {

View File

@@ -84,8 +84,8 @@ func makeStruct(structPtr interface{}, c *Container, partyParamsCount int) *Stru
}
isErrHandler := isErrorHandler(typ)
newContainer := c.Clone()
newContainer.fillReport(typ.String(), bindings)
// Add the controller dependency itself as func dependency but with a known type which should be explicit binding
// in order to keep its maximum priority.
newContainer.Register(s.Acquire).Explicitly().DestType = typ