diff --git a/config/config.go b/config/config.go index bfd79e85..f46f862b 100644 --- a/config/config.go +++ b/config/config.go @@ -48,22 +48,39 @@ import ( ) // Configer defines how to get and set value from configuration raw data. +// Deprecated: using pkg/config, we will delete this in v2.1.0 type Configer interface { + // Deprecated: using pkg/config, we will delete this in v2.1.0 Set(key, val string) error //support section::key type in given key when using ini type. + // Deprecated: using pkg/config, we will delete this in v2.1.0 String(key string) string //support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same. + // Deprecated: using pkg/config, we will delete this in v2.1.0 Strings(key string) []string //get string slice + // Deprecated: using pkg/config, we will delete this in v2.1.0 Int(key string) (int, error) + // Deprecated: using pkg/config, we will delete this in v2.1.0 Int64(key string) (int64, error) + // Deprecated: using pkg/config, we will delete this in v2.1.0 Bool(key string) (bool, error) + // Deprecated: using pkg/config, we will delete this in v2.1.0 Float(key string) (float64, error) + // Deprecated: using pkg/config, we will delete this in v2.1.0 DefaultString(key string, defaultVal string) string // support section::key type in key string when using ini and json type; Int,Int64,Bool,Float,DIY are same. + // Deprecated: using pkg/config, we will delete this in v2.1.0 DefaultStrings(key string, defaultVal []string) []string //get string slice + // Deprecated: using pkg/config, we will delete this in v2.1.0 DefaultInt(key string, defaultVal int) int + // Deprecated: using pkg/config, we will delete this in v2.1.0 DefaultInt64(key string, defaultVal int64) int64 + // Deprecated: using pkg/config, we will delete this in v2.1.0 DefaultBool(key string, defaultVal bool) bool + // Deprecated: using pkg/config, we will delete this in v2.1.0 DefaultFloat(key string, defaultVal float64) float64 + // Deprecated: using pkg/config, we will delete this in v2.1.0 DIY(key string) (interface{}, error) + // Deprecated: using pkg/config, we will delete this in v2.1.0 GetSection(section string) (map[string]string, error) + // Deprecated: using pkg/config, we will delete this in v2.1.0 SaveConfigFile(filename string) error } diff --git a/config/env/env.go b/config/env/env.go index 34f094fe..1a6c2527 100644 --- a/config/env/env.go +++ b/config/env/env.go @@ -36,6 +36,7 @@ func init() { // Get returns a value by key. // If the key does not exist, the default value will be returned. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func Get(key string, defVal string) string { if val := env.Get(key); val != nil { return val.(string) @@ -45,6 +46,7 @@ func Get(key string, defVal string) string { // MustGet returns a value by key. // If the key does not exist, it will return an error. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func MustGet(key string) (string, error) { if val := env.Get(key); val != nil { return val.(string), nil @@ -54,12 +56,14 @@ func MustGet(key string) (string, error) { // Set sets a value in the ENV copy. // This does not affect the child process environment. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func Set(key string, value string) { env.Set(key, value) } // MustSet sets a value in the ENV copy and the child process environment. // It returns an error in case the set operation failed. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func MustSet(key string, value string) error { err := os.Setenv(key, value) if err != nil { @@ -70,6 +74,7 @@ func MustSet(key string, value string) error { } // GetAll returns all keys/values in the current child process environment. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func GetAll() map[string]string { items := env.Items() envs := make(map[string]string, env.Count()) diff --git a/config/fake.go b/config/fake.go index d21ab820..07e56ce2 100644 --- a/config/fake.go +++ b/config/fake.go @@ -27,16 +27,16 @@ type fakeConfigContainer struct { func (c *fakeConfigContainer) getData(key string) string { return c.data[strings.ToLower(key)] } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) Set(key, val string) error { c.data[strings.ToLower(key)] = val return nil } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) String(key string) string { return c.getData(key) } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) DefaultString(key string, defaultval string) string { v := c.String(key) if v == "" { @@ -44,7 +44,7 @@ func (c *fakeConfigContainer) DefaultString(key string, defaultval string) strin } return v } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) Strings(key string) []string { v := c.String(key) if v == "" { @@ -52,7 +52,7 @@ func (c *fakeConfigContainer) Strings(key string) []string { } return strings.Split(v, ";") } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) DefaultStrings(key string, defaultval []string) []string { v := c.Strings(key) if v == nil { @@ -60,11 +60,11 @@ func (c *fakeConfigContainer) DefaultStrings(key string, defaultval []string) [] } return v } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) Int(key string) (int, error) { return strconv.Atoi(c.getData(key)) } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) DefaultInt(key string, defaultval int) int { v, err := c.Int(key) if err != nil { @@ -72,11 +72,11 @@ func (c *fakeConfigContainer) DefaultInt(key string, defaultval int) int { } return v } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) Int64(key string) (int64, error) { return strconv.ParseInt(c.getData(key), 10, 64) } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) DefaultInt64(key string, defaultval int64) int64 { v, err := c.Int64(key) if err != nil { @@ -84,11 +84,11 @@ func (c *fakeConfigContainer) DefaultInt64(key string, defaultval int64) int64 { } return v } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) Bool(key string) (bool, error) { return ParseBool(c.getData(key)) } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) DefaultBool(key string, defaultval bool) bool { v, err := c.Bool(key) if err != nil { @@ -96,11 +96,11 @@ func (c *fakeConfigContainer) DefaultBool(key string, defaultval bool) bool { } return v } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) Float(key string) (float64, error) { return strconv.ParseFloat(c.getData(key), 64) } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) DefaultFloat(key string, defaultval float64) float64 { v, err := c.Float(key) if err != nil { @@ -108,18 +108,18 @@ func (c *fakeConfigContainer) DefaultFloat(key string, defaultval float64) float } return v } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) DIY(key string) (interface{}, error) { if v, ok := c.data[strings.ToLower(key)]; ok { return v, nil } return nil, errors.New("key not find") } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) GetSection(section string) (map[string]string, error) { return nil, errors.New("not implement in the fakeConfigContainer") } - +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *fakeConfigContainer) SaveConfigFile(filename string) error { return errors.New("not implement in the fakeConfigContainer") } @@ -127,6 +127,7 @@ func (c *fakeConfigContainer) SaveConfigFile(filename string) error { var _ Configer = new(fakeConfigContainer) // NewFakeConfig return a fake Configer +// Deprecated: using pkg/config, we will delete this in v2.1.0 func NewFakeConfig() Configer { return &fakeConfigContainer{ data: make(map[string]string), diff --git a/config/ini.go b/config/ini.go index 002e5e05..1da293dc 100644 --- a/config/ini.go +++ b/config/ini.go @@ -41,10 +41,12 @@ var ( ) // IniConfig implements Config to parse ini file. +// Deprecated: using pkg/config, we will delete this in v2.1.0 type IniConfig struct { } // Parse creates a new Config and parses the file configuration from the named file. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (ini *IniConfig) Parse(name string) (Configer, error) { return ini.parseFile(name) } @@ -208,6 +210,7 @@ func (ini *IniConfig) parseData(dir string, data []byte) (*IniConfigContainer, e // ParseData parse ini the data // When include other.conf,other.conf is either absolute directory // or under beego in default temporary directory(/tmp/beego[-username]). +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (ini *IniConfig) ParseData(data []byte) (Configer, error) { dir := "beego" currentUser, err := user.Current() @@ -224,6 +227,7 @@ func (ini *IniConfig) ParseData(data []byte) (Configer, error) { // IniConfigContainer A Config represents the ini configuration. // When set and get value, support key as section:name type. +// Deprecated: using pkg/config, we will delete this in v2.1.0 type IniConfigContainer struct { data map[string]map[string]string // section=> key:val sectionComment map[string]string // section : comment @@ -232,12 +236,14 @@ type IniConfigContainer struct { } // Bool returns the boolean value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) Bool(key string) (bool, error) { return ParseBool(c.getdata(key)) } // DefaultBool returns the boolean value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) DefaultBool(key string, defaultval bool) bool { v, err := c.Bool(key) if err != nil { @@ -247,12 +253,14 @@ func (c *IniConfigContainer) DefaultBool(key string, defaultval bool) bool { } // Int returns the integer value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) Int(key string) (int, error) { return strconv.Atoi(c.getdata(key)) } // DefaultInt returns the integer value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) DefaultInt(key string, defaultval int) int { v, err := c.Int(key) if err != nil { @@ -262,12 +270,14 @@ func (c *IniConfigContainer) DefaultInt(key string, defaultval int) int { } // Int64 returns the int64 value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) Int64(key string) (int64, error) { return strconv.ParseInt(c.getdata(key), 10, 64) } // DefaultInt64 returns the int64 value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) DefaultInt64(key string, defaultval int64) int64 { v, err := c.Int64(key) if err != nil { @@ -277,12 +287,14 @@ func (c *IniConfigContainer) DefaultInt64(key string, defaultval int64) int64 { } // Float returns the float value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) Float(key string) (float64, error) { return strconv.ParseFloat(c.getdata(key), 64) } // DefaultFloat returns the float64 value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) DefaultFloat(key string, defaultval float64) float64 { v, err := c.Float(key) if err != nil { @@ -292,12 +304,14 @@ func (c *IniConfigContainer) DefaultFloat(key string, defaultval float64) float6 } // String returns the string value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) String(key string) string { return c.getdata(key) } // DefaultString returns the string value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) DefaultString(key string, defaultval string) string { v := c.String(key) if v == "" { @@ -308,6 +322,7 @@ func (c *IniConfigContainer) DefaultString(key string, defaultval string) string // Strings returns the []string value for a given key. // Return nil if config value does not exist or is empty. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) Strings(key string) []string { v := c.String(key) if v == "" { @@ -318,6 +333,7 @@ func (c *IniConfigContainer) Strings(key string) []string { // DefaultStrings returns the []string value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []string { v := c.Strings(key) if v == nil { @@ -327,6 +343,7 @@ func (c *IniConfigContainer) DefaultStrings(key string, defaultval []string) []s } // GetSection returns map for the given section +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) GetSection(section string) (map[string]string, error) { if v, ok := c.data[section]; ok { return v, nil @@ -337,6 +354,7 @@ func (c *IniConfigContainer) GetSection(section string) (map[string]string, erro // SaveConfigFile save the config into file. // // BUG(env): The environment variable config item will be saved with real value in SaveConfigFile Function. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) { // Write configuration file by filename. f, err := os.Create(filename) @@ -437,6 +455,7 @@ func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) { // Set writes a new value for key. // if write to one section, the key need be "section::key". // if the section is not existed, it panics. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) Set(key, value string) error { c.Lock() defer c.Unlock() @@ -465,6 +484,7 @@ func (c *IniConfigContainer) Set(key, value string) error { } // DIY returns the raw value by a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *IniConfigContainer) DIY(key string) (v interface{}, err error) { if v, ok := c.data[strings.ToLower(key)]; ok { return v, nil diff --git a/config/json.go b/config/json.go index c4ef25cd..74a50d34 100644 --- a/config/json.go +++ b/config/json.go @@ -26,10 +26,12 @@ import ( ) // JSONConfig is a json config parser and implements Config interface. +// Deprecated: using pkg/config, we will delete this in v2.1.0 type JSONConfig struct { } // Parse returns a ConfigContainer with parsed json config map. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (js *JSONConfig) Parse(filename string) (Configer, error) { file, err := os.Open(filename) if err != nil { @@ -45,6 +47,7 @@ func (js *JSONConfig) Parse(filename string) (Configer, error) { } // ParseData returns a ConfigContainer with json string +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (js *JSONConfig) ParseData(data []byte) (Configer, error) { x := &JSONConfigContainer{ data: make(map[string]interface{}), @@ -66,12 +69,14 @@ func (js *JSONConfig) ParseData(data []byte) (Configer, error) { // JSONConfigContainer A Config represents the json configuration. // Only when get value, support key as section:name type. +// Deprecated: using pkg/config, we will delete this in v2.1.0 type JSONConfigContainer struct { data map[string]interface{} sync.RWMutex } // Bool returns the boolean value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) Bool(key string) (bool, error) { val := c.getData(key) if val != nil { @@ -82,6 +87,7 @@ func (c *JSONConfigContainer) Bool(key string) (bool, error) { // DefaultBool return the bool value if has no error // otherwise return the defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) DefaultBool(key string, defaultval bool) bool { if v, err := c.Bool(key); err == nil { return v @@ -90,6 +96,7 @@ func (c *JSONConfigContainer) DefaultBool(key string, defaultval bool) bool { } // Int returns the integer value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) Int(key string) (int, error) { val := c.getData(key) if val != nil { @@ -105,6 +112,7 @@ func (c *JSONConfigContainer) Int(key string) (int, error) { // DefaultInt returns the integer value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) DefaultInt(key string, defaultval int) int { if v, err := c.Int(key); err == nil { return v @@ -113,6 +121,7 @@ func (c *JSONConfigContainer) DefaultInt(key string, defaultval int) int { } // Int64 returns the int64 value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) Int64(key string) (int64, error) { val := c.getData(key) if val != nil { @@ -126,6 +135,7 @@ func (c *JSONConfigContainer) Int64(key string) (int64, error) { // DefaultInt64 returns the int64 value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) DefaultInt64(key string, defaultval int64) int64 { if v, err := c.Int64(key); err == nil { return v @@ -134,6 +144,7 @@ func (c *JSONConfigContainer) DefaultInt64(key string, defaultval int64) int64 { } // Float returns the float value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) Float(key string) (float64, error) { val := c.getData(key) if val != nil { @@ -147,6 +158,7 @@ func (c *JSONConfigContainer) Float(key string) (float64, error) { // DefaultFloat returns the float64 value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) DefaultFloat(key string, defaultval float64) float64 { if v, err := c.Float(key); err == nil { return v @@ -155,6 +167,7 @@ func (c *JSONConfigContainer) DefaultFloat(key string, defaultval float64) float } // String returns the string value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) String(key string) string { val := c.getData(key) if val != nil { @@ -167,6 +180,7 @@ func (c *JSONConfigContainer) String(key string) string { // DefaultString returns the string value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) DefaultString(key string, defaultval string) string { // TODO FIXME should not use "" to replace non existence if v := c.String(key); v != "" { @@ -176,6 +190,7 @@ func (c *JSONConfigContainer) DefaultString(key string, defaultval string) strin } // Strings returns the []string value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) Strings(key string) []string { stringVal := c.String(key) if stringVal == "" { @@ -186,6 +201,7 @@ func (c *JSONConfigContainer) Strings(key string) []string { // DefaultStrings returns the []string value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) DefaultStrings(key string, defaultval []string) []string { if v := c.Strings(key); v != nil { return v @@ -194,6 +210,7 @@ func (c *JSONConfigContainer) DefaultStrings(key string, defaultval []string) [] } // GetSection returns map for the given section +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) GetSection(section string) (map[string]string, error) { if v, ok := c.data[section]; ok { return v.(map[string]string), nil @@ -202,6 +219,7 @@ func (c *JSONConfigContainer) GetSection(section string) (map[string]string, err } // SaveConfigFile save the config into file +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) SaveConfigFile(filename string) (err error) { // Write configuration file by filename. f, err := os.Create(filename) @@ -218,6 +236,7 @@ func (c *JSONConfigContainer) SaveConfigFile(filename string) (err error) { } // Set writes a new value for key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) Set(key, val string) error { c.Lock() defer c.Unlock() @@ -226,6 +245,7 @@ func (c *JSONConfigContainer) Set(key, val string) error { } // DIY returns the raw value by a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) DIY(key string) (v interface{}, err error) { val := c.getData(key) if val != nil { @@ -235,6 +255,7 @@ func (c *JSONConfigContainer) DIY(key string) (v interface{}, err error) { } // section.key or key +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *JSONConfigContainer) getData(key string) interface{} { if len(key) == 0 { return nil diff --git a/config/xml/xml.go b/config/xml/xml.go index 494242d3..1601561f 100644 --- a/config/xml/xml.go +++ b/config/xml/xml.go @@ -46,9 +46,11 @@ import ( // Config is a xml config parser and implements Config interface. // xml configurations should be included in tag. // only support key/value pair as value as each item. +// Deprecated: using pkg/config, we will delete this in v2.1.0 type Config struct{} // Parse returns a ConfigContainer with parsed xml config map. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (xc *Config) Parse(filename string) (config.Configer, error) { context, err := ioutil.ReadFile(filename) if err != nil { @@ -59,6 +61,7 @@ func (xc *Config) Parse(filename string) (config.Configer, error) { } // ParseData xml data +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (xc *Config) ParseData(data []byte) (config.Configer, error) { x := &ConfigContainer{data: make(map[string]interface{})} @@ -73,12 +76,14 @@ func (xc *Config) ParseData(data []byte) (config.Configer, error) { } // ConfigContainer A Config represents the xml configuration. +// Deprecated: using pkg/config, we will delete this in v2.1.0 type ConfigContainer struct { data map[string]interface{} sync.Mutex } // Bool returns the boolean value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) Bool(key string) (bool, error) { if v := c.data[key]; v != nil { return config.ParseBool(v) @@ -88,6 +93,7 @@ func (c *ConfigContainer) Bool(key string) (bool, error) { // DefaultBool return the bool value if has no error // otherwise return the defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool { v, err := c.Bool(key) if err != nil { @@ -97,12 +103,14 @@ func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool { } // Int returns the integer value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) Int(key string) (int, error) { return strconv.Atoi(c.data[key].(string)) } // DefaultInt returns the integer value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DefaultInt(key string, defaultval int) int { v, err := c.Int(key) if err != nil { @@ -112,12 +120,14 @@ func (c *ConfigContainer) DefaultInt(key string, defaultval int) int { } // Int64 returns the int64 value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) Int64(key string) (int64, error) { return strconv.ParseInt(c.data[key].(string), 10, 64) } // DefaultInt64 returns the int64 value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 { v, err := c.Int64(key) if err != nil { @@ -128,12 +138,14 @@ func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 { } // Float returns the float value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) Float(key string) (float64, error) { return strconv.ParseFloat(c.data[key].(string), 64) } // DefaultFloat returns the float64 value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 { v, err := c.Float(key) if err != nil { @@ -143,6 +155,7 @@ func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 { } // String returns the string value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) String(key string) string { if v, ok := c.data[key].(string); ok { return v @@ -152,6 +165,7 @@ func (c *ConfigContainer) String(key string) string { // DefaultString returns the string value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DefaultString(key string, defaultval string) string { v := c.String(key) if v == "" { @@ -161,6 +175,7 @@ func (c *ConfigContainer) DefaultString(key string, defaultval string) string { } // Strings returns the []string value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) Strings(key string) []string { v := c.String(key) if v == "" { @@ -171,6 +186,7 @@ func (c *ConfigContainer) Strings(key string) []string { // DefaultStrings returns the []string value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string { v := c.Strings(key) if v == nil { @@ -180,6 +196,7 @@ func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []stri } // GetSection returns map for the given section +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) GetSection(section string) (map[string]string, error) { if v, ok := c.data[section].(map[string]interface{}); ok { mapstr := make(map[string]string) @@ -192,6 +209,7 @@ func (c *ConfigContainer) GetSection(section string) (map[string]string, error) } // SaveConfigFile save the config into file +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) SaveConfigFile(filename string) (err error) { // Write configuration file by filename. f, err := os.Create(filename) @@ -208,6 +226,7 @@ func (c *ConfigContainer) SaveConfigFile(filename string) (err error) { } // Set writes a new value for key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) Set(key, val string) error { c.Lock() defer c.Unlock() @@ -216,6 +235,7 @@ func (c *ConfigContainer) Set(key, val string) error { } // DIY returns the raw value by a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DIY(key string) (v interface{}, err error) { if v, ok := c.data[key]; ok { return v, nil diff --git a/config/yaml/yaml.go b/config/yaml/yaml.go index a5644c7b..725f905b 100644 --- a/config/yaml/yaml.go +++ b/config/yaml/yaml.go @@ -45,9 +45,11 @@ import ( ) // Config is a yaml config parser and implements Config interface. +// Deprecated: using pkg/config, we will delete this in v2.1.0 type Config struct{} // Parse returns a ConfigContainer with parsed yaml config map. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (yaml *Config) Parse(filename string) (y config.Configer, err error) { cnf, err := ReadYmlReader(filename) if err != nil { @@ -60,6 +62,7 @@ func (yaml *Config) Parse(filename string) (y config.Configer, err error) { } // ParseData parse yaml data +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (yaml *Config) ParseData(data []byte) (config.Configer, error) { cnf, err := parseYML(data) if err != nil { @@ -73,6 +76,7 @@ func (yaml *Config) ParseData(data []byte) (config.Configer, error) { // ReadYmlReader Read yaml file to map. // if json like, use json package, unless goyaml2 package. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func ReadYmlReader(path string) (cnf map[string]interface{}, err error) { buf, err := ioutil.ReadFile(path) if err != nil { @@ -117,12 +121,14 @@ func parseYML(buf []byte) (cnf map[string]interface{}, err error) { } // ConfigContainer A Config represents the yaml configuration. +// Deprecated: using pkg/config, we will delete this in v2.1.0 type ConfigContainer struct { data map[string]interface{} sync.RWMutex } // Bool returns the boolean value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) Bool(key string) (bool, error) { v, err := c.getData(key) if err != nil { @@ -133,6 +139,7 @@ func (c *ConfigContainer) Bool(key string) (bool, error) { // DefaultBool return the bool value if has no error // otherwise return the defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool { v, err := c.Bool(key) if err != nil { @@ -142,6 +149,7 @@ func (c *ConfigContainer) DefaultBool(key string, defaultval bool) bool { } // Int returns the integer value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) Int(key string) (int, error) { if v, err := c.getData(key); err != nil { return 0, err @@ -155,6 +163,7 @@ func (c *ConfigContainer) Int(key string) (int, error) { // DefaultInt returns the integer value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DefaultInt(key string, defaultval int) int { v, err := c.Int(key) if err != nil { @@ -164,6 +173,7 @@ func (c *ConfigContainer) DefaultInt(key string, defaultval int) int { } // Int64 returns the int64 value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) Int64(key string) (int64, error) { if v, err := c.getData(key); err != nil { return 0, err @@ -175,6 +185,7 @@ func (c *ConfigContainer) Int64(key string) (int64, error) { // DefaultInt64 returns the int64 value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 { v, err := c.Int64(key) if err != nil { @@ -184,6 +195,7 @@ func (c *ConfigContainer) DefaultInt64(key string, defaultval int64) int64 { } // Float returns the float value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) Float(key string) (float64, error) { if v, err := c.getData(key); err != nil { return 0.0, err @@ -199,6 +211,7 @@ func (c *ConfigContainer) Float(key string) (float64, error) { // DefaultFloat returns the float64 value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 { v, err := c.Float(key) if err != nil { @@ -208,6 +221,7 @@ func (c *ConfigContainer) DefaultFloat(key string, defaultval float64) float64 { } // String returns the string value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) String(key string) string { if v, err := c.getData(key); err == nil { if vv, ok := v.(string); ok { @@ -219,6 +233,7 @@ func (c *ConfigContainer) String(key string) string { // DefaultString returns the string value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DefaultString(key string, defaultval string) string { v := c.String(key) if v == "" { @@ -228,6 +243,7 @@ func (c *ConfigContainer) DefaultString(key string, defaultval string) string { } // Strings returns the []string value for a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) Strings(key string) []string { v := c.String(key) if v == "" { @@ -238,6 +254,7 @@ func (c *ConfigContainer) Strings(key string) []string { // DefaultStrings returns the []string value for a given key. // if err != nil return defaultval +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []string { v := c.Strings(key) if v == nil { @@ -247,6 +264,7 @@ func (c *ConfigContainer) DefaultStrings(key string, defaultval []string) []stri } // GetSection returns map for the given section +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) GetSection(section string) (map[string]string, error) { if v, ok := c.data[section]; ok { @@ -256,6 +274,7 @@ func (c *ConfigContainer) GetSection(section string) (map[string]string, error) } // SaveConfigFile save the config into file +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) SaveConfigFile(filename string) (err error) { // Write configuration file by filename. f, err := os.Create(filename) @@ -268,6 +287,7 @@ func (c *ConfigContainer) SaveConfigFile(filename string) (err error) { } // Set writes a new value for key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) Set(key, val string) error { c.Lock() defer c.Unlock() @@ -276,6 +296,7 @@ func (c *ConfigContainer) Set(key, val string) error { } // DIY returns the raw value by a given key. +// Deprecated: using pkg/config, we will delete this in v2.1.0 func (c *ConfigContainer) DIY(key string) (v interface{}, err error) { return c.getData(key) } diff --git a/go.mod b/go.mod index 1951d76d..97ad8b87 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,9 @@ require ( github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c // indirect github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b // indirect golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 + golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect + golang.org/x/tools v0.0.0-20200117065230-39095c1d176c + google.golang.org/grpc v1.31.0 // indirect gopkg.in/yaml.v2 v2.2.8 ) diff --git a/httplib/httplib.go b/httplib/httplib.go index 60aa4e8b..8ae95641 100644 --- a/httplib/httplib.go +++ b/httplib/httplib.go @@ -74,6 +74,7 @@ func createDefaultCookie() { } // SetDefaultSetting Overwrite default settings +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func SetDefaultSetting(setting BeegoHTTPSettings) { settingMutex.Lock() defer settingMutex.Unlock() @@ -81,6 +82,7 @@ func SetDefaultSetting(setting BeegoHTTPSettings) { } // NewBeegoRequest return *BeegoHttpRequest with specific method +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func NewBeegoRequest(rawurl, method string) *BeegoHTTPRequest { var resp http.Response u, err := url.Parse(rawurl) @@ -106,31 +108,37 @@ func NewBeegoRequest(rawurl, method string) *BeegoHTTPRequest { } // Get returns *BeegoHttpRequest with GET method. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func Get(url string) *BeegoHTTPRequest { return NewBeegoRequest(url, "GET") } // Post returns *BeegoHttpRequest with POST method. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func Post(url string) *BeegoHTTPRequest { return NewBeegoRequest(url, "POST") } // Put returns *BeegoHttpRequest with PUT method. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func Put(url string) *BeegoHTTPRequest { return NewBeegoRequest(url, "PUT") } // Delete returns *BeegoHttpRequest DELETE method. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func Delete(url string) *BeegoHTTPRequest { return NewBeegoRequest(url, "DELETE") } // Head returns *BeegoHttpRequest with HEAD method. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func Head(url string) *BeegoHTTPRequest { return NewBeegoRequest(url, "HEAD") } // BeegoHTTPSettings is the http.Client setting +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 type BeegoHTTPSettings struct { ShowDebug bool UserAgent string @@ -148,6 +156,7 @@ type BeegoHTTPSettings struct { } // BeegoHTTPRequest provides more useful methods for requesting one url than http.Request. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 type BeegoHTTPRequest struct { url string req *http.Request @@ -160,35 +169,41 @@ type BeegoHTTPRequest struct { } // GetRequest return the request object +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) GetRequest() *http.Request { return b.req } // Setting Change request settings +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) Setting(setting BeegoHTTPSettings) *BeegoHTTPRequest { b.setting = setting return b } // SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) SetBasicAuth(username, password string) *BeegoHTTPRequest { b.req.SetBasicAuth(username, password) return b } // SetEnableCookie sets enable/disable cookiejar +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) SetEnableCookie(enable bool) *BeegoHTTPRequest { b.setting.EnableCookie = enable return b } // SetUserAgent sets User-Agent header field +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) SetUserAgent(useragent string) *BeegoHTTPRequest { b.setting.UserAgent = useragent return b } // Debug sets show debug or not when executing request. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) Debug(isdebug bool) *BeegoHTTPRequest { b.setting.ShowDebug = isdebug return b @@ -198,28 +213,33 @@ func (b *BeegoHTTPRequest) Debug(isdebug bool) *BeegoHTTPRequest { // default is 0 means no retried. // -1 means retried forever. // others means retried times. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) Retries(times int) *BeegoHTTPRequest { b.setting.Retries = times return b } +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) RetryDelay(delay time.Duration) *BeegoHTTPRequest { b.setting.RetryDelay = delay return b } // DumpBody setting whether need to Dump the Body. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) DumpBody(isdump bool) *BeegoHTTPRequest { b.setting.DumpBody = isdump return b } // DumpRequest return the DumpRequest +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) DumpRequest() []byte { return b.dump } // SetTimeout sets connect time out and read-write time out for BeegoRequest. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) SetTimeout(connectTimeout, readWriteTimeout time.Duration) *BeegoHTTPRequest { b.setting.ConnectTimeout = connectTimeout b.setting.ReadWriteTimeout = readWriteTimeout @@ -227,18 +247,21 @@ func (b *BeegoHTTPRequest) SetTimeout(connectTimeout, readWriteTimeout time.Dura } // SetTLSClientConfig sets tls connection configurations if visiting https url. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) SetTLSClientConfig(config *tls.Config) *BeegoHTTPRequest { b.setting.TLSClientConfig = config return b } // Header add header item string in request. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) Header(key, value string) *BeegoHTTPRequest { b.req.Header.Set(key, value) return b } // SetHost set the request host +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) SetHost(host string) *BeegoHTTPRequest { b.req.Host = host return b @@ -246,6 +269,7 @@ func (b *BeegoHTTPRequest) SetHost(host string) *BeegoHTTPRequest { // SetProtocolVersion Set the protocol version for incoming requests. // Client requests always use HTTP/1.1. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) SetProtocolVersion(vers string) *BeegoHTTPRequest { if len(vers) == 0 { vers = "HTTP/1.1" @@ -262,12 +286,14 @@ func (b *BeegoHTTPRequest) SetProtocolVersion(vers string) *BeegoHTTPRequest { } // SetCookie add cookie into request. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) SetCookie(cookie *http.Cookie) *BeegoHTTPRequest { b.req.Header.Add("Cookie", cookie.String()) return b } // SetTransport set the setting transport +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) SetTransport(transport http.RoundTripper) *BeegoHTTPRequest { b.setting.Transport = transport return b @@ -280,6 +306,7 @@ func (b *BeegoHTTPRequest) SetTransport(transport http.RoundTripper) *BeegoHTTPR // u, _ := url.ParseRequestURI("http://127.0.0.1:8118") // return u, nil // } +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) SetProxy(proxy func(*http.Request) (*url.URL, error)) *BeegoHTTPRequest { b.setting.Proxy = proxy return b @@ -289,6 +316,7 @@ func (b *BeegoHTTPRequest) SetProxy(proxy func(*http.Request) (*url.URL, error)) // // If CheckRedirect is nil, the Client uses its default policy, // which is to stop after 10 consecutive requests. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) SetCheckRedirect(redirect func(req *http.Request, via []*http.Request) error) *BeegoHTTPRequest { b.setting.CheckRedirect = redirect return b @@ -296,6 +324,7 @@ func (b *BeegoHTTPRequest) SetCheckRedirect(redirect func(req *http.Request, via // Param adds query param in to request. // params build query string as ?key1=value1&key2=value2... +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) Param(key, value string) *BeegoHTTPRequest { if param, ok := b.params[key]; ok { b.params[key] = append(param, value) @@ -306,6 +335,7 @@ func (b *BeegoHTTPRequest) Param(key, value string) *BeegoHTTPRequest { } // PostFile add a post file to the request +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) PostFile(formname, filename string) *BeegoHTTPRequest { b.files[formname] = filename return b @@ -313,6 +343,7 @@ func (b *BeegoHTTPRequest) PostFile(formname, filename string) *BeegoHTTPRequest // Body adds request raw body. // it supports string and []byte. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) Body(data interface{}) *BeegoHTTPRequest { switch t := data.(type) { case string: @@ -328,6 +359,7 @@ func (b *BeegoHTTPRequest) Body(data interface{}) *BeegoHTTPRequest { } // XMLBody adds request raw body encoding by XML. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) XMLBody(obj interface{}) (*BeegoHTTPRequest, error) { if b.req.Body == nil && obj != nil { byts, err := xml.Marshal(obj) @@ -342,6 +374,7 @@ func (b *BeegoHTTPRequest) XMLBody(obj interface{}) (*BeegoHTTPRequest, error) { } // YAMLBody adds request raw body encoding by YAML. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) YAMLBody(obj interface{}) (*BeegoHTTPRequest, error) { if b.req.Body == nil && obj != nil { byts, err := yaml.Marshal(obj) @@ -356,6 +389,7 @@ func (b *BeegoHTTPRequest) YAMLBody(obj interface{}) (*BeegoHTTPRequest, error) } // JSONBody adds request raw body encoding by JSON. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) JSONBody(obj interface{}) (*BeegoHTTPRequest, error) { if b.req.Body == nil && obj != nil { byts, err := json.Marshal(obj) @@ -438,6 +472,7 @@ func (b *BeegoHTTPRequest) getResponse() (*http.Response, error) { } // DoRequest will do the client.Do +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) DoRequest() (resp *http.Response, err error) { var paramBody string if len(b.params) > 0 { @@ -531,6 +566,7 @@ func (b *BeegoHTTPRequest) DoRequest() (resp *http.Response, err error) { // String returns the body string in response. // it calls Response inner. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) String() (string, error) { data, err := b.Bytes() if err != nil { @@ -542,6 +578,7 @@ func (b *BeegoHTTPRequest) String() (string, error) { // Bytes returns the body []byte in response. // it calls Response inner. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) Bytes() ([]byte, error) { if b.body != nil { return b.body, nil @@ -568,6 +605,7 @@ func (b *BeegoHTTPRequest) Bytes() ([]byte, error) { // ToFile saves the body data in response to one file. // it calls Response inner. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) ToFile(filename string) error { resp, err := b.getResponse() if err != nil { @@ -608,6 +646,7 @@ func pathExistAndMkdir(filename string) (err error) { // ToJSON returns the map that marshals from the body bytes as json in response . // it calls Response inner. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) ToJSON(v interface{}) error { data, err := b.Bytes() if err != nil { @@ -618,6 +657,7 @@ func (b *BeegoHTTPRequest) ToJSON(v interface{}) error { // ToXML returns the map that marshals from the body bytes as xml in response . // it calls Response inner. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) ToXML(v interface{}) error { data, err := b.Bytes() if err != nil { @@ -628,6 +668,7 @@ func (b *BeegoHTTPRequest) ToXML(v interface{}) error { // ToYAML returns the map that marshals from the body bytes as yaml in response . // it calls Response inner. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) ToYAML(v interface{}) error { data, err := b.Bytes() if err != nil { @@ -637,11 +678,13 @@ func (b *BeegoHTTPRequest) ToYAML(v interface{}) error { } // Response executes request client gets response mannually. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func (b *BeegoHTTPRequest) Response() (*http.Response, error) { return b.getResponse() } // TimeoutDialer returns functions of connection dialer with timeout settings for http.Transport Dial field. +// Deprecated: using pkg/httplib, we will delete this in v2.1.0 func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) { return func(netw, addr string) (net.Conn, error) { conn, err := net.DialTimeout(netw, addr, cTimeout) diff --git a/pkg/beego.go b/pkg/beego.go index 8ebe0bab..c08ae528 100644 --- a/pkg/beego.go +++ b/pkg/beego.go @@ -97,6 +97,7 @@ func initBeforeHTTPRun() { registerTemplate, registerAdmin, registerGzip, + registerCommentRouter, ) for _, hk := range hooks { diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index 82585c4e..049fb758 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -47,23 +47,23 @@ import ( // c.Incr("counter") // now is 2 // count := c.Get("counter").(int) type Cache interface { - // get cached value by key. + // Get a cached value by key. Get(key string) interface{} // GetMulti is a batch version of Get. GetMulti(keys []string) []interface{} - // set cached value with key and expire time. + // Set a cached value with key and expire time. Put(key string, val interface{}, timeout time.Duration) error - // delete cached value by key. + // Delete cached value by key. Delete(key string) error - // increase cached int value by key, as a counter. + // Increment a cached int value by key, as a counter. Incr(key string) error - // decrease cached int value by key, as a counter. + // Decrement a cached int value by key, as a counter. Decr(key string) error - // check if cached value exists or not. + // Check if a cached value exists or not. IsExist(key string) bool - // clear all cache. + // Clear all cache. ClearAll() error - // start gc routine based on config string settings. + // Start gc routine based on config string settings. StartAndGC(config string) error } @@ -85,9 +85,9 @@ func Register(name string, adapter Instance) { adapters[name] = adapter } -// NewCache Create a new cache driver by adapter name and config string. -// config need to be correct JSON as string: {"interval":360}. -// it will start gc automatically. +// NewCache creates a new cache driver by adapter name and config string. +// config: must be in JSON format such as {"interval":360}. +// Starts gc automatically. func NewCache(adapterName, config string) (adapter Cache, err error) { instanceFunc, ok := adapters[adapterName] if !ok { diff --git a/pkg/cache/file.go b/pkg/cache/file.go index dcc60bc0..0e5c44be 100644 --- a/pkg/cache/file.go +++ b/pkg/cache/file.go @@ -54,7 +54,7 @@ type FileCache struct { EmbedExpiry int } -// NewFileCache cerates a new file cache with no config. +// NewFileCache creates a new file cache with no config. // The level and expiry need to be set in the method StartAndGC as config string. func NewFileCache() Cache { // return &FileCache{CachePath:FileCachePath, FileSuffix:FileCacheFileSuffix} diff --git a/pkg/cache/memcache/memcache.go b/pkg/cache/memcache/memcache.go index b08596eb..94fc61dc 100644 --- a/pkg/cache/memcache/memcache.go +++ b/pkg/cache/memcache/memcache.go @@ -46,7 +46,7 @@ type Cache struct { conninfo []string } -// NewMemCache create new memcache adapter. +// NewMemCache creates a new memcache adapter. func NewMemCache() cache.Cache { return &Cache{} } @@ -64,7 +64,7 @@ func (rc *Cache) Get(key string) interface{} { return nil } -// GetMulti get value from memcache. +// GetMulti gets a value from a key in memcache. func (rc *Cache) GetMulti(keys []string) []interface{} { size := len(keys) var rv []interface{} @@ -89,7 +89,7 @@ func (rc *Cache) GetMulti(keys []string) []interface{} { return rv } -// Put put value to memcache. +// Put puts a value into memcache. func (rc *Cache) Put(key string, val interface{}, timeout time.Duration) error { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -107,7 +107,7 @@ func (rc *Cache) Put(key string, val interface{}, timeout time.Duration) error { return rc.conn.Set(&item) } -// Delete delete value in memcache. +// Delete deletes a value in memcache. func (rc *Cache) Delete(key string) error { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -117,7 +117,7 @@ func (rc *Cache) Delete(key string) error { return rc.conn.Delete(key) } -// Incr increase counter. +// Incr increases counter. func (rc *Cache) Incr(key string) error { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -128,7 +128,7 @@ func (rc *Cache) Incr(key string) error { return err } -// Decr decrease counter. +// Decr decreases counter. func (rc *Cache) Decr(key string) error { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -139,7 +139,7 @@ func (rc *Cache) Decr(key string) error { return err } -// IsExist check value exists in memcache. +// IsExist checks if a value exists in memcache. func (rc *Cache) IsExist(key string) bool { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -150,7 +150,7 @@ func (rc *Cache) IsExist(key string) bool { return err == nil } -// ClearAll clear all cached in memcache. +// ClearAll clears all cache in memcache. func (rc *Cache) ClearAll() error { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -160,9 +160,9 @@ func (rc *Cache) ClearAll() error { return rc.conn.FlushAll() } -// StartAndGC start memcache adapter. -// config string is like {"conn":"connection info"}. -// if connecting error, return. +// StartAndGC starts the memcache adapter. +// config: must be in the format {"conn":"connection info"}. +// If an error occurs during connecting, an error is returned func (rc *Cache) StartAndGC(config string) error { var cf map[string]string json.Unmarshal([]byte(config), &cf) diff --git a/pkg/cache/redis/redis.go b/pkg/cache/redis/redis.go index a5fec591..68a934bf 100644 --- a/pkg/cache/redis/redis.go +++ b/pkg/cache/redis/redis.go @@ -43,7 +43,7 @@ import ( ) var ( - // DefaultKey the collection name of redis for cache adapter. + // The collection name of redis for the cache adapter. DefaultKey = "beecacheRedis" ) @@ -56,16 +56,16 @@ type Cache struct { password string maxIdle int - // the timeout to a value less than the redis server's timeout. + // Timeout value (less than the redis server's timeout value) timeout time.Duration } -// NewRedisCache create new redis cache with default collection name. +// NewRedisCache creates a new redis cache with default collection name. func NewRedisCache() cache.Cache { return &Cache{key: DefaultKey} } -// actually do the redis cmds, args[0] must be the key name. +// Execute the redis commands. args[0] must be the key name func (rc *Cache) do(commandName string, args ...interface{}) (reply interface{}, err error) { if len(args) < 1 { return nil, errors.New("missing required arguments") @@ -90,7 +90,7 @@ func (rc *Cache) Get(key string) interface{} { return nil } -// GetMulti get cache from redis. +// GetMulti gets cache from redis. func (rc *Cache) GetMulti(keys []string) []interface{} { c := rc.p.Get() defer c.Close() @@ -105,19 +105,19 @@ func (rc *Cache) GetMulti(keys []string) []interface{} { return values } -// Put put cache to redis. +// Put puts cache into redis. func (rc *Cache) Put(key string, val interface{}, timeout time.Duration) error { _, err := rc.do("SETEX", key, int64(timeout/time.Second), val) return err } -// Delete delete cache in redis. +// Delete deletes a key's cache in redis. func (rc *Cache) Delete(key string) error { _, err := rc.do("DEL", key) return err } -// IsExist check cache's existence in redis. +// IsExist checks cache's existence in redis. func (rc *Cache) IsExist(key string) bool { v, err := redis.Bool(rc.do("EXISTS", key)) if err != nil { @@ -126,19 +126,19 @@ func (rc *Cache) IsExist(key string) bool { return v } -// Incr increase counter in redis. +// Incr increases a key's counter in redis. func (rc *Cache) Incr(key string) error { _, err := redis.Bool(rc.do("INCRBY", key, 1)) return err } -// Decr decrease counter in redis. +// Decr decreases a key's counter in redis. func (rc *Cache) Decr(key string) error { _, err := redis.Bool(rc.do("INCRBY", key, -1)) return err } -// ClearAll clean all cache in redis. delete this redis collection. +// ClearAll deletes all cache in the redis collection func (rc *Cache) ClearAll() error { cachedKeys, err := rc.Scan(rc.key + ":*") if err != nil { @@ -154,7 +154,7 @@ func (rc *Cache) ClearAll() error { return err } -// Scan scan all keys matching the pattern. a better choice than `keys` +// Scan scans all keys matching a given pattern. func (rc *Cache) Scan(pattern string) (keys []string, err error) { c := rc.p.Get() defer c.Close() @@ -183,10 +183,9 @@ func (rc *Cache) Scan(pattern string) (keys []string, err error) { } } -// StartAndGC start redis cache adapter. -// config is like {"key":"collection key","conn":"connection info","dbNum":"0"} -// the cache item in redis are stored forever, -// so no gc operation. +// StartAndGC starts the redis cache adapter. +// config: must be in this format {"key":"collection key","conn":"connection info","dbNum":"0"} +// Cached items in redis are stored forever, no garbage collection happens func (rc *Cache) StartAndGC(config string) error { var cf map[string]string json.Unmarshal([]byte(config), &cf) diff --git a/pkg/cache/ssdb/ssdb.go b/pkg/cache/ssdb/ssdb.go index 62a63c60..038b2ebe 100644 --- a/pkg/cache/ssdb/ssdb.go +++ b/pkg/cache/ssdb/ssdb.go @@ -18,12 +18,12 @@ type Cache struct { conninfo []string } -//NewSsdbCache create new ssdb adapter. +//NewSsdbCache creates new ssdb adapter. func NewSsdbCache() cache.Cache { return &Cache{} } -// Get get value from memcache. +// Get gets a key's value from memcache. func (rc *Cache) Get(key string) interface{} { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -37,7 +37,7 @@ func (rc *Cache) Get(key string) interface{} { return nil } -// GetMulti get value from memcache. +// GetMulti gets one or keys values from memcache. func (rc *Cache) GetMulti(keys []string) []interface{} { size := len(keys) var values []interface{} @@ -63,7 +63,7 @@ func (rc *Cache) GetMulti(keys []string) []interface{} { return values } -// DelMulti get value from memcache. +// DelMulti deletes one or more keys from memcache func (rc *Cache) DelMulti(keys []string) error { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -74,7 +74,8 @@ func (rc *Cache) DelMulti(keys []string) error { return err } -// Put put value to memcache. only support string. +// Put puts value into memcache. +// value: must be of type string func (rc *Cache) Put(key string, value interface{}, timeout time.Duration) error { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -102,7 +103,7 @@ func (rc *Cache) Put(key string, value interface{}, timeout time.Duration) error return errors.New("bad response") } -// Delete delete value in memcache. +// Delete deletes a value in memcache. func (rc *Cache) Delete(key string) error { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -113,7 +114,7 @@ func (rc *Cache) Delete(key string) error { return err } -// Incr increase counter. +// Incr increases a key's counter. func (rc *Cache) Incr(key string) error { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -124,7 +125,7 @@ func (rc *Cache) Incr(key string) error { return err } -// Decr decrease counter. +// Decr decrements a key's counter. func (rc *Cache) Decr(key string) error { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -135,7 +136,7 @@ func (rc *Cache) Decr(key string) error { return err } -// IsExist check value exists in memcache. +// IsExist checks if a key exists in memcache. func (rc *Cache) IsExist(key string) bool { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -153,7 +154,7 @@ func (rc *Cache) IsExist(key string) bool { } -// ClearAll clear all cached in memcache. +// ClearAll clears all cached items in memcache. func (rc *Cache) ClearAll() error { if rc.conn == nil { if err := rc.connectInit(); err != nil { @@ -195,9 +196,9 @@ func (rc *Cache) Scan(keyStart string, keyEnd string, limit int) ([]string, erro return resp, nil } -// StartAndGC start memcache adapter. -// config string is like {"conn":"connection info"}. -// if connecting error, return. +// StartAndGC starts the memcache adapter. +// config: must be in the format {"conn":"connection info"}. +// If an error occurs during connection, an error is returned func (rc *Cache) StartAndGC(config string) error { var cf map[string]string json.Unmarshal([]byte(config), &cf) diff --git a/pkg/config.go b/pkg/config.go index 2a5dec25..0cfb7a4c 100644 --- a/pkg/config.go +++ b/pkg/config.go @@ -86,6 +86,7 @@ type WebConfig struct { TemplateLeft string TemplateRight string ViewsPath string + CommentRouterPath string EnableXSRF bool XSRFKey string XSRFExpire int @@ -245,6 +246,7 @@ func newBConfig() *Config { TemplateLeft: "{{", TemplateRight: "}}", ViewsPath: "views", + CommentRouterPath: "controllers", EnableXSRF: false, XSRFKey: "beegoxsrf", XSRFExpire: 0, diff --git a/pkg/config/ini/ini.go b/pkg/config/ini.go similarity index 96% rename from pkg/config/ini/ini.go rename to pkg/config/ini.go index a3c6462d..f5921308 100644 --- a/pkg/config/ini/ini.go +++ b/pkg/config/ini.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ini +package config import ( "bufio" @@ -26,8 +26,6 @@ import ( "strconv" "strings" "sync" - - "github.com/astaxie/beego/pkg/config" ) var ( @@ -47,7 +45,7 @@ type IniConfig struct { } // Parse creates a new Config and parses the file configuration from the named file. -func (ini *IniConfig) Parse(name string) (config.Configer, error) { +func (ini *IniConfig) Parse(name string) (Configer, error) { return ini.parseFile(name) } @@ -197,7 +195,7 @@ func (ini *IniConfig) parseData(dir string, data []byte) (*IniConfigContainer, e val = bytes.Trim(val, `"`) } - cfg.data[section][key] = config.ExpandValueEnv(string(val)) + cfg.data[section][key] = ExpandValueEnv(string(val)) if comment.Len() > 0 { cfg.keyComment[section+"."+key] = comment.String() comment.Reset() @@ -210,7 +208,7 @@ func (ini *IniConfig) parseData(dir string, data []byte) (*IniConfigContainer, e // ParseData parse ini the data // When include other.conf,other.conf is either absolute directory // or under beego in default temporary directory(/tmp/beego[-username]). -func (ini *IniConfig) ParseData(data []byte) (config.Configer, error) { +func (ini *IniConfig) ParseData(data []byte) (Configer, error) { dir := "beego" currentUser, err := user.Current() if err == nil { @@ -224,7 +222,7 @@ func (ini *IniConfig) ParseData(data []byte) (config.Configer, error) { return ini.parseData(dir, data) } -// IniConfigContainer A Config represents the ini configuration. +// IniConfigContainer is a config which represents the ini configuration. // When set and get value, support key as section:name type. type IniConfigContainer struct { data map[string]map[string]string // section=> key:val @@ -235,7 +233,7 @@ type IniConfigContainer struct { // Bool returns the boolean value for a given key. func (c *IniConfigContainer) Bool(key string) (bool, error) { - return config.ParseBool(c.getdata(key)) + return ParseBool(c.getdata(key)) } // DefaultBool returns the boolean value for a given key. @@ -502,5 +500,5 @@ func (c *IniConfigContainer) getdata(key string) string { } func init() { - config.Register("ini", &IniConfig{}) + Register("ini", &IniConfig{}) } diff --git a/pkg/config/ini/ini_test.go b/pkg/config/ini_test.go similarity index 95% rename from pkg/config/ini/ini_test.go rename to pkg/config/ini_test.go index 70f1091d..ffcdb294 100644 --- a/pkg/config/ini/ini_test.go +++ b/pkg/config/ini_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ini +package config import ( "fmt" @@ -20,8 +20,6 @@ import ( "os" "strings" "testing" - - "github.com/astaxie/beego/pkg/config" ) func TestIni(t *testing.T) { @@ -94,7 +92,7 @@ password = ${GOPATH} } f.Close() defer os.Remove("testini.conf") - iniconf, err := config.NewConfig("ini", "testini.conf") + iniconf, err := NewConfig("ini", "testini.conf") if err != nil { t.Fatal(err) } @@ -167,7 +165,7 @@ httpport=8080 name=mysql ` ) - cfg, err := config.NewConfigData("ini", []byte(inicontext)) + cfg, err := NewConfigData("ini", []byte(inicontext)) if err != nil { t.Fatal(err) } diff --git a/pkg/config/json/json.go b/pkg/config/json/json.go index 49bd38ff..ede3cce5 100644 --- a/pkg/config/json/json.go +++ b/pkg/config/json/json.go @@ -66,7 +66,7 @@ func (js *JSONConfig) ParseData(data []byte) (config.Configer, error) { return x, nil } -// JSONConfigContainer A Config represents the json configuration. +// JSONConfigContainer is a config which represents the json configuration. // Only when get value, support key as section:name type. type JSONConfigContainer struct { data map[string]interface{} diff --git a/pkg/config/xml/xml.go b/pkg/config/xml/xml.go index b1cce5c8..d8c018e6 100644 --- a/pkg/config/xml/xml.go +++ b/pkg/config/xml/xml.go @@ -72,7 +72,7 @@ func (xc *Config) ParseData(data []byte) (config.Configer, error) { return x, nil } -// ConfigContainer A Config represents the xml configuration. +// ConfigContainer is a Config which represents the xml configuration. type ConfigContainer struct { data map[string]interface{} sync.Mutex diff --git a/pkg/config/yaml/yaml.go b/pkg/config/yaml/yaml.go index 3dcb45fd..63a30208 100644 --- a/pkg/config/yaml/yaml.go +++ b/pkg/config/yaml/yaml.go @@ -116,7 +116,7 @@ func parseYML(buf []byte) (cnf map[string]interface{}, err error) { return } -// ConfigContainer A Config represents the yaml configuration. +// ConfigContainer is a config which represents the yaml configuration. type ConfigContainer struct { data map[string]interface{} sync.RWMutex diff --git a/pkg/context/acceptencoder.go b/pkg/context/acceptencoder.go index b4e2492c..8ed6a853 100644 --- a/pkg/context/acceptencoder.go +++ b/pkg/context/acceptencoder.go @@ -28,18 +28,18 @@ import ( ) var ( - //Default size==20B same as nginx + // Default size==20B same as nginx defaultGzipMinLength = 20 - //Content will only be compressed if content length is either unknown or greater than gzipMinLength. + // Content will only be compressed if content length is either unknown or greater than gzipMinLength. gzipMinLength = defaultGzipMinLength - //The compression level used for deflate compression. (0-9). + // Compression level used for deflate compression. (0-9). gzipCompressLevel int - //List of HTTP methods to compress. If not set, only GET requests are compressed. + // List of HTTP methods to compress. If not set, only GET requests are compressed. includedMethods map[string]bool getMethodOnly bool ) -// InitGzip init the gzipcompress +// InitGzip initializes the gzipcompress func InitGzip(minLength, compressLevel int, methods []string) { if minLength >= 0 { gzipMinLength = minLength @@ -98,9 +98,9 @@ func (ac acceptEncoder) put(wr resetWriter, level int) { } wr.Reset(nil) - //notice - //compressionLevel==BestCompression DOES NOT MATTER - //sync.Pool will not memory leak + // notice + // compressionLevel==BestCompression DOES NOT MATTER + // sync.Pool will not memory leak switch level { case gzipCompressLevel: @@ -119,10 +119,10 @@ var ( bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr }}, } - //according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed - //deflate - //The "zlib" format defined in RFC 1950 [31] in combination with - //the "deflate" compression mechanism described in RFC 1951 [29]. + // According to: http://tools.ietf.org/html/rfc2616#section-3.5 the deflate compress in http is zlib indeed + // deflate + // The "zlib" format defined in RFC 1950 [31] in combination with + // the "deflate" compression mechanism described in RFC 1951 [29]. deflateCompressEncoder = acceptEncoder{ name: "deflate", levelEncode: func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr }, @@ -145,7 +145,7 @@ func WriteFile(encoding string, writer io.Writer, file *os.File) (bool, string, return writeLevel(encoding, writer, file, flate.BestCompression) } -// WriteBody reads writes content to writer by the specific encoding(gzip/deflate) +// WriteBody reads writes content to writer by the specific encoding(gzip/deflate) func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string, error) { if encoding == "" || len(content) < gzipMinLength { _, err := writer.Write(content) @@ -154,8 +154,8 @@ func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string, return writeLevel(encoding, writer, bytes.NewReader(content), gzipCompressLevel) } -// writeLevel reads from reader,writes to writer by specific encoding and compress level -// the compress level is defined by deflate package +// writeLevel reads from reader and writes to writer by specific encoding and compress level. +// The compress level is defined by deflate package func writeLevel(encoding string, writer io.Writer, reader io.Reader, level int) (bool, string, error) { var outputWriter resetWriter var err error diff --git a/pkg/context/context.go b/pkg/context/context.go index 9f974551..f7b325a9 100644 --- a/pkg/context/context.go +++ b/pkg/context/context.go @@ -38,7 +38,7 @@ import ( "github.com/astaxie/beego/pkg/utils" ) -//commonly used mime-types +// Commonly used mime-types const ( ApplicationJSON = "application/json" ApplicationXML = "application/xml" @@ -55,7 +55,7 @@ func NewContext() *Context { } // Context Http request context struct including BeegoInput, BeegoOutput, http.Request and http.ResponseWriter. -// BeegoInput and BeegoOutput provides some api to operate request and response more easily. +// BeegoInput and BeegoOutput provides an api to operate request and response more easily. type Context struct { Input *BeegoInput Output *BeegoOutput @@ -64,7 +64,7 @@ type Context struct { _xsrfToken string } -// Reset init Context, BeegoInput and BeegoOutput +// Reset initializes Context, BeegoInput and BeegoOutput func (ctx *Context) Reset(rw http.ResponseWriter, r *http.Request) { ctx.Request = r if ctx.ResponseWriter == nil { @@ -76,37 +76,36 @@ func (ctx *Context) Reset(rw http.ResponseWriter, r *http.Request) { ctx._xsrfToken = "" } -// Redirect does redirection to localurl with http header status code. +// Redirect redirects to localurl with http header status code. func (ctx *Context) Redirect(status int, localurl string) { http.Redirect(ctx.ResponseWriter, ctx.Request, localurl, status) } -// Abort stops this request. -// if beego.ErrorMaps exists, panic body. +// Abort stops the request. +// If beego.ErrorMaps exists, panic body. func (ctx *Context) Abort(status int, body string) { ctx.Output.SetStatus(status) panic(body) } -// WriteString Write string to response body. -// it sends response body. +// WriteString writes a string to response body. func (ctx *Context) WriteString(content string) { ctx.ResponseWriter.Write([]byte(content)) } -// GetCookie Get cookie from request by a given key. -// It's alias of BeegoInput.Cookie. +// GetCookie gets a cookie from a request for a given key. +// (Alias of BeegoInput.Cookie) func (ctx *Context) GetCookie(key string) string { return ctx.Input.Cookie(key) } -// SetCookie Set cookie for response. -// It's alias of BeegoOutput.Cookie. +// SetCookie sets a cookie for a response. +// (Alias of BeegoOutput.Cookie) func (ctx *Context) SetCookie(name string, value string, others ...interface{}) { ctx.Output.Cookie(name, value, others...) } -// GetSecureCookie Get secure cookie from request by a given key. +// GetSecureCookie gets a secure cookie from a request for a given key. func (ctx *Context) GetSecureCookie(Secret, key string) (string, bool) { val := ctx.Input.Cookie(key) if val == "" { @@ -133,7 +132,7 @@ func (ctx *Context) GetSecureCookie(Secret, key string) (string, bool) { return string(res), true } -// SetSecureCookie Set Secure cookie for response. +// SetSecureCookie sets a secure cookie for a response. func (ctx *Context) SetSecureCookie(Secret, name, value string, others ...interface{}) { vs := base64.URLEncoding.EncodeToString([]byte(value)) timestamp := strconv.FormatInt(time.Now().UnixNano(), 10) @@ -144,7 +143,7 @@ func (ctx *Context) SetSecureCookie(Secret, name, value string, others ...interf ctx.Output.Cookie(name, cookie, others...) } -// XSRFToken creates a xsrf token string and returns. +// XSRFToken creates and returns an xsrf token string func (ctx *Context) XSRFToken(key string, expire int64) string { if ctx._xsrfToken == "" { token, ok := ctx.GetSecureCookie(key, "_xsrf") @@ -157,8 +156,8 @@ func (ctx *Context) XSRFToken(key string, expire int64) string { return ctx._xsrfToken } -// CheckXSRFCookie checks xsrf token in this request is valid or not. -// the token can provided in request header "X-Xsrftoken" and "X-CsrfToken" +// CheckXSRFCookie checks if the XSRF token in this request is valid or not. +// The token can be provided in the request header in the form "X-Xsrftoken" or "X-CsrfToken" // or in form field value named as "_xsrf". func (ctx *Context) CheckXSRFCookie() bool { token := ctx.Input.Query("_xsrf") @@ -195,8 +194,8 @@ func (ctx *Context) RenderMethodResult(result interface{}) { } } -//Response is a wrapper for the http.ResponseWriter -//started set to true if response was written to then don't execute other handler +// Response is a wrapper for the http.ResponseWriter +// Started: if true, response was already written to so the other handler will not be executed type Response struct { http.ResponseWriter Started bool @@ -210,16 +209,16 @@ func (r *Response) reset(rw http.ResponseWriter) { r.Started = false } -// Write writes the data to the connection as part of an HTTP reply, -// and sets `started` to true. -// started means the response has sent out. +// Write writes the data to the connection as part of a HTTP reply, +// and sets `Started` to true. +// Started: if true, the response was already sent func (r *Response) Write(p []byte) (int, error) { r.Started = true return r.ResponseWriter.Write(p) } -// WriteHeader sends an HTTP response header with status code, -// and sets `started` to true. +// WriteHeader sends a HTTP response header with status code, +// and sets `Started` to true. func (r *Response) WriteHeader(code int) { if r.Status > 0 { //prevent multiple response.WriteHeader calls diff --git a/pkg/context/input.go b/pkg/context/input.go index 04347e04..5ff85f43 100644 --- a/pkg/context/input.go +++ b/pkg/context/input.go @@ -43,7 +43,7 @@ var ( ) // BeegoInput operates the http request header, data, cookie and body. -// it also contains router params and current session. +// Contains router params and current session. type BeegoInput struct { Context *Context CruSession session.Store @@ -56,7 +56,7 @@ type BeegoInput struct { RunController reflect.Type } -// NewInput return BeegoInput generated by Context. +// NewInput returns the BeegoInput generated by context. func NewInput() *BeegoInput { return &BeegoInput{ pnames: make([]string, 0, maxParam), @@ -65,7 +65,7 @@ func NewInput() *BeegoInput { } } -// Reset init the BeegoInput +// Reset initializes the BeegoInput func (input *BeegoInput) Reset(ctx *Context) { input.Context = ctx input.CruSession = nil @@ -77,27 +77,27 @@ func (input *BeegoInput) Reset(ctx *Context) { input.RequestBody = []byte{} } -// Protocol returns request protocol name, such as HTTP/1.1 . +// Protocol returns the request protocol name, such as HTTP/1.1 . func (input *BeegoInput) Protocol() string { return input.Context.Request.Proto } -// URI returns full request url with query string, fragment. +// URI returns the full request url with query, string and fragment. func (input *BeegoInput) URI() string { return input.Context.Request.RequestURI } -// URL returns request url path (without query string, fragment). +// URL returns the request url path (without query, string and fragment). func (input *BeegoInput) URL() string { return input.Context.Request.URL.EscapedPath() } -// Site returns base site url as scheme://domain type. +// Site returns the base site url as scheme://domain type. func (input *BeegoInput) Site() string { return input.Scheme() + "://" + input.Domain() } -// Scheme returns request scheme as "http" or "https". +// Scheme returns the request scheme as "http" or "https". func (input *BeegoInput) Scheme() string { if scheme := input.Header("X-Forwarded-Proto"); scheme != "" { return scheme @@ -111,14 +111,13 @@ func (input *BeegoInput) Scheme() string { return "https" } -// Domain returns host name. -// Alias of Host method. +// Domain returns the host name (alias of host method) func (input *BeegoInput) Domain() string { return input.Host() } -// Host returns host name. -// if no host info in request, return localhost. +// Host returns the host name. +// If no host info in request, return localhost. func (input *BeegoInput) Host() string { if input.Context.Request.Host != "" { if hostPart, _, err := net.SplitHostPort(input.Context.Request.Host); err == nil { @@ -134,7 +133,7 @@ func (input *BeegoInput) Method() string { return input.Context.Request.Method } -// Is returns boolean of this request is on given method, such as Is("POST"). +// Is returns the boolean value of this request is on given method, such as Is("POST"). func (input *BeegoInput) Is(method string) bool { return input.Method() == method } @@ -174,7 +173,7 @@ func (input *BeegoInput) IsPatch() bool { return input.Is("PATCH") } -// IsAjax returns boolean of this request is generated by ajax. +// IsAjax returns boolean of is this request generated by ajax. func (input *BeegoInput) IsAjax() bool { return input.Header("X-Requested-With") == "XMLHttpRequest" } @@ -251,7 +250,7 @@ func (input *BeegoInput) Refer() string { } // SubDomains returns sub domain string. -// if aa.bb.domain.com, returns aa.bb . +// if aa.bb.domain.com, returns aa.bb func (input *BeegoInput) SubDomains() string { parts := strings.Split(input.Host(), ".") if len(parts) >= 3 { @@ -306,7 +305,7 @@ func (input *BeegoInput) Params() map[string]string { return m } -// SetParam will set the param with key and value +// SetParam sets the param with key and value func (input *BeegoInput) SetParam(key, val string) { // check if already exists for i, v := range input.pnames { @@ -319,9 +318,8 @@ func (input *BeegoInput) SetParam(key, val string) { input.pnames = append(input.pnames, key) } -// ResetParams clears any of the input's Params -// This function is used to clear parameters so they may be reset between filter -// passes. +// ResetParams clears any of the input's params +// Used to clear parameters so they may be reset between filter passes. func (input *BeegoInput) ResetParams() { input.pnames = input.pnames[:0] input.pvalues = input.pvalues[:0] @@ -391,7 +389,7 @@ func (input *BeegoInput) CopyBody(MaxMemory int64) []byte { return requestbody } -// Data return the implicit data in the input +// Data returns the implicit data in the input func (input *BeegoInput) Data() map[interface{}]interface{} { input.dataLock.Lock() defer input.dataLock.Unlock() @@ -412,7 +410,7 @@ func (input *BeegoInput) GetData(key interface{}) interface{} { } // SetData stores data with given key in this context. -// This data are only available in this context. +// This data is only available in this context. func (input *BeegoInput) SetData(key, val interface{}) { input.dataLock.Lock() defer input.dataLock.Unlock() diff --git a/pkg/context/output.go b/pkg/context/output.go index 238dcf45..0a530244 100644 --- a/pkg/context/output.go +++ b/pkg/context/output.go @@ -42,12 +42,12 @@ type BeegoOutput struct { } // NewOutput returns new BeegoOutput. -// it contains nothing now. +// Empty when initialized func NewOutput() *BeegoOutput { return &BeegoOutput{} } -// Reset init BeegoOutput +// Reset initializes BeegoOutput func (output *BeegoOutput) Reset(ctx *Context) { output.Context = ctx output.Status = 0 @@ -58,9 +58,9 @@ func (output *BeegoOutput) Header(key, val string) { output.Context.ResponseWriter.Header().Set(key, val) } -// Body sets response body content. -// if EnableGzip, compress content string. -// it sends out response body directly. +// Body sets the response body content. +// if EnableGzip, content is compressed. +// Sends out response body directly. func (output *BeegoOutput) Body(content []byte) error { var encoding string var buf = &bytes.Buffer{} @@ -85,13 +85,13 @@ func (output *BeegoOutput) Body(content []byte) error { return nil } -// Cookie sets cookie value via given key. -// others are ordered as cookie's max age time, path,domain, secure and httponly. +// Cookie sets a cookie value via given key. +// others: used to set a cookie's max age time, path,domain, secure and httponly. func (output *BeegoOutput) Cookie(name string, value string, others ...interface{}) { var b bytes.Buffer fmt.Fprintf(&b, "%s=%s", sanitizeName(name), sanitizeValue(value)) - //fix cookie not work in IE + // fix cookie not work in IE if len(others) > 0 { var maxAge int64 @@ -183,7 +183,7 @@ func errorRenderer(err error) Renderer { }) } -// JSON writes json to response body. +// JSON writes json to the response body. // if encoding is true, it converts utf-8 to \u0000 type. func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, encoding bool) error { output.Header("Content-Type", "application/json; charset=utf-8") @@ -204,7 +204,7 @@ func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, encoding bool) return output.Body(content) } -// YAML writes yaml to response body. +// YAML writes yaml to the response body. func (output *BeegoOutput) YAML(data interface{}) error { output.Header("Content-Type", "application/x-yaml; charset=utf-8") var content []byte @@ -217,7 +217,7 @@ func (output *BeegoOutput) YAML(data interface{}) error { return output.Body(content) } -// JSONP writes jsonp to response body. +// JSONP writes jsonp to the response body. func (output *BeegoOutput) JSONP(data interface{}, hasIndent bool) error { output.Header("Content-Type", "application/javascript; charset=utf-8") var content []byte @@ -243,7 +243,7 @@ func (output *BeegoOutput) JSONP(data interface{}, hasIndent bool) error { return output.Body(callbackContent.Bytes()) } -// XML writes xml string to response body. +// XML writes xml string to the response body. func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error { output.Header("Content-Type", "application/xml; charset=utf-8") var content []byte @@ -260,7 +260,7 @@ func (output *BeegoOutput) XML(data interface{}, hasIndent bool) error { return output.Body(content) } -// ServeFormatted serve YAML, XML OR JSON, depending on the value of the Accept header +// ServeFormatted serves YAML, XML or JSON, depending on the value of the Accept header func (output *BeegoOutput) ServeFormatted(data interface{}, hasIndent bool, hasEncode ...bool) { accept := output.Context.Input.Header("Accept") switch accept { @@ -274,7 +274,7 @@ func (output *BeegoOutput) ServeFormatted(data interface{}, hasIndent bool, hasE } // Download forces response for download file. -// it prepares the download response header automatically. +// Prepares the download response header automatically. func (output *BeegoOutput) Download(file string, filename ...string) { // check get file error, file not found or other error. if _, err := os.Stat(file); err != nil { @@ -323,61 +323,61 @@ func (output *BeegoOutput) ContentType(ext string) { } } -// SetStatus sets response status code. -// It writes response header directly. +// SetStatus sets the response status code. +// Writes response header directly. func (output *BeegoOutput) SetStatus(status int) { output.Status = status } -// IsCachable returns boolean of this request is cached. +// IsCachable returns boolean of if this request is cached. // HTTP 304 means cached. func (output *BeegoOutput) IsCachable() bool { return output.Status >= 200 && output.Status < 300 || output.Status == 304 } -// IsEmpty returns boolean of this request is empty. +// IsEmpty returns boolean of if this request is empty. // HTTP 201,204 and 304 means empty. func (output *BeegoOutput) IsEmpty() bool { return output.Status == 201 || output.Status == 204 || output.Status == 304 } -// IsOk returns boolean of this request runs well. +// IsOk returns boolean of if this request was ok. // HTTP 200 means ok. func (output *BeegoOutput) IsOk() bool { return output.Status == 200 } -// IsSuccessful returns boolean of this request runs successfully. +// IsSuccessful returns boolean of this request was successful. // HTTP 2xx means ok. func (output *BeegoOutput) IsSuccessful() bool { return output.Status >= 200 && output.Status < 300 } -// IsRedirect returns boolean of this request is redirection header. +// IsRedirect returns boolean of if this request is redirected. // HTTP 301,302,307 means redirection. func (output *BeegoOutput) IsRedirect() bool { return output.Status == 301 || output.Status == 302 || output.Status == 303 || output.Status == 307 } -// IsForbidden returns boolean of this request is forbidden. +// IsForbidden returns boolean of if this request is forbidden. // HTTP 403 means forbidden. func (output *BeegoOutput) IsForbidden() bool { return output.Status == 403 } -// IsNotFound returns boolean of this request is not found. +// IsNotFound returns boolean of if this request is not found. // HTTP 404 means not found. func (output *BeegoOutput) IsNotFound() bool { return output.Status == 404 } -// IsClientError returns boolean of this request client sends error data. +// IsClientError returns boolean of if this request client sends error data. // HTTP 4xx means client error. func (output *BeegoOutput) IsClientError() bool { return output.Status >= 400 && output.Status < 500 } -// IsServerError returns boolean of this server handler errors. +// IsServerError returns boolean of if this server handler errors. // HTTP 5xx means server internal error. func (output *BeegoOutput) IsServerError() bool { return output.Status >= 500 && output.Status < 600 diff --git a/pkg/context/param/methodparams.go b/pkg/context/param/methodparams.go index cd6708a2..b5ccbdd0 100644 --- a/pkg/context/param/methodparams.go +++ b/pkg/context/param/methodparams.go @@ -22,7 +22,7 @@ const ( header ) -//New creates a new MethodParam with name and specific options +// New creates a new MethodParam with name and specific options func New(name string, opts ...MethodParamOption) *MethodParam { return newParam(name, nil, opts) } @@ -35,7 +35,7 @@ func newParam(name string, parser paramParser, opts []MethodParamOption) (param return } -//Make creates an array of MethodParmas or an empty array +// Make creates an array of MethodParmas or an empty array func Make(list ...*MethodParam) []*MethodParam { if len(list) > 0 { return list diff --git a/pkg/context/renderer.go b/pkg/context/renderer.go index 36a7cb53..5a078332 100644 --- a/pkg/context/renderer.go +++ b/pkg/context/renderer.go @@ -1,6 +1,6 @@ package context -// Renderer defines an http response renderer +// Renderer defines a http response renderer type Renderer interface { Render(ctx *Context) } diff --git a/pkg/context/response.go b/pkg/context/response.go index 9c3c715a..d80cfe89 100644 --- a/pkg/context/response.go +++ b/pkg/context/response.go @@ -7,21 +7,21 @@ import ( ) const ( - //BadRequest indicates http error 400 + //BadRequest indicates HTTP error 400 BadRequest StatusCode = http.StatusBadRequest - //NotFound indicates http error 404 + //NotFound indicates HTTP error 404 NotFound StatusCode = http.StatusNotFound ) -// StatusCode sets the http response status code +// StatusCode sets the HTTP response status code type StatusCode int func (s StatusCode) Error() string { return strconv.Itoa(int(s)) } -// Render sets the http status code +// Render sets the HTTP status code func (s StatusCode) Render(ctx *Context) { ctx.Output.SetStatus(int(s)) } diff --git a/pkg/grace/server.go b/pkg/grace/server.go index 008a6171..13fa6e34 100644 --- a/pkg/grace/server.go +++ b/pkg/grace/server.go @@ -29,8 +29,8 @@ type Server struct { terminalChan chan error } -// Serve accepts incoming connections on the Listener l, -// creating a new service goroutine for each. +// Serve accepts incoming connections on the Listener l +// and creates a new service goroutine for each. // The service goroutines read requests and then call srv.Handler to reply to them. func (srv *Server) Serve() (err error) { srv.state = StateRunning diff --git a/pkg/hooks.go b/pkg/hooks.go index 8c782383..f511e216 100644 --- a/pkg/hooks.go +++ b/pkg/hooks.go @@ -102,3 +102,13 @@ func registerGzip() error { } return nil } + +func registerCommentRouter() error { + if BConfig.RunMode == DEV { + if err := parserPkg(filepath.Join(WorkPath, BConfig.WebConfig.CommentRouterPath)); err != nil { + return err + } + } + + return nil +} \ No newline at end of file diff --git a/pkg/httplib/filter.go b/pkg/httplib/filter.go new file mode 100644 index 00000000..72a497d0 --- /dev/null +++ b/pkg/httplib/filter.go @@ -0,0 +1,24 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package httplib + +import ( + "context" + "net/http" +) + +type FilterChain func(next Filter) Filter + +type Filter func(ctx context.Context, req *BeegoHTTPRequest) (*http.Response, error) diff --git a/pkg/httplib/filter/opentracing/filter.go b/pkg/httplib/filter/opentracing/filter.go new file mode 100644 index 00000000..5f409c63 --- /dev/null +++ b/pkg/httplib/filter/opentracing/filter.go @@ -0,0 +1,77 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package opentracing + +import ( + "context" + "net/http" + "strconv" + + logKit "github.com/go-kit/kit/log" + opentracingKit "github.com/go-kit/kit/tracing/opentracing" + "github.com/opentracing/opentracing-go" + "github.com/opentracing/opentracing-go/log" + + "github.com/astaxie/beego/pkg/httplib" +) + +type FilterChainBuilder struct { + // CustomSpanFunc users are able to custom their span + CustomSpanFunc func(span opentracing.Span, ctx context.Context, + req *httplib.BeegoHTTPRequest, resp *http.Response, err error) +} + +func (builder *FilterChainBuilder) FilterChain(next httplib.Filter) httplib.Filter { + + return func(ctx context.Context, req *httplib.BeegoHTTPRequest) (*http.Response, error) { + + method := req.GetRequest().Method + host := req.GetRequest().URL.Host + path := req.GetRequest().URL.Path + + proto := req.GetRequest().Proto + + scheme := req.GetRequest().URL.Scheme + + operationName := host + path + "#" + method + span, spanCtx := opentracing.StartSpanFromContext(ctx, operationName) + defer span.Finish() + + inject := opentracingKit.ContextToHTTP(opentracing.GlobalTracer(), logKit.NewNopLogger()) + inject(spanCtx, req.GetRequest()) + resp, err := next(spanCtx, req) + + if resp != nil { + span.SetTag("status", strconv.Itoa(resp.StatusCode)) + } + + span.SetTag("method", method) + span.SetTag("host", host) + span.SetTag("path", path) + span.SetTag("proto", proto) + span.SetTag("scheme", scheme) + + span.LogFields(log.String("url", req.GetRequest().URL.String())) + + if err != nil { + span.LogFields(log.String("error", err.Error())) + } + + if builder.CustomSpanFunc != nil { + builder.CustomSpanFunc(span, ctx, req, resp, err) + } + return resp, err + } +} diff --git a/pkg/httplib/filter/opentracing/filter_test.go b/pkg/httplib/filter/opentracing/filter_test.go new file mode 100644 index 00000000..aa687541 --- /dev/null +++ b/pkg/httplib/filter/opentracing/filter_test.go @@ -0,0 +1,42 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package opentracing + +import ( + "context" + "errors" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/astaxie/beego/pkg/httplib" +) + +func TestFilterChainBuilder_FilterChain(t *testing.T) { + next := func(ctx context.Context, req *httplib.BeegoHTTPRequest) (*http.Response, error) { + time.Sleep(100 * time.Millisecond) + return &http.Response{ + StatusCode: 404, + }, errors.New("hello") + } + builder := &FilterChainBuilder{} + filter := builder.FilterChain(next) + req := httplib.Get("https://github.com/notifications?query=repo%3Aastaxie%2Fbeego") + resp, err := filter(context.Background(), req) + assert.NotNil(t, resp) + assert.NotNil(t, err) +} diff --git a/pkg/httplib/filter/prometheus/filter.go b/pkg/httplib/filter/prometheus/filter.go new file mode 100644 index 00000000..a0b24d67 --- /dev/null +++ b/pkg/httplib/filter/prometheus/filter.go @@ -0,0 +1,73 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package prometheus + +import ( + "context" + "net/http" + "strconv" + "time" + + "github.com/prometheus/client_golang/prometheus" + + beego "github.com/astaxie/beego/pkg" + "github.com/astaxie/beego/pkg/httplib" +) + +type FilterChainBuilder struct { + summaryVec prometheus.ObserverVec +} + +func (builder *FilterChainBuilder) FilterChain(next httplib.Filter) httplib.Filter { + + builder.summaryVec = prometheus.NewSummaryVec(prometheus.SummaryOpts{ + Name: "beego", + Subsystem: "remote_http_request", + ConstLabels: map[string]string{ + "server": beego.BConfig.ServerName, + "env": beego.BConfig.RunMode, + "appname": beego.BConfig.AppName, + }, + Help: "The statics info for remote http requests", + }, []string{"proto", "scheme", "method", "host", "path", "status", "duration", "isError"}) + + return func(ctx context.Context, req *httplib.BeegoHTTPRequest) (*http.Response, error) { + startTime := time.Now() + resp, err := next(ctx, req) + endTime := time.Now() + go builder.report(startTime, endTime, ctx, req, resp, err) + return resp, err + } +} + +func (builder *FilterChainBuilder) report(startTime time.Time, endTime time.Time, + ctx context.Context, req *httplib.BeegoHTTPRequest, resp *http.Response, err error) { + + proto := req.GetRequest().Proto + + scheme := req.GetRequest().URL.Scheme + method := req.GetRequest().Method + + host := req.GetRequest().URL.Host + path := req.GetRequest().URL.Path + + status := resp.StatusCode + + dur := int(endTime.Sub(startTime) / time.Millisecond) + + + builder.summaryVec.WithLabelValues(proto, scheme, method, host, path, + strconv.Itoa(status), strconv.Itoa(dur), strconv.FormatBool(err == nil)) +} diff --git a/pkg/httplib/filter/prometheus/filter_test.go b/pkg/httplib/filter/prometheus/filter_test.go new file mode 100644 index 00000000..e15d82e5 --- /dev/null +++ b/pkg/httplib/filter/prometheus/filter_test.go @@ -0,0 +1,41 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package prometheus + +import ( + "context" + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/astaxie/beego/pkg/httplib" +) + +func TestFilterChainBuilder_FilterChain(t *testing.T) { + next := func(ctx context.Context, req *httplib.BeegoHTTPRequest) (*http.Response, error) { + time.Sleep(100 * time.Millisecond) + return &http.Response{ + StatusCode: 404, + }, nil + } + builder := &FilterChainBuilder{} + filter := builder.FilterChain(next) + req := httplib.Get("https://github.com/notifications?query=repo%3Aastaxie%2Fbeego") + resp, err := filter(context.Background(), req) + assert.NotNil(t, resp) + assert.Nil(t, err) +} diff --git a/pkg/httplib/httplib.go b/pkg/httplib/httplib.go index 60aa4e8b..f8ab80a1 100644 --- a/pkg/httplib/httplib.go +++ b/pkg/httplib/httplib.go @@ -34,6 +34,7 @@ package httplib import ( "bytes" "compress/gzip" + "context" "crypto/tls" "encoding/json" "encoding/xml" @@ -66,6 +67,11 @@ var defaultSetting = BeegoHTTPSettings{ var defaultCookieJar http.CookieJar var settingMutex sync.Mutex +// it will be the last filter and execute request.Do +var doRequestFilter = func(ctx context.Context, req *BeegoHTTPRequest) (*http.Response, error) { + return req.doRequest(ctx) +} + // createDefaultCookie creates a global cookiejar to store cookies. func createDefaultCookie() { settingMutex.Lock() @@ -73,14 +79,14 @@ func createDefaultCookie() { defaultCookieJar, _ = cookiejar.New(nil) } -// SetDefaultSetting Overwrite default settings +// SetDefaultSetting overwrites default settings func SetDefaultSetting(setting BeegoHTTPSettings) { settingMutex.Lock() defer settingMutex.Unlock() defaultSetting = setting } -// NewBeegoRequest return *BeegoHttpRequest with specific method +// NewBeegoRequest returns *BeegoHttpRequest with specific method func NewBeegoRequest(rawurl, method string) *BeegoHTTPRequest { var resp http.Response u, err := url.Parse(rawurl) @@ -145,9 +151,10 @@ type BeegoHTTPSettings struct { DumpBody bool Retries int // if set to -1 means will retry forever RetryDelay time.Duration + FilterChains []FilterChain } -// BeegoHTTPRequest provides more useful methods for requesting one url than http.Request. +// BeegoHTTPRequest provides more useful methods than http.Request for requesting a url. type BeegoHTTPRequest struct { url string req *http.Request @@ -159,12 +166,12 @@ type BeegoHTTPRequest struct { dump []byte } -// GetRequest return the request object +// GetRequest returns the request object func (b *BeegoHTTPRequest) GetRequest() *http.Request { return b.req } -// Setting Change request settings +// Setting changes request settings func (b *BeegoHTTPRequest) Setting(setting BeegoHTTPSettings) *BeegoHTTPRequest { b.setting = setting return b @@ -195,26 +202,27 @@ func (b *BeegoHTTPRequest) Debug(isdebug bool) *BeegoHTTPRequest { } // Retries sets Retries times. -// default is 0 means no retried. -// -1 means retried forever. -// others means retried times. +// default is 0 (never retry) +// -1 retry indefinitely (forever) +// Other numbers specify the exact retry amount func (b *BeegoHTTPRequest) Retries(times int) *BeegoHTTPRequest { b.setting.Retries = times return b } +// RetryDelay sets the time to sleep between reconnection attempts func (b *BeegoHTTPRequest) RetryDelay(delay time.Duration) *BeegoHTTPRequest { b.setting.RetryDelay = delay return b } -// DumpBody setting whether need to Dump the Body. +// DumpBody sets the DumbBody field func (b *BeegoHTTPRequest) DumpBody(isdump bool) *BeegoHTTPRequest { b.setting.DumpBody = isdump return b } -// DumpRequest return the DumpRequest +// DumpRequest returns the DumpRequest func (b *BeegoHTTPRequest) DumpRequest() []byte { return b.dump } @@ -226,13 +234,13 @@ func (b *BeegoHTTPRequest) SetTimeout(connectTimeout, readWriteTimeout time.Dura return b } -// SetTLSClientConfig sets tls connection configurations if visiting https url. +// SetTLSClientConfig sets TLS connection configuration if visiting HTTPS url. func (b *BeegoHTTPRequest) SetTLSClientConfig(config *tls.Config) *BeegoHTTPRequest { b.setting.TLSClientConfig = config return b } -// Header add header item string in request. +// Header adds header item string in request. func (b *BeegoHTTPRequest) Header(key, value string) *BeegoHTTPRequest { b.req.Header.Set(key, value) return b @@ -244,7 +252,7 @@ func (b *BeegoHTTPRequest) SetHost(host string) *BeegoHTTPRequest { return b } -// SetProtocolVersion Set the protocol version for incoming requests. +// SetProtocolVersion sets the protocol version for incoming requests. // Client requests always use HTTP/1.1. func (b *BeegoHTTPRequest) SetProtocolVersion(vers string) *BeegoHTTPRequest { if len(vers) == 0 { @@ -261,19 +269,19 @@ func (b *BeegoHTTPRequest) SetProtocolVersion(vers string) *BeegoHTTPRequest { return b } -// SetCookie add cookie into request. +// SetCookie adds a cookie to the request. func (b *BeegoHTTPRequest) SetCookie(cookie *http.Cookie) *BeegoHTTPRequest { b.req.Header.Add("Cookie", cookie.String()) return b } -// SetTransport set the setting transport +// SetTransport sets the transport field func (b *BeegoHTTPRequest) SetTransport(transport http.RoundTripper) *BeegoHTTPRequest { b.setting.Transport = transport return b } -// SetProxy set the http proxy +// SetProxy sets the HTTP proxy // example: // // func(req *http.Request) (*url.URL, error) { @@ -294,6 +302,18 @@ func (b *BeegoHTTPRequest) SetCheckRedirect(redirect func(req *http.Request, via return b } +// SetFilters will use the filter as the invocation filters +func (b *BeegoHTTPRequest) SetFilters(fcs ...FilterChain) *BeegoHTTPRequest { + b.setting.FilterChains = fcs + return b +} + +// AddFilters adds filter +func (b *BeegoHTTPRequest) AddFilters(fcs ...FilterChain) *BeegoHTTPRequest { + b.setting.FilterChains = append(b.setting.FilterChains, fcs...) + return b +} + // Param adds query param in to request. // params build query string as ?key1=value1&key2=value2... func (b *BeegoHTTPRequest) Param(key, value string) *BeegoHTTPRequest { @@ -305,14 +325,14 @@ func (b *BeegoHTTPRequest) Param(key, value string) *BeegoHTTPRequest { return b } -// PostFile add a post file to the request +// PostFile adds a post file to the request func (b *BeegoHTTPRequest) PostFile(formname, filename string) *BeegoHTTPRequest { b.files[formname] = filename return b } // Body adds request raw body. -// it supports string and []byte. +// Supports string and []byte. func (b *BeegoHTTPRequest) Body(data interface{}) *BeegoHTTPRequest { switch t := data.(type) { case string: @@ -327,7 +347,7 @@ func (b *BeegoHTTPRequest) Body(data interface{}) *BeegoHTTPRequest { return b } -// XMLBody adds request raw body encoding by XML. +// XMLBody adds the request raw body encoded in XML. func (b *BeegoHTTPRequest) XMLBody(obj interface{}) (*BeegoHTTPRequest, error) { if b.req.Body == nil && obj != nil { byts, err := xml.Marshal(obj) @@ -341,7 +361,7 @@ func (b *BeegoHTTPRequest) XMLBody(obj interface{}) (*BeegoHTTPRequest, error) { return b, nil } -// YAMLBody adds request raw body encoding by YAML. +// YAMLBody adds the request raw body encoded in YAML. func (b *BeegoHTTPRequest) YAMLBody(obj interface{}) (*BeegoHTTPRequest, error) { if b.req.Body == nil && obj != nil { byts, err := yaml.Marshal(obj) @@ -355,7 +375,7 @@ func (b *BeegoHTTPRequest) YAMLBody(obj interface{}) (*BeegoHTTPRequest, error) return b, nil } -// JSONBody adds request raw body encoding by JSON. +// JSONBody adds the request raw body encoded in JSON. func (b *BeegoHTTPRequest) JSONBody(obj interface{}) (*BeegoHTTPRequest, error) { if b.req.Body == nil && obj != nil { byts, err := json.Marshal(obj) @@ -396,7 +416,7 @@ func (b *BeegoHTTPRequest) buildURL(paramBody string) { if err != nil { log.Println("Httplib:", err) } - //iocopy + // iocopy _, err = io.Copy(fileWriter, fh) fh.Close() if err != nil { @@ -437,8 +457,23 @@ func (b *BeegoHTTPRequest) getResponse() (*http.Response, error) { return resp, nil } -// DoRequest will do the client.Do +// DoRequest executes client.Do func (b *BeegoHTTPRequest) DoRequest() (resp *http.Response, err error) { + return b.DoRequestWithCtx(context.Background()) +} + +func (b *BeegoHTTPRequest) DoRequestWithCtx(ctx context.Context) (resp *http.Response, err error) { + + root := doRequestFilter + if len(b.setting.FilterChains) > 0 { + for i := len(b.setting.FilterChains) - 1; i >= 0; i-- { + root = b.setting.FilterChains[i](root) + } + } + return root(ctx, b) +} + +func (b *BeegoHTTPRequest) doRequest(ctx context.Context) (resp *http.Response, err error) { var paramBody string if len(b.params) > 0 { var buf bytes.Buffer @@ -530,7 +565,7 @@ func (b *BeegoHTTPRequest) DoRequest() (resp *http.Response, err error) { } // String returns the body string in response. -// it calls Response inner. +// Calls Response inner. func (b *BeegoHTTPRequest) String() (string, error) { data, err := b.Bytes() if err != nil { @@ -541,7 +576,7 @@ func (b *BeegoHTTPRequest) String() (string, error) { } // Bytes returns the body []byte in response. -// it calls Response inner. +// Calls Response inner. func (b *BeegoHTTPRequest) Bytes() ([]byte, error) { if b.body != nil { return b.body, nil @@ -567,7 +602,7 @@ func (b *BeegoHTTPRequest) Bytes() ([]byte, error) { } // ToFile saves the body data in response to one file. -// it calls Response inner. +// Calls Response inner. func (b *BeegoHTTPRequest) ToFile(filename string) error { resp, err := b.getResponse() if err != nil { @@ -590,7 +625,7 @@ func (b *BeegoHTTPRequest) ToFile(filename string) error { return err } -//Check that the file directory exists, there is no automatically created +// Check if the file directory exists. If it doesn't then it's created func pathExistAndMkdir(filename string) (err error) { filename = path.Dir(filename) _, err = os.Stat(filename) @@ -606,8 +641,8 @@ func pathExistAndMkdir(filename string) (err error) { return err } -// ToJSON returns the map that marshals from the body bytes as json in response . -// it calls Response inner. +// ToJSON returns the map that marshals from the body bytes as json in response. +// Calls Response inner. func (b *BeegoHTTPRequest) ToJSON(v interface{}) error { data, err := b.Bytes() if err != nil { @@ -617,7 +652,7 @@ func (b *BeegoHTTPRequest) ToJSON(v interface{}) error { } // ToXML returns the map that marshals from the body bytes as xml in response . -// it calls Response inner. +// Calls Response inner. func (b *BeegoHTTPRequest) ToXML(v interface{}) error { data, err := b.Bytes() if err != nil { @@ -627,7 +662,7 @@ func (b *BeegoHTTPRequest) ToXML(v interface{}) error { } // ToYAML returns the map that marshals from the body bytes as yaml in response . -// it calls Response inner. +// Calls Response inner. func (b *BeegoHTTPRequest) ToYAML(v interface{}) error { data, err := b.Bytes() if err != nil { @@ -636,7 +671,7 @@ func (b *BeegoHTTPRequest) ToYAML(v interface{}) error { return yaml.Unmarshal(data, v) } -// Response executes request client gets response mannually. +// Response executes request client gets response manually. func (b *BeegoHTTPRequest) Response() (*http.Response, error) { return b.getResponse() } diff --git a/pkg/logs/accesslog.go b/pkg/logs/accesslog.go index 9011b602..e380c54a 100644 --- a/pkg/logs/accesslog.go +++ b/pkg/logs/accesslog.go @@ -28,7 +28,7 @@ const ( jsonFormat = "JSON_FORMAT" ) -// AccessLogRecord struct for holding access log data. +// AccessLogRecord is astruct for holding access log data. type AccessLogRecord struct { RemoteAddr string `json:"remote_addr"` RequestTime time.Time `json:"request_time"` diff --git a/pkg/logs/alils/alils.go b/pkg/logs/alils/alils.go index 8397b3da..fd1a4e28 100644 --- a/pkg/logs/alils/alils.go +++ b/pkg/logs/alils/alils.go @@ -11,9 +11,9 @@ import ( ) const ( - // CacheSize set the flush size + // CacheSize sets the flush size CacheSize int = 64 - // Delimiter define the topic delimiter + // Delimiter defines the topic delimiter Delimiter string = "##" ) @@ -31,7 +31,7 @@ type Config struct { } // aliLSWriter implements LoggerInterface. -// it writes messages in keep-live tcp connection. +// Writes messages in keep-live tcp connection. type aliLSWriter struct { store *LogStore group []*LogGroup @@ -41,14 +41,14 @@ type aliLSWriter struct { Config } -// NewAliLS create a new Logger +// NewAliLS creates a new Logger func NewAliLS() logs.Logger { alils := new(aliLSWriter) alils.Level = logs.LevelTrace return alils } -// Init parse config and init struct +// Init parses config and initializes struct func (c *aliLSWriter) Init(jsonConfig string) (err error) { json.Unmarshal([]byte(jsonConfig), c) @@ -101,8 +101,8 @@ func (c *aliLSWriter) Init(jsonConfig string) (err error) { return nil } -// WriteMsg write message in connection. -// if connection is down, try to re-connect. +// WriteMsg writes a message in connection. +// If connection is down, try to re-connect. func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error) { if level > c.Level { diff --git a/pkg/logs/alils/config.go b/pkg/logs/alils/config.go index e8c24448..d0b67c24 100755 --- a/pkg/logs/alils/config.go +++ b/pkg/logs/alils/config.go @@ -4,10 +4,10 @@ const ( version = "0.5.0" // SDK version signatureMethod = "hmac-sha1" // Signature method - // OffsetNewest stands for the log head offset, i.e. the offset that will be + // OffsetNewest is the log head offset, i.e. the offset that will be // assigned to the next message that will be produced to the shard. OffsetNewest = "end" - // OffsetOldest stands for the oldest offset available on the logstore for a + // OffsetOldest is the the oldest offset available on the logstore for a // shard. OffsetOldest = "begin" ) diff --git a/pkg/logs/alils/log.pb.go b/pkg/logs/alils/log.pb.go index 601b0d78..b18fb9b7 100755 --- a/pkg/logs/alils/log.pb.go +++ b/pkg/logs/alils/log.pb.go @@ -31,13 +31,13 @@ type Log struct { // Reset the Log func (m *Log) Reset() { *m = Log{} } -// String return the Compact Log +// String returns the Compact Log func (m *Log) String() string { return proto.CompactTextString(m) } // ProtoMessage not implemented func (*Log) ProtoMessage() {} -// GetTime return the Log's Time +// GetTime returns the Log's Time func (m *Log) GetTime() uint32 { if m != nil && m.Time != nil { return *m.Time @@ -45,7 +45,7 @@ func (m *Log) GetTime() uint32 { return 0 } -// GetContents return the Log's Contents +// GetContents returns the Log's Contents func (m *Log) GetContents() []*LogContent { if m != nil { return m.Contents @@ -53,7 +53,7 @@ func (m *Log) GetContents() []*LogContent { return nil } -// LogContent define the Log content struct +// LogContent defines the Log content struct type LogContent struct { Key *string `protobuf:"bytes,1,req,name=Key" json:"Key,omitempty"` Value *string `protobuf:"bytes,2,req,name=Value" json:"Value,omitempty"` @@ -63,13 +63,13 @@ type LogContent struct { // Reset LogContent func (m *LogContent) Reset() { *m = LogContent{} } -// String return the compact text +// String returns the compact text func (m *LogContent) String() string { return proto.CompactTextString(m) } // ProtoMessage not implemented func (*LogContent) ProtoMessage() {} -// GetKey return the Key +// GetKey returns the key func (m *LogContent) GetKey() string { if m != nil && m.Key != nil { return *m.Key @@ -77,7 +77,7 @@ func (m *LogContent) GetKey() string { return "" } -// GetValue return the Value +// GetValue returns the value func (m *LogContent) GetValue() string { if m != nil && m.Value != nil { return *m.Value @@ -85,7 +85,7 @@ func (m *LogContent) GetValue() string { return "" } -// LogGroup define the logs struct +// LogGroup defines the logs struct type LogGroup struct { Logs []*Log `protobuf:"bytes,1,rep,name=Logs" json:"Logs,omitempty"` Reserved *string `protobuf:"bytes,2,opt,name=Reserved" json:"Reserved,omitempty"` @@ -97,13 +97,13 @@ type LogGroup struct { // Reset LogGroup func (m *LogGroup) Reset() { *m = LogGroup{} } -// String return the compact text +// String returns the compact text func (m *LogGroup) String() string { return proto.CompactTextString(m) } // ProtoMessage not implemented func (*LogGroup) ProtoMessage() {} -// GetLogs return the loggroup logs +// GetLogs returns the loggroup logs func (m *LogGroup) GetLogs() []*Log { if m != nil { return m.Logs @@ -111,7 +111,8 @@ func (m *LogGroup) GetLogs() []*Log { return nil } -// GetReserved return Reserved +// GetReserved returns Reserved. An empty string is returned +// if an error occurs func (m *LogGroup) GetReserved() string { if m != nil && m.Reserved != nil { return *m.Reserved @@ -119,7 +120,8 @@ func (m *LogGroup) GetReserved() string { return "" } -// GetTopic return Topic +// GetTopic returns Topic. An empty string is returned +// if an error occurs func (m *LogGroup) GetTopic() string { if m != nil && m.Topic != nil { return *m.Topic @@ -127,7 +129,8 @@ func (m *LogGroup) GetTopic() string { return "" } -// GetSource return Source +// GetSource returns source. An empty string is returned +// if an error occurs func (m *LogGroup) GetSource() string { if m != nil && m.Source != nil { return *m.Source @@ -135,7 +138,7 @@ func (m *LogGroup) GetSource() string { return "" } -// LogGroupList define the LogGroups +// LogGroupList defines the LogGroups type LogGroupList struct { LogGroups []*LogGroup `protobuf:"bytes,1,rep,name=logGroups" json:"logGroups,omitempty"` XXXUnrecognized []byte `json:"-"` @@ -144,13 +147,13 @@ type LogGroupList struct { // Reset LogGroupList func (m *LogGroupList) Reset() { *m = LogGroupList{} } -// String return compact text +// String returns compact text func (m *LogGroupList) String() string { return proto.CompactTextString(m) } // ProtoMessage not implemented func (*LogGroupList) ProtoMessage() {} -// GetLogGroups return the LogGroups +// GetLogGroups returns the LogGroups func (m *LogGroupList) GetLogGroups() []*LogGroup { if m != nil { return m.LogGroups @@ -158,7 +161,7 @@ func (m *LogGroupList) GetLogGroups() []*LogGroup { return nil } -// Marshal the logs to byte slice +// Marshal marshals the logs to byte slice func (m *Log) Marshal() (data []byte, err error) { size := m.Size() data = make([]byte, size) @@ -353,7 +356,7 @@ func encodeVarintLog(data []byte, offset int, v uint64) int { return offset + 1 } -// Size return the log's size +// Size returns the log's size func (m *Log) Size() (n int) { var l int _ = l @@ -372,7 +375,7 @@ func (m *Log) Size() (n int) { return n } -// Size return LogContent size based on Key and Value +// Size returns LogContent size based on Key and Value func (m *LogContent) Size() (n int) { var l int _ = l @@ -390,7 +393,7 @@ func (m *LogContent) Size() (n int) { return n } -// Size return LogGroup size based on Logs +// Size returns LogGroup size based on Logs func (m *LogGroup) Size() (n int) { var l int _ = l @@ -418,7 +421,7 @@ func (m *LogGroup) Size() (n int) { return n } -// Size return LogGroupList size +// Size returns LogGroupList size func (m *LogGroupList) Size() (n int) { var l int _ = l @@ -448,7 +451,7 @@ func sozLog(x uint64) (n int) { return sovLog((x << 1) ^ (x >> 63)) } -// Unmarshal data to log +// Unmarshal unmarshals data to log func (m *Log) Unmarshal(data []byte) error { var hasFields [1]uint64 l := len(data) @@ -557,7 +560,7 @@ func (m *Log) Unmarshal(data []byte) error { return nil } -// Unmarshal data to LogContent +// Unmarshal unmarshals data to LogContent func (m *LogContent) Unmarshal(data []byte) error { var hasFields [1]uint64 l := len(data) @@ -679,7 +682,7 @@ func (m *LogContent) Unmarshal(data []byte) error { return nil } -// Unmarshal data to LogGroup +// Unmarshal unmarshals data to LogGroup func (m *LogGroup) Unmarshal(data []byte) error { l := len(data) iNdEx := 0 @@ -853,7 +856,7 @@ func (m *LogGroup) Unmarshal(data []byte) error { return nil } -// Unmarshal data to LogGroupList +// Unmarshal unmarshals data to LogGroupList func (m *LogGroupList) Unmarshal(data []byte) error { l := len(data) iNdEx := 0 diff --git a/pkg/logs/alils/log_config.go b/pkg/logs/alils/log_config.go index e8564efb..7daeb864 100755 --- a/pkg/logs/alils/log_config.go +++ b/pkg/logs/alils/log_config.go @@ -1,6 +1,6 @@ package alils -// InputDetail define log detail +// InputDetail defines log detail type InputDetail struct { LogType string `json:"logType"` LogPath string `json:"logPath"` @@ -15,13 +15,13 @@ type InputDetail struct { TopicFormat string `json:"topicFormat"` } -// OutputDetail define the output detail +// OutputDetail defines the output detail type OutputDetail struct { Endpoint string `json:"endpoint"` LogStoreName string `json:"logstoreName"` } -// LogConfig define Log Config +// LogConfig defines Log Config type LogConfig struct { Name string `json:"configName"` InputType string `json:"inputType"` diff --git a/pkg/logs/alils/log_project.go b/pkg/logs/alils/log_project.go index 59db8cbf..7ede3fef 100755 --- a/pkg/logs/alils/log_project.go +++ b/pkg/logs/alils/log_project.go @@ -20,7 +20,7 @@ type errorMessage struct { Message string `json:"errorMessage"` } -// LogProject Define the Ali Project detail +// LogProject defines the Ali Project detail type LogProject struct { Name string // Project name Endpoint string // IP or hostname of SLS endpoint diff --git a/pkg/logs/alils/log_store.go b/pkg/logs/alils/log_store.go index fa502736..d5ff25e2 100755 --- a/pkg/logs/alils/log_store.go +++ b/pkg/logs/alils/log_store.go @@ -12,7 +12,7 @@ import ( "github.com/gogo/protobuf/proto" ) -// LogStore Store the logs +// LogStore stores the logs type LogStore struct { Name string `json:"logstoreName"` TTL int @@ -24,7 +24,7 @@ type LogStore struct { project *LogProject } -// Shard define the Log Shard +// Shard defines the Log Shard type Shard struct { ShardID int `json:"shardID"` } @@ -71,7 +71,7 @@ func (s *LogStore) ListShards() (shardIDs []int, err error) { return } -// PutLogs put logs into logstore. +// PutLogs puts logs into logstore. // The callers should transform user logs into LogGroup. func (s *LogStore) PutLogs(lg *LogGroup) (err error) { body, err := proto.Marshal(lg) diff --git a/pkg/logs/alils/machine_group.go b/pkg/logs/alils/machine_group.go index b6c69a14..101faeb4 100755 --- a/pkg/logs/alils/machine_group.go +++ b/pkg/logs/alils/machine_group.go @@ -8,13 +8,13 @@ import ( "net/http/httputil" ) -// MachineGroupAttribute define the Attribute +// MachineGroupAttribute defines the Attribute type MachineGroupAttribute struct { ExternalName string `json:"externalName"` TopicName string `json:"groupTopic"` } -// MachineGroup define the machine Group +// MachineGroup defines the machine Group type MachineGroup struct { Name string `json:"groupName"` Type string `json:"groupType"` @@ -29,20 +29,20 @@ type MachineGroup struct { project *LogProject } -// Machine define the Machine +// Machine defines the Machine type Machine struct { IP string UniqueID string `json:"machine-uniqueid"` UserdefinedID string `json:"userdefined-id"` } -// MachineList define the Machine List +// MachineList defines the Machine List type MachineList struct { Total int Machines []*Machine } -// ListMachines returns machine list of this machine group. +// ListMachines returns the machine list of this machine group. func (m *MachineGroup) ListMachines() (ms []*Machine, total int, err error) { h := map[string]string{ "x-sls-bodyrawsize": "0", diff --git a/pkg/logs/conn.go b/pkg/logs/conn.go index 74c458ab..8b55bde7 100644 --- a/pkg/logs/conn.go +++ b/pkg/logs/conn.go @@ -22,7 +22,7 @@ import ( ) // connWriter implements LoggerInterface. -// it writes messages in keep-live tcp connection. +// Writes messages in keep-live tcp connection. type connWriter struct { lg *logWriter innerWriter io.WriteCloser @@ -33,21 +33,21 @@ type connWriter struct { Level int `json:"level"` } -// NewConn create new ConnWrite returning as LoggerInterface. +// NewConn creates new ConnWrite returning as LoggerInterface. func NewConn() Logger { conn := new(connWriter) conn.Level = LevelTrace return conn } -// Init init connection writer with json config. -// json config only need key "level". +// Init initializes a connection writer with json config. +// json config only needs they "level" key func (c *connWriter) Init(jsonConfig string) error { return json.Unmarshal([]byte(jsonConfig), c) } -// WriteMsg write message in connection. -// if connection is down, try to re-connect. +// WriteMsg writes message in connection. +// If connection is down, try to re-connect. func (c *connWriter) WriteMsg(when time.Time, msg string, level int) error { if level > c.Level { return nil diff --git a/pkg/logs/console.go b/pkg/logs/console.go index 3dcaee1d..b2cc2907 100644 --- a/pkg/logs/console.go +++ b/pkg/logs/console.go @@ -26,7 +26,7 @@ import ( // brush is a color join function type brush func(string) string -// newBrush return a fix color Brush +// newBrush returns a fix color Brush func newBrush(color string) brush { pre := "\033[" reset := "\033[0m" @@ -53,7 +53,7 @@ type consoleWriter struct { Colorful bool `json:"color"` //this filed is useful only when system's terminal supports color } -// NewConsole create ConsoleWriter returning as LoggerInterface. +// NewConsole creates ConsoleWriter returning as LoggerInterface. func NewConsole() Logger { cw := &consoleWriter{ lg: newLogWriter(ansicolor.NewAnsiColorWriter(os.Stdout)), @@ -63,8 +63,8 @@ func NewConsole() Logger { return cw } -// Init init console logger. -// jsonConfig like '{"level":LevelTrace}'. +// Init initianlizes the console logger. +// jsonConfig must be in the format '{"level":LevelTrace}' func (c *consoleWriter) Init(jsonConfig string) error { if len(jsonConfig) == 0 { return nil @@ -72,7 +72,7 @@ func (c *consoleWriter) Init(jsonConfig string) error { return json.Unmarshal([]byte(jsonConfig), c) } -// WriteMsg write message in console. +// WriteMsg writes message in console. func (c *consoleWriter) WriteMsg(when time.Time, msg string, level int) error { if level > c.Level { return nil diff --git a/pkg/logs/es/es.go b/pkg/logs/es/es.go index af6a7892..7542b577 100644 --- a/pkg/logs/es/es.go +++ b/pkg/logs/es/es.go @@ -15,7 +15,7 @@ import ( "github.com/astaxie/beego/pkg/logs" ) -// NewES return a LoggerInterface +// NewES returns a LoggerInterface func NewES() logs.Logger { cw := &esLogger{ Level: logs.LevelDebug, @@ -59,7 +59,7 @@ func (el *esLogger) Init(jsonconfig string) error { return nil } -// WriteMsg will write the msg and level into es +// WriteMsg writes the msg and level into es func (el *esLogger) WriteMsg(when time.Time, msg string, level int) error { if level > el.Level { return nil diff --git a/pkg/logs/file.go b/pkg/logs/file.go index 40a3572a..fbe10b55 100644 --- a/pkg/logs/file.go +++ b/pkg/logs/file.go @@ -30,7 +30,7 @@ import ( ) // fileLogWriter implements LoggerInterface. -// It writes messages by lines limit, file size limit, or time frequency. +// Writes messages by lines limit, file size limit, or time frequency. type fileLogWriter struct { sync.RWMutex // write log order by order and atomic incr maxLinesCurLines and maxSizeCurSize // The opened file @@ -71,7 +71,7 @@ type fileLogWriter struct { fileNameOnly, suffix string // like "project.log", project is fileNameOnly and .log is suffix } -// newFileWriter create a FileLogWriter returning as LoggerInterface. +// newFileWriter creates a FileLogWriter returning as LoggerInterface. func newFileWriter() Logger { w := &fileLogWriter{ Daily: true, @@ -143,7 +143,7 @@ func (w *fileLogWriter) needRotateHourly(size int, hour int) bool { } -// WriteMsg write logger message into file. +// WriteMsg writes logger message into file. func (w *fileLogWriter) WriteMsg(when time.Time, msg string, level int) error { if level > w.Level { return nil @@ -286,7 +286,7 @@ func (w *fileLogWriter) lines() (int, error) { return count, nil } -// DoRotate means it need to write file in new file. +// DoRotate means it needs to write logs into a new file. // new file name like xx.2013-01-01.log (daily) or xx.001.log (by line or size) func (w *fileLogWriter) doRotate(logTime time.Time) error { // file exists @@ -397,7 +397,7 @@ func (w *fileLogWriter) Destroy() { w.fileWriter.Close() } -// Flush flush file logger. +// Flush flushes file logger. // there are no buffering messages in file logger in memory. // flush file means sync file from disk. func (w *fileLogWriter) Flush() { diff --git a/pkg/logs/jianliao.go b/pkg/logs/jianliao.go index 88ba0f9a..71e7e2bf 100644 --- a/pkg/logs/jianliao.go +++ b/pkg/logs/jianliao.go @@ -18,7 +18,7 @@ type JLWriter struct { Level int `json:"level"` } -// newJLWriter create jiaoliao writer. +// newJLWriter creates jiaoliao writer. func newJLWriter() Logger { return &JLWriter{Level: LevelTrace} } @@ -28,8 +28,8 @@ func (s *JLWriter) Init(jsonconfig string) error { return json.Unmarshal([]byte(jsonconfig), s) } -// WriteMsg write message in smtp writer. -// it will send an email with subject and only this message. +// WriteMsg writes message in smtp writer. +// Sends an email with subject and only this message. func (s *JLWriter) WriteMsg(when time.Time, msg string, level int) error { if level > s.Level { return nil diff --git a/pkg/logs/log.go b/pkg/logs/log.go index 39c006d2..4824918b 100644 --- a/pkg/logs/log.go +++ b/pkg/logs/log.go @@ -108,7 +108,7 @@ func Register(name string, log newLoggerFunc) { } // BeeLogger is default logger in beego application. -// it can contain several providers and log message into all providers. +// Can contain several providers and log message into all providers. type BeeLogger struct { lock sync.Mutex level int @@ -140,7 +140,7 @@ type logMsg struct { var logMsgPool *sync.Pool // NewLogger returns a new BeeLogger. -// channelLen means the number of messages in chan(used where asynchronous is true). +// channelLen: the number of messages in chan(used where asynchronous is true). // if the buffering chan is full, logger adapters write to file or other way. func NewLogger(channelLens ...int64) *BeeLogger { bl := new(BeeLogger) @@ -155,7 +155,7 @@ func NewLogger(channelLens ...int64) *BeeLogger { return bl } -// Async set the log to asynchronous and start the goroutine +// Async sets the log to asynchronous and start the goroutine func (bl *BeeLogger) Async(msgLen ...int64) *BeeLogger { bl.lock.Lock() defer bl.lock.Unlock() @@ -178,7 +178,7 @@ func (bl *BeeLogger) Async(msgLen ...int64) *BeeLogger { } // SetLogger provides a given logger adapter into BeeLogger with config string. -// config need to be correct JSON as string: {"interval":360}. +// config must in in JSON format like {"interval":360}} func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error { config := append(configs, "{}")[0] for _, l := range bl.outputs { @@ -203,7 +203,7 @@ func (bl *BeeLogger) setLogger(adapterName string, configs ...string) error { } // SetLogger provides a given logger adapter into BeeLogger with config string. -// config need to be correct JSON as string: {"interval":360}. +// config must in in JSON format like {"interval":360}} func (bl *BeeLogger) SetLogger(adapterName string, configs ...string) error { bl.lock.Lock() defer bl.lock.Unlock() @@ -214,7 +214,7 @@ func (bl *BeeLogger) SetLogger(adapterName string, configs ...string) error { return bl.setLogger(adapterName, configs...) } -// DelLogger remove a logger adapter in BeeLogger. +// DelLogger removes a logger adapter in BeeLogger. func (bl *BeeLogger) DelLogger(adapterName string) error { bl.lock.Lock() defer bl.lock.Unlock() @@ -306,9 +306,9 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error return nil } -// SetLevel Set log message level. +// SetLevel sets log message level. // If message level (such as LevelDebug) is higher than logger level (such as LevelWarning), -// log providers will not even be sent the message. +// log providers will not be sent the message. func (bl *BeeLogger) SetLevel(l int) { bl.level = l } diff --git a/pkg/logs/slack.go b/pkg/logs/slack.go index 1cd2e5ae..e78eeab6 100644 --- a/pkg/logs/slack.go +++ b/pkg/logs/slack.go @@ -14,7 +14,7 @@ type SLACKWriter struct { Level int `json:"level"` } -// newSLACKWriter create jiaoliao writer. +// newSLACKWriter creates jiaoliao writer. func newSLACKWriter() Logger { return &SLACKWriter{Level: LevelTrace} } @@ -25,7 +25,7 @@ func (s *SLACKWriter) Init(jsonconfig string) error { } // WriteMsg write message in smtp writer. -// it will send an email with subject and only this message. +// Sends an email with subject and only this message. func (s *SLACKWriter) WriteMsg(when time.Time, msg string, level int) error { if level > s.Level { return nil diff --git a/pkg/logs/smtp.go b/pkg/logs/smtp.go index 6208d7b8..720c2d25 100644 --- a/pkg/logs/smtp.go +++ b/pkg/logs/smtp.go @@ -35,7 +35,7 @@ type SMTPWriter struct { Level int `json:"level"` } -// NewSMTPWriter create smtp writer. +// NewSMTPWriter creates the smtp writer. func newSMTPWriter() Logger { return &SMTPWriter{Level: LevelTrace} } @@ -115,8 +115,8 @@ func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAd return client.Quit() } -// WriteMsg write message in smtp writer. -// it will send an email with subject and only this message. +// WriteMsg writes message in smtp writer. +// Sends an email with subject and only this message. func (s *SMTPWriter) WriteMsg(when time.Time, msg string, level int) error { if level > s.Level { return nil diff --git a/pkg/orm/do_nothing_omr_test.go b/pkg/orm/do_nothing_omr_test.go new file mode 100644 index 00000000..92cde38b --- /dev/null +++ b/pkg/orm/do_nothing_omr_test.go @@ -0,0 +1,134 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package orm + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestDoNothingOrm(t *testing.T) { + o := &DoNothingOrm{} + err := o.DoTxWithCtxAndOpts(nil, nil, nil) + assert.Nil(t, err) + + err = o.DoTxWithCtx(nil, nil) + assert.Nil(t, err) + + err = o.DoTx(nil) + assert.Nil(t, err) + + err = o.DoTxWithOpts(nil, nil) + assert.Nil(t, err) + + assert.Nil(t, o.Driver()) + + assert.Nil(t, o.QueryM2MWithCtx(nil, nil, "")) + assert.Nil(t, o.QueryM2M(nil, "")) + assert.Nil(t, o.ReadWithCtx(nil, nil)) + assert.Nil(t, o.Read(nil)) + + txOrm, err := o.BeginWithCtxAndOpts(nil, nil) + assert.Nil(t, err) + assert.Nil(t, txOrm) + + txOrm, err = o.BeginWithCtx(nil) + assert.Nil(t, err) + assert.Nil(t, txOrm) + + txOrm, err = o.BeginWithOpts(nil) + assert.Nil(t, err) + assert.Nil(t, txOrm) + + txOrm, err = o.Begin() + assert.Nil(t, err) + assert.Nil(t, txOrm) + + assert.Nil(t, o.RawWithCtx(nil, "")) + assert.Nil(t, o.Raw("")) + + i, err := o.InsertMulti(0, nil) + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + + i, err = o.Insert(nil) + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + + i, err = o.InsertWithCtx(nil, nil) + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + + i, err = o.InsertOrUpdateWithCtx(nil, nil) + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + + i, err = o.InsertOrUpdate(nil) + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + + i, err = o.InsertMultiWithCtx(nil, 0, nil) + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + + i, err = o.LoadRelatedWithCtx(nil, nil, "") + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + + i, err = o.LoadRelated(nil, "") + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + + assert.Nil(t, o.QueryTableWithCtx(nil, nil)) + assert.Nil(t, o.QueryTable(nil)) + + assert.Nil(t, o.Read(nil)) + assert.Nil(t, o.ReadWithCtx(nil, nil)) + assert.Nil(t, o.ReadForUpdateWithCtx(nil, nil)) + assert.Nil(t, o.ReadForUpdate(nil)) + + ok, i, err := o.ReadOrCreate(nil, "") + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + assert.False(t, ok) + + ok, i, err = o.ReadOrCreateWithCtx(nil, nil, "") + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + assert.False(t, ok) + + i, err = o.Delete(nil) + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + + i, err = o.DeleteWithCtx(nil, nil) + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + + i, err = o.Update(nil) + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + + i, err = o.UpdateWithCtx(nil, nil) + assert.Nil(t, err) + assert.Equal(t, int64(0), i) + + assert.Nil(t, o.DBStats()) + + to := &DoNothingTxOrm{} + assert.Nil(t, to.Commit()) + assert.Nil(t, to.Rollback()) +} diff --git a/pkg/orm/do_nothing_orm.go b/pkg/orm/do_nothing_orm.go new file mode 100644 index 00000000..87b0a2ae --- /dev/null +++ b/pkg/orm/do_nothing_orm.go @@ -0,0 +1,178 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package orm + +import ( + "context" + "database/sql" +) + +// DoNothingOrm won't do anything, usually you use this to custom your mock Ormer implementation +// I think golang mocking interface is hard to use +// this may help you to integrate with Ormer + +var _ Ormer = new(DoNothingOrm) + +type DoNothingOrm struct { +} + +func (d *DoNothingOrm) Read(md interface{}, cols ...string) error { + return nil +} + +func (d *DoNothingOrm) ReadWithCtx(ctx context.Context, md interface{}, cols ...string) error { + return nil +} + +func (d *DoNothingOrm) ReadForUpdate(md interface{}, cols ...string) error { + return nil +} + +func (d *DoNothingOrm) ReadForUpdateWithCtx(ctx context.Context, md interface{}, cols ...string) error { + return nil +} + +func (d *DoNothingOrm) ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, int64, error) { + return false, 0, nil +} + +func (d *DoNothingOrm) ReadOrCreateWithCtx(ctx context.Context, md interface{}, col1 string, cols ...string) (bool, int64, error) { + return false, 0, nil +} + +func (d *DoNothingOrm) LoadRelated(md interface{}, name string, args ...interface{}) (int64, error) { + return 0, nil +} + +func (d *DoNothingOrm) LoadRelatedWithCtx(ctx context.Context, md interface{}, name string, args ...interface{}) (int64, error) { + return 0, nil +} + +func (d *DoNothingOrm) QueryM2M(md interface{}, name string) QueryM2Mer { + return nil +} + +func (d *DoNothingOrm) QueryM2MWithCtx(ctx context.Context, md interface{}, name string) QueryM2Mer { + return nil +} + +func (d *DoNothingOrm) QueryTable(ptrStructOrTableName interface{}) QuerySeter { + return nil +} + +func (d *DoNothingOrm) QueryTableWithCtx(ctx context.Context, ptrStructOrTableName interface{}) QuerySeter { + return nil +} + +func (d *DoNothingOrm) DBStats() *sql.DBStats { + return nil +} + +func (d *DoNothingOrm) Insert(md interface{}) (int64, error) { + return 0, nil +} + +func (d *DoNothingOrm) InsertWithCtx(ctx context.Context, md interface{}) (int64, error) { + return 0, nil +} + +func (d *DoNothingOrm) InsertOrUpdate(md interface{}, colConflitAndArgs ...string) (int64, error) { + return 0, nil +} + +func (d *DoNothingOrm) InsertOrUpdateWithCtx(ctx context.Context, md interface{}, colConflitAndArgs ...string) (int64, error) { + return 0, nil +} + +func (d *DoNothingOrm) InsertMulti(bulk int, mds interface{}) (int64, error) { + return 0, nil +} + +func (d *DoNothingOrm) InsertMultiWithCtx(ctx context.Context, bulk int, mds interface{}) (int64, error) { + return 0, nil +} + +func (d *DoNothingOrm) Update(md interface{}, cols ...string) (int64, error) { + return 0, nil +} + +func (d *DoNothingOrm) UpdateWithCtx(ctx context.Context, md interface{}, cols ...string) (int64, error) { + return 0, nil +} + +func (d *DoNothingOrm) Delete(md interface{}, cols ...string) (int64, error) { + return 0, nil +} + +func (d *DoNothingOrm) DeleteWithCtx(ctx context.Context, md interface{}, cols ...string) (int64, error) { + return 0, nil +} + +func (d *DoNothingOrm) Raw(query string, args ...interface{}) RawSeter { + return nil +} + +func (d *DoNothingOrm) RawWithCtx(ctx context.Context, query string, args ...interface{}) RawSeter { + return nil +} + +func (d *DoNothingOrm) Driver() Driver { + return nil +} + +func (d *DoNothingOrm) Begin() (TxOrmer, error) { + return nil, nil +} + +func (d *DoNothingOrm) BeginWithCtx(ctx context.Context) (TxOrmer, error) { + return nil, nil +} + +func (d *DoNothingOrm) BeginWithOpts(opts *sql.TxOptions) (TxOrmer, error) { + return nil, nil +} + +func (d *DoNothingOrm) BeginWithCtxAndOpts(ctx context.Context, opts *sql.TxOptions) (TxOrmer, error) { + return nil, nil +} + +func (d *DoNothingOrm) DoTx(task func(txOrm TxOrmer) error) error { + return nil +} + +func (d *DoNothingOrm) DoTxWithCtx(ctx context.Context, task func(txOrm TxOrmer) error) error { + return nil +} + +func (d *DoNothingOrm) DoTxWithOpts(opts *sql.TxOptions, task func(txOrm TxOrmer) error) error { + return nil +} + +func (d *DoNothingOrm) DoTxWithCtxAndOpts(ctx context.Context, opts *sql.TxOptions, task func(txOrm TxOrmer) error) error { + return nil +} + +// DoNothingTxOrm is similar with DoNothingOrm, usually you use it to test +type DoNothingTxOrm struct { + DoNothingOrm +} + +func (d *DoNothingTxOrm) Commit() error { + return nil +} + +func (d *DoNothingTxOrm) Rollback() error { + return nil +} diff --git a/pkg/orm/filter.go b/pkg/orm/filter.go new file mode 100644 index 00000000..d04b8c42 --- /dev/null +++ b/pkg/orm/filter.go @@ -0,0 +1,36 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package orm + +import ( + "context" +) + +// FilterChain is used to build a Filter +// don't forget to call next(...) inside your Filter +type FilterChain func(next Filter) Filter + +// Filter's behavior is a little big strang. +// it's only be called when users call methods of Ormer +type Filter func(ctx context.Context, inv *Invocation) + +var globalFilterChains = make([]FilterChain, 0, 4) + +// AddGlobalFilterChain adds a new FilterChain +// All orm instances built after this invocation will use this filterChain, +// but instances built before this invocation will not be affected +func AddGlobalFilterChain(filterChain FilterChain) { + globalFilterChains = append(globalFilterChains, filterChain) +} \ No newline at end of file diff --git a/pkg/orm/filter/opentracing/filter.go b/pkg/orm/filter/opentracing/filter.go new file mode 100644 index 00000000..a55ae6d2 --- /dev/null +++ b/pkg/orm/filter/opentracing/filter.go @@ -0,0 +1,59 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package opentracing + +import ( + "context" + + "github.com/opentracing/opentracing-go" + + "github.com/astaxie/beego/pkg/orm" +) + +// FilterChainBuilder provides an extension point +// this Filter's behavior looks a little bit strange +// for example: +// if we want to trace QuerySetter +// actually we trace invoking "QueryTable" and "QueryTableWithCtx" +type FilterChainBuilder struct { + // CustomSpanFunc users are able to custom their span + CustomSpanFunc func(span opentracing.Span, ctx context.Context, inv *orm.Invocation) +} + +func (builder *FilterChainBuilder) FilterChain(next orm.Filter) orm.Filter { + return func(ctx context.Context, inv *orm.Invocation) { + operationName := builder.operationName(ctx, inv) + span, spanCtx := opentracing.StartSpanFromContext(ctx, operationName) + defer span.Finish() + + next(spanCtx, inv) + span.SetTag("Method", inv.Method) + span.SetTag("Table", inv.GetTableName()) + span.SetTag("InsideTx", inv.InsideTx) + span.SetTag("TxName", spanCtx.Value(orm.TxNameKey)) + + if builder.CustomSpanFunc != nil { + builder.CustomSpanFunc(span, spanCtx, inv) + } + + } +} + +func (builder *FilterChainBuilder) operationName(ctx context.Context, inv *orm.Invocation) string { + if n, ok := ctx.Value(orm.TxNameKey).(string); ok { + return inv.Method + "#" + n + } + return inv.Method + "#" + inv.GetTableName() +} diff --git a/pkg/orm/filter/opentracing/filter_test.go b/pkg/orm/filter/opentracing/filter_test.go new file mode 100644 index 00000000..1428df8a --- /dev/null +++ b/pkg/orm/filter/opentracing/filter_test.go @@ -0,0 +1,43 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package opentracing + +import ( + "context" + "testing" + "time" + + "github.com/opentracing/opentracing-go" + + "github.com/astaxie/beego/pkg/orm" +) + +func TestFilterChainBuilder_FilterChain(t *testing.T) { + next := func(ctx context.Context, inv *orm.Invocation) { + inv.TxName = "Hello" + } + + builder := &FilterChainBuilder{ + CustomSpanFunc: func(span opentracing.Span, ctx context.Context, inv *orm.Invocation) { + span.SetTag("hello", "hell") + }, + } + + inv := &orm.Invocation{ + Method: "Hello", + TxStartTime: time.Now(), + } + builder.FilterChain(next)(context.Background(), inv) +} \ No newline at end of file diff --git a/pkg/orm/filter/prometheus/filter.go b/pkg/orm/filter/prometheus/filter.go new file mode 100644 index 00000000..33fdf78f --- /dev/null +++ b/pkg/orm/filter/prometheus/filter.go @@ -0,0 +1,88 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package prometheus + +import ( + "context" + "strconv" + "strings" + "time" + + "github.com/prometheus/client_golang/prometheus" + + beego "github.com/astaxie/beego/pkg" + "github.com/astaxie/beego/pkg/orm" +) + +// FilterChainBuilder is an extension point, +// when we want to support some configuration, +// please use this structure +// this Filter's behavior looks a little bit strange +// for example: +// if we want to records the metrics of QuerySetter +// actually we only records metrics of invoking "QueryTable" and "QueryTableWithCtx" +type FilterChainBuilder struct { + summaryVec prometheus.ObserverVec +} + +func NewFilterChainBuilder() *FilterChainBuilder { + summaryVec := prometheus.NewSummaryVec(prometheus.SummaryOpts{ + Name: "beego", + Subsystem: "orm_operation", + ConstLabels: map[string]string{ + "server": beego.BConfig.ServerName, + "env": beego.BConfig.RunMode, + "appname": beego.BConfig.AppName, + }, + Help: "The statics info for orm operation", + }, []string{"method", "name", "duration", "insideTx", "txName"}) + + prometheus.MustRegister(summaryVec) + return &FilterChainBuilder{ + summaryVec: summaryVec, + } +} + +func (builder *FilterChainBuilder) FilterChain(next orm.Filter) orm.Filter { + return func(ctx context.Context, inv *orm.Invocation) { + startTime := time.Now() + next(ctx, inv) + endTime := time.Now() + dur := (endTime.Sub(startTime)) / time.Millisecond + + // if the TPS is too large, here may be some problem + // thinking about using goroutine pool + go builder.report(ctx, inv, dur) + } +} + +func (builder *FilterChainBuilder) report(ctx context.Context, inv *orm.Invocation, dur time.Duration) { + // start a transaction, we don't record it + if strings.HasPrefix(inv.Method, "Begin") { + return + } + if inv.Method == "Commit" || inv.Method == "Rollback" { + builder.reportTxn(ctx, inv) + return + } + builder.summaryVec.WithLabelValues(inv.Method, inv.GetTableName(), strconv.Itoa(int(dur)), + strconv.FormatBool(inv.InsideTx), inv.TxName) +} + +func (builder *FilterChainBuilder) reportTxn(ctx context.Context, inv *orm.Invocation) { + dur := time.Now().Sub(inv.TxStartTime) / time.Millisecond + builder.summaryVec.WithLabelValues(inv.Method, inv.TxName, strconv.Itoa(int(dur)), + strconv.FormatBool(inv.InsideTx), inv.TxName) +} diff --git a/pkg/orm/filter/prometheus/filter_test.go b/pkg/orm/filter/prometheus/filter_test.go new file mode 100644 index 00000000..a71e8f50 --- /dev/null +++ b/pkg/orm/filter/prometheus/filter_test.go @@ -0,0 +1,60 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package prometheus + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + + "github.com/astaxie/beego/pkg/orm" +) + +func TestFilterChainBuilder_FilterChain(t *testing.T) { + builder := NewFilterChainBuilder() + assert.NotNil(t, builder.summaryVec) + + filter := builder.FilterChain(func(ctx context.Context, inv *orm.Invocation) { + inv.Method = "coming" + }) + assert.NotNil(t, filter) + + inv := &orm.Invocation{} + filter(context.Background(), inv) + assert.Equal(t, "coming", inv.Method) + + inv = &orm.Invocation{ + Method: "Hello", + TxStartTime: time.Now(), + } + builder.reportTxn(context.Background(), inv) + + inv = &orm.Invocation{ + Method: "Begin", + } + + ctx := context.Background() + // it will be ignored + builder.report(ctx, inv, time.Second) + + inv.Method = "Commit" + builder.report(ctx, inv, time.Second) + + inv.Method = "Update" + builder.report(ctx, inv, time.Second) + +} diff --git a/pkg/orm/filter_orm_decorator.go b/pkg/orm/filter_orm_decorator.go new file mode 100644 index 00000000..eb26ea68 --- /dev/null +++ b/pkg/orm/filter_orm_decorator.go @@ -0,0 +1,519 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package orm + +import ( + "context" + "database/sql" + "reflect" + "time" +) + +const TxNameKey = "TxName" + +type filterOrmDecorator struct { + ormer + TxBeginner + TxCommitter + + root Filter + + insideTx bool + txStartTime time.Time + txName string +} + +func NewFilterOrmDecorator(delegate Ormer, filterChains ...FilterChain) Ormer { + res := &filterOrmDecorator{ + ormer: delegate, + TxBeginner: delegate, + root: func(ctx context.Context, inv *Invocation) { + inv.execute() + }, + } + + for i := len(filterChains) - 1; i >= 0; i-- { + node := filterChains[i] + res.root = node(res.root) + } + return res +} + +func NewFilterTxOrmDecorator(delegate TxOrmer, root Filter, txName string) TxOrmer { + res := &filterOrmDecorator{ + ormer: delegate, + TxCommitter: delegate, + root: root, + insideTx: true, + txStartTime: time.Now(), + txName: txName, + } + return res +} + +func (f *filterOrmDecorator) Read(md interface{}, cols ...string) error { + return f.ReadWithCtx(context.Background(), md, cols...) +} + +func (f *filterOrmDecorator) ReadWithCtx(ctx context.Context, md interface{}, cols ...string) (err error) { + mi, _ := modelCache.getByMd(md) + inv := &Invocation{ + Method: "ReadWithCtx", + Args: []interface{}{md, cols}, + Md: md, + mi: mi, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + err = f.ormer.ReadWithCtx(ctx, md, cols...) + }, + } + f.root(ctx, inv) + return err +} + +func (f *filterOrmDecorator) ReadForUpdate(md interface{}, cols ...string) error { + return f.ReadForUpdateWithCtx(context.Background(), md, cols...) +} + +func (f *filterOrmDecorator) ReadForUpdateWithCtx(ctx context.Context, md interface{}, cols ...string) error { + var err error + mi, _ := modelCache.getByMd(md) + inv := &Invocation{ + Method: "ReadForUpdateWithCtx", + Args: []interface{}{md, cols}, + Md: md, + mi: mi, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + err = f.ormer.ReadForUpdateWithCtx(ctx, md, cols...) + }, + } + f.root(ctx, inv) + return err +} + +func (f *filterOrmDecorator) ReadOrCreate(md interface{}, col1 string, cols ...string) (bool, int64, error) { + return f.ReadOrCreateWithCtx(context.Background(), md, col1, cols...) +} + +func (f *filterOrmDecorator) ReadOrCreateWithCtx(ctx context.Context, md interface{}, col1 string, cols ...string) (bool, int64, error) { + var ( + ok bool + res int64 + err error + ) + + mi, _ := modelCache.getByMd(md) + inv := &Invocation{ + Method: "ReadOrCreateWithCtx", + Args: []interface{}{md, col1, cols}, + Md: md, + mi: mi, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + ok, res, err = f.ormer.ReadOrCreateWithCtx(ctx, md, col1, cols...) + }, + } + f.root(ctx, inv) + return ok, res, err +} + +func (f *filterOrmDecorator) LoadRelated(md interface{}, name string, args ...interface{}) (int64, error) { + return f.LoadRelatedWithCtx(context.Background(), md, name, args...) +} + +func (f *filterOrmDecorator) LoadRelatedWithCtx(ctx context.Context, md interface{}, name string, args ...interface{}) (int64, error) { + var ( + res int64 + err error + ) + + mi, _ := modelCache.getByMd(md) + inv := &Invocation{ + Method: "LoadRelatedWithCtx", + Args: []interface{}{md, name, args}, + Md: md, + mi: mi, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + res, err = f.ormer.LoadRelatedWithCtx(ctx, md, name, args...) + }, + } + f.root(ctx, inv) + return res, err +} + +func (f *filterOrmDecorator) QueryM2M(md interface{}, name string) QueryM2Mer { + return f.QueryM2MWithCtx(context.Background(), md, name) +} + +func (f *filterOrmDecorator) QueryM2MWithCtx(ctx context.Context, md interface{}, name string) QueryM2Mer { + var ( + res QueryM2Mer + ) + + mi, _ := modelCache.getByMd(md) + inv := &Invocation{ + Method: "QueryM2MWithCtx", + Args: []interface{}{md, name}, + Md: md, + mi: mi, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + res = f.ormer.QueryM2MWithCtx(ctx, md, name) + }, + } + f.root(ctx, inv) + return res +} + +func (f *filterOrmDecorator) QueryTable(ptrStructOrTableName interface{}) QuerySeter { + return f.QueryTableWithCtx(context.Background(), ptrStructOrTableName) +} + +func (f *filterOrmDecorator) QueryTableWithCtx(ctx context.Context, ptrStructOrTableName interface{}) QuerySeter { + var ( + res QuerySeter + name string + md interface{} + mi *modelInfo + ) + + if table, ok := ptrStructOrTableName.(string); ok { + name = table + } else { + name = getFullName(indirectType(reflect.TypeOf(ptrStructOrTableName))) + md = ptrStructOrTableName + } + + if m, ok := modelCache.getByFullName(name); ok { + mi = m + } + + inv := &Invocation{ + Method: "QueryTableWithCtx", + Args: []interface{}{ptrStructOrTableName}, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + Md: md, + mi: mi, + f: func() { + res = f.ormer.QueryTableWithCtx(ctx, ptrStructOrTableName) + }, + } + f.root(ctx, inv) + return res +} + +func (f *filterOrmDecorator) DBStats() *sql.DBStats { + var ( + res *sql.DBStats + ) + inv := &Invocation{ + Method: "DBStats", + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + res = f.ormer.DBStats() + }, + } + f.root(context.Background(), inv) + return res +} + +func (f *filterOrmDecorator) Insert(md interface{}) (int64, error) { + return f.InsertWithCtx(context.Background(), md) +} + +func (f *filterOrmDecorator) InsertWithCtx(ctx context.Context, md interface{}) (int64, error) { + var ( + res int64 + err error + ) + mi, _ := modelCache.getByMd(md) + inv := &Invocation{ + Method: "InsertWithCtx", + Args: []interface{}{md}, + Md: md, + mi: mi, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + res, err = f.ormer.InsertWithCtx(ctx, md) + }, + } + f.root(ctx, inv) + return res, err +} + +func (f *filterOrmDecorator) InsertOrUpdate(md interface{}, colConflitAndArgs ...string) (int64, error) { + return f.InsertOrUpdateWithCtx(context.Background(), md, colConflitAndArgs...) +} + +func (f *filterOrmDecorator) InsertOrUpdateWithCtx(ctx context.Context, md interface{}, colConflitAndArgs ...string) (int64, error) { + var ( + res int64 + err error + ) + mi, _ := modelCache.getByMd(md) + inv := &Invocation{ + Method: "InsertOrUpdateWithCtx", + Args: []interface{}{md, colConflitAndArgs}, + Md: md, + mi: mi, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + res, err = f.ormer.InsertOrUpdateWithCtx(ctx, md, colConflitAndArgs...) + }, + } + f.root(ctx, inv) + return res, err +} + +func (f *filterOrmDecorator) InsertMulti(bulk int, mds interface{}) (int64, error) { + return f.InsertMultiWithCtx(context.Background(), bulk, mds) +} + +// InsertMultiWithCtx uses the first element's model info +func (f *filterOrmDecorator) InsertMultiWithCtx(ctx context.Context, bulk int, mds interface{}) (int64, error) { + var ( + res int64 + err error + md interface{} + mi *modelInfo + ) + + sind := reflect.Indirect(reflect.ValueOf(mds)) + + if (sind.Kind() == reflect.Array || sind.Kind() == reflect.Slice) && sind.Len() > 0 { + ind := reflect.Indirect(sind.Index(0)) + md = ind.Interface() + mi, _ = modelCache.getByMd(md) + } + + inv := &Invocation{ + Method: "InsertMultiWithCtx", + Args: []interface{}{bulk, mds}, + Md: md, + mi: mi, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + res, err = f.ormer.InsertMultiWithCtx(ctx, bulk, mds) + }, + } + f.root(ctx, inv) + return res, err +} + +func (f *filterOrmDecorator) Update(md interface{}, cols ...string) (int64, error) { + return f.UpdateWithCtx(context.Background(), md, cols...) +} + +func (f *filterOrmDecorator) UpdateWithCtx(ctx context.Context, md interface{}, cols ...string) (int64, error) { + var ( + res int64 + err error + ) + mi, _ := modelCache.getByMd(md) + inv := &Invocation{ + Method: "UpdateWithCtx", + Args: []interface{}{md, cols}, + Md: md, + mi: mi, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + res, err = f.ormer.UpdateWithCtx(ctx, md, cols...) + }, + } + f.root(ctx, inv) + return res, err +} + +func (f *filterOrmDecorator) Delete(md interface{}, cols ...string) (int64, error) { + return f.DeleteWithCtx(context.Background(), md, cols...) +} + +func (f *filterOrmDecorator) DeleteWithCtx(ctx context.Context, md interface{}, cols ...string) (int64, error) { + var ( + res int64 + err error + ) + mi, _ := modelCache.getByMd(md) + inv := &Invocation{ + Method: "DeleteWithCtx", + Args: []interface{}{md, cols}, + Md: md, + mi: mi, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + res, err = f.ormer.DeleteWithCtx(ctx, md, cols...) + }, + } + f.root(ctx, inv) + return res, err +} + +func (f *filterOrmDecorator) Raw(query string, args ...interface{}) RawSeter { + return f.RawWithCtx(context.Background(), query, args...) +} + +func (f *filterOrmDecorator) RawWithCtx(ctx context.Context, query string, args ...interface{}) RawSeter { + var ( + res RawSeter + ) + inv := &Invocation{ + Method: "RawWithCtx", + Args: []interface{}{query, args}, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + res = f.ormer.RawWithCtx(ctx, query, args...) + }, + } + f.root(ctx, inv) + return res +} + +func (f *filterOrmDecorator) Driver() Driver { + var ( + res Driver + ) + inv := &Invocation{ + Method: "Driver", + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + res = f.ormer.Driver() + }, + } + f.root(context.Background(), inv) + return res +} + +func (f *filterOrmDecorator) Begin() (TxOrmer, error) { + return f.BeginWithCtxAndOpts(context.Background(), nil) +} + +func (f *filterOrmDecorator) BeginWithCtx(ctx context.Context) (TxOrmer, error) { + return f.BeginWithCtxAndOpts(ctx, nil) +} + +func (f *filterOrmDecorator) BeginWithOpts(opts *sql.TxOptions) (TxOrmer, error) { + return f.BeginWithCtxAndOpts(context.Background(), opts) +} + +func (f *filterOrmDecorator) BeginWithCtxAndOpts(ctx context.Context, opts *sql.TxOptions) (TxOrmer, error) { + var ( + res TxOrmer + err error + ) + inv := &Invocation{ + Method: "BeginWithCtxAndOpts", + Args: []interface{}{opts}, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + f: func() { + res, err = f.TxBeginner.BeginWithCtxAndOpts(ctx, opts) + res = NewFilterTxOrmDecorator(res, f.root, getTxNameFromCtx(ctx)) + }, + } + f.root(ctx, inv) + return res, err +} + +func (f *filterOrmDecorator) DoTx(task func(txOrm TxOrmer) error) error { + return f.DoTxWithCtxAndOpts(context.Background(), nil, task) +} + +func (f *filterOrmDecorator) DoTxWithCtx(ctx context.Context, task func(txOrm TxOrmer) error) error { + return f.DoTxWithCtxAndOpts(ctx, nil, task) +} + +func (f *filterOrmDecorator) DoTxWithOpts(opts *sql.TxOptions, task func(txOrm TxOrmer) error) error { + return f.DoTxWithCtxAndOpts(context.Background(), opts, task) +} + +func (f *filterOrmDecorator) DoTxWithCtxAndOpts(ctx context.Context, opts *sql.TxOptions, task func(txOrm TxOrmer) error) error { + var ( + err error + ) + + inv := &Invocation{ + Method: "DoTxWithCtxAndOpts", + Args: []interface{}{opts, task}, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + TxName: getTxNameFromCtx(ctx), + f: func() { + err = f.TxBeginner.DoTxWithCtxAndOpts(ctx, opts, task) + }, + } + f.root(ctx, inv) + return err +} + +func (f *filterOrmDecorator) Commit() error { + var ( + err error + ) + inv := &Invocation{ + Method: "Commit", + Args: []interface{}{}, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + TxName: f.txName, + f: func() { + err = f.TxCommitter.Commit() + }, + } + f.root(context.Background(), inv) + return err +} + +func (f *filterOrmDecorator) Rollback() error { + var ( + err error + ) + inv := &Invocation{ + Method: "Rollback", + Args: []interface{}{}, + InsideTx: f.insideTx, + TxStartTime: f.txStartTime, + TxName: f.txName, + f: func() { + err = f.TxCommitter.Rollback() + }, + } + f.root(context.Background(), inv) + return err +} + +func getTxNameFromCtx(ctx context.Context) string { + txName := "" + if n, ok := ctx.Value(TxNameKey).(string); ok { + txName = n + } + return txName +} + diff --git a/pkg/orm/filter_orm_decorator_test.go b/pkg/orm/filter_orm_decorator_test.go new file mode 100644 index 00000000..d1099eaf --- /dev/null +++ b/pkg/orm/filter_orm_decorator_test.go @@ -0,0 +1,432 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package orm + +import ( + "context" + "database/sql" + "errors" + "sync" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFilterOrmDecorator_Read(t *testing.T) { + + register() + + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "ReadWithCtx", inv.Method) + assert.Equal(t, 2, len(inv.Args)) + assert.Equal(t, "FILTER_TEST", inv.GetTableName()) + next(ctx, inv) + } + }) + + fte := &FilterTestEntity{} + err := od.Read(fte) + assert.NotNil(t, err) + assert.Equal(t, "read error", err.Error()) +} + +func TestFilterOrmDecorator_BeginTx(t *testing.T) { + register() + + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + if inv.Method == "BeginWithCtxAndOpts" { + assert.Equal(t, 1, len(inv.Args)) + assert.Equal(t, "", inv.GetTableName()) + assert.False(t, inv.InsideTx) + } else if inv.Method == "Commit" { + assert.Equal(t, 0, len(inv.Args)) + assert.Equal(t, "Commit_tx", inv.TxName) + assert.Equal(t, "", inv.GetTableName()) + assert.True(t, inv.InsideTx) + } else if inv.Method == "Rollback" { + assert.Equal(t, 0, len(inv.Args)) + assert.Equal(t, "Rollback_tx", inv.TxName) + assert.Equal(t, "", inv.GetTableName()) + assert.True(t, inv.InsideTx) + } else { + t.Fail() + } + + next(ctx, inv) + } + }) + to, err := od.Begin() + assert.True(t, validateBeginResult(t, to, err)) + + to, err = od.BeginWithOpts(nil) + assert.True(t, validateBeginResult(t, to, err)) + + ctx := context.WithValue(context.Background(), TxNameKey, "Commit_tx") + to, err = od.BeginWithCtx(ctx) + assert.True(t, validateBeginResult(t, to, err)) + + err = to.Commit() + assert.NotNil(t, err) + assert.Equal(t, "commit", err.Error()) + + ctx = context.WithValue(context.Background(), TxNameKey, "Rollback_tx") + to, err = od.BeginWithCtxAndOpts(ctx, nil) + assert.True(t, validateBeginResult(t, to, err)) + + err = to.Rollback() + assert.NotNil(t, err) + assert.Equal(t, "rollback", err.Error()) +} + +func TestFilterOrmDecorator_DBStats(t *testing.T) { + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "DBStats", inv.Method) + assert.Equal(t, 0, len(inv.Args)) + assert.Equal(t, "", inv.GetTableName()) + next(ctx, inv) + } + }) + res := od.DBStats() + assert.NotNil(t, res) + assert.Equal(t, -1, res.MaxOpenConnections) +} + +func TestFilterOrmDecorator_Delete(t *testing.T) { + register() + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "DeleteWithCtx", inv.Method) + assert.Equal(t, 2, len(inv.Args)) + assert.Equal(t, "FILTER_TEST", inv.GetTableName()) + next(ctx, inv) + } + }) + res, err := od.Delete(&FilterTestEntity{}) + assert.NotNil(t, err) + assert.Equal(t, "delete error", err.Error()) + assert.Equal(t, int64(-2), res) +} + +func TestFilterOrmDecorator_DoTx(t *testing.T) { + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "DoTxWithCtxAndOpts", inv.Method) + assert.Equal(t, 2, len(inv.Args)) + assert.Equal(t, "", inv.GetTableName()) + assert.False(t, inv.InsideTx) + next(ctx, inv) + } + }) + + err := od.DoTx(func(txOrm TxOrmer) error { + return errors.New("tx error") + }) + assert.NotNil(t, err) + assert.Equal(t, "tx error", err.Error()) + + err = od.DoTxWithCtx(context.Background(), func(txOrm TxOrmer) error { + return errors.New("tx ctx error") + }) + assert.NotNil(t, err) + assert.Equal(t, "tx ctx error", err.Error()) + + err = od.DoTxWithOpts(nil, func(txOrm TxOrmer) error { + return errors.New("tx opts error") + }) + assert.NotNil(t, err) + assert.Equal(t, "tx opts error", err.Error()) + + od = NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "DoTxWithCtxAndOpts", inv.Method) + assert.Equal(t, 2, len(inv.Args)) + assert.Equal(t, "", inv.GetTableName()) + assert.Equal(t, "do tx name", inv.TxName) + assert.False(t, inv.InsideTx) + next(ctx, inv) + } + }) + + ctx := context.WithValue(context.Background(), TxNameKey, "do tx name") + err = od.DoTxWithCtxAndOpts(ctx, nil, func(txOrm TxOrmer) error { + return errors.New("tx ctx opts error") + }) + assert.NotNil(t, err) + assert.Equal(t, "tx ctx opts error", err.Error()) +} + +func TestFilterOrmDecorator_Driver(t *testing.T) { + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "Driver", inv.Method) + assert.Equal(t, 0, len(inv.Args)) + assert.Equal(t, "", inv.GetTableName()) + assert.False(t, inv.InsideTx) + next(ctx, inv) + } + }) + res := od.Driver() + assert.Nil(t, res) +} + +func TestFilterOrmDecorator_Insert(t *testing.T) { + register() + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "InsertWithCtx", inv.Method) + assert.Equal(t, 1, len(inv.Args)) + assert.Equal(t, "FILTER_TEST", inv.GetTableName()) + assert.False(t, inv.InsideTx) + next(ctx, inv) + } + }) + + i, err := od.Insert(&FilterTestEntity{}) + assert.NotNil(t, err) + assert.Equal(t, "insert error", err.Error()) + assert.Equal(t, int64(100), i) +} + +func TestFilterOrmDecorator_InsertMulti(t *testing.T) { + register() + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "InsertMultiWithCtx", inv.Method) + assert.Equal(t, 2, len(inv.Args)) + assert.Equal(t, "FILTER_TEST", inv.GetTableName()) + assert.False(t, inv.InsideTx) + next(ctx, inv) + } + }) + + bulk := []*FilterTestEntity{&FilterTestEntity{}, &FilterTestEntity{}} + i, err := od.InsertMulti(2, bulk) + assert.NotNil(t, err) + assert.Equal(t, "insert multi error", err.Error()) + assert.Equal(t, int64(2), i) +} + +func TestFilterOrmDecorator_InsertOrUpdate(t *testing.T) { + register() + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "InsertOrUpdateWithCtx", inv.Method) + assert.Equal(t, 2, len(inv.Args)) + assert.Equal(t, "FILTER_TEST", inv.GetTableName()) + assert.False(t, inv.InsideTx) + next(ctx, inv) + } + }) + i, err := od.InsertOrUpdate(&FilterTestEntity{}) + assert.NotNil(t, err) + assert.Equal(t, "insert or update error", err.Error()) + assert.Equal(t, int64(1), i) +} + +func TestFilterOrmDecorator_LoadRelated(t *testing.T) { + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "LoadRelatedWithCtx", inv.Method) + assert.Equal(t, 3, len(inv.Args)) + assert.Equal(t, "FILTER_TEST", inv.GetTableName()) + assert.False(t, inv.InsideTx) + next(ctx, inv) + } + }) + i, err := od.LoadRelated(&FilterTestEntity{}, "hello") + assert.NotNil(t, err) + assert.Equal(t, "load related error", err.Error()) + assert.Equal(t, int64(99), i) +} + +func TestFilterOrmDecorator_QueryM2M(t *testing.T) { + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "QueryM2MWithCtx", inv.Method) + assert.Equal(t, 2, len(inv.Args)) + assert.Equal(t, "FILTER_TEST", inv.GetTableName()) + assert.False(t, inv.InsideTx) + next(ctx, inv) + } + }) + res := od.QueryM2M(&FilterTestEntity{}, "hello") + assert.Nil(t, res) +} + +func TestFilterOrmDecorator_QueryTable(t *testing.T) { + register() + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "QueryTableWithCtx", inv.Method) + assert.Equal(t, 1, len(inv.Args)) + assert.Equal(t, "FILTER_TEST", inv.GetTableName()) + assert.False(t, inv.InsideTx) + next(ctx, inv) + } + }) + res := od.QueryTable(&FilterTestEntity{}) + assert.Nil(t, res) +} + +func TestFilterOrmDecorator_Raw(t *testing.T) { + register() + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "RawWithCtx", inv.Method) + assert.Equal(t, 2, len(inv.Args)) + assert.Equal(t, "", inv.GetTableName()) + assert.False(t, inv.InsideTx) + next(ctx, inv) + } + }) + res := od.Raw("hh") + assert.Nil(t, res) +} + +func TestFilterOrmDecorator_ReadForUpdate(t *testing.T) { + register() + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "ReadForUpdateWithCtx", inv.Method) + assert.Equal(t, 2, len(inv.Args)) + assert.Equal(t, "FILTER_TEST", inv.GetTableName()) + assert.False(t, inv.InsideTx) + next(ctx, inv) + } + }) + err := od.ReadForUpdate(&FilterTestEntity{}) + assert.NotNil(t, err) + assert.Equal(t, "read for update error", err.Error()) +} + +func TestFilterOrmDecorator_ReadOrCreate(t *testing.T) { + register() + o := &filterMockOrm{} + od := NewFilterOrmDecorator(o, func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + assert.Equal(t, "ReadOrCreateWithCtx", inv.Method) + assert.Equal(t, 3, len(inv.Args)) + assert.Equal(t, "FILTER_TEST", inv.GetTableName()) + assert.False(t, inv.InsideTx) + next(ctx, inv) + } + }) + ok, i, err := od.ReadOrCreate(&FilterTestEntity{}, "name") + assert.NotNil(t, err) + assert.Equal(t, "read or create error", err.Error()) + assert.True(t, ok) + assert.Equal(t, int64(13), i) +} + +// filterMockOrm is only used in this test file +type filterMockOrm struct { + DoNothingOrm +} + +func (f *filterMockOrm) ReadOrCreateWithCtx(ctx context.Context, md interface{}, col1 string, cols ...string) (bool, int64, error) { + return true, 13, errors.New("read or create error") +} + +func (f *filterMockOrm) ReadForUpdateWithCtx(ctx context.Context, md interface{}, cols ...string) error { + return errors.New("read for update error") +} + +func (f *filterMockOrm) LoadRelatedWithCtx(ctx context.Context, md interface{}, name string, args ...interface{}) (int64, error) { + return 99, errors.New("load related error") +} + +func (f *filterMockOrm) InsertOrUpdateWithCtx(ctx context.Context, md interface{}, colConflitAndArgs ...string) (int64, error) { + return 1, errors.New("insert or update error") +} + +func (f *filterMockOrm) InsertMultiWithCtx(ctx context.Context, bulk int, mds interface{}) (int64, error) { + return 2, errors.New("insert multi error") +} + +func (f *filterMockOrm) InsertWithCtx(ctx context.Context, md interface{}) (int64, error) { + return 100, errors.New("insert error") +} + +func (f *filterMockOrm) DoTxWithCtxAndOpts(ctx context.Context, opts *sql.TxOptions, task func(txOrm TxOrmer) error) error { + return task(nil) +} + +func (f *filterMockOrm) DeleteWithCtx(ctx context.Context, md interface{}, cols ...string) (int64, error) { + return -2, errors.New("delete error") +} + +func (f *filterMockOrm) BeginWithCtxAndOpts(ctx context.Context, opts *sql.TxOptions) (TxOrmer, error) { + return &filterMockOrm{}, errors.New("begin tx") +} + +func (f *filterMockOrm) ReadWithCtx(ctx context.Context, md interface{}, cols ...string) error { + return errors.New("read error") +} + +func (f *filterMockOrm) Commit() error { + return errors.New("commit") +} + +func (f *filterMockOrm) Rollback() error { + return errors.New("rollback") +} + +func (f *filterMockOrm) DBStats() *sql.DBStats { + return &sql.DBStats{ + MaxOpenConnections: -1, + } +} + +func validateBeginResult(t *testing.T, to TxOrmer, err error) bool { + assert.NotNil(t, err) + assert.Equal(t, "begin tx", err.Error()) + _, ok := to.(*filterOrmDecorator).TxCommitter.(*filterMockOrm) + assert.True(t, ok) + return true +} + +var filterTestEntityRegisterOnce sync.Once + +type FilterTestEntity struct { + ID int + Name string +} + +func register() { + filterTestEntityRegisterOnce.Do(func() { + RegisterModel(&FilterTestEntity{}) + }) +} + +func (f *FilterTestEntity) TableName() string { + return "FILTER_TEST" +} diff --git a/pkg/orm/filter_test.go b/pkg/orm/filter_test.go new file mode 100644 index 00000000..0f2944c7 --- /dev/null +++ b/pkg/orm/filter_test.go @@ -0,0 +1,31 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package orm + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestAddGlobalFilterChain(t *testing.T) { + AddGlobalFilterChain(func(next Filter) Filter { + return func(ctx context.Context, inv *Invocation) { + + } + }) + assert.Equal(t, 1, len(globalFilterChains)) +} diff --git a/pkg/orm/invocation.go b/pkg/orm/invocation.go new file mode 100644 index 00000000..1c9fee09 --- /dev/null +++ b/pkg/orm/invocation.go @@ -0,0 +1,48 @@ +// Copyright 2020 beego +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package orm + +import ( + "time" +) + +// Invocation represents an "Orm" invocation +type Invocation struct { + Method string + // Md may be nil in some cases. It depends on method + Md interface{} + // the args are all arguments except context.Context + Args []interface{} + + mi *modelInfo + // f is the Orm operation + f func() + + // insideTx indicates whether this is inside a transaction + InsideTx bool + TxStartTime time.Time + TxName string +} + +func (inv *Invocation) GetTableName() string { + if inv.mi != nil{ + return inv.mi.table + } + return "" +} + +func (inv *Invocation) execute() { + inv.f() +} diff --git a/pkg/orm/models.go b/pkg/orm/models.go index 4776bcba..c8fbcced 100644 --- a/pkg/orm/models.go +++ b/pkg/orm/models.go @@ -15,6 +15,7 @@ package orm import ( + "reflect" "sync" ) @@ -73,6 +74,14 @@ func (mc *_modelCache) getByFullName(name string) (mi *modelInfo, ok bool) { return } +func (mc *_modelCache) getByMd(md interface{}) (*modelInfo, bool) { + val := reflect.ValueOf(md) + ind := reflect.Indirect(val) + typ := ind.Type() + name := getFullName(typ) + return mc.getByFullName(name) +} + // set model info to collection func (mc *_modelCache) set(table string, mi *modelInfo) *modelInfo { mii := mc.cache[table] diff --git a/pkg/orm/orm_test.go b/pkg/orm/orm_test.go index e3dafecd..f5242a46 100644 --- a/pkg/orm/orm_test.go +++ b/pkg/orm/orm_test.go @@ -2486,3 +2486,5 @@ func TestInsertOrUpdate(t *testing.T) { throwFailNow(t, AssertIs((((user2.Status+1)-1)*3)/3, test.Status)) } } + + diff --git a/pkg/orm/types.go b/pkg/orm/types.go index cb0f97cc..9624fd94 100644 --- a/pkg/orm/types.go +++ b/pkg/orm/types.go @@ -204,17 +204,19 @@ type DriverGetter interface { Driver() Driver } -type Ormer interface { +type ormer interface { DQL DML DriverGetter +} + +type Ormer interface { + ormer TxBeginner } type TxOrmer interface { - DQL - DML - DriverGetter + ormer TxCommitter } diff --git a/pkg/parser.go b/pkg/parser.go index 606be190..d7ab45f0 100644 --- a/pkg/parser.go +++ b/pkg/parser.go @@ -19,8 +19,7 @@ import ( "errors" "fmt" "go/ast" - "go/parser" - "go/token" + "golang.org/x/tools/go/packages" "io/ioutil" "os" "path/filepath" @@ -76,7 +75,7 @@ func init() { pkgLastupdate = make(map[string]int64) } -func parserPkg(pkgRealpath, pkgpath string) error { +func parserPkg(pkgRealpath string) error { rep := strings.NewReplacer("\\", "_", "/", "_", ".", "_") commentFilename, _ = filepath.Rel(AppPath, pkgRealpath) commentFilename = commentPrefix + rep.Replace(commentFilename) + ".go" @@ -85,24 +84,23 @@ func parserPkg(pkgRealpath, pkgpath string) error { return nil } genInfoList = make(map[string][]ControllerComments) - fileSet := token.NewFileSet() - astPkgs, err := parser.ParseDir(fileSet, pkgRealpath, func(info os.FileInfo) bool { - name := info.Name() - return !info.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") - }, parser.ParseComments) + pkgs, err := packages.Load(&packages.Config{ + Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedSyntax, + Dir: pkgRealpath, + }, "./...") if err != nil { return err } - for _, pkg := range astPkgs { - for _, fl := range pkg.Files { + for _, pkg := range pkgs { + for _, fl := range pkg.Syntax { for _, d := range fl.Decls { switch specDecl := d.(type) { case *ast.FuncDecl: if specDecl.Recv != nil { exp, ok := specDecl.Recv.List[0].Type.(*ast.StarExpr) // Check that the type is correct first beforing throwing to parser if ok { - parserComments(specDecl, fmt.Sprint(exp.X), pkgpath) + parserComments(specDecl, fmt.Sprint(exp.X), pkg.PkgPath) } } } @@ -566,8 +564,17 @@ func getpathTime(pkgRealpath string) (lastupdate int64, err error) { return lastupdate, err } for _, f := range fl { - if lastupdate < f.ModTime().UnixNano() { - lastupdate = f.ModTime().UnixNano() + var t int64 + if f.IsDir() { + t, err = getpathTime(filepath.Join(pkgRealpath, f.Name())) + if err != nil { + return lastupdate, err + } + } else { + t = f.ModTime().UnixNano() + } + if lastupdate < t { + lastupdate = t } } return lastupdate, nil diff --git a/pkg/router.go b/pkg/router.go index b0c23003..8caba94a 100644 --- a/pkg/router.go +++ b/pkg/router.go @@ -18,9 +18,7 @@ import ( "errors" "fmt" "net/http" - "os" "path" - "path/filepath" "reflect" "strconv" "strings" @@ -257,45 +255,6 @@ func (p *ControllerRegister) addToRouter(method, pattern string, r *ControllerIn // Include only when the Runmode is dev will generate router file in the router/auto.go from the controller // Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{}) func (p *ControllerRegister) Include(cList ...ControllerInterface) { - if BConfig.RunMode == DEV { - skip := make(map[string]bool, 10) - wgopath := utils.GetGOPATHs() - go111module := os.Getenv(`GO111MODULE`) - for _, c := range cList { - reflectVal := reflect.ValueOf(c) - t := reflect.Indirect(reflectVal).Type() - // for go modules - if go111module == `on` { - pkgpath := filepath.Join(WorkPath, "..", t.PkgPath()) - if utils.FileExists(pkgpath) { - if pkgpath != "" { - if _, ok := skip[pkgpath]; !ok { - skip[pkgpath] = true - parserPkg(pkgpath, t.PkgPath()) - } - } - } - } else { - if len(wgopath) == 0 { - panic("you are in dev mode. So please set gopath") - } - pkgpath := "" - for _, wg := range wgopath { - wg, _ = filepath.EvalSymlinks(filepath.Join(wg, "src", t.PkgPath())) - if utils.FileExists(wg) { - pkgpath = wg - break - } - } - if pkgpath != "" { - if _, ok := skip[pkgpath]; !ok { - skip[pkgpath] = true - parserPkg(pkgpath, t.PkgPath()) - } - } - } - } - } for _, c := range cList { reflectVal := reflect.ValueOf(c) t := reflect.Indirect(reflectVal).Type() diff --git a/pkg/web/filter/opentracing/filter.go b/pkg/web/filter/opentracing/filter.go index 8e332c7d..822d5e4d 100644 --- a/pkg/web/filter/opentracing/filter.go +++ b/pkg/web/filter/opentracing/filter.go @@ -15,37 +15,44 @@ package opentracing import ( + "context" + + logKit "github.com/go-kit/kit/log" + opentracingKit "github.com/go-kit/kit/tracing/opentracing" "github.com/opentracing/opentracing-go" beego "github.com/astaxie/beego/pkg" - "github.com/astaxie/beego/pkg/context" + beegoCtx "github.com/astaxie/beego/pkg/context" ) // FilterChainBuilder provides an extension point that we can support more configurations if necessary type FilterChainBuilder struct { // CustomSpanFunc makes users to custom the span. - CustomSpanFunc func(span opentracing.Span, ctx *context.Context) + CustomSpanFunc func(span opentracing.Span, ctx *beegoCtx.Context) } func (builder *FilterChainBuilder) FilterChain(next beego.FilterFunc) beego.FilterFunc { - return func(ctx *context.Context) { - span := opentracing.SpanFromContext(ctx.Request.Context()) - spanCtx := ctx.Request.Context() - if span == nil { - operationName := ctx.Input.URL() - // it means that there is not any span, so we create a span as the root span. - // TODO, if we support multiple servers, this need to be changed - route, found := beego.BeeApp.Handlers.FindRouter(ctx) - if found { - operationName = route.GetPattern() - } - span, spanCtx = opentracing.StartSpanFromContext(spanCtx, operationName) - newReq := ctx.Request.Clone(spanCtx) - ctx.Reset(ctx.ResponseWriter.ResponseWriter, newReq) + return func(ctx *beegoCtx.Context) { + var ( + spanCtx context.Context + span opentracing.Span + ) + operationName := builder.operationName(ctx) + + if preSpan := opentracing.SpanFromContext(ctx.Request.Context()); preSpan == nil { + inject := opentracingKit.HTTPToContext(opentracing.GlobalTracer(), operationName, logKit.NewNopLogger()) + spanCtx = inject(ctx.Request.Context(), ctx.Request) + span = opentracing.SpanFromContext(spanCtx) + } else { + span, spanCtx = opentracing.StartSpanFromContext(ctx.Request.Context(), operationName) } defer span.Finish() + + newReq := ctx.Request.Clone(spanCtx) + ctx.Reset(ctx.ResponseWriter.ResponseWriter, newReq) + next(ctx) // if you think we need to do more things, feel free to create an issue to tell us span.SetTag("status", ctx.Output.Status) @@ -56,3 +63,14 @@ func (builder *FilterChainBuilder) FilterChain(next beego.FilterFunc) beego.Filt } } } + +func (builder *FilterChainBuilder) operationName(ctx *beegoCtx.Context) string { + operationName := ctx.Input.URL() + // it means that there is not any span, so we create a span as the root span. + // TODO, if we support multiple servers, this need to be changed + route, found := beego.BeeApp.Handlers.FindRouter(ctx) + if found { + operationName = route.GetPattern() + } + return operationName +}