From f1f575fd5cb01364de45da1d69aa15f6ca857876 Mon Sep 17 00:00:00 2001 From: John Date: Sat, 28 Mar 2020 00:37:23 +0800 Subject: [PATCH] improve package gins/gfile/intlog --- .example/other/config.toml | 6 ++ .example/other/test.go | 36 ++++++--- container/gvar/gvar.go | 5 ++ debug/gdebug/gdebug_testdata.go | 2 +- .../gjson/gjson_z_example_pattern_test.go | 28 +++++++ errors/gerror/gerror_error.go | 2 +- internal/intlog/intlog.go | 10 ++- os/gcfg/gcfg_z_example_pattern_test.go | 47 +++++++++++ os/gfile/gfile.go | 60 +++----------- os/gfile/gfile_home.go | 80 +++++++++++++++++++ os/glog/glog_logger_config.go | 3 + os/gview/gview_config.go | 3 + text/gregex/gregex_z_bench_test.go | 8 +- util/gutil/gutil_map.go | 6 +- util/gutil/gutil_slice.go | 15 ++++ 15 files changed, 240 insertions(+), 71 deletions(-) create mode 100644 os/gcfg/gcfg_z_example_pattern_test.go create mode 100644 os/gfile/gfile_home.go create mode 100644 util/gutil/gutil_slice.go diff --git a/.example/other/config.toml b/.example/other/config.toml index 8dea1312e..de8af20fe 100644 --- a/.example/other/config.toml +++ b/.example/other/config.toml @@ -7,6 +7,12 @@ default = "127.0.0.1:6379,0" cache = "127.0.0.1:6379,1" +# Logger. +[logger] + Path = "/tmp/log/gf-app" + Level = "all" + Stdout = true + [viewer] delimiters = ["${", "}"] autoencode = true \ No newline at end of file diff --git a/.example/other/test.go b/.example/other/test.go index dc663f15f..d9dc550f4 100644 --- a/.example/other/test.go +++ b/.example/other/test.go @@ -2,18 +2,30 @@ package main import ( "github.com/gogf/gf/frame/g" - "github.com/gogf/gf/net/ghttp" + "github.com/gogf/gf/frame/gins" + "github.com/gogf/gf/os/glog" ) -func main() { - //g.Server().Run() - s := g.Server() - s.BindHandler("/aaa", func(r *ghttp.Request) { - r.Cookie.Set("theme", "default") - r.Session.Set("name", "john") - content := `Config:{{.Config.redis.cache}}, Cookie:{{.Cookie.theme}}, Session:{{.Session.name}}, Query:{{.Query.name}}` - r.Response.WriteTplContent(content, nil) - }) - s.SetPort(8199) - s.Run() +func getNameLogger(name, path string) *glog.Logger { + inst := gins.Get(name) + if inst == nil { + logger := g.Log(name) + logConf := map[string]interface{}{ + "Path": path, + "Level": "ALL", + } + if err := logger.SetConfigWithMap(logConf); err != nil { + panic(err) + } + return logger + } + return inst.(*glog.Logger) +} + +func main() { + alog := getNameLogger("logger.日志1", "c:/logger1") + alog.Print(1) + + blog := getNameLogger("logger.日志2", "c:/logger2") + blog.Print(2) } diff --git a/container/gvar/gvar.go b/container/gvar/gvar.go index 1d4c87934..fb8349d29 100644 --- a/container/gvar/gvar.go +++ b/container/gvar/gvar.go @@ -46,6 +46,11 @@ func Create(value interface{}, safe ...bool) Var { return v } +// Clone does a shallow copy of current Var and returns a pointer to this Var. +func (v *Var) Clone() *Var { + return New(v.Val(), v.safe) +} + // Set sets to , and returns the old value. func (v *Var) Set(value interface{}) (old interface{}) { if v.safe { diff --git a/debug/gdebug/gdebug_testdata.go b/debug/gdebug/gdebug_testdata.go index d16705f39..f0be40a72 100644 --- a/debug/gdebug/gdebug_testdata.go +++ b/debug/gdebug/gdebug_testdata.go @@ -12,7 +12,7 @@ import ( // TestDataPath retrieves and returns the testdata path of current package, // which is used for unit testing cases only. -// The parameter specifies the its sub-folders/sub-files, +// The optional parameter specifies the its sub-folders/sub-files, // which will be joined with current system separator and returned with the path. func TestDataPath(names ...string) string { path := CallerDirectory() + string(filepath.Separator) + "testdata" diff --git a/encoding/gjson/gjson_z_example_pattern_test.go b/encoding/gjson/gjson_z_example_pattern_test.go index ff0911009..9af658333 100644 --- a/encoding/gjson/gjson_z_example_pattern_test.go +++ b/encoding/gjson/gjson_z_example_pattern_test.go @@ -69,3 +69,31 @@ func Example_patternViolenceCheck() { // Output: // Users Count: 101 } + +func Example_mapSliceChange() { + jsonContent := `{"map":{"key":"value"}, "slice":[59,90]}` + j, _ := gjson.LoadJson(jsonContent) + m := j.GetMap("map") + fmt.Println(m) + + // Change the key-value pair. + m["key"] = "john" + + // It changes the underlying key-value pair. + fmt.Println(j.GetMap("map")) + + s := j.GetArray("slice") + fmt.Println(s) + + // Change the value of specified index. + s[0] = 100 + + // It changes the underlying slice. + fmt.Println(j.GetArray("slice")) + + // output: + // map[key:value] + // map[key:john] + // [59 90] + // [100 90] +} diff --git a/errors/gerror/gerror_error.go b/errors/gerror/gerror_error.go index 462b85662..7a743014a 100644 --- a/errors/gerror/gerror_error.go +++ b/errors/gerror/gerror_error.go @@ -132,7 +132,7 @@ func formatSubStack(st stack, buffer *bytes.Buffer) { continue } // Avoid GF stacks if not in GF development. - if !intlog.IsGFDebug() { + if !intlog.IsEnabled() { if strings.Contains(file, "github.com/gogf/gf/") { continue } diff --git a/internal/intlog/intlog.go b/internal/intlog/intlog.go index 221084dd9..c91ca11ec 100644 --- a/internal/intlog/intlog.go +++ b/internal/intlog/intlog.go @@ -31,8 +31,14 @@ func init() { } } -// IsGFDebug checks and returns whether current process is in GF development. -func IsGFDebug() bool { +// SetEnabled enables/disables the internal logging manually. +// Note that this function is not current safe, be aware of the DATA RACE. +func SetEnabled(enabled bool) { + isGFDebug = enabled +} + +// IsEnabled checks and returns whether current process is in GF development. +func IsEnabled() bool { return isGFDebug } diff --git a/os/gcfg/gcfg_z_example_pattern_test.go b/os/gcfg/gcfg_z_example_pattern_test.go new file mode 100644 index 000000000..9616cd85c --- /dev/null +++ b/os/gcfg/gcfg_z_example_pattern_test.go @@ -0,0 +1,47 @@ +// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gcfg_test + +import ( + "fmt" + "github.com/gogf/gf/frame/g" + "github.com/gogf/gf/internal/intlog" + "github.com/gogf/gf/os/gcfg" +) + +func Example_mapSliceChange() { + intlog.SetEnabled(false) + defer intlog.SetEnabled(true) + // For testing/example only. + content := `{"map":{"key":"value"}, "slice":[59,90]}` + gcfg.SetContent(content) + defer gcfg.RemoveContent() + + m := g.Cfg().GetMap("map") + fmt.Println(m) + + // Change the key-value pair. + m["key"] = "john" + + // It changes the underlying key-value pair. + fmt.Println(g.Cfg().GetMap("map")) + + s := g.Cfg().GetArray("slice") + fmt.Println(s) + + // Change the value of specified index. + s[0] = 100 + + // It changes the underlying slice. + fmt.Println(g.Cfg().GetArray("slice")) + + // output: + // map[key:value] + // map[key:john] + // [59 90] + // [100 90] +} diff --git a/os/gfile/gfile.go b/os/gfile/gfile.go index 54dbbc9be..0c0f2dcbd 100644 --- a/os/gfile/gfile.go +++ b/os/gfile/gfile.go @@ -8,14 +8,10 @@ package gfile import ( - "bytes" - "errors" "github.com/gogf/gf/text/gstr" "os" "os/exec" - "os/user" "path/filepath" - "runtime" "strings" "time" @@ -386,52 +382,14 @@ func ExtName(path string) string { return strings.TrimLeft(Ext(path), ".") } -// Home returns absolute path of current user's home directory. -func Home() (string, error) { - u, err := user.Current() - if nil == err { - return u.HomeDir, nil +// TempDir retrieves and returns the temporary directory of current system. +// It return "/tmp" is current in *nix system, or else it returns os.TempDir(). +// The optional parameter specifies the its sub-folders/sub-files, +// which will be joined with current system separator and returned with the path. +func TempDir(names ...string) string { + path := tempDir + for _, name := range names { + path += Separator + name } - if "windows" == runtime.GOOS { - return homeWindows() - } - return homeUnix() -} - -func homeUnix() (string, error) { - if home := os.Getenv("HOME"); home != "" { - return home, nil - } - var stdout bytes.Buffer - cmd := exec.Command("sh", "-c", "eval echo ~$USER") - cmd.Stdout = &stdout - if err := cmd.Run(); err != nil { - return "", err - } - - result := strings.TrimSpace(stdout.String()) - if result == "" { - return "", errors.New("blank output when reading home directory") - } - - return result, nil -} - -func homeWindows() (string, error) { - drive := os.Getenv("HOMEDRIVE") - path := os.Getenv("HOMEPATH") - home := drive + path - if drive == "" || path == "" { - home = os.Getenv("USERPROFILE") - } - if home == "" { - return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank") - } - - return home, nil -} - -// See os.TempDir(). -func TempDir() string { - return tempDir + return path } diff --git a/os/gfile/gfile_home.go b/os/gfile/gfile_home.go new file mode 100644 index 000000000..2842864b4 --- /dev/null +++ b/os/gfile/gfile_home.go @@ -0,0 +1,80 @@ +// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gfile + +import ( + "bytes" + "errors" + "os" + "os/exec" + "os/user" + "runtime" + "strings" +) + +// Home returns absolute path of current user's home directory. +// The optional parameter specifies the its sub-folders/sub-files, +// which will be joined with current system separator and returned with the path. +func Home(names ...string) (string, error) { + path, err := getHomePath() + if err != nil { + return "", err + } + for _, name := range names { + path += Separator + name + } + return path, nil +} + +// getHomePath returns absolute path of current user's home directory. +func getHomePath() (string, error) { + u, err := user.Current() + if nil == err { + return u.HomeDir, nil + } + if "windows" == runtime.GOOS { + return homeWindows() + } + return homeUnix() +} + +// homeUnix retrieves and returns the home on unix system. +func homeUnix() (string, error) { + if home := os.Getenv("HOME"); home != "" { + return home, nil + } + var stdout bytes.Buffer + cmd := exec.Command("sh", "-c", "eval echo ~$USER") + cmd.Stdout = &stdout + if err := cmd.Run(); err != nil { + return "", err + } + + result := strings.TrimSpace(stdout.String()) + if result == "" { + return "", errors.New("blank output when reading home directory") + } + + return result, nil +} + +// homeWindows retrieves and returns the home on windows system. +func homeWindows() (string, error) { + var ( + drive = os.Getenv("HOMEDRIVE") + path = os.Getenv("HOMEPATH") + home = drive + path + ) + if drive == "" || path == "" { + home = os.Getenv("USERPROFILE") + } + if home == "" { + return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank") + } + + return home, nil +} diff --git a/os/glog/glog_logger_config.go b/os/glog/glog_logger_config.go index fee886e87..b7d1248cd 100644 --- a/os/glog/glog_logger_config.go +++ b/os/glog/glog_logger_config.go @@ -80,6 +80,9 @@ func (l *Logger) SetConfigWithMap(m map[string]interface{}) error { if m == nil || len(m) == 0 { return errors.New("configuration cannot be empty") } + // The m now is a shallow copy of m. + // A little tricky, isn't it? + m = gutil.CopyMap(m) // Change string configuration to int value for level. levelKey, levelValue := gutil.MapPossibleItemByKey(m, "Level") if levelValue != nil { diff --git a/os/gview/gview_config.go b/os/gview/gview_config.go index f256225f5..417be07fa 100644 --- a/os/gview/gview_config.go +++ b/os/gview/gview_config.go @@ -61,6 +61,9 @@ func (view *View) SetConfigWithMap(m map[string]interface{}) error { if m == nil || len(m) == 0 { return errors.New("configuration cannot be empty") } + // The m now is a shallow copy of m. + // A little tricky, isn't it? + m = gutil.CopyMap(m) // Most common used configuration support for single view path. _, v1 := gutil.MapPossibleItemByKey(m, "paths") _, v2 := gutil.MapPossibleItemByKey(m, "path") diff --git a/text/gregex/gregex_z_bench_test.go b/text/gregex/gregex_z_bench_test.go index a6c9e4af9..e4c9f9339 100644 --- a/text/gregex/gregex_z_bench_test.go +++ b/text/gregex/gregex_z_bench_test.go @@ -18,12 +18,18 @@ import ( var pattern = `(\w+).+\-\-\s*(.+)` var src = `GF is best! -- John` -func Benchmark_GF(b *testing.B) { +func Benchmark_GF_IsMatchString(b *testing.B) { for i := 0; i < b.N; i++ { gregex.IsMatchString(pattern, src) } } +func Benchmark_GF_MatchString(b *testing.B) { + for i := 0; i < b.N; i++ { + gregex.MatchString(pattern, src) + } +} + func Benchmark_Compile(b *testing.B) { var wcdRegexp = regexp.MustCompile(pattern) for i := 0; i < b.N; i++ { diff --git a/util/gutil/gutil_map.go b/util/gutil/gutil_map.go index 1ffe5b5ba..0b5d7e0dd 100644 --- a/util/gutil/gutil_map.go +++ b/util/gutil/gutil_map.go @@ -4,7 +4,6 @@ // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. -// Package gutil provides utility functions. package gutil import ( @@ -17,8 +16,9 @@ var ( replaceCharReg, _ = regexp.Compile(`[\-\.\_\s]+`) ) -// MapCopy does memory from map to . -func MapCopy(data map[string]interface{}) (copy map[string]interface{}) { +// CopyMap does a shallow copy from map to for most commonly used map type +// map[string]interface{}. +func CopyMap(data map[string]interface{}) (copy map[string]interface{}) { copy = make(map[string]interface{}, len(data)) for k, v := range data { copy[k] = v diff --git a/util/gutil/gutil_slice.go b/util/gutil/gutil_slice.go new file mode 100644 index 000000000..28a5e9015 --- /dev/null +++ b/util/gutil/gutil_slice.go @@ -0,0 +1,15 @@ +// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gutil + +// CopySlice does a shallow copy of slice for most commonly used slice type +// []interface{}. +func CopySlice(data []interface{}) []interface{} { + newData := make([]interface{}, len(data)) + copy(newData, data) + return newData +}