From 50ffaef33fd68e801cc9a680f5b5f3749a1902c6 Mon Sep 17 00:00:00 2001 From: John Guo Date: Sat, 26 Jun 2021 16:23:54 +0800 Subject: [PATCH] add context for intlog/gsession;improve struct/structs converting for package gconv --- database/gdb/gdb.go | 4 +- database/gdb/gdb_driver_mssql.go | 2 +- database/gdb/gdb_driver_mysql.go | 2 +- database/gdb/gdb_driver_oracle.go | 2 +- database/gdb/gdb_driver_pgsql.go | 2 +- database/gdb/gdb_driver_sqlite.go | 2 +- database/gdb/gdb_model_select.go | 4 +- database/gdb/gdb_type_record.go | 2 +- database/gdb/gdb_type_result.go | 2 +- database/gdb/gdb_z_mysql_struct_test.go | 21 +- database/gredis/gredis.go | 2 +- database/gredis/gredis_config.go | 5 +- encoding/gcompress/gcompress_zip.go | 3 +- frame/gins/gins_database.go | 13 +- i18n/gi18n/gi18n_manager.go | 24 +- internal/intlog/intlog.go | 61 +++-- net/ghttp/ghttp_request.go | 7 +- net/ghttp/ghttp_request_param_file.go | 8 +- net/ghttp/ghttp_server.go | 13 +- net/ghttp/ghttp_server_admin_process.go | 5 +- net/ghttp/ghttp_server_admin_unix.go | 5 +- net/ghttp/ghttp_server_config.go | 5 +- net/ghttp/ghttp_server_handler.go | 4 +- net/ghttp/internal/client/client_request.go | 6 +- os/gcfg/gcfg.go | 5 +- os/gcfg/gcfg_config.go | 11 +- os/gfsnotify/gfsnotify.go | 3 +- os/gfsnotify/gfsnotify_watcher.go | 13 +- os/gfsnotify/gfsnotify_watcher_loop.go | 19 +- os/glog/glog_logger.go | 40 +-- os/glog/glog_logger_chaining.go | 6 +- os/glog/glog_logger_config.go | 4 +- os/glog/glog_logger_rotate.go | 37 +-- os/gproc/gproc_process.go | 6 +- os/gproc/gproc_signal.go | 3 +- os/gres/gres_func_zip.go | 3 +- os/gres/gres_resource.go | 5 +- os/gsession/gsession_manager.go | 4 +- os/gsession/gsession_session.go | 43 ++-- os/gsession/gsession_storage.go | 23 +- os/gsession/gsession_storage_file.go | 36 +-- os/gsession/gsession_storage_memory.go | 28 +-- os/gsession/gsession_storage_redis.go | 47 ++-- .../gsession_storage_redis_hashtable.go | 47 ++-- .../gsession_unit_storage_file_test.go | 7 +- .../gsession_unit_storage_memory_test.go | 7 +- ...ssion_unit_storage_redis_hashtable_test.go | 13 +- .../gsession_unit_storage_redis_test.go | 13 +- os/gspath/gspath.go | 3 +- os/gview/gview.go | 10 +- os/gview/gview_config.go | 3 +- os/gview/gview_parse.go | 2 +- util/gconv/gconv.go | 228 ++++++++++-------- util/gconv/gconv_map.go | 2 +- util/gconv/gconv_scan.go | 1 + util/gconv/gconv_struct.go | 25 +- util/gconv/gconv_structs.go | 35 ++- util/gconv/gconv_z_unit_scan_test.go | 2 +- 58 files changed, 517 insertions(+), 421 deletions(-) diff --git a/database/gdb/gdb.go b/database/gdb/gdb.go index fead99d3b..c0ecb2a83 100644 --- a/database/gdb/gdb.go +++ b/database/gdb/gdb.go @@ -486,14 +486,16 @@ func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error // Cache the underlying connection pool object by node. v, _ := internalCache.GetOrSetFuncLock(node.String(), func() (interface{}, error) { intlog.Printf( + c.db.GetCtx(), `open new connection, master:%#v, config:%#v, node:%#v`, master, c.config, node, ) defer func() { if err != nil { - intlog.Printf(`open new connection failed: %v, %#v`, err, node) + intlog.Printf(c.db.GetCtx(), `open new connection failed: %v, %#v`, err, node) } else { intlog.Printf( + c.db.GetCtx(), `open new connection success, master:%#v, config:%#v, node:%#v`, master, c.config, node, ) diff --git a/database/gdb/gdb_driver_mssql.go b/database/gdb/gdb_driver_mssql.go index 4ee218504..0e91b48d8 100644 --- a/database/gdb/gdb_driver_mssql.go +++ b/database/gdb/gdb_driver_mssql.go @@ -50,7 +50,7 @@ func (d *DriverMssql) Open(config *ConfigNode) (*sql.DB, error) { config.User, config.Pass, config.Host, config.Port, config.Name, ) } - intlog.Printf("Open: %s", source) + intlog.Printf(d.GetCtx(), "Open: %s", source) if db, err := sql.Open("sqlserver", source); err == nil { return db, nil } else { diff --git a/database/gdb/gdb_driver_mysql.go b/database/gdb/gdb_driver_mysql.go index adb1db26a..b03b56839 100644 --- a/database/gdb/gdb_driver_mysql.go +++ b/database/gdb/gdb_driver_mysql.go @@ -52,7 +52,7 @@ func (d *DriverMysql) Open(config *ConfigNode) (*sql.DB, error) { source = fmt.Sprintf("%s&loc=%s", source, url.QueryEscape(config.Timezone)) } } - intlog.Printf("Open: %s", source) + intlog.Printf(d.GetCtx(), "Open: %s", source) if db, err := sql.Open("mysql", source); err == nil { return db, nil } else { diff --git a/database/gdb/gdb_driver_oracle.go b/database/gdb/gdb_driver_oracle.go index e6bb6fd13..682b5eee9 100644 --- a/database/gdb/gdb_driver_oracle.go +++ b/database/gdb/gdb_driver_oracle.go @@ -56,7 +56,7 @@ func (d *DriverOracle) Open(config *ConfigNode) (*sql.DB, error) { config.User, config.Pass, config.Host, config.Port, config.Name, ) } - intlog.Printf("Open: %s", source) + intlog.Printf(d.GetCtx(), "Open: %s", source) if db, err := sql.Open("oci8", source); err == nil { return db, nil } else { diff --git a/database/gdb/gdb_driver_pgsql.go b/database/gdb/gdb_driver_pgsql.go index a31546ae9..28d924e84 100644 --- a/database/gdb/gdb_driver_pgsql.go +++ b/database/gdb/gdb_driver_pgsql.go @@ -51,7 +51,7 @@ func (d *DriverPgsql) Open(config *ConfigNode) (*sql.DB, error) { source = fmt.Sprintf("%s timezone=%s", source, config.Timezone) } } - intlog.Printf("Open: %s", source) + intlog.Printf(d.GetCtx(), "Open: %s", source) if db, err := sql.Open("postgres", source); err == nil { return db, nil } else { diff --git a/database/gdb/gdb_driver_sqlite.go b/database/gdb/gdb_driver_sqlite.go index 5dc37c2ae..b236a3889 100644 --- a/database/gdb/gdb_driver_sqlite.go +++ b/database/gdb/gdb_driver_sqlite.go @@ -47,7 +47,7 @@ func (d *DriverSqlite) Open(config *ConfigNode) (*sql.DB, error) { if absolutePath, _ := gfile.Search(source); absolutePath != "" { source = absolutePath } - intlog.Printf("Open: %s", source) + intlog.Printf(d.GetCtx(), "Open: %s", source) if db, err := sql.Open("sqlite3", source); err == nil { return db, nil } else { diff --git a/database/gdb/gdb_model_select.go b/database/gdb/gdb_model_select.go index 9d1dab718..cd39c4332 100644 --- a/database/gdb/gdb_model_select.go +++ b/database/gdb/gdb_model_select.go @@ -546,11 +546,11 @@ func (m *Model) doGetAllBySql(sql string, args ...interface{}) (result Result, e if cacheKey != "" && err == nil { if m.cacheDuration < 0 { if _, err := cacheObj.Remove(cacheKey); err != nil { - intlog.Error(err) + intlog.Error(m.GetCtx(), err) } } else { if err := cacheObj.Set(cacheKey, result, m.cacheDuration); err != nil { - intlog.Error(err) + intlog.Error(m.GetCtx(), err) } } } diff --git a/database/gdb/gdb_type_record.go b/database/gdb/gdb_type_record.go index 3685dd296..a660ec4ef 100644 --- a/database/gdb/gdb_type_record.go +++ b/database/gdb/gdb_type_record.go @@ -52,7 +52,7 @@ func (r Record) Struct(pointer interface{}) error { } return nil } - return gconv.StructTag(r.Map(), pointer, OrmTagForStruct) + return gconv.StructTag(r, pointer, OrmTagForStruct) } // IsEmpty checks and returns whether `r` is empty. diff --git a/database/gdb/gdb_type_result.go b/database/gdb/gdb_type_result.go index 05e15026c..489e3bc47 100644 --- a/database/gdb/gdb_type_result.go +++ b/database/gdb/gdb_type_result.go @@ -189,5 +189,5 @@ func (r Result) RecordKeyUint(key string) map[uint]Record { // Structs converts `r` to struct slice. // Note that the parameter `pointer` should be type of *[]struct/*[]*struct. func (r Result) Structs(pointer interface{}) (err error) { - return gconv.StructsTag(r.List(), pointer, OrmTagForStruct) + return gconv.StructsTag(r, pointer, OrmTagForStruct) } diff --git a/database/gdb/gdb_z_mysql_struct_test.go b/database/gdb/gdb_z_mysql_struct_test.go index eb895be5a..d4d7a7373 100644 --- a/database/gdb/gdb_z_mysql_struct_test.go +++ b/database/gdb/gdb_z_mysql_struct_test.go @@ -8,10 +8,13 @@ package gdb_test import ( "database/sql" + "github.com/gogf/gf/database/gdb" + "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gtime" "github.com/gogf/gf/test/gtest" "github.com/gogf/gf/util/gconv" + "reflect" "testing" ) @@ -395,17 +398,17 @@ type User struct { } func (user *User) UnmarshalValue(value interface{}) error { - switch result := value.(type) { - case map[string]interface{}: - user.Id = result["id"].(int) - user.Passport = result["passport"].(string) - user.Password = "" - user.Nickname = result["nickname"].(string) - user.CreateTime = gtime.New(result["create_time"]) + if record, ok := value.(gdb.Record); ok { + *user = User{ + Id: record["id"].Int(), + Passport: record["passport"].String(), + Password: "", + Nickname: record["nickname"].String(), + CreateTime: record["create_time"].GTime(), + } return nil - default: - return gconv.Struct(value, user) } + return gerror.Newf(`unsupported value type for UnmarshalValue: %v`, reflect.TypeOf(value)) } func Test_Model_Scan_UnmarshalValue(t *testing.T) { diff --git a/database/gredis/gredis.go b/database/gredis/gredis.go index 13211d81d..8de774e15 100644 --- a/database/gredis/gredis.go +++ b/database/gredis/gredis.go @@ -114,7 +114,7 @@ func New(config *Config) *Redis { if err != nil { return nil, err } - intlog.Printf(`open new connection, config:%+v`, config) + intlog.Printf(context.TODO(), `open new connection, config:%+v`, config) // AUTH if len(config.Pass) > 0 { if _, err := c.Do("AUTH", config.Pass); err != nil { diff --git a/database/gredis/gredis_config.go b/database/gredis/gredis_config.go index c2f2ba42e..121b9c4a1 100644 --- a/database/gredis/gredis_config.go +++ b/database/gredis/gredis_config.go @@ -7,6 +7,7 @@ package gredis import ( + "context" "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/internal/intlog" @@ -36,7 +37,7 @@ func SetConfig(config *Config, name ...string) { configs.Set(group, config) instances.Remove(group) - intlog.Printf(`SetConfig for group "%s": %+v`, group, config) + intlog.Printf(context.TODO(), `SetConfig for group "%s": %+v`, group, config) } // SetConfigByStr sets the global configuration for specified group with string. @@ -78,7 +79,7 @@ func RemoveConfig(name ...string) { configs.Remove(group) instances.Remove(group) - intlog.Printf(`RemoveConfig: %s`, group) + intlog.Printf(context.TODO(), `RemoveConfig: %s`, group) } // ConfigFromStr parses and returns config from given str. diff --git a/encoding/gcompress/gcompress_zip.go b/encoding/gcompress/gcompress_zip.go index 72991aff9..dad27820b 100644 --- a/encoding/gcompress/gcompress_zip.go +++ b/encoding/gcompress/gcompress_zip.go @@ -9,6 +9,7 @@ package gcompress import ( "archive/zip" "bytes" + "context" "github.com/gogf/gf/internal/intlog" "github.com/gogf/gf/os/gfile" "github.com/gogf/gf/text/gstr" @@ -92,7 +93,7 @@ func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix headerPrefix = strings.Replace(headerPrefix, "//", "/", -1) for _, file := range files { if exclude == file { - intlog.Printf(`exclude file path: %s`, file) + intlog.Printf(context.TODO(), `exclude file path: %s`, file) continue } dir := gfile.Dir(file[len(path):]) diff --git a/frame/gins/gins_database.go b/frame/gins/gins_database.go index 506a66cf0..1206ee7d4 100644 --- a/frame/gins/gins_database.go +++ b/frame/gins/gins_database.go @@ -7,6 +7,7 @@ package gins import ( + "context" "fmt" "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/internal/intlog" @@ -92,11 +93,11 @@ func Database(name ...string) gdb.DB { } if len(cg) > 0 { if gdb.GetConfig(group) == nil { - intlog.Printf("add configuration for group: %s, %#v", g, cg) + intlog.Printf(context.TODO(), "add configuration for group: %s, %#v", g, cg) gdb.SetConfigGroup(g, cg) } else { - intlog.Printf("ignore configuration as it already exists for group: %s, %#v", g, cg) - intlog.Printf("%s, %#v", g, cg) + intlog.Printf(context.TODO(), "ignore configuration as it already exists for group: %s, %#v", g, cg) + intlog.Printf(context.TODO(), "%s, %#v", g, cg) } } } @@ -110,11 +111,11 @@ func Database(name ...string) gdb.DB { if len(cg) > 0 { if gdb.GetConfig(group) == nil { - intlog.Printf("add configuration for group: %s, %#v", gdb.DefaultGroupName, cg) + intlog.Printf(context.TODO(), "add configuration for group: %s, %#v", gdb.DefaultGroupName, cg) gdb.SetConfigGroup(gdb.DefaultGroupName, cg) } else { - intlog.Printf("ignore configuration as it already exists for group: %s, %#v", gdb.DefaultGroupName, cg) - intlog.Printf("%s, %#v", gdb.DefaultGroupName, cg) + intlog.Printf(context.TODO(), "ignore configuration as it already exists for group: %s, %#v", gdb.DefaultGroupName, cg) + intlog.Printf(context.TODO(), "%s, %#v", gdb.DefaultGroupName, cg) } } } diff --git a/i18n/gi18n/gi18n_manager.go b/i18n/gi18n/gi18n_manager.go index 0949c1f44..d289e2053 100644 --- a/i18n/gi18n/gi18n_manager.go +++ b/i18n/gi18n/gi18n_manager.go @@ -70,7 +70,7 @@ func New(options ...Options) *Manager { gregex.Quote(opts.Delimiters[1]), ), } - intlog.Printf(`New: %#v`, m) + intlog.Printf(context.TODO(), `New: %#v`, m) return m } @@ -105,20 +105,20 @@ func (m *Manager) SetPath(path string) error { } m.options.Path = realPath } - intlog.Printf(`SetPath: %s`, m.options.Path) + intlog.Printf(context.TODO(), `SetPath: %s`, m.options.Path) return nil } // SetLanguage sets the language for translator. func (m *Manager) SetLanguage(language string) { m.options.Language = language - intlog.Printf(`SetLanguage: %s`, m.options.Language) + intlog.Printf(context.TODO(), `SetLanguage: %s`, m.options.Language) } // SetDelimiters sets the delimiters for translator. func (m *Manager) SetDelimiters(left, right string) { m.pattern = fmt.Sprintf(`%s(\w+)%s`, gregex.Quote(left), gregex.Quote(right)) - intlog.Printf(`SetDelimiters: %v`, m.pattern) + intlog.Printf(context.TODO(), `SetDelimiters: %v`, m.pattern) } // T is alias of Translate for convenience. @@ -139,7 +139,7 @@ func (m *Manager) TranslateFormat(ctx context.Context, format string, values ... // Translate translates with configured language. func (m *Manager) Translate(ctx context.Context, content string) string { - m.init() + m.init(ctx) m.mu.RLock() defer m.mu.RUnlock() transLang := m.options.Language @@ -163,14 +163,14 @@ func (m *Manager) Translate(ctx context.Context, content string) string { } return match[0] }) - intlog.Printf(`Translate for language: %s`, transLang) + intlog.Printf(ctx, `Translate for language: %s`, transLang) return result } // GetContent retrieves and returns the configured content for given key and specified language. // It returns an empty string if not found. func (m *Manager) GetContent(ctx context.Context, key string) string { - m.init() + m.init(ctx) m.mu.RLock() defer m.mu.RUnlock() transLang := m.options.Language @@ -185,7 +185,7 @@ func (m *Manager) GetContent(ctx context.Context, key string) string { // init initializes the manager for lazy initialization design. // The i18n manager is only initialized once. -func (m *Manager) init() { +func (m *Manager) init(ctx context.Context) { m.mu.RLock() // If the data is not nil, means it's already initialized. if m.data != nil { @@ -223,17 +223,13 @@ func (m *Manager) init() { m.data[lang][k] = gconv.String(v) } } else { - intlog.Errorf("load i18n file '%s' failed: %v", name, err) + intlog.Errorf(ctx, "load i18n file '%s' failed: %v", name, err) } } } } else if m.options.Path != "" { files, _ := gfile.ScanDirFile(m.options.Path, "*.*", true) if len(files) == 0 { - //intlog.Printf( - // "no i18n files found in configured directory: %s", - // m.options.Path, - //) return } var ( @@ -258,7 +254,7 @@ func (m *Manager) init() { m.data[lang][k] = gconv.String(v) } } else { - intlog.Errorf("load i18n file '%s' failed: %v", file, err) + intlog.Errorf(ctx, "load i18n file '%s' failed: %v", file, err) } } // Monitor changes of i18n files for hot reload feature. diff --git a/internal/intlog/intlog.go b/internal/intlog/intlog.go index f2675ce91..d5ca85d6a 100644 --- a/internal/intlog/intlog.go +++ b/internal/intlog/intlog.go @@ -8,9 +8,12 @@ package intlog import ( + "bytes" + "context" "fmt" "github.com/gogf/gf/debug/gdebug" "github.com/gogf/gf/internal/utils" + "go.opentelemetry.io/otel/trace" "path/filepath" "time" ) @@ -39,42 +42,56 @@ func SetEnabled(enabled bool) { // Print prints `v` with newline using fmt.Println. // The parameter `v` can be multiple variables. -func Print(v ...interface{}) { - if !isGFDebug { - return - } - fmt.Println(append([]interface{}{now(), "[INTE]", file()}, v...)...) +func Print(ctx context.Context, v ...interface{}) { + doPrint(ctx, fmt.Sprint(v...), false) } // Printf prints `v` with format `format` using fmt.Printf. // The parameter `v` can be multiple variables. -func Printf(format string, v ...interface{}) { - if !isGFDebug { - return - } - fmt.Printf(now()+" [INTE] "+file()+" "+format+"\n", v...) +func Printf(ctx context.Context, format string, v ...interface{}) { + doPrint(ctx, fmt.Sprintf(format, v...), false) } // Error prints `v` with newline using fmt.Println. // The parameter `v` can be multiple variables. -func Error(v ...interface{}) { - if !isGFDebug { - return - } - array := append([]interface{}{now(), "[INTE]", file()}, v...) - array = append(array, "\n"+gdebug.StackWithFilter(stackFilterKey)) - fmt.Println(array...) +func Error(ctx context.Context, v ...interface{}) { + doPrint(ctx, fmt.Sprint(v...), true) } // Errorf prints `v` with format `format` using fmt.Printf. -func Errorf(format string, v ...interface{}) { +func Errorf(ctx context.Context, format string, v ...interface{}) { + doPrint(ctx, fmt.Sprintf(format, v...), true) +} + +func doPrint(ctx context.Context, content string, stack bool) { if !isGFDebug { return } - fmt.Printf( - now()+" [INTE] "+file()+" "+format+"\n%s\n", - append(v, gdebug.StackWithFilter(stackFilterKey))..., - ) + buffer := bytes.NewBuffer(nil) + buffer.WriteString(now()) + buffer.WriteString(" [INTE] ") + buffer.WriteString(file()) + if s := traceIdStr(ctx); s != "" { + buffer.WriteString(" " + s) + } + buffer.WriteString(content) + buffer.WriteString("\n") + if stack { + buffer.WriteString(gdebug.StackWithFilter(stackFilterKey)) + } + fmt.Print(buffer.String()) +} + +// traceIdStr retrieves and returns the trace id string for logging output. +func traceIdStr(ctx context.Context) string { + if ctx == nil { + return "" + } + spanCtx := trace.SpanContextFromContext(ctx) + if traceId := spanCtx.TraceID(); traceId.IsValid() { + return "{" + traceId.String() + "}" + } + return "" } // now returns current time string. diff --git a/net/ghttp/ghttp_request.go b/net/ghttp/ghttp_request.go index a07e115b5..fa86d02c5 100644 --- a/net/ghttp/ghttp_request.go +++ b/net/ghttp/ghttp_request.go @@ -73,7 +73,10 @@ func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request { EnterTime: gtime.TimestampMilli(), } request.Cookie = GetCookie(request) - request.Session = s.sessionManager.New(request.GetSessionId()) + request.Session = s.sessionManager.New( + r.Context(), + request.GetSessionId(), + ) request.Response.Request = request request.Middleware = &middleware{ request: request, @@ -84,7 +87,7 @@ func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request { address = request.RemoteAddr header = fmt.Sprintf("%v", request.Header) ) - intlog.Print(address, header) + intlog.Print(r.Context(), address, header) return guid.S([]byte(address), []byte(header)) }) if err != nil { diff --git a/net/ghttp/ghttp_request_param_file.go b/net/ghttp/ghttp_request_param_file.go index c5b803221..47811dfde 100644 --- a/net/ghttp/ghttp_request_param_file.go +++ b/net/ghttp/ghttp_request_param_file.go @@ -7,7 +7,9 @@ package ghttp import ( + "context" "errors" + "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/internal/intlog" "github.com/gogf/gf/os/gfile" "github.com/gogf/gf/os/gtime" @@ -21,6 +23,7 @@ import ( // UploadFile wraps the multipart uploading file with more and convenient features. type UploadFile struct { *multipart.FileHeader + ctx context.Context } // UploadFiles is array type for *UploadFile. @@ -40,7 +43,7 @@ func (f *UploadFile) Save(dirPath string, randomlyRename ...bool) (filename stri return } } else if !gfile.IsDir(dirPath) { - return "", errors.New(`parameter "dirPath" should be a directory path`) + return "", gerror.New(`parameter "dirPath" should be a directory path`) } file, err := f.Open() @@ -60,7 +63,7 @@ func (f *UploadFile) Save(dirPath string, randomlyRename ...bool) (filename stri return "", err } defer newFile.Close() - intlog.Printf(`save upload file: %s`, filePath) + intlog.Printf(f.ctx, `save upload file: %s`, filePath) if _, err := io.Copy(newFile, file); err != nil { return "", err } @@ -114,6 +117,7 @@ func (r *Request) GetUploadFiles(name string) UploadFiles { uploadFiles := make(UploadFiles, len(multipartFiles)) for k, v := range multipartFiles { uploadFiles[k] = &UploadFile{ + ctx: r.Context(), FileHeader: v, } } diff --git a/net/ghttp/ghttp_server.go b/net/ghttp/ghttp_server.go index 2aa6b18cc..ab7738e38 100644 --- a/net/ghttp/ghttp_server.go +++ b/net/ghttp/ghttp_server.go @@ -8,6 +8,7 @@ package ghttp import ( "bytes" + "context" "github.com/gogf/gf/debug/gdebug" "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/internal/intlog" @@ -70,10 +71,10 @@ func serverProcessInit() { // Process message handler. // It's enabled only graceful feature is enabled. if gracefulEnabled { - intlog.Printf("%d: graceful reload feature is enabled", gproc.Pid()) + intlog.Printf(context.TODO(), "%d: graceful reload feature is enabled", gproc.Pid()) go handleProcessMessage() } else { - intlog.Printf("%d: graceful reload feature is disabled", gproc.Pid()) + intlog.Printf(context.TODO(), "%d: graceful reload feature is disabled", gproc.Pid()) } // It's an ugly calling for better initializing the main package path @@ -195,7 +196,7 @@ func (s *Server) Start() error { if gproc.IsChild() { gtimer.SetTimeout(time.Duration(s.config.GracefulTimeout)*time.Second, func() { if err := gproc.Send(gproc.PPid(), []byte("exit"), adminGProcCommGroup); err != nil { - intlog.Error("server error in process communication:", err) + intlog.Error(context.TODO(), "server error in process communication:", err) } }) } @@ -315,9 +316,9 @@ func (s *Server) Run() { // Remove plugins. if len(s.plugins) > 0 { for _, p := range s.plugins { - intlog.Printf(`remove plugin: %s`, p.Name()) + intlog.Printf(context.TODO(), `remove plugin: %s`, p.Name()) if err := p.Remove(); err != nil { - intlog.Errorf("%+v", err) + intlog.Errorf(context.TODO(), "%+v", err) } } } @@ -333,7 +334,7 @@ func Wait() { s := v.(*Server) if len(s.plugins) > 0 { for _, p := range s.plugins { - intlog.Printf(`remove plugin: %s`, p.Name()) + intlog.Printf(context.TODO(), `remove plugin: %s`, p.Name()) p.Remove() } } diff --git a/net/ghttp/ghttp_server_admin_process.go b/net/ghttp/ghttp_server_admin_process.go index d8a36a831..6cb27d05f 100644 --- a/net/ghttp/ghttp_server_admin_process.go +++ b/net/ghttp/ghttp_server_admin_process.go @@ -8,6 +8,7 @@ package ghttp import ( "bytes" + "context" "errors" "fmt" "github.com/gogf/gf/internal/intlog" @@ -266,10 +267,10 @@ func handleProcessMessage() { for { if msg := gproc.Receive(adminGProcCommGroup); msg != nil { if bytes.EqualFold(msg.Data, []byte("exit")) { - intlog.Printf("%d: process message: exit", gproc.Pid()) + intlog.Printf(context.TODO(), "%d: process message: exit", gproc.Pid()) shutdownWebServersGracefully() allDoneChan <- struct{}{} - intlog.Printf("%d: process message: exit done", gproc.Pid()) + intlog.Printf(context.TODO(), "%d: process message: exit done", gproc.Pid()) return } } diff --git a/net/ghttp/ghttp_server_admin_unix.go b/net/ghttp/ghttp_server_admin_unix.go index b4f0cf6b7..3e5591473 100644 --- a/net/ghttp/ghttp_server_admin_unix.go +++ b/net/ghttp/ghttp_server_admin_unix.go @@ -9,6 +9,7 @@ package ghttp import ( + "context" "github.com/gogf/gf/internal/intlog" "os" "os/signal" @@ -33,7 +34,7 @@ func handleProcessSignal() { ) for { sig = <-procSignalChan - intlog.Printf(`signal received: %s`, sig.String()) + intlog.Printf(context.TODO(), `signal received: %s`, sig.String()) switch sig { // Shutdown the servers. case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGABRT: @@ -49,7 +50,7 @@ func handleProcessSignal() { // Restart the servers. case syscall.SIGUSR1: if err := restartWebServers(sig.String()); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } return diff --git a/net/ghttp/ghttp_server_config.go b/net/ghttp/ghttp_server_config.go index 0d4888e45..5021c26d8 100644 --- a/net/ghttp/ghttp_server_config.go +++ b/net/ghttp/ghttp_server_config.go @@ -7,6 +7,7 @@ package ghttp import ( + "context" "crypto/tls" "fmt" "github.com/gogf/gf/internal/intlog" @@ -333,11 +334,11 @@ func (s *Server) SetConfig(c ServerConfig) error { } } if err := s.config.Logger.SetLevelStr(s.config.LogLevel); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } SetGraceful(c.Graceful) - intlog.Printf("SetConfig: %+v", s.config) + intlog.Printf(context.TODO(), "SetConfig: %+v", s.config) return nil } diff --git a/net/ghttp/ghttp_server_handler.go b/net/ghttp/ghttp_server_handler.go index cf9fcfb0a..64bdf0ee1 100644 --- a/net/ghttp/ghttp_server_handler.go +++ b/net/ghttp/ghttp_server_handler.go @@ -83,12 +83,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // to release the file descriptor in time. err := request.Request.Body.Close() if err != nil { - intlog.Error(err) + intlog.Error(request.Context(), err) } if request.Request.Response != nil { err = request.Request.Response.Body.Close() if err != nil { - intlog.Error(err) + intlog.Error(request.Context(), err) } } }() diff --git a/net/ghttp/internal/client/client_request.go b/net/ghttp/internal/client/client_request.go index 545e8e7b9..2da8b6043 100644 --- a/net/ghttp/internal/client/client_request.go +++ b/net/ghttp/internal/client/client_request.go @@ -195,12 +195,12 @@ func (c *Client) prepareRequest(method, url string, data ...interface{}) (req *h if f, err := os.Open(path); err == nil { if _, err = io.Copy(file, f); err != nil { if err := f.Close(); err != nil { - intlog.Errorf(`%+v`, err) + intlog.Errorf(c.ctx, `%+v`, err) } return nil, err } if err := f.Close(); err != nil { - intlog.Errorf(`%+v`, err) + intlog.Errorf(c.ctx, `%+v`, err) } } else { return nil, err @@ -303,7 +303,7 @@ func (c *Client) callRequest(req *http.Request) (resp *Response, err error) { // The response might not be nil when err != nil. if resp.Response != nil { if err := resp.Response.Body.Close(); err != nil { - intlog.Errorf(`%+v`, err) + intlog.Errorf(c.ctx, `%+v`, err) } } if c.retryCount > 0 { diff --git a/os/gcfg/gcfg.go b/os/gcfg/gcfg.go index b872cbf78..ec8bf5153 100644 --- a/os/gcfg/gcfg.go +++ b/os/gcfg/gcfg.go @@ -8,6 +8,7 @@ package gcfg import ( + "context" "github.com/gogf/gf/container/garray" "github.com/gogf/gf/container/gmap" "github.com/gogf/gf/internal/intlog" @@ -82,7 +83,7 @@ func RemoveContent(file ...string) { } }) - intlog.Printf(`RemoveContent: %s`, name) + intlog.Printf(context.TODO(), `RemoveContent: %s`, name) } // ClearContent removes all global configuration contents. @@ -95,7 +96,7 @@ func ClearContent() { } }) - intlog.Print(`RemoveConfig`) + intlog.Print(context.TODO(), `RemoveConfig`) } // errorPrint checks whether printing error to stdout. diff --git a/os/gcfg/gcfg_config.go b/os/gcfg/gcfg_config.go index a76a36e41..d21f91978 100644 --- a/os/gcfg/gcfg_config.go +++ b/os/gcfg/gcfg_config.go @@ -8,6 +8,7 @@ package gcfg import ( "bytes" + "context" "errors" "fmt" "github.com/gogf/gf/container/garray" @@ -54,20 +55,20 @@ func New(file ...string) *Config { } else { // Dir path of working dir. if err := c.AddPath(gfile.Pwd()); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } // Dir path of main package. if mainPath := gfile.MainPkgPath(); mainPath != "" && gfile.Exists(mainPath) { if err := c.AddPath(mainPath); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } } // Dir path of binary. if selfPath := gfile.SelfDir(); selfPath != "" && gfile.Exists(selfPath) { if err := c.AddPath(selfPath); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } } } @@ -163,7 +164,7 @@ func (c *Config) SetPath(path string) error { c.jsonMap.Clear() c.searchPaths.Clear() c.searchPaths.Append(realPath) - intlog.Print("SetPath:", realPath) + intlog.Print(context.TODO(), "SetPath:", realPath) return nil } @@ -237,7 +238,7 @@ func (c *Config) AddPath(path string) error { return nil } c.searchPaths.Append(realPath) - intlog.Print("AddPath:", realPath) + intlog.Print(context.TODO(), "AddPath:", realPath) return nil } diff --git a/os/gfsnotify/gfsnotify.go b/os/gfsnotify/gfsnotify.go index 619454189..670370b33 100644 --- a/os/gfsnotify/gfsnotify.go +++ b/os/gfsnotify/gfsnotify.go @@ -8,6 +8,7 @@ package gfsnotify import ( + "context" "errors" "fmt" "github.com/gogf/gf/container/gset" @@ -88,7 +89,7 @@ func New() (*Watcher, error) { if watcher, err := fsnotify.NewWatcher(); err == nil { w.watcher = watcher } else { - intlog.Printf("New watcher failed: %v", err) + intlog.Printf(context.TODO(), "New watcher failed: %v", err) return nil, err } w.watchLoop() diff --git a/os/gfsnotify/gfsnotify_watcher.go b/os/gfsnotify/gfsnotify_watcher.go index 37067a988..ab0f92eec 100644 --- a/os/gfsnotify/gfsnotify_watcher.go +++ b/os/gfsnotify/gfsnotify_watcher.go @@ -7,6 +7,7 @@ package gfsnotify import ( + "context" "errors" "fmt" "github.com/gogf/gf/internal/intlog" @@ -45,9 +46,9 @@ func (w *Watcher) AddOnce(name, path string, callbackFunc func(event *Event), re for _, subPath := range fileAllDirs(path) { if fileIsDir(subPath) { if err := w.watcher.Add(subPath); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } else { - intlog.Printf("watcher adds monitor for: %s", subPath) + intlog.Printf(context.TODO(), "watcher adds monitor for: %s", subPath) } } } @@ -93,9 +94,9 @@ func (w *Watcher) addWithCallbackFunc(name, path string, callbackFunc func(event }) // Add the path to underlying monitor. if err := w.watcher.Add(path); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } else { - intlog.Printf("watcher adds monitor for: %s", path) + intlog.Printf(context.TODO(), "watcher adds monitor for: %s", path) } // Add the callback to global callback map. callbackIdMap.Set(callback.Id, callback) @@ -108,7 +109,7 @@ func (w *Watcher) addWithCallbackFunc(name, path string, callbackFunc func(event func (w *Watcher) Close() { w.events.Close() if err := w.watcher.Close(); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } close(w.closeChan) } @@ -131,7 +132,7 @@ func (w *Watcher) Remove(path string) error { for _, subPath := range subPaths { if w.checkPathCanBeRemoved(subPath) { if err := w.watcher.Remove(subPath); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } } } diff --git a/os/gfsnotify/gfsnotify_watcher_loop.go b/os/gfsnotify/gfsnotify_watcher_loop.go index 531225051..2618239ce 100644 --- a/os/gfsnotify/gfsnotify_watcher_loop.go +++ b/os/gfsnotify/gfsnotify_watcher_loop.go @@ -7,6 +7,7 @@ package gfsnotify import ( + "context" "github.com/gogf/gf/container/glist" "github.com/gogf/gf/internal/intlog" ) @@ -34,7 +35,7 @@ func (w *Watcher) watchLoop() { }, repeatEventFilterDuration) case err := <-w.watcher.Errors: - intlog.Error(err) + intlog.Error(context.TODO(), err) } } }() @@ -60,9 +61,9 @@ func (w *Watcher) eventLoop() { // It adds the path back to monitor. // We need no worry about the repeat adding. if err := w.watcher.Add(event.Path); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } else { - intlog.Printf("fake remove event, watcher re-adds monitor for: %s", event.Path) + intlog.Printf(context.TODO(), "fake remove event, watcher re-adds monitor for: %s", event.Path) } // Change the event to RENAME, which means it renames itself to its origin name. event.Op = RENAME @@ -76,9 +77,9 @@ func (w *Watcher) eventLoop() { // It might lost the monitoring for the path, so we add the path back to monitor. // We need no worry about the repeat adding. if err := w.watcher.Add(event.Path); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } else { - intlog.Printf("fake rename event, watcher re-adds monitor for: %s", event.Path) + intlog.Printf(context.TODO(), "fake rename event, watcher re-adds monitor for: %s", event.Path) } // Change the event to CHMOD. event.Op = CHMOD @@ -94,18 +95,18 @@ func (w *Watcher) eventLoop() { for _, subPath := range fileAllDirs(event.Path) { if fileIsDir(subPath) { if err := w.watcher.Add(subPath); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } else { - intlog.Printf("folder creation event, watcher adds monitor for: %s", subPath) + intlog.Printf(context.TODO(), "folder creation event, watcher adds monitor for: %s", subPath) } } } } else { // If it's a file, it directly adds it to monitor. if err := w.watcher.Add(event.Path); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } else { - intlog.Printf("file creation event, watcher adds monitor for: %s", event.Path) + intlog.Printf(context.TODO(), "file creation event, watcher adds monitor for: %s", event.Path) } } diff --git a/os/glog/glog_logger.go b/os/glog/glog_logger.go index 397a779bc..0f5552554 100644 --- a/os/glog/glog_logger.go +++ b/os/glog/glog_logger.go @@ -38,11 +38,12 @@ type Logger struct { } const ( - defaultFileFormat = `{Y-m-d}.log` - defaultFileFlags = os.O_CREATE | os.O_WRONLY | os.O_APPEND - defaultFilePerm = os.FileMode(0666) - defaultFileExpire = time.Minute - pathFilterKey = "/os/glog/glog" + defaultFileFormat = `{Y-m-d}.log` + defaultFileFlags = os.O_CREATE | os.O_WRONLY | os.O_APPEND + defaultFilePerm = os.FileMode(0666) + defaultFileExpire = time.Minute + pathFilterKey = "/os/glog/glog" + memoryLockPrefixForPrintingToFile = "glog.printToFile:" ) const ( @@ -106,7 +107,7 @@ func (l *Logger) print(ctx context.Context, level int, values ...interface{}) { if p.config.RotateSize > 0 || p.config.RotateExpire > 0 { if !p.init.Val() && p.init.Cas(false, true) { gtimer.AddOnce(p.config.RotateCheckInterval, p.rotateChecksTimely) - intlog.Printf("logger rotation initialized: every %s", p.config.RotateCheckInterval.String()) + intlog.Printf(ctx, "logger rotation initialized: every %s", p.config.RotateCheckInterval.String()) } } @@ -168,7 +169,7 @@ func (l *Logger) print(ctx context.Context, level int, values ...interface{}) { // Tracing values. spanCtx := trace.SpanContextFromContext(ctx) if traceId := spanCtx.TraceID(); traceId.IsValid() { - input.CtxStr = "{TraceID:" + traceId.String() + "}" + input.CtxStr = "{" + traceId.String() + "}" } // Context values. if len(l.config.CtxKeys) > 0 { @@ -210,7 +211,7 @@ func (l *Logger) print(ctx context.Context, level int, values ...interface{}) { input.Next() }) if err != nil { - intlog.Error(err) + intlog.Error(ctx, err) } } else { input.Next() @@ -223,27 +224,26 @@ func (l *Logger) printToWriter(ctx context.Context, input *HandlerInput) { if l.config.Writer == nil { // Output content to disk file. if l.config.Path != "" { - l.printToFile(input.Time, buffer) + l.printToFile(ctx, input.Time, buffer) } // Allow output to stdout? if l.config.StdoutPrint { if _, err := os.Stdout.Write(buffer.Bytes()); err != nil { - intlog.Error(err) + intlog.Error(ctx, err) } } } else { if _, err := l.config.Writer.Write(buffer.Bytes()); err != nil { - // panic(err) - intlog.Error(err) + intlog.Error(ctx, err) } } } // printToFile outputs logging content to disk file. -func (l *Logger) printToFile(t time.Time, buffer *bytes.Buffer) { +func (l *Logger) printToFile(ctx context.Context, t time.Time, buffer *bytes.Buffer) { var ( logFilePath = l.getFilePath(t) - memoryLockKey = "glog.printToFile:" + logFilePath + memoryLockKey = memoryLockPrefixForPrintingToFile + logFilePath ) gmlock.Lock(memoryLockKey) defer gmlock.Unlock(memoryLockKey) @@ -255,20 +255,20 @@ func (l *Logger) printToFile(t time.Time, buffer *bytes.Buffer) { } } // Logging content outputting to disk file. - if file := l.getFilePointer(logFilePath); file == nil { - intlog.Errorf(`got nil file pointer for: %s`, logFilePath) + if file := l.getFilePointer(ctx, logFilePath); file == nil { + intlog.Errorf(ctx, `got nil file pointer for: %s`, logFilePath) } else { if _, err := file.Write(buffer.Bytes()); err != nil { - intlog.Error(err) + intlog.Error(ctx, err) } if err := file.Close(); err != nil { - intlog.Error(err) + intlog.Error(ctx, err) } } } // getFilePointer retrieves and returns a file pointer from file pool. -func (l *Logger) getFilePointer(path string) *gfpool.File { +func (l *Logger) getFilePointer(ctx context.Context, path string) *gfpool.File { file, err := gfpool.Open( path, defaultFileFlags, @@ -277,7 +277,7 @@ func (l *Logger) getFilePointer(path string) *gfpool.File { ) if err != nil { // panic(err) - intlog.Error(err) + intlog.Error(ctx, err) } return file } diff --git a/os/glog/glog_logger_chaining.go b/os/glog/glog_logger_chaining.go index 3a5080b62..c0213b982 100644 --- a/os/glog/glog_logger_chaining.go +++ b/os/glog/glog_logger_chaining.go @@ -60,7 +60,7 @@ func (l *Logger) Path(path string) *Logger { if path != "" { if err := logger.SetPath(path); err != nil { // panic(err) - intlog.Error(err) + intlog.Error(l.getCtx(), err) } } return logger @@ -79,7 +79,7 @@ func (l *Logger) Cat(category string) *Logger { if logger.config.Path != "" { if err := logger.SetPath(gfile.Join(logger.config.Path, category)); err != nil { // panic(err) - intlog.Error(err) + intlog.Error(l.getCtx(), err) } } return logger @@ -122,7 +122,7 @@ func (l *Logger) LevelStr(levelStr string) *Logger { } if err := logger.SetLevelStr(levelStr); err != nil { // panic(err) - intlog.Error(err) + intlog.Error(l.getCtx(), err) } return logger } diff --git a/os/glog/glog_logger_config.go b/os/glog/glog_logger_config.go index 709a7976c..ac295c1c5 100644 --- a/os/glog/glog_logger_config.go +++ b/os/glog/glog_logger_config.go @@ -71,11 +71,11 @@ func (l *Logger) SetConfig(config Config) error { // Necessary validation. if config.Path != "" { if err := l.SetPath(config.Path); err != nil { - intlog.Error(err) + intlog.Error(l.ctx, err) return err } } - intlog.Printf("SetConfig: %+v", l.config) + intlog.Printf(l.ctx, "SetConfig: %+v", l.config) return nil } diff --git a/os/glog/glog_logger_rotate.go b/os/glog/glog_logger_rotate.go index 8471e55f2..697793854 100644 --- a/os/glog/glog_logger_rotate.go +++ b/os/glog/glog_logger_rotate.go @@ -31,7 +31,7 @@ func (l *Logger) rotateFileBySize(now time.Time) { } if err := l.doRotateFile(l.getFilePath(now)); err != nil { // panic(err) - intlog.Error(err) + intlog.Error(l.ctx, err) } } @@ -48,7 +48,11 @@ func (l *Logger) doRotateFile(filePath string) error { if err := gfile.Remove(filePath); err != nil { return err } - intlog.Printf(`%d size exceeds, no backups set, remove original logging file: %s`, l.config.RotateSize, filePath) + intlog.Printf( + l.ctx, + `%d size exceeds, no backups set, remove original logging file: %s`, + l.config.RotateSize, filePath, + ) return nil } // Else it creates new backup files. @@ -83,7 +87,7 @@ func (l *Logger) doRotateFile(filePath string) error { if !gfile.Exists(newFilePath) { break } else { - intlog.Printf(`rotation file exists, continue: %s`, newFilePath) + intlog.Printf(l.ctx, `rotation file exists, continue: %s`, newFilePath) } } if err := gfile.Rename(filePath, newFilePath); err != nil { @@ -99,6 +103,7 @@ func (l *Logger) rotateChecksTimely() { // Checks whether file rotation not enabled. if l.config.RotateSize <= 0 && l.config.RotateExpire == 0 { intlog.Printf( + l.ctx, "logging rotation ignore checks: RotateSize: %d, RotateExpire: %s", l.config.RotateSize, l.config.RotateExpire.String(), ) @@ -118,9 +123,9 @@ func (l *Logger) rotateChecksTimely() { files, err = gfile.ScanDirFile(l.config.Path, pattern, true) ) if err != nil { - intlog.Error(err) + intlog.Error(l.ctx, err) } - intlog.Printf("logging rotation start checks: %+v", files) + intlog.Printf(l.ctx, "logging rotation start checks: %+v", files) // ============================================================= // Rotation of expired file checks. // ============================================================= @@ -139,11 +144,12 @@ func (l *Logger) rotateChecksTimely() { if subDuration > l.config.RotateExpire { expireRotated = true intlog.Printf( + l.ctx, `%v - %v = %v > %v, rotation expire logging file: %s`, now, mtime, subDuration, l.config.RotateExpire, file, ) if err := l.doRotateFile(file); err != nil { - intlog.Error(err) + intlog.Error(l.ctx, err) } } } @@ -151,7 +157,7 @@ func (l *Logger) rotateChecksTimely() { // Update the files array. files, err = gfile.ScanDirFile(l.config.Path, pattern, true) if err != nil { - intlog.Error(err) + intlog.Error(l.ctx, err) } } } @@ -176,19 +182,19 @@ func (l *Logger) rotateChecksTimely() { needCompressFileArray.Iterator(func(_ int, path string) bool { err := gcompress.GzipFile(path, path+".gz") if err == nil { - intlog.Printf(`compressed done, remove original logging file: %s`, path) + intlog.Printf(l.ctx, `compressed done, remove original logging file: %s`, path) if err = gfile.Remove(path); err != nil { - intlog.Print(err) + intlog.Print(l.ctx, err) } } else { - intlog.Print(err) + intlog.Print(l.ctx, err) } return true }) // Update the files array. files, err = gfile.ScanDirFile(l.config.Path, pattern, true) if err != nil { - intlog.Error(err) + intlog.Error(l.ctx, err) } } } @@ -223,14 +229,14 @@ func (l *Logger) rotateChecksTimely() { backupFilesMap[originalLoggingFilePath].Add(file) } } - intlog.Printf(`calculated backup files map: %+v`, backupFilesMap) + intlog.Printf(l.ctx, `calculated backup files map: %+v`, backupFilesMap) for _, array := range backupFilesMap { diff := array.Len() - l.config.RotateBackupLimit for i := 0; i < diff; i++ { path, _ := array.PopLeft() - intlog.Printf(`remove exceeded backup limit file: %s`, path) + intlog.Printf(l.ctx, `remove exceeded backup limit file: %s`, path) if err := gfile.Remove(path.(string)); err != nil { - intlog.Error(err) + intlog.Error(l.ctx, err) } } } @@ -247,11 +253,12 @@ func (l *Logger) rotateChecksTimely() { subDuration = now.Sub(mtime) if subDuration > l.config.RotateBackupExpire { intlog.Printf( + l.ctx, `%v - %v = %v > %v, remove expired backup file: %s`, now, mtime, subDuration, l.config.RotateBackupExpire, path, ) if err := gfile.Remove(path); err != nil { - intlog.Error(err) + intlog.Error(l.ctx, err) } return true } else { diff --git a/os/gproc/gproc_process.go b/os/gproc/gproc_process.go index 74bf04344..eb386345e 100644 --- a/os/gproc/gproc_process.go +++ b/os/gproc/gproc_process.go @@ -7,6 +7,7 @@ package gproc import ( + "context" "errors" "fmt" "github.com/gogf/gf/internal/intlog" @@ -118,12 +119,11 @@ func (p *Process) Kill() error { } if runtime.GOOS != "windows" { if err = p.Process.Release(); err != nil { - intlog.Error(err) - //return err + intlog.Error(context.TODO(), err) } } _, err = p.Process.Wait() - intlog.Error(err) + intlog.Error(context.TODO(), err) //return err return nil } else { diff --git a/os/gproc/gproc_signal.go b/os/gproc/gproc_signal.go index 08d059e00..1f742289f 100644 --- a/os/gproc/gproc_signal.go +++ b/os/gproc/gproc_signal.go @@ -7,6 +7,7 @@ package gproc import ( + "context" "github.com/gogf/gf/internal/intlog" "os" "os/signal" @@ -67,7 +68,7 @@ func Listen() { for { wg := sync.WaitGroup{} sig = <-sigChan - intlog.Printf(`signal received: %s`, sig.String()) + intlog.Printf(context.TODO(), `signal received: %s`, sig.String()) if handlers, ok := signalHandlerMap[sig]; ok { for _, handler := range handlers { wg.Add(1) diff --git a/os/gres/gres_func_zip.go b/os/gres/gres_func_zip.go index bc6e0ac50..706bd02bc 100644 --- a/os/gres/gres_func_zip.go +++ b/os/gres/gres_func_zip.go @@ -8,6 +8,7 @@ package gres import ( "archive/zip" + "context" "github.com/gogf/gf/internal/fileinfo" "github.com/gogf/gf/internal/intlog" "github.com/gogf/gf/os/gfile" @@ -70,7 +71,7 @@ func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix headerPrefix = strings.Replace(headerPrefix, "//", "/", -1) for _, file := range files { if exclude == file { - intlog.Printf(`exclude file path: %s`, file) + intlog.Printf(context.TODO(), `exclude file path: %s`, file) continue } err = zipFile(file, headerPrefix+gfile.Dir(file[len(path):]), zipWriter) diff --git a/os/gres/gres_resource.go b/os/gres/gres_resource.go index 2ed7b2e46..cb9213b00 100644 --- a/os/gres/gres_resource.go +++ b/os/gres/gres_resource.go @@ -7,6 +7,7 @@ package gres import ( + "context" "fmt" "github.com/gogf/gf/internal/intlog" "os" @@ -42,7 +43,7 @@ func New() *Resource { func (r *Resource) Add(content string, prefix ...string) error { files, err := UnpackContent(content) if err != nil { - intlog.Printf("Add resource files failed: %v", err) + intlog.Printf(context.TODO(), "Add resource files failed: %v", err) return err } namePrefix := "" @@ -53,7 +54,7 @@ func (r *Resource) Add(content string, prefix ...string) error { files[i].resource = r r.tree.Set(namePrefix+files[i].file.Name, files[i]) } - intlog.Printf("Add %d files to resource manager", r.tree.Size()) + intlog.Printf(context.TODO(), "Add %d files to resource manager", r.tree.Size()) return nil } diff --git a/os/gsession/gsession_manager.go b/os/gsession/gsession_manager.go index c52095146..7c69c6fe4 100644 --- a/os/gsession/gsession_manager.go +++ b/os/gsession/gsession_manager.go @@ -7,6 +7,7 @@ package gsession import ( + "context" "github.com/gogf/gf/container/gmap" "time" @@ -41,13 +42,14 @@ func New(ttl time.Duration, storage ...Storage) *Manager { // New creates or fetches the session for given session id. // The parameter is optional, it creates a new one if not it's passed // depending on Storage.New. -func (m *Manager) New(sessionId ...string) *Session { +func (m *Manager) New(ctx context.Context, sessionId ...string) *Session { var id string if len(sessionId) > 0 && sessionId[0] != "" { id = sessionId[0] } return &Session{ id: id, + ctx: ctx, manager: m, } } diff --git a/os/gsession/gsession_session.go b/os/gsession/gsession_session.go index 17e764852..85d4d1995 100644 --- a/os/gsession/gsession_session.go +++ b/os/gsession/gsession_session.go @@ -7,6 +7,7 @@ package gsession import ( + "context" "errors" "github.com/gogf/gf/internal/intlog" "time" @@ -17,10 +18,12 @@ import ( "github.com/gogf/gf/util/gconv" ) -// Session struct for storing single session data, -// which is bound to a single request. +// Session struct for storing single session data, which is bound to a single request. +// The Session struct is the interface with user, but the Storage is the underlying adapter designed interface +// for functionality implements. type Session struct { id string // Session id. + ctx context.Context // Context for current session, note that: one session one context. data *gmap.StrAnyMap // Session data. dirty bool // Used to mark session is modified. start bool // Used to mark session is started. @@ -42,12 +45,12 @@ func (s *Session) init() { // Retrieve memory session data from manager. if r, _ := s.manager.sessionData.Get(s.id); r != nil { s.data = r.(*gmap.StrAnyMap) - intlog.Print("session init data:", s.data) + intlog.Print(s.ctx, "session init data:", s.data) } // Retrieve stored session data from storage. if s.manager.storage != nil { - if s.data, err = s.manager.storage.GetSession(s.id, s.manager.ttl, s.data); err != nil { - intlog.Errorf("session restoring failed for id '%s': %v", s.id, err) + if s.data, err = s.manager.storage.GetSession(s.ctx, s.id, s.manager.ttl, s.data); err != nil { + intlog.Errorf(s.ctx, "session restoring failed for id '%s': %v", s.id, err) } } } @@ -57,7 +60,7 @@ func (s *Session) init() { } // Use default session id creating function of storage. if s.id == "" { - s.id = s.manager.storage.New(s.manager.ttl) + s.id = s.manager.storage.New(s.ctx, s.manager.ttl) } // Use default session id creating function. if s.id == "" { @@ -78,11 +81,11 @@ func (s *Session) Close() { size := s.data.Size() if s.manager.storage != nil { if s.dirty { - if err := s.manager.storage.SetSession(s.id, s.data, s.manager.ttl); err != nil { + if err := s.manager.storage.SetSession(s.ctx, s.id, s.data, s.manager.ttl); err != nil { panic(err) } } else if size > 0 { - if err := s.manager.storage.UpdateTTL(s.id, s.manager.ttl); err != nil { + if err := s.manager.storage.UpdateTTL(s.ctx, s.id, s.manager.ttl); err != nil { panic(err) } } @@ -96,7 +99,7 @@ func (s *Session) Close() { // Set sets key-value pair to this session. func (s *Session) Set(key string, value interface{}) error { s.init() - if err := s.manager.storage.Set(s.id, key, value, s.manager.ttl); err != nil { + if err := s.manager.storage.Set(s.ctx, s.id, key, value, s.manager.ttl); err != nil { if err == ErrorDisabled { s.data.Set(key, value) } else { @@ -116,7 +119,7 @@ func (s *Session) Sets(data map[string]interface{}) error { // SetMap batch sets the session using map. func (s *Session) SetMap(data map[string]interface{}) error { s.init() - if err := s.manager.storage.SetMap(s.id, data, s.manager.ttl); err != nil { + if err := s.manager.storage.SetMap(s.ctx, s.id, data, s.manager.ttl); err != nil { if err == ErrorDisabled { s.data.Sets(data) } else { @@ -134,7 +137,7 @@ func (s *Session) Remove(keys ...string) error { } s.init() for _, key := range keys { - if err := s.manager.storage.Remove(s.id, key); err != nil { + if err := s.manager.storage.Remove(s.ctx, s.id, key); err != nil { if err == ErrorDisabled { s.data.Remove(key) } else { @@ -157,7 +160,7 @@ func (s *Session) RemoveAll() error { return nil } s.init() - if err := s.manager.storage.RemoveAll(s.id); err != nil { + if err := s.manager.storage.RemoveAll(s.ctx, s.id); err != nil { if err == ErrorDisabled { s.data.Clear() } else { @@ -200,7 +203,7 @@ func (s *Session) SetIdFunc(f func(ttl time.Duration) string) error { func (s *Session) Map() map[string]interface{} { if s.id != "" { s.init() - if data := s.manager.storage.GetMap(s.id); data != nil { + if data := s.manager.storage.GetMap(s.ctx, s.id); data != nil { return data } return s.data.Map() @@ -212,7 +215,7 @@ func (s *Session) Map() map[string]interface{} { func (s *Session) Size() int { if s.id != "" { s.init() - if size := s.manager.storage.GetSize(s.id); size >= 0 { + if size := s.manager.storage.GetSize(s.ctx, s.id); size >= 0 { return size } return s.data.Size() @@ -239,7 +242,7 @@ func (s *Session) Get(key string, def ...interface{}) interface{} { return nil } s.init() - if v := s.manager.storage.Get(s.id, key); v != nil { + if v := s.manager.storage.Get(s.ctx, s.id, key); v != nil { return v } if v := s.data.Get(key); v != nil { @@ -363,16 +366,6 @@ func (s *Session) GetStruct(key string, pointer interface{}, mapping ...map[stri return gconv.Struct(s.Get(key), pointer, mapping...) } -// Deprecated, use GetStruct instead. -func (s *Session) GetStructDeep(key string, pointer interface{}, mapping ...map[string]string) error { - return gconv.StructDeep(s.Get(key), pointer, mapping...) -} - func (s *Session) GetStructs(key string, pointer interface{}, mapping ...map[string]string) error { return gconv.Structs(s.Get(key), pointer, mapping...) } - -// Deprecated, use GetStructs instead. -func (s *Session) GetStructsDeep(key string, pointer interface{}, mapping ...map[string]string) error { - return gconv.StructsDeep(s.Get(key), pointer, mapping...) -} diff --git a/os/gsession/gsession_storage.go b/os/gsession/gsession_storage.go index 02b72e322..87ef2a669 100644 --- a/os/gsession/gsession_storage.go +++ b/os/gsession/gsession_storage.go @@ -7,6 +7,7 @@ package gsession import ( + "context" "github.com/gogf/gf/container/gmap" "time" ) @@ -15,31 +16,31 @@ import ( type Storage interface { // New creates a custom session id. // This function can be used for custom session creation. - New(ttl time.Duration) (id string) + New(ctx context.Context, ttl time.Duration) (id string) // Get retrieves and returns session value with given key. // It returns nil if the key does not exist in the session. - Get(id string, key string) interface{} + Get(ctx context.Context, id string, key string) interface{} // GetMap retrieves all key-value pairs as map from storage. - GetMap(id string) map[string]interface{} + GetMap(ctx context.Context, id string) map[string]interface{} // GetSize retrieves and returns the size of key-value pairs from storage. - GetSize(id string) int + GetSize(ctx context.Context, id string) int // Set sets one key-value session pair to the storage. // The parameter specifies the TTL for the session id. - Set(id string, key string, value interface{}, ttl time.Duration) error + Set(ctx context.Context, id string, key string, value interface{}, ttl time.Duration) error // SetMap batch sets key-value session pairs as map to the storage. // The parameter specifies the TTL for the session id. - SetMap(id string, data map[string]interface{}, ttl time.Duration) error + SetMap(ctx context.Context, id string, data map[string]interface{}, ttl time.Duration) error // Remove deletes key with its value from storage. - Remove(id string, key string) error + Remove(ctx context.Context, id string, key string) error // RemoveAll deletes all key-value pairs from storage. - RemoveAll(id string) error + RemoveAll(ctx context.Context, id string) error // GetSession returns the session data as *gmap.StrAnyMap for given session id from storage. // @@ -48,14 +49,14 @@ type Storage interface { // and for some storage it might be nil if memory storage is disabled. // // This function is called ever when session starts. It returns nil if the TTL is exceeded. - GetSession(id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) + GetSession(ctx context.Context, id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) // SetSession updates the data for specified session id. // This function is called ever after session, which is changed dirty, is closed. // This copy all session data map from memory to storage. - SetSession(id string, data *gmap.StrAnyMap, ttl time.Duration) error + SetSession(ctx context.Context, id string, data *gmap.StrAnyMap, ttl time.Duration) error // UpdateTTL updates the TTL for specified session id. // This function is called ever after session, which is not dirty, is closed. - UpdateTTL(id string, ttl time.Duration) error + UpdateTTL(ctx context.Context, id string, ttl time.Duration) error } diff --git a/os/gsession/gsession_storage_file.go b/os/gsession/gsession_storage_file.go index fb0bc7ca6..7bbbaf2ef 100644 --- a/os/gsession/gsession_storage_file.go +++ b/os/gsession/gsession_storage_file.go @@ -7,6 +7,7 @@ package gsession import ( + "context" "github.com/gogf/gf/container/gmap" "github.com/gogf/gf/errors/gerror" "github.com/gogf/gf/internal/intlog" @@ -80,8 +81,8 @@ func (s *StorageFile) updateSessionTimely() { if id = s.updatingIdSet.Pop(); id == "" { break } - if err = s.updateSessionTTl(id); err != nil { - intlog.Error(err) + if err = s.updateSessionTTl(context.TODO(), id); err != nil { + intlog.Error(context.TODO(), err) } } } @@ -104,45 +105,45 @@ func (s *StorageFile) sessionFilePath(id string) string { // New creates a session id. // This function can be used for custom session creation. -func (s *StorageFile) New(ttl time.Duration) (id string) { +func (s *StorageFile) New(ctx context.Context, ttl time.Duration) (id string) { return "" } // Get retrieves session value with given key. // It returns nil if the key does not exist in the session. -func (s *StorageFile) Get(id string, key string) interface{} { +func (s *StorageFile) Get(ctx context.Context, id string, key string) interface{} { return nil } // GetMap retrieves all key-value pairs as map from storage. -func (s *StorageFile) GetMap(id string) map[string]interface{} { +func (s *StorageFile) GetMap(ctx context.Context, id string) map[string]interface{} { return nil } // GetSize retrieves the size of key-value pairs from storage. -func (s *StorageFile) GetSize(id string) int { +func (s *StorageFile) GetSize(ctx context.Context, id string) int { return -1 } // Set sets key-value session pair to the storage. // The parameter specifies the TTL for the session id (not for the key-value pair). -func (s *StorageFile) Set(id string, key string, value interface{}, ttl time.Duration) error { +func (s *StorageFile) Set(ctx context.Context, id string, key string, value interface{}, ttl time.Duration) error { return ErrorDisabled } // SetMap batch sets key-value session pairs with map to the storage. // The parameter specifies the TTL for the session id(not for the key-value pair). -func (s *StorageFile) SetMap(id string, data map[string]interface{}, ttl time.Duration) error { +func (s *StorageFile) SetMap(ctx context.Context, id string, data map[string]interface{}, ttl time.Duration) error { return ErrorDisabled } // Remove deletes key with its value from storage. -func (s *StorageFile) Remove(id string, key string) error { +func (s *StorageFile) Remove(ctx context.Context, id string, key string) error { return ErrorDisabled } // RemoveAll deletes all key-value pairs from storage. -func (s *StorageFile) RemoveAll(id string) error { +func (s *StorageFile) RemoveAll(ctx context.Context, id string) error { return ErrorDisabled } @@ -153,11 +154,10 @@ func (s *StorageFile) RemoveAll(id string) error { // and for some storage it might be nil if memory storage is disabled. // // This function is called ever when session starts. -func (s *StorageFile) GetSession(id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) { +func (s *StorageFile) GetSession(ctx context.Context, id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) { if data != nil { return data, nil } - //intlog.Printf("StorageFile.GetSession: %s, %v", id, ttl) path := s.sessionFilePath(id) content := gfile.GetBytes(path) if len(content) > 8 { @@ -189,8 +189,8 @@ func (s *StorageFile) GetSession(id string, ttl time.Duration, data *gmap.StrAny // SetSession updates the data map for specified session id. // This function is called ever after session, which is changed dirty, is closed. // This copy all session data map from memory to storage. -func (s *StorageFile) SetSession(id string, data *gmap.StrAnyMap, ttl time.Duration) error { - intlog.Printf("StorageFile.SetSession: %s, %v, %v", id, data, ttl) +func (s *StorageFile) SetSession(ctx context.Context, id string, data *gmap.StrAnyMap, ttl time.Duration) error { + intlog.Printf(ctx, "StorageFile.SetSession: %s, %v, %v", id, data, ttl) path := s.sessionFilePath(id) content, err := json.Marshal(data) if err != nil { @@ -222,8 +222,8 @@ func (s *StorageFile) SetSession(id string, data *gmap.StrAnyMap, ttl time.Durat // UpdateTTL updates the TTL for specified session id. // This function is called ever after session, which is not dirty, is closed. // It just adds the session id to the async handling queue. -func (s *StorageFile) UpdateTTL(id string, ttl time.Duration) error { - intlog.Printf("StorageFile.UpdateTTL: %s, %v", id, ttl) +func (s *StorageFile) UpdateTTL(ctx context.Context, id string, ttl time.Duration) error { + intlog.Printf(ctx, "StorageFile.UpdateTTL: %s, %v", id, ttl) if ttl >= DefaultStorageFileLoopInterval { s.updatingIdSet.Add(id) } @@ -231,8 +231,8 @@ func (s *StorageFile) UpdateTTL(id string, ttl time.Duration) error { } // updateSessionTTL updates the TTL for specified session id. -func (s *StorageFile) updateSessionTTl(id string) error { - intlog.Printf("StorageFile.updateSession: %s", id) +func (s *StorageFile) updateSessionTTl(ctx context.Context, id string) error { + intlog.Printf(ctx, "StorageFile.updateSession: %s", id) path := s.sessionFilePath(id) file, err := gfile.OpenWithFlag(path, os.O_WRONLY) if err != nil { diff --git a/os/gsession/gsession_storage_memory.go b/os/gsession/gsession_storage_memory.go index 7b41e7ff6..26f217b92 100644 --- a/os/gsession/gsession_storage_memory.go +++ b/os/gsession/gsession_storage_memory.go @@ -7,6 +7,7 @@ package gsession import ( + "context" "github.com/gogf/gf/container/gmap" "time" ) @@ -21,45 +22,45 @@ func NewStorageMemory() *StorageMemory { // New creates a session id. // This function can be used for custom session creation. -func (s *StorageMemory) New(ttl time.Duration) (id string) { +func (s *StorageMemory) New(ctx context.Context, ttl time.Duration) (id string) { return "" } // Get retrieves session value with given key. // It returns nil if the key does not exist in the session. -func (s *StorageMemory) Get(id string, key string) interface{} { +func (s *StorageMemory) Get(ctx context.Context, id string, key string) interface{} { return nil } // GetMap retrieves all key-value pairs as map from storage. -func (s *StorageMemory) GetMap(id string) map[string]interface{} { +func (s *StorageMemory) GetMap(ctx context.Context, id string) map[string]interface{} { return nil } // GetSize retrieves the size of key-value pairs from storage. -func (s *StorageMemory) GetSize(id string) int { +func (s *StorageMemory) GetSize(ctx context.Context, id string) int { return -1 } // Set sets key-value session pair to the storage. // The parameter specifies the TTL for the session id (not for the key-value pair). -func (s *StorageMemory) Set(id string, key string, value interface{}, ttl time.Duration) error { +func (s *StorageMemory) Set(ctx context.Context, id string, key string, value interface{}, ttl time.Duration) error { return ErrorDisabled } // SetMap batch sets key-value session pairs with map to the storage. // The parameter specifies the TTL for the session id(not for the key-value pair). -func (s *StorageMemory) SetMap(id string, data map[string]interface{}, ttl time.Duration) error { +func (s *StorageMemory) SetMap(ctx context.Context, id string, data map[string]interface{}, ttl time.Duration) error { return ErrorDisabled } // Remove deletes key with its value from storage. -func (s *StorageMemory) Remove(id string, key string) error { +func (s *StorageMemory) Remove(ctx context.Context, id string, key string) error { return ErrorDisabled } // RemoveAll deletes all key-value pairs from storage. -func (s *StorageMemory) RemoveAll(id string) error { +func (s *StorageMemory) RemoveAll(ctx context.Context, id string) error { return ErrorDisabled } @@ -70,25 +71,20 @@ func (s *StorageMemory) RemoveAll(id string) error { // and for some storage it might be nil if memory storage is disabled. // // This function is called ever when session starts. -func (s *StorageMemory) GetSession(id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) { +func (s *StorageMemory) GetSession(ctx context.Context, id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) { return data, nil } // SetSession updates the data map for specified session id. // This function is called ever after session, which is changed dirty, is closed. // This copy all session data map from memory to storage. -func (s *StorageMemory) SetSession(id string, data *gmap.StrAnyMap, ttl time.Duration) error { +func (s *StorageMemory) SetSession(ctx context.Context, id string, data *gmap.StrAnyMap, ttl time.Duration) error { return nil } // UpdateTTL updates the TTL for specified session id. // This function is called ever after session, which is not dirty, is closed. // It just adds the session id to the async handling queue. -func (s *StorageMemory) UpdateTTL(id string, ttl time.Duration) error { - return nil -} - -// doUpdateTTL updates the TTL for session id. -func (s *StorageMemory) doUpdateTTL(id string) error { +func (s *StorageMemory) UpdateTTL(ctx context.Context, id string, ttl time.Duration) error { return nil } diff --git a/os/gsession/gsession_storage_redis.go b/os/gsession/gsession_storage_redis.go index 8d26e2db6..a8b8016af 100644 --- a/os/gsession/gsession_storage_redis.go +++ b/os/gsession/gsession_storage_redis.go @@ -7,6 +7,7 @@ package gsession import ( + "context" "github.com/gogf/gf/container/gmap" "github.com/gogf/gf/database/gredis" "github.com/gogf/gf/internal/intlog" @@ -44,7 +45,7 @@ func NewStorageRedis(redis *gredis.Redis, prefix ...string) *StorageRedis { } // Batch updates the TTL for session ids timely. gtimer.AddSingleton(DefaultStorageRedisLoopInterval, func() { - intlog.Print("StorageRedis.timer start") + intlog.Print(context.TODO(), "StorageRedis.timer start") var ( id string err error @@ -54,57 +55,57 @@ func NewStorageRedis(redis *gredis.Redis, prefix ...string) *StorageRedis { if id, ttlSeconds = s.updatingIdMap.Pop(); id == "" { break } else { - if err = s.doUpdateTTL(id, ttlSeconds); err != nil { - intlog.Error(err) + if err = s.doUpdateTTL(context.TODO(), id, ttlSeconds); err != nil { + intlog.Error(context.TODO(), err) } } } - intlog.Print("StorageRedis.timer end") + intlog.Print(context.TODO(), "StorageRedis.timer end") }) return s } // New creates a session id. // This function can be used for custom session creation. -func (s *StorageRedis) New(ttl time.Duration) (id string) { +func (s *StorageRedis) New(ctx context.Context, ttl time.Duration) (id string) { return "" } // Get retrieves session value with given key. // It returns nil if the key does not exist in the session. -func (s *StorageRedis) Get(id string, key string) interface{} { +func (s *StorageRedis) Get(ctx context.Context, id string, key string) interface{} { return nil } // GetMap retrieves all key-value pairs as map from storage. -func (s *StorageRedis) GetMap(id string) map[string]interface{} { +func (s *StorageRedis) GetMap(ctx context.Context, id string) map[string]interface{} { return nil } // GetSize retrieves the size of key-value pairs from storage. -func (s *StorageRedis) GetSize(id string) int { +func (s *StorageRedis) GetSize(ctx context.Context, id string) int { return -1 } // Set sets key-value session pair to the storage. // The parameter specifies the TTL for the session id (not for the key-value pair). -func (s *StorageRedis) Set(id string, key string, value interface{}, ttl time.Duration) error { +func (s *StorageRedis) Set(ctx context.Context, id string, key string, value interface{}, ttl time.Duration) error { return ErrorDisabled } // SetMap batch sets key-value session pairs with map to the storage. // The parameter specifies the TTL for the session id(not for the key-value pair). -func (s *StorageRedis) SetMap(id string, data map[string]interface{}, ttl time.Duration) error { +func (s *StorageRedis) SetMap(ctx context.Context, id string, data map[string]interface{}, ttl time.Duration) error { return ErrorDisabled } // Remove deletes key with its value from storage. -func (s *StorageRedis) Remove(id string, key string) error { +func (s *StorageRedis) Remove(ctx context.Context, id string, key string) error { return ErrorDisabled } // RemoveAll deletes all key-value pairs from storage. -func (s *StorageRedis) RemoveAll(id string) error { +func (s *StorageRedis) RemoveAll(ctx context.Context, id string) error { return ErrorDisabled } @@ -115,9 +116,9 @@ func (s *StorageRedis) RemoveAll(id string) error { // and for some storage it might be nil if memory storage is disabled. // // This function is called ever when session starts. -func (s *StorageRedis) GetSession(id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) { - intlog.Printf("StorageRedis.GetSession: %s, %v", id, ttl) - r, err := s.redis.DoVar("GET", s.key(id)) +func (s *StorageRedis) GetSession(ctx context.Context, id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) { + intlog.Printf(ctx, "StorageRedis.GetSession: %s, %v", id, ttl) + r, err := s.redis.Ctx(ctx).DoVar("GET", s.key(id)) if err != nil { return nil, err } @@ -143,21 +144,21 @@ func (s *StorageRedis) GetSession(id string, ttl time.Duration, data *gmap.StrAn // SetSession updates the data map for specified session id. // This function is called ever after session, which is changed dirty, is closed. // This copy all session data map from memory to storage. -func (s *StorageRedis) SetSession(id string, data *gmap.StrAnyMap, ttl time.Duration) error { - intlog.Printf("StorageRedis.SetSession: %s, %v, %v", id, data, ttl) +func (s *StorageRedis) SetSession(ctx context.Context, id string, data *gmap.StrAnyMap, ttl time.Duration) error { + intlog.Printf(ctx, "StorageRedis.SetSession: %s, %v, %v", id, data, ttl) content, err := json.Marshal(data) if err != nil { return err } - _, err = s.redis.DoVar("SETEX", s.key(id), int64(ttl.Seconds()), content) + _, err = s.redis.Ctx(ctx).DoVar("SETEX", s.key(id), int64(ttl.Seconds()), content) return err } // UpdateTTL updates the TTL for specified session id. // This function is called ever after session, which is not dirty, is closed. // It just adds the session id to the async handling queue. -func (s *StorageRedis) UpdateTTL(id string, ttl time.Duration) error { - intlog.Printf("StorageRedis.UpdateTTL: %s, %v", id, ttl) +func (s *StorageRedis) UpdateTTL(ctx context.Context, id string, ttl time.Duration) error { + intlog.Printf(ctx, "StorageRedis.UpdateTTL: %s, %v", id, ttl) if ttl >= DefaultStorageRedisLoopInterval { s.updatingIdMap.Set(id, int(ttl.Seconds())) } @@ -165,9 +166,9 @@ func (s *StorageRedis) UpdateTTL(id string, ttl time.Duration) error { } // doUpdateTTL updates the TTL for session id. -func (s *StorageRedis) doUpdateTTL(id string, ttlSeconds int) error { - intlog.Printf("StorageRedis.doUpdateTTL: %s, %d", id, ttlSeconds) - _, err := s.redis.DoVar("EXPIRE", s.key(id), ttlSeconds) +func (s *StorageRedis) doUpdateTTL(ctx context.Context, id string, ttlSeconds int) error { + intlog.Printf(ctx, "StorageRedis.doUpdateTTL: %s, %d", id, ttlSeconds) + _, err := s.redis.Ctx(ctx).DoVar("EXPIRE", s.key(id), ttlSeconds) return err } diff --git a/os/gsession/gsession_storage_redis_hashtable.go b/os/gsession/gsession_storage_redis_hashtable.go index 15eb825a3..352e5f8b7 100644 --- a/os/gsession/gsession_storage_redis_hashtable.go +++ b/os/gsession/gsession_storage_redis_hashtable.go @@ -7,6 +7,7 @@ package gsession import ( + "context" "time" "github.com/gogf/gf/container/gmap" @@ -38,14 +39,14 @@ func NewStorageRedisHashTable(redis *gredis.Redis, prefix ...string) *StorageRed // New creates a session id. // This function can be used for custom session creation. -func (s *StorageRedisHashTable) New(ttl time.Duration) (id string) { +func (s *StorageRedisHashTable) New(ctx context.Context, ttl time.Duration) (id string) { return "" } // Get retrieves session value with given key. // It returns nil if the key does not exist in the session. -func (s *StorageRedisHashTable) Get(id string, key string) interface{} { - r, _ := s.redis.Do("HGET", s.key(id), key) +func (s *StorageRedisHashTable) Get(ctx context.Context, id string, key string) interface{} { + r, _ := s.redis.Ctx(ctx).Do("HGET", s.key(id), key) if r != nil { return gconv.String(r) } @@ -53,8 +54,8 @@ func (s *StorageRedisHashTable) Get(id string, key string) interface{} { } // GetMap retrieves all key-value pairs as map from storage. -func (s *StorageRedisHashTable) GetMap(id string) map[string]interface{} { - r, err := s.redis.DoVar("HGETALL", s.key(id)) +func (s *StorageRedisHashTable) GetMap(ctx context.Context, id string) map[string]interface{} { + r, err := s.redis.Ctx(ctx).DoVar("HGETALL", s.key(id)) if err != nil { return nil } @@ -71,21 +72,21 @@ func (s *StorageRedisHashTable) GetMap(id string) map[string]interface{} { } // GetSize retrieves the size of key-value pairs from storage. -func (s *StorageRedisHashTable) GetSize(id string) int { - r, _ := s.redis.DoVar("HLEN", s.key(id)) +func (s *StorageRedisHashTable) GetSize(ctx context.Context, id string) int { + r, _ := s.redis.Ctx(ctx).DoVar("HLEN", s.key(id)) return r.Int() } // Set sets key-value session pair to the storage. // The parameter specifies the TTL for the session id (not for the key-value pair). -func (s *StorageRedisHashTable) Set(id string, key string, value interface{}, ttl time.Duration) error { - _, err := s.redis.Do("HSET", s.key(id), key, value) +func (s *StorageRedisHashTable) Set(ctx context.Context, id string, key string, value interface{}, ttl time.Duration) error { + _, err := s.redis.Ctx(ctx).Do("HSET", s.key(id), key, value) return err } // SetMap batch sets key-value session pairs with map to the storage. // The parameter specifies the TTL for the session id(not for the key-value pair). -func (s *StorageRedisHashTable) SetMap(id string, data map[string]interface{}, ttl time.Duration) error { +func (s *StorageRedisHashTable) SetMap(ctx context.Context, id string, data map[string]interface{}, ttl time.Duration) error { array := make([]interface{}, len(data)*2+1) array[0] = s.key(id) @@ -95,19 +96,19 @@ func (s *StorageRedisHashTable) SetMap(id string, data map[string]interface{}, t array[index+1] = v index += 2 } - _, err := s.redis.Do("HMSET", array...) + _, err := s.redis.Ctx(ctx).Do("HMSET", array...) return err } // Remove deletes key with its value from storage. -func (s *StorageRedisHashTable) Remove(id string, key string) error { - _, err := s.redis.Do("HDEL", s.key(id), key) +func (s *StorageRedisHashTable) Remove(ctx context.Context, id string, key string) error { + _, err := s.redis.Ctx(ctx).Do("HDEL", s.key(id), key) return err } // RemoveAll deletes all key-value pairs from storage. -func (s *StorageRedisHashTable) RemoveAll(id string) error { - _, err := s.redis.Do("DEL", s.key(id)) +func (s *StorageRedisHashTable) RemoveAll(ctx context.Context, id string) error { + _, err := s.redis.Ctx(ctx).Do("DEL", s.key(id)) return err } @@ -118,9 +119,9 @@ func (s *StorageRedisHashTable) RemoveAll(id string) error { // and for some storage it might be nil if memory storage is disabled. // // This function is called ever when session starts. -func (s *StorageRedisHashTable) GetSession(id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) { - intlog.Printf("StorageRedisHashTable.GetSession: %s, %v", id, ttl) - r, err := s.redis.DoVar("EXISTS", s.key(id)) +func (s *StorageRedisHashTable) GetSession(ctx context.Context, id string, ttl time.Duration, data *gmap.StrAnyMap) (*gmap.StrAnyMap, error) { + intlog.Printf(ctx, "StorageRedisHashTable.GetSession: %s, %v", id, ttl) + r, err := s.redis.Ctx(ctx).DoVar("EXISTS", s.key(id)) if err != nil { return nil, err } @@ -133,17 +134,17 @@ func (s *StorageRedisHashTable) GetSession(id string, ttl time.Duration, data *g // SetSession updates the data map for specified session id. // This function is called ever after session, which is changed dirty, is closed. // This copy all session data map from memory to storage. -func (s *StorageRedisHashTable) SetSession(id string, data *gmap.StrAnyMap, ttl time.Duration) error { - intlog.Printf("StorageRedisHashTable.SetSession: %s, %v", id, ttl) - _, err := s.redis.Do("EXPIRE", s.key(id), int64(ttl.Seconds())) +func (s *StorageRedisHashTable) SetSession(ctx context.Context, id string, data *gmap.StrAnyMap, ttl time.Duration) error { + intlog.Printf(ctx, "StorageRedisHashTable.SetSession: %s, %v", id, ttl) + _, err := s.redis.Ctx(ctx).Do("EXPIRE", s.key(id), int64(ttl.Seconds())) return err } // UpdateTTL updates the TTL for specified session id. // This function is called ever after session, which is not dirty, is closed. // It just adds the session id to the async handling queue. -func (s *StorageRedisHashTable) UpdateTTL(id string, ttl time.Duration) error { - intlog.Printf("StorageRedisHashTable.UpdateTTL: %s, %v", id, ttl) +func (s *StorageRedisHashTable) UpdateTTL(ctx context.Context, id string, ttl time.Duration) error { + intlog.Printf(ctx, "StorageRedisHashTable.UpdateTTL: %s, %v", id, ttl) _, err := s.redis.Do("EXPIRE", s.key(id), int64(ttl.Seconds())) return err } diff --git a/os/gsession/gsession_unit_storage_file_test.go b/os/gsession/gsession_unit_storage_file_test.go index edd872b06..3a7c7ebde 100644 --- a/os/gsession/gsession_unit_storage_file_test.go +++ b/os/gsession/gsession_unit_storage_file_test.go @@ -7,6 +7,7 @@ package gsession_test import ( + "context" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gsession" "testing" @@ -20,7 +21,7 @@ func Test_StorageFile(t *testing.T) { manager := gsession.New(time.Second, storage) sessionId := "" gtest.C(t, func(t *gtest.T) { - s := manager.New() + s := manager.New(context.TODO()) defer s.Close() s.Set("k1", "v1") s.Set("k2", "v2") @@ -34,7 +35,7 @@ func Test_StorageFile(t *testing.T) { time.Sleep(500 * time.Millisecond) gtest.C(t, func(t *gtest.T) { - s := manager.New(sessionId) + s := manager.New(context.TODO(), sessionId) t.Assert(s.Get("k1"), "v1") t.Assert(s.Get("k2"), "v2") t.Assert(s.Get("k3"), "v3") @@ -66,7 +67,7 @@ func Test_StorageFile(t *testing.T) { time.Sleep(1000 * time.Millisecond) gtest.C(t, func(t *gtest.T) { - s := manager.New(sessionId) + s := manager.New(context.TODO(), sessionId) t.Assert(s.Size(), 0) t.Assert(s.Get("k5"), nil) t.Assert(s.Get("k6"), nil) diff --git a/os/gsession/gsession_unit_storage_memory_test.go b/os/gsession/gsession_unit_storage_memory_test.go index 054e9948d..c42413d34 100644 --- a/os/gsession/gsession_unit_storage_memory_test.go +++ b/os/gsession/gsession_unit_storage_memory_test.go @@ -7,6 +7,7 @@ package gsession_test import ( + "context" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gsession" "testing" @@ -20,7 +21,7 @@ func Test_StorageMemory(t *testing.T) { manager := gsession.New(time.Second, storage) sessionId := "" gtest.C(t, func(t *gtest.T) { - s := manager.New() + s := manager.New(context.TODO()) defer s.Close() s.Set("k1", "v1") s.Set("k2", "v2") @@ -34,7 +35,7 @@ func Test_StorageMemory(t *testing.T) { time.Sleep(500 * time.Millisecond) gtest.C(t, func(t *gtest.T) { - s := manager.New(sessionId) + s := manager.New(context.TODO(), sessionId) t.Assert(s.Get("k1"), "v1") t.Assert(s.Get("k2"), "v2") t.Assert(s.Get("k3"), "v3") @@ -66,7 +67,7 @@ func Test_StorageMemory(t *testing.T) { time.Sleep(1000 * time.Millisecond) gtest.C(t, func(t *gtest.T) { - s := manager.New(sessionId) + s := manager.New(context.TODO(), sessionId) t.Assert(s.Size(), 0) t.Assert(s.Get("k5"), nil) t.Assert(s.Get("k6"), nil) diff --git a/os/gsession/gsession_unit_storage_redis_hashtable_test.go b/os/gsession/gsession_unit_storage_redis_hashtable_test.go index 6ce58ef38..20d7ff082 100644 --- a/os/gsession/gsession_unit_storage_redis_hashtable_test.go +++ b/os/gsession/gsession_unit_storage_redis_hashtable_test.go @@ -7,6 +7,7 @@ package gsession_test import ( + "context" "github.com/gogf/gf/database/gredis" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gsession" @@ -26,7 +27,7 @@ func Test_StorageRedisHashTable(t *testing.T) { manager := gsession.New(time.Second, storage) sessionId := "" gtest.C(t, func(t *gtest.T) { - s := manager.New() + s := manager.New(context.TODO()) defer s.Close() s.Set("k1", "v1") s.Set("k2", "v2") @@ -38,7 +39,7 @@ func Test_StorageRedisHashTable(t *testing.T) { sessionId = s.Id() }) gtest.C(t, func(t *gtest.T) { - s := manager.New(sessionId) + s := manager.New(context.TODO(), sessionId) t.Assert(s.Get("k1"), "v1") t.Assert(s.Get("k2"), "v2") t.Assert(s.Get("k3"), "v3") @@ -71,7 +72,7 @@ func Test_StorageRedisHashTable(t *testing.T) { time.Sleep(1500 * time.Millisecond) gtest.C(t, func(t *gtest.T) { - s := manager.New(sessionId) + s := manager.New(context.TODO(), sessionId) t.Assert(s.Size(), 0) t.Assert(s.Get("k5"), nil) t.Assert(s.Get("k6"), nil) @@ -89,7 +90,7 @@ func Test_StorageRedisHashTablePrefix(t *testing.T) { manager := gsession.New(time.Second, storage) sessionId := "" gtest.C(t, func(t *gtest.T) { - s := manager.New() + s := manager.New(context.TODO()) defer s.Close() s.Set("k1", "v1") s.Set("k2", "v2") @@ -101,7 +102,7 @@ func Test_StorageRedisHashTablePrefix(t *testing.T) { sessionId = s.Id() }) gtest.C(t, func(t *gtest.T) { - s := manager.New(sessionId) + s := manager.New(context.TODO(), sessionId) t.Assert(s.Get("k1"), "v1") t.Assert(s.Get("k2"), "v2") t.Assert(s.Get("k3"), "v3") @@ -134,7 +135,7 @@ func Test_StorageRedisHashTablePrefix(t *testing.T) { time.Sleep(1500 * time.Millisecond) gtest.C(t, func(t *gtest.T) { - s := manager.New(sessionId) + s := manager.New(context.TODO(), sessionId) t.Assert(s.Size(), 0) t.Assert(s.Get("k5"), nil) t.Assert(s.Get("k6"), nil) diff --git a/os/gsession/gsession_unit_storage_redis_test.go b/os/gsession/gsession_unit_storage_redis_test.go index f0fd9f3b2..53a5e754b 100644 --- a/os/gsession/gsession_unit_storage_redis_test.go +++ b/os/gsession/gsession_unit_storage_redis_test.go @@ -7,6 +7,7 @@ package gsession_test import ( + "context" "github.com/gogf/gf/database/gredis" "github.com/gogf/gf/frame/g" "github.com/gogf/gf/os/gsession" @@ -24,7 +25,7 @@ func Test_StorageRedis(t *testing.T) { manager := gsession.New(time.Second, storage) sessionId := "" gtest.C(t, func(t *gtest.T) { - s := manager.New() + s := manager.New(context.TODO()) defer s.Close() s.Set("k1", "v1") s.Set("k2", "v2") @@ -38,7 +39,7 @@ func Test_StorageRedis(t *testing.T) { time.Sleep(500 * time.Millisecond) gtest.C(t, func(t *gtest.T) { - s := manager.New(sessionId) + s := manager.New(context.TODO(), sessionId) t.Assert(s.Get("k1"), "v1") t.Assert(s.Get("k2"), "v2") t.Assert(s.Get("k3"), "v3") @@ -70,7 +71,7 @@ func Test_StorageRedis(t *testing.T) { time.Sleep(1000 * time.Millisecond) gtest.C(t, func(t *gtest.T) { - s := manager.New(sessionId) + s := manager.New(context.TODO(), sessionId) t.Assert(s.Size(), 0) t.Assert(s.Get("k5"), nil) t.Assert(s.Get("k6"), nil) @@ -86,7 +87,7 @@ func Test_StorageRedisPrefix(t *testing.T) { manager := gsession.New(time.Second, storage) sessionId := "" gtest.C(t, func(t *gtest.T) { - s := manager.New() + s := manager.New(context.TODO()) defer s.Close() s.Set("k1", "v1") s.Set("k2", "v2") @@ -100,7 +101,7 @@ func Test_StorageRedisPrefix(t *testing.T) { time.Sleep(500 * time.Millisecond) gtest.C(t, func(t *gtest.T) { - s := manager.New(sessionId) + s := manager.New(context.TODO(), sessionId) t.Assert(s.Get("k1"), "v1") t.Assert(s.Get("k2"), "v2") t.Assert(s.Get("k3"), "v3") @@ -132,7 +133,7 @@ func Test_StorageRedisPrefix(t *testing.T) { time.Sleep(1000 * time.Millisecond) gtest.C(t, func(t *gtest.T) { - s := manager.New(sessionId) + s := manager.New(context.TODO(), sessionId) t.Assert(s.Size(), 0) t.Assert(s.Get("k5"), nil) t.Assert(s.Get("k6"), nil) diff --git a/os/gspath/gspath.go b/os/gspath/gspath.go index d17ce2658..ca3c7c290 100644 --- a/os/gspath/gspath.go +++ b/os/gspath/gspath.go @@ -12,6 +12,7 @@ package gspath import ( + "context" "errors" "fmt" "github.com/gogf/gf/internal/intlog" @@ -113,7 +114,7 @@ func (sp *SPath) Set(path string) (realPath string, err error) { sp.removeMonitorByPath(v) } } - intlog.Print("paths clear:", sp.paths) + intlog.Print(context.TODO(), "paths clear:", sp.paths) sp.paths.Clear() if sp.cache != nil { sp.cache.Clear() diff --git a/os/gview/gview.go b/os/gview/gview.go index 26dbd393e..1b072f6e3 100644 --- a/os/gview/gview.go +++ b/os/gview/gview.go @@ -72,14 +72,14 @@ func New(path ...string) *View { } if len(path) > 0 && len(path[0]) > 0 { if err := view.SetPath(path[0]); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } } else { // Customized dir path from env/cmd. if envPath := gcmd.GetOptWithEnv(commandEnvKeyForPath).String(); envPath != "" { if gfile.Exists(envPath) { if err := view.SetPath(envPath); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } } else { if errorPrint() { @@ -89,18 +89,18 @@ func New(path ...string) *View { } else { // Dir path of working dir. if err := view.SetPath(gfile.Pwd()); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } // Dir path of binary. if selfPath := gfile.SelfDir(); selfPath != "" && gfile.Exists(selfPath) { if err := view.AddPath(selfPath); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } } // Dir path of main package. if mainPath := gfile.MainPkgPath(); mainPath != "" && gfile.Exists(mainPath) { if err := view.AddPath(mainPath); err != nil { - intlog.Error(err) + intlog.Error(context.TODO(), err) } } } diff --git a/os/gview/gview_config.go b/os/gview/gview_config.go index 508344a0a..4e68da421 100644 --- a/os/gview/gview_config.go +++ b/os/gview/gview_config.go @@ -7,6 +7,7 @@ package gview import ( + "context" "errors" "fmt" "github.com/gogf/gf/i18n/gi18n" @@ -67,7 +68,7 @@ func (view *View) SetConfig(config Config) error { // It's just cache, do not hesitate clearing it. templates.Clear() - intlog.Printf("SetConfig: %+v", view.config) + intlog.Printf(context.TODO(), "SetConfig: %+v", view.config) return nil } diff --git a/os/gview/gview_parse.go b/os/gview/gview_parse.go index f69d7e08b..e7675413a 100644 --- a/os/gview/gview_parse.go +++ b/os/gview/gview_parse.go @@ -83,7 +83,7 @@ func (view *View) Parse(ctx context.Context, file string, params ...Params) (res templates.Clear() gfsnotify.Exit() }); err != nil { - intlog.Error(err) + intlog.Error(ctx, err) } } return &fileCacheItem{ diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index be6b027ac..eb3480a24 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -46,238 +46,254 @@ var ( StructTagPriority = []string{"gconv", "param", "params", "c", "p", "json"} ) -// Convert converts the variable `any` to the type `t`, the type `t` is specified by string. -// The optional parameter `params` is used for additional necessary parameter for this conversion. -// It supports common types conversion as its conversion based on type name string. -func Convert(any interface{}, t string, params ...interface{}) interface{} { - switch t { +type doConvertInput struct { + FromValue interface{} // Value that is converted from. + ToTypeName string // Target value type name in string. + ReferValue interface{} // Referred value, a value in type `ToTypeName`. + Extra []interface{} // Extra values for implementing the converting. +} + +func doConvert(input doConvertInput) interface{} { + switch input.ToTypeName { case "int": - return Int(any) + return Int(input.FromValue) case "*int": - if _, ok := any.(*int); ok { - return any + if _, ok := input.FromValue.(*int); ok { + return input.FromValue } - v := Int(any) + v := Int(input.FromValue) return &v case "int8": - return Int8(any) + return Int8(input.FromValue) case "*int8": - if _, ok := any.(*int8); ok { - return any + if _, ok := input.FromValue.(*int8); ok { + return input.FromValue } - v := Int8(any) + v := Int8(input.FromValue) return &v case "int16": - return Int16(any) + return Int16(input.FromValue) case "*int16": - if _, ok := any.(*int16); ok { - return any + if _, ok := input.FromValue.(*int16); ok { + return input.FromValue } - v := Int16(any) + v := Int16(input.FromValue) return &v case "int32": - return Int32(any) + return Int32(input.FromValue) case "*int32": - if _, ok := any.(*int32); ok { - return any + if _, ok := input.FromValue.(*int32); ok { + return input.FromValue } - v := Int32(any) + v := Int32(input.FromValue) return &v case "int64": - return Int64(any) + return Int64(input.FromValue) case "*int64": - if _, ok := any.(*int64); ok { - return any + if _, ok := input.FromValue.(*int64); ok { + return input.FromValue } - v := Int64(any) + v := Int64(input.FromValue) return &v case "uint": - return Uint(any) + return Uint(input.FromValue) case "*uint": - if _, ok := any.(*uint); ok { - return any + if _, ok := input.FromValue.(*uint); ok { + return input.FromValue } - v := Uint(any) + v := Uint(input.FromValue) return &v case "uint8": - return Uint8(any) + return Uint8(input.FromValue) case "*uint8": - if _, ok := any.(*uint8); ok { - return any + if _, ok := input.FromValue.(*uint8); ok { + return input.FromValue } - v := Uint8(any) + v := Uint8(input.FromValue) return &v case "uint16": - return Uint16(any) + return Uint16(input.FromValue) case "*uint16": - if _, ok := any.(*uint16); ok { - return any + if _, ok := input.FromValue.(*uint16); ok { + return input.FromValue } - v := Uint16(any) + v := Uint16(input.FromValue) return &v case "uint32": - return Uint32(any) + return Uint32(input.FromValue) case "*uint32": - if _, ok := any.(*uint32); ok { - return any + if _, ok := input.FromValue.(*uint32); ok { + return input.FromValue } - v := Uint32(any) + v := Uint32(input.FromValue) return &v case "uint64": - return Uint64(any) + return Uint64(input.FromValue) case "*uint64": - if _, ok := any.(*uint64); ok { - return any + if _, ok := input.FromValue.(*uint64); ok { + return input.FromValue } - v := Uint64(any) + v := Uint64(input.FromValue) return &v case "float32": - return Float32(any) + return Float32(input.FromValue) case "*float32": - if _, ok := any.(*float32); ok { - return any + if _, ok := input.FromValue.(*float32); ok { + return input.FromValue } - v := Float32(any) + v := Float32(input.FromValue) return &v case "float64": - return Float64(any) + return Float64(input.FromValue) case "*float64": - if _, ok := any.(*float64); ok { - return any + if _, ok := input.FromValue.(*float64); ok { + return input.FromValue } - v := Float64(any) + v := Float64(input.FromValue) return &v case "bool": - return Bool(any) + return Bool(input.FromValue) case "*bool": - if _, ok := any.(*bool); ok { - return any + if _, ok := input.FromValue.(*bool); ok { + return input.FromValue } - v := Bool(any) + v := Bool(input.FromValue) return &v case "string": - return String(any) + return String(input.FromValue) case "*string": - if _, ok := any.(*string); ok { - return any + if _, ok := input.FromValue.(*string); ok { + return input.FromValue } - v := String(any) + v := String(input.FromValue) return &v case "[]byte": - return Bytes(any) + return Bytes(input.FromValue) case "[]int": - return Ints(any) + return Ints(input.FromValue) case "[]int32": - return Int32s(any) + return Int32s(input.FromValue) case "[]int64": - return Int64s(any) + return Int64s(input.FromValue) case "[]uint": - return Uints(any) + return Uints(input.FromValue) case "[]uint32": - return Uint32s(any) + return Uint32s(input.FromValue) case "[]uint64": - return Uint64s(any) + return Uint64s(input.FromValue) case "[]float32": - return Float32s(any) + return Float32s(input.FromValue) case "[]float64": - return Float64s(any) + return Float64s(input.FromValue) case "[]string": - return Strings(any) + return Strings(input.FromValue) case "Time", "time.Time": - if len(params) > 0 { - return Time(any, String(params[0])) + if len(input.Extra) > 0 { + return Time(input.FromValue, String(input.Extra[0])) } - return Time(any) + return Time(input.FromValue) case "*time.Time": var v interface{} - if len(params) > 0 { - v = Time(any, String(params[0])) + if len(input.Extra) > 0 { + v = Time(input.FromValue, String(input.Extra[0])) } else { - if _, ok := any.(*time.Time); ok { - return any + if _, ok := input.FromValue.(*time.Time); ok { + return input.FromValue } - v = Time(any) + v = Time(input.FromValue) } return &v case "GTime", "gtime.Time": - if len(params) > 0 { - if v := GTime(any, String(params[0])); v != nil { + if len(input.Extra) > 0 { + if v := GTime(input.FromValue, String(input.Extra[0])); v != nil { return *v } else { return *gtime.New() } } - if v := GTime(any); v != nil { + if v := GTime(input.FromValue); v != nil { return *v } else { return *gtime.New() } case "*gtime.Time": - if len(params) > 0 { - if v := GTime(any, String(params[0])); v != nil { + if len(input.Extra) > 0 { + if v := GTime(input.FromValue, String(input.Extra[0])); v != nil { return v } else { return gtime.New() } } - if v := GTime(any); v != nil { + if v := GTime(input.FromValue); v != nil { return v } else { return gtime.New() } case "Duration", "time.Duration": - return Duration(any) + return Duration(input.FromValue) case "*time.Duration": - if _, ok := any.(*time.Duration); ok { - return any + if _, ok := input.FromValue.(*time.Duration); ok { + return input.FromValue } - v := Duration(any) + v := Duration(input.FromValue) return &v case "map[string]string": - return MapStrStr(any) + return MapStrStr(input.FromValue) case "map[string]interface{}": - return Map(any) + return Map(input.FromValue) case "[]map[string]interface{}": - return Maps(any) - - //case "gvar.Var": - // // TODO remove reflect usage to create gvar.Var, considering using unsafe pointer - // rv := reflect.New(intstore.ReflectTypeVarImp) - // ri := rv.Interface() - // if v, ok := ri.(apiSet); ok { - // v.Set(any) - // } else if v, ok := ri.(apiUnmarshalValue); ok { - // v.UnmarshalValue(any) - // } else { - // rv.Set(reflect.ValueOf(any)) - // } - // return ri + return Maps(input.FromValue) default: - return any + if input.ReferValue != nil { + var ( + referReflectValue reflect.Value + ) + if v, ok := input.ReferValue.(reflect.Value); ok { + referReflectValue = v + } else { + referReflectValue = reflect.ValueOf(input.ReferValue) + } + input.ToTypeName = referReflectValue.Kind().String() + input.ReferValue = nil + return doConvert(input) + } + return input.FromValue } } +// Convert converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string. +// The optional parameter `extraParams` is used for additional necessary parameter for this conversion. +// It supports common types conversion as its conversion based on type name string. +func Convert(fromValue interface{}, toTypeName string, extraParams ...interface{}) interface{} { + return doConvert(doConvertInput{ + FromValue: fromValue, + ToTypeName: toTypeName, + ReferValue: nil, + Extra: extraParams, + }) +} + // Byte converts `any` to byte. func Byte(any interface{}) byte { if v, ok := any.(byte); ok { diff --git a/util/gconv/gconv_map.go b/util/gconv/gconv_map.go index 6685433b2..f2878ce56 100644 --- a/util/gconv/gconv_map.go +++ b/util/gconv/gconv_map.go @@ -166,7 +166,7 @@ func doMapConvert(value interface{}, recursive bool, tags ...string) map[string] dataMap[String(reflectValue.Index(i).Interface())] = nil } } - case reflect.Map, reflect.Struct: + case reflect.Map, reflect.Struct, reflect.Interface: convertedValue := doMapConvertForMapOrStructValue(true, value, recursive, newTags...) if m, ok := convertedValue.(map[string]interface{}); ok { return m diff --git a/util/gconv/gconv_scan.go b/util/gconv/gconv_scan.go index 4b481057b..1dd76832a 100644 --- a/util/gconv/gconv_scan.go +++ b/util/gconv/gconv_scan.go @@ -32,6 +32,7 @@ func Scan(params interface{}, pointer interface{}, mapping ...map[string]string) switch pointerElemKind { case reflect.Map: return MapToMap(params, pointer, mapping...) + case reflect.Array, reflect.Slice: var ( sliceElem = pointerElem.Elem() diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index 09920e1f6..354905ad2 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -107,6 +107,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string var ( paramsReflectValue reflect.Value + paramsInterface interface{} // DO NOT use `params` directly as it might be type of `reflect.Value` pointerReflectValue reflect.Value pointerReflectKind reflect.Kind pointerElemReflectValue reflect.Value // The pointed element. @@ -116,6 +117,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string } else { paramsReflectValue = reflect.ValueOf(params) } + paramsInterface = paramsReflectValue.Interface() if v, ok := pointer.(reflect.Value); ok { pointerReflectValue = v pointerElemReflectValue = v @@ -139,7 +141,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string } // Normal unmarshalling interfaces checks. - if err, ok := bindVarToReflectValueWithInterfaceCheck(pointerReflectValue, params); ok { + if err, ok := bindVarToReflectValueWithInterfaceCheck(pointerReflectValue, paramsInterface); ok { return err } @@ -154,7 +156,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string // return v.UnmarshalValue(params) //} // Note that it's `pointerElemReflectValue` here not `pointerReflectValue`. - if err, ok := bindVarToReflectValueWithInterfaceCheck(pointerElemReflectValue, params); ok { + if err, ok := bindVarToReflectValueWithInterfaceCheck(pointerElemReflectValue, paramsInterface); ok { return err } // Retrieve its element, may be struct at last. @@ -163,7 +165,7 @@ func doStruct(params interface{}, pointer interface{}, mapping map[string]string // paramsMap is the map[string]interface{} type variable for params. // DO NOT use MapDeep here. - paramsMap := Map(params) + paramsMap := Map(paramsInterface) if paramsMap == nil { return gerror.Newf("convert params to map failed: %v", params) } @@ -304,7 +306,7 @@ func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, map return nil } defer func() { - if e := recover(); e != nil { + if exception := recover(); exception != nil { if err = bindVarToReflectValue(structFieldValue, value, mapping, priorityTag); err != nil { err = gerror.Wrapf(err, `error binding value to attribute "%s"`, name) } @@ -314,7 +316,13 @@ func bindVarToStructAttr(elem reflect.Value, name string, value interface{}, map if empty.IsNil(value) { structFieldValue.Set(reflect.Zero(structFieldValue.Type())) } else { - structFieldValue.Set(reflect.ValueOf(Convert(value, structFieldValue.Type().String()))) + structFieldValue.Set(reflect.ValueOf(doConvert( + doConvertInput{ + FromValue: value, + ToTypeName: structFieldValue.Type().String(), + ReferValue: structFieldValue, + }, + ))) } return nil } @@ -335,9 +343,11 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value i } pointer = reflectValue.Interface() } + // UnmarshalValue. if v, ok := pointer.(apiUnmarshalValue); ok { return v.UnmarshalValue(value), ok } + // UnmarshalText. if v, ok := pointer.(apiUnmarshalText); ok { if s, ok := value.(string); ok { return v.UnmarshalText([]byte(s)), ok @@ -450,11 +460,12 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, ma default: defer func() { - if e := recover(); e != nil { + if exception := recover(); exception != nil { err = gerror.New( - fmt.Sprintf(`cannot convert value "%+v" to type "%s"`, + fmt.Sprintf(`cannot convert value "%+v" to type "%s":%+v`, value, structFieldValue.Type().String(), + exception, ), ) } diff --git a/util/gconv/gconv_structs.go b/util/gconv/gconv_structs.go index 8d3626d36..d8aafef79 100644 --- a/util/gconv/gconv_structs.go +++ b/util/gconv/gconv_structs.go @@ -100,13 +100,34 @@ func doStructs(params interface{}, pointer interface{}, mapping map[string]strin } } // Converting `params` to map slice. - paramsMaps := Maps(params) + var ( + paramsList []interface{} + paramsRv = reflect.ValueOf(params) + paramsKind = paramsRv.Kind() + ) + for paramsKind == reflect.Ptr { + paramsRv = paramsRv.Elem() + paramsKind = paramsRv.Kind() + } + switch paramsKind { + case reflect.Slice, reflect.Array: + paramsList = make([]interface{}, paramsRv.Len()) + for i := 0; i < paramsRv.Len(); i++ { + paramsList[i] = paramsRv.Index(i) + } + default: + var paramsMaps = Maps(params) + paramsList = make([]interface{}, len(paramsMaps)) + for i := 0; i < len(paramsMaps); i++ { + paramsList[i] = paramsMaps[i] + } + } // If `params` is an empty slice, no conversion. - if len(paramsMaps) == 0 { + if len(paramsList) == 0 { return nil } var ( - reflectElemArray = reflect.MakeSlice(pointerRv.Type().Elem(), len(paramsMaps), len(paramsMaps)) + reflectElemArray = reflect.MakeSlice(pointerRv.Type().Elem(), len(paramsList), len(paramsList)) itemType = reflectElemArray.Index(0).Type() itemTypeKind = itemType.Kind() pointerRvElem = pointerRv.Elem() @@ -114,7 +135,7 @@ func doStructs(params interface{}, pointer interface{}, mapping map[string]strin ) if itemTypeKind == reflect.Ptr { // Pointer element. - for i := 0; i < len(paramsMaps); i++ { + for i := 0; i < len(paramsList); i++ { var tempReflectValue reflect.Value if i < pointerRvLength { // Might be nil. @@ -123,21 +144,21 @@ func doStructs(params interface{}, pointer interface{}, mapping map[string]strin if !tempReflectValue.IsValid() { tempReflectValue = reflect.New(itemType.Elem()).Elem() } - if err = doStruct(paramsMaps[i], tempReflectValue, mapping, priorityTag); err != nil { + if err = doStruct(paramsList[i], tempReflectValue, mapping, priorityTag); err != nil { return err } reflectElemArray.Index(i).Set(tempReflectValue.Addr()) } } else { // Struct element. - for i := 0; i < len(paramsMaps); i++ { + for i := 0; i < len(paramsList); i++ { var tempReflectValue reflect.Value if i < pointerRvLength { tempReflectValue = pointerRvElem.Index(i) } else { tempReflectValue = reflect.New(itemType).Elem() } - if err = doStruct(paramsMaps[i], tempReflectValue, mapping, priorityTag); err != nil { + if err = doStruct(paramsList[i], tempReflectValue, mapping, priorityTag); err != nil { return err } reflectElemArray.Index(i).Set(tempReflectValue) diff --git a/util/gconv/gconv_z_unit_scan_test.go b/util/gconv/gconv_z_unit_scan_test.go index d80448818..541baf7dc 100644 --- a/util/gconv/gconv_z_unit_scan_test.go +++ b/util/gconv/gconv_z_unit_scan_test.go @@ -58,7 +58,7 @@ func Test_Scan_StructStructs(t *testing.T) { } ) err := gconv.Scan(params, &users) - t.Assert(err, nil) + t.AssertNil(err) t.Assert(users, g.Slice{ &User{ Uid: 1,