mirror of
https://gitee.com/johng/gf
synced 2026-07-04 13:02:36 +08:00
Merge branch 'develop'
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -15,4 +15,5 @@ cbuild
|
||||
**/.DS_Store
|
||||
.test/
|
||||
cmd/gf/main
|
||||
cmd/gf/gf
|
||||
go.work
|
||||
|
||||
@ -11,6 +11,10 @@ var (
|
||||
|
||||
type cGen struct {
|
||||
g.Meta `name:"gen" brief:"{cGenBrief}" dc:"{cGenDc}"`
|
||||
cGenDao
|
||||
cGenPb
|
||||
cGenPbEntity
|
||||
cGenService
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
@ -138,6 +138,7 @@ func init() {
|
||||
}
|
||||
|
||||
type (
|
||||
cGenDao struct{}
|
||||
cGenDaoInput struct {
|
||||
g.Meta `name:"dao" config:"{cGenDaoConfig}" usage:"{cGenDaoUsage}" brief:"{cGenDaoBrief}" eg:"{cGenDaoEg}" ad:"{cGenDaoAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{cGenDaoBriefPath}" d:"internal"`
|
||||
@ -170,7 +171,7 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func (c cGen) Dao(ctx context.Context, in cGenDaoInput) (out *cGenDaoOutput, err error) {
|
||||
func (c cGenDao) Dao(ctx context.Context, in cGenDaoInput) (out *cGenDaoOutput, err error) {
|
||||
if g.Cfg().Available(ctx) {
|
||||
v := g.Cfg().MustGet(ctx, cGenDaoConfig)
|
||||
if v.IsSlice() {
|
||||
|
||||
@ -13,13 +13,14 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
cGenPb struct{}
|
||||
cGenPbInput struct {
|
||||
g.Meta `name:"pb" brief:"parse proto files and generate protobuf go files"`
|
||||
}
|
||||
cGenPbOutput struct{}
|
||||
)
|
||||
|
||||
func (c cGen) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err error) {
|
||||
func (c cGenPb) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err error) {
|
||||
// Necessary check.
|
||||
if gproc.SearchBinary("protoc") == "" {
|
||||
mlog.Fatalf(`command "protoc" not found in your environment, please install protoc first to proceed this command`)
|
||||
|
||||
@ -19,6 +19,29 @@ import (
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
type (
|
||||
cGenPbEntity struct{}
|
||||
cGenPbEntityInput struct {
|
||||
g.Meta `name:"pbentity" config:"{cGenPbEntityConfig}" brief:"{cGenPbEntityBrief}" eg:"{cGenPbEntityEg}" ad:"{cGenPbEntityAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{cGenPbEntityBriefPath}"`
|
||||
Package string `name:"package" short:"k" brief:"{cGenPbEntityBriefPackage}"`
|
||||
Link string `name:"link" short:"l" brief:"{cGenPbEntityBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{cGenPbEntityBriefTables}"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{cGenPbEntityBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{cGenPbEntityBriefRemovePrefix}"`
|
||||
NameCase string `name:"nameCase" short:"n" brief:"{cGenPbEntityBriefNameCase}" d:"Camel"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{cGenPbEntityBriefJsonCase}" d:"CamelLower"`
|
||||
Option string `name:"option" short:"o" brief:"{cGenPbEntityBriefOption}"`
|
||||
}
|
||||
cGenPbEntityOutput struct{}
|
||||
|
||||
cGenPbEntityInternalInput struct {
|
||||
cGenPbEntityInput
|
||||
TableName string // TableName specifies the table name of the table.
|
||||
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
cGenPbEntityConfig = `gfcli.gen.pbentity`
|
||||
cGenPbEntityBrief = `generate entity message files in protobuf3 format`
|
||||
@ -83,28 +106,6 @@ set it to "none" to ignore json tag generating.
|
||||
`
|
||||
)
|
||||
|
||||
type (
|
||||
cGenPbEntityInput struct {
|
||||
g.Meta `name:"pbentity" config:"{cGenPbEntityConfig}" brief:"{cGenPbEntityBrief}" eg:"{cGenPbEntityEg}" ad:"{cGenPbEntityAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{cGenPbEntityBriefPath}"`
|
||||
Package string `name:"package" short:"k" brief:"{cGenPbEntityBriefPackage}"`
|
||||
Link string `name:"link" short:"l" brief:"{cGenPbEntityBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{cGenPbEntityBriefTables}"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{cGenPbEntityBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{cGenPbEntityBriefRemovePrefix}"`
|
||||
NameCase string `name:"nameCase" short:"n" brief:"{cGenPbEntityBriefNameCase}" d:"Camel"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{cGenPbEntityBriefJsonCase}" d:"CamelLower"`
|
||||
Option string `name:"option" short:"o" brief:"{cGenPbEntityBriefOption}"`
|
||||
}
|
||||
cGenPbEntityOutput struct{}
|
||||
|
||||
cGenPbEntityInternalInput struct {
|
||||
cGenPbEntityInput
|
||||
TableName string // TableName specifies the table name of the table.
|
||||
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`cGenPbEntityConfig`: cGenPbEntityConfig,
|
||||
@ -124,7 +125,7 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
func (c cGen) PbEntity(ctx context.Context, in cGenPbEntityInput) (out *cGenPbEntityOutput, err error) {
|
||||
func (c cGenPbEntity) PbEntity(ctx context.Context, in cGenPbEntityInput) (out *cGenPbEntityOutput, err error) {
|
||||
var (
|
||||
config = g.Cfg()
|
||||
)
|
||||
|
||||
@ -18,15 +18,16 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
cGenService struct{}
|
||||
cGenServiceInput struct {
|
||||
g.Meta `name:"service" config:"gfcli.gen.service" brief:"parse struct and associated functions from packages to generate service go file"`
|
||||
SrcFolder string `short:"s" name:"srcFolder" brief:"source folder path to be parsed. default: internal/logic" d:"internal/logic"`
|
||||
DstFolder string `short:"d" name:"dstFolder" brief:"destination folder path storing automatically generated go files. default: internal/service" d:"internal/service"`
|
||||
WatchFile string `short:"w" name:"watchFile" brief:"used in file watcher, it generates service go files only if given file is under srcFolder"`
|
||||
StPattern string `short:"a" name:"stPattern" brief:"regular expression matching struct name for generating service. default: s([A-Z]\\\w+)" d:"s([A-Z]\\w+)"`
|
||||
Packages string `short:"p" name:"packages" brief:"produce go files only for given source packages, multiple packages joined with char ','"`
|
||||
ImportPrefix string `short:"i" name:"importPrefix" brief:"custom import prefix to calculate import path for generated importing go file of logic"`
|
||||
OverWrite bool `short:"o" name:"overwrite" brief:"overwrite service go files that already exist in generating folder. default: true" d:"true" orphan:"true"`
|
||||
SrcFolder string `short:"s" name:"srcFolder" brief:"source folder path to be parsed. default: internal/logic" d:"internal/logic"`
|
||||
DstFolder string `short:"d" name:"dstFolder" brief:"destination folder path storing automatically generated go files. default: internal/service" d:"internal/service"`
|
||||
WatchFile string `short:"w" name:"watchFile" brief:"used in file watcher, it generates service go files only if given file is under srcFolder"`
|
||||
StPattern string `short:"a" name:"stPattern" brief:"regular expression matching struct name for generating service. default: s([A-Z]\\\\w+)" d:"s([A-Z]\\w+)"`
|
||||
Packages []string `short:"p" name:"packages" brief:"produce go files only for given source packages"`
|
||||
ImportPrefix string `short:"i" name:"importPrefix" brief:"custom import prefix to calculate import path for generated importing go file of logic"`
|
||||
OverWrite bool `short:"o" name:"overwrite" brief:"overwrite service go files that already exist in generating folder. default: true" d:"true" orphan:"true"`
|
||||
}
|
||||
cGenServiceOutput struct{}
|
||||
)
|
||||
@ -35,7 +36,7 @@ const (
|
||||
genServiceFileLockSeconds = 10
|
||||
)
|
||||
|
||||
func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServiceOutput, err error) {
|
||||
func (c cGenService) Service(ctx context.Context, in cGenServiceInput) (out *cGenServiceOutput, err error) {
|
||||
// File lock to avoid multiple processes.
|
||||
var (
|
||||
flockFilePath = gfile.Temp("gf.cli.gen.service.lock")
|
||||
@ -101,13 +102,12 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
|
||||
}
|
||||
|
||||
var (
|
||||
isDirty bool
|
||||
files []string
|
||||
fileContent string
|
||||
matches [][]string
|
||||
importSrcPackages []string
|
||||
inputPackages = gstr.SplitAndTrim(in.Packages, ",")
|
||||
dstPackageName = gstr.ToLower(gfile.Basename(in.DstFolder))
|
||||
isDirty bool
|
||||
files []string
|
||||
fileContent string
|
||||
initImportSrcPackages []string
|
||||
inputPackages = in.Packages
|
||||
dstPackageName = gstr.ToLower(gfile.Basename(in.DstFolder))
|
||||
)
|
||||
srcFolders, err := gfile.ScanDir(in.SrcFolder, "*", false)
|
||||
if err != nil {
|
||||
@ -125,56 +125,25 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
|
||||
}
|
||||
var (
|
||||
// StructName => FunctionDefinitions
|
||||
srcPkgInterfaceMap = make(map[string]*garray.StrArray)
|
||||
srcPkgInterfaceFuncArray *garray.StrArray
|
||||
ok bool
|
||||
srcPkgInterfaceMap = make(map[string]*garray.StrArray)
|
||||
srcImportedPackages = garray.NewSortedStrArray().SetUnique(true)
|
||||
ok bool
|
||||
)
|
||||
for _, file := range files {
|
||||
fileContent = gfile.GetContents(file)
|
||||
matches, err = gregex.MatchAllString(`func \((.+?)\) ([\s\S]+?) {`, fileContent)
|
||||
// Calculate imported packages of source go files.
|
||||
err = c.calculateImportedPackages(fileContent, srcImportedPackages)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, match := range matches {
|
||||
var (
|
||||
structName string
|
||||
structMatch []string
|
||||
funcReceiver = gstr.Trim(match[1])
|
||||
receiverArray = gstr.SplitAndTrim(funcReceiver, " ")
|
||||
functionHead = gstr.Trim(gstr.Replace(match[2], "\n", ""))
|
||||
)
|
||||
if len(receiverArray) > 1 {
|
||||
structName = receiverArray[1]
|
||||
} else {
|
||||
structName = receiverArray[0]
|
||||
}
|
||||
structName = gstr.Trim(structName, "*")
|
||||
|
||||
// Xxx(\n ctx context.Context, req *v1.XxxReq,\n) -> Xxx(ctx context.Context, req *v1.XxxReq)
|
||||
functionHead = gstr.Replace(functionHead, `,)`, `)`)
|
||||
functionHead, _ = gregex.ReplaceString(`\(\s+`, `(`, functionHead)
|
||||
functionHead, _ = gregex.ReplaceString(`\s{2,}`, ` `, functionHead)
|
||||
if !gstr.IsLetterUpper(functionHead[0]) {
|
||||
continue
|
||||
}
|
||||
if structMatch, err = gregex.MatchString(in.StPattern, structName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(structMatch) < 1 {
|
||||
continue
|
||||
}
|
||||
structName = gstr.CaseCamel(structMatch[1])
|
||||
if srcPkgInterfaceFuncArray, ok = srcPkgInterfaceMap[structName]; !ok {
|
||||
srcPkgInterfaceMap[structName] = garray.NewStrArray()
|
||||
srcPkgInterfaceFuncArray = srcPkgInterfaceMap[structName]
|
||||
}
|
||||
// Remove package name calls of `dstPackageName` in produced codes.
|
||||
functionHead, _ = gregex.ReplaceString(fmt.Sprintf(`\*{0,1}%s\.`, dstPackageName), ``, functionHead)
|
||||
srcPkgInterfaceFuncArray.Append(functionHead)
|
||||
// Calculate functions and interfaces for service generating.
|
||||
err = c.calculateInterfaceFunctions(in, fileContent, srcPkgInterfaceMap, dstPackageName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
importSrcPackages = append(
|
||||
importSrcPackages,
|
||||
initImportSrcPackages = append(
|
||||
initImportSrcPackages,
|
||||
fmt.Sprintf(`%s/%s`, in.ImportPrefix, gfile.Basename(srcFolder)),
|
||||
)
|
||||
// Ignore source packages if input packages given.
|
||||
@ -186,7 +155,7 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
|
||||
continue
|
||||
}
|
||||
// Generating go files for service.
|
||||
if ok, err = c.generateServiceFiles(in, srcPkgInterfaceMap, dstPackageName); err != nil {
|
||||
if ok, err = c.generateServiceFiles(in, srcPkgInterfaceMap, srcImportedPackages.Slice(), dstPackageName); err != nil {
|
||||
return
|
||||
}
|
||||
if ok {
|
||||
@ -196,8 +165,8 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
|
||||
|
||||
if isDirty {
|
||||
// Generate initialization go file.
|
||||
if len(importSrcPackages) > 0 {
|
||||
if err = c.generateInitializationFile(in, importSrcPackages); err != nil {
|
||||
if len(initImportSrcPackages) > 0 {
|
||||
if err = c.generateInitializationFile(in, initImportSrcPackages); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -218,13 +187,86 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
|
||||
return
|
||||
}
|
||||
|
||||
func (c cGen) generateServiceFiles(
|
||||
in cGenServiceInput, srcPkgInterfaceMap map[string]*garray.StrArray, dstPackageName string,
|
||||
func (c cGenService) calculateImportedPackages(fileContent string, srcImportedPackages *garray.SortedStrArray) (err error) {
|
||||
var match []string
|
||||
match, err = gregex.MatchString(`\s+import\s+\(([\s\S]+?)\)`, fileContent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(match) < 2 {
|
||||
return nil
|
||||
}
|
||||
importPart := gstr.Trim(match[1])
|
||||
srcImportedPackages.Append(gstr.SplitAndTrim(importPart, "\n")...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c cGenService) calculateInterfaceFunctions(
|
||||
in cGenServiceInput, fileContent string, srcPkgInterfaceMap map[string]*garray.StrArray, dstPackageName string,
|
||||
) (err error) {
|
||||
var (
|
||||
ok bool
|
||||
matches [][]string
|
||||
srcPkgInterfaceFuncArray *garray.StrArray
|
||||
)
|
||||
matches, err = gregex.MatchAllString(`func \((.+?)\) ([\s\S]+?) {`, fileContent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, match := range matches {
|
||||
var (
|
||||
structName string
|
||||
structMatch []string
|
||||
funcReceiver = gstr.Trim(match[1])
|
||||
receiverArray = gstr.SplitAndTrim(funcReceiver, " ")
|
||||
functionHead = gstr.Trim(gstr.Replace(match[2], "\n", ""))
|
||||
)
|
||||
if len(receiverArray) > 1 {
|
||||
structName = receiverArray[1]
|
||||
} else {
|
||||
structName = receiverArray[0]
|
||||
}
|
||||
structName = gstr.Trim(structName, "*")
|
||||
|
||||
// Xxx(\n ctx context.Context, req *v1.XxxReq,\n) -> Xxx(ctx context.Context, req *v1.XxxReq)
|
||||
functionHead = gstr.Replace(functionHead, `,)`, `)`)
|
||||
functionHead, _ = gregex.ReplaceString(`\(\s+`, `(`, functionHead)
|
||||
functionHead, _ = gregex.ReplaceString(`\s{2,}`, ` `, functionHead)
|
||||
if !gstr.IsLetterUpper(functionHead[0]) {
|
||||
continue
|
||||
}
|
||||
if structMatch, err = gregex.MatchString(in.StPattern, structName); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(structMatch) < 1 {
|
||||
continue
|
||||
}
|
||||
structName = gstr.CaseCamel(structMatch[1])
|
||||
if srcPkgInterfaceFuncArray, ok = srcPkgInterfaceMap[structName]; !ok {
|
||||
srcPkgInterfaceMap[structName] = garray.NewStrArray()
|
||||
srcPkgInterfaceFuncArray = srcPkgInterfaceMap[structName]
|
||||
}
|
||||
// Remove package name calls of `dstPackageName` in produced codes.
|
||||
functionHead, _ = gregex.ReplaceString(fmt.Sprintf(`\*{0,1}%s\.`, dstPackageName), ``, functionHead)
|
||||
srcPkgInterfaceFuncArray.Append(functionHead)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c cGenService) generateServiceFiles(
|
||||
in cGenServiceInput,
|
||||
srcPkgInterfaceMap map[string]*garray.StrArray,
|
||||
srcImportedPackages []string,
|
||||
dstPackageName string,
|
||||
) (ok bool, err error) {
|
||||
srcImportedPackagesContent := fmt.Sprintf(
|
||||
"import (\n%s\n)", gstr.Join(srcImportedPackages, "\n"),
|
||||
)
|
||||
for structName, funcArray := range srcPkgInterfaceMap {
|
||||
var (
|
||||
filePath = gfile.Join(in.DstFolder, gstr.ToLower(structName)+".go")
|
||||
generatedContent = gstr.ReplaceByMap(consts.TemplateGenServiceContent, g.MapStrStr{
|
||||
"{Imports}": srcImportedPackagesContent,
|
||||
"{StructName}": structName,
|
||||
"{PackageName}": dstPackageName,
|
||||
"{FuncDefinition}": funcArray.Join("\n\t"),
|
||||
@ -250,7 +292,7 @@ func (c cGen) generateServiceFiles(
|
||||
}
|
||||
|
||||
// isToGenerateServiceGoFile checks and returns whether the service content dirty.
|
||||
func (c cGen) isToGenerateServiceGoFile(filePath string, funcArray *garray.StrArray) bool {
|
||||
func (c cGenService) isToGenerateServiceGoFile(filePath string, funcArray *garray.StrArray) bool {
|
||||
if !utils.IsFileDoNotEdit(filePath) {
|
||||
mlog.Debugf(`ignore file as it is manually maintained: %s`, filePath)
|
||||
return false
|
||||
@ -280,7 +322,7 @@ func (c cGen) isToGenerateServiceGoFile(filePath string, funcArray *garray.StrAr
|
||||
return false
|
||||
}
|
||||
|
||||
func (c cGen) generateInitializationFile(in cGenServiceInput, importSrcPackages []string) (err error) {
|
||||
func (c cGenService) generateInitializationFile(in cGenServiceInput, importSrcPackages []string) (err error) {
|
||||
var (
|
||||
srcPackageName = gstr.ToLower(gfile.Basename(in.SrcFolder))
|
||||
srcFilePath = gfile.Join(in.SrcFolder, srcPackageName+".go")
|
||||
@ -306,7 +348,7 @@ func (c cGen) generateInitializationFile(in cGenServiceInput, importSrcPackages
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c cGen) replaceGeneratedServiceContentGFV2(in cGenServiceInput) (err error) {
|
||||
func (c cGenService) replaceGeneratedServiceContentGFV2(in cGenServiceInput) (err error) {
|
||||
return gfile.ReplaceDirFunc(func(path, content string) string {
|
||||
if gstr.Contains(content, `"github.com/gogf/gf`) && !gstr.Contains(content, `"github.com/gogf/gf/v2`) {
|
||||
content = gstr.Replace(content, `"github.com/gogf/gf"`, `"github.com/gogf/gf/v2"`)
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/os/gres"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
)
|
||||
@ -48,7 +49,8 @@ func init() {
|
||||
type cInitInput struct {
|
||||
g.Meta `name:"init"`
|
||||
Name string `name:"NAME" arg:"true" v:"required" brief:"{cInitNameBrief}"`
|
||||
Mono bool `name:"mono" short:"m" brief:"initialize a mono-repo instead a single-repo" orphan:"true"`
|
||||
Mono bool `name:"mono" short:"m" brief:"initialize a mono-repo instead a single-repo" orphan:"true"`
|
||||
Update bool `name:"update" short:"u" brief:"update to the latest goframe version" orphan:"true"`
|
||||
}
|
||||
type cInitOutput struct{}
|
||||
|
||||
@ -89,6 +91,18 @@ func (c cInit) Index(ctx context.Context, in cInitInput) (out *cInitOutput, err
|
||||
return
|
||||
}
|
||||
|
||||
// Update the GoFrame version.
|
||||
if in.Update {
|
||||
mlog.Print("update goframe...")
|
||||
updateCommand := `go get -u github.com/gogf/gf/v2@latest`
|
||||
if in.Name != "." {
|
||||
updateCommand = fmt.Sprintf(`cd %s && %s`, in.Name, updateCommand)
|
||||
}
|
||||
if err = gproc.ShellRun(updateCommand); err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
mlog.Print("initialization done! ")
|
||||
if !in.Mono {
|
||||
enjoyCommand := `gf run main.go`
|
||||
|
||||
@ -7,6 +7,8 @@ const TemplateGenServiceContent = `
|
||||
|
||||
package {PackageName}
|
||||
|
||||
{Imports}
|
||||
|
||||
type I{StructName} interface {
|
||||
{FuncDefinition}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -331,9 +331,6 @@ var (
|
||||
// in the field name as it conflicts with "db.table.field" pattern in SOME situations.
|
||||
regularFieldNameWithoutDotRegPattern = `^[\w\-]+$`
|
||||
|
||||
// tableFieldsMap caches the table information retrieved from database.
|
||||
tableFieldsMap = gmap.New(true)
|
||||
|
||||
// allDryRun sets dry-run feature for all database connections.
|
||||
// It is commonly used for command options for convenience.
|
||||
allDryRun = false
|
||||
@ -399,8 +396,7 @@ func doNewByNode(node ConfigNode, group string) (db DB, err error) {
|
||||
config: &node,
|
||||
}
|
||||
if v, ok := driverMap[node.Type]; ok {
|
||||
c.db, err = v.New(c, &node)
|
||||
if err != nil {
|
||||
if c.db, err = v.New(c, &node); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.db, nil
|
||||
|
||||
@ -13,6 +13,8 @@ import (
|
||||
|
||||
"github.com/gogf/gf/v2/os/gcache"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
// Config is the configuration management object.
|
||||
@ -72,6 +74,12 @@ func SetConfig(config Config) {
|
||||
defer instances.Clear()
|
||||
configs.Lock()
|
||||
defer configs.Unlock()
|
||||
for k, nodes := range config {
|
||||
for i, node := range nodes {
|
||||
nodes[i] = parseConfigNode(node)
|
||||
}
|
||||
config[k] = nodes
|
||||
}
|
||||
configs.config = config
|
||||
}
|
||||
|
||||
@ -80,6 +88,9 @@ func SetConfigGroup(group string, nodes ConfigGroup) {
|
||||
defer instances.Clear()
|
||||
configs.Lock()
|
||||
defer configs.Unlock()
|
||||
for i, node := range nodes {
|
||||
nodes[i] = parseConfigNode(node)
|
||||
}
|
||||
configs.config[group] = nodes
|
||||
}
|
||||
|
||||
@ -88,7 +99,19 @@ func AddConfigNode(group string, node ConfigNode) {
|
||||
defer instances.Clear()
|
||||
configs.Lock()
|
||||
defer configs.Unlock()
|
||||
configs.config[group] = append(configs.config[group], node)
|
||||
configs.config[group] = append(configs.config[group], parseConfigNode(node))
|
||||
}
|
||||
|
||||
// parseConfigNode parses `Link` configuration syntax.
|
||||
func parseConfigNode(node ConfigNode) ConfigNode {
|
||||
if node.Link != "" && node.Type == "" {
|
||||
match, _ := gregex.MatchString(`([a-z]+):(.+)`, node.Link)
|
||||
if len(match) == 3 {
|
||||
node.Type = gstr.Trim(match[1])
|
||||
node.Link = gstr.Trim(match[2])
|
||||
}
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// AddDefaultConfigNode adds one node configuration to configuration of default group.
|
||||
|
||||
@ -168,9 +168,13 @@ func Test_Error(t *testing.T) {
|
||||
_, err = conn.Do(ctx, "Subscribe", "gf")
|
||||
t.AssertNil(err)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
_, err = redis.Do(ctx, "PUBLISH", "gf", "test")
|
||||
t.AssertNil(err)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
v, err = conn.Receive(ctx)
|
||||
t.AssertNil(err)
|
||||
t.Assert(v.Val().(*gredis.Subscription).Channel, "gf")
|
||||
|
||||
@ -16,8 +16,6 @@ import (
|
||||
"github.com/gogf/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
@ -173,13 +171,5 @@ func parseDBConfigNode(value interface{}) *gdb.ConfigNode {
|
||||
if _, v := gutil.MapPossibleItemByKey(nodeMap, "Link"); v != nil {
|
||||
node.Link = gconv.String(v)
|
||||
}
|
||||
// Parse `Link` configuration syntax.
|
||||
if node.Link != "" && node.Type == "" {
|
||||
match, _ := gregex.MatchString(`([a-z]+):(.+)`, node.Link)
|
||||
if len(match) == 3 {
|
||||
node.Type = gstr.Trim(match[1])
|
||||
node.Link = gstr.Trim(match[2])
|
||||
}
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
@ -83,6 +83,9 @@ func Server(name ...interface{}) *ghttp.Server {
|
||||
ctx,
|
||||
fmt.Sprintf(`%s.%s.%s`, configNodeName, instanceName, consts.ConfigNodeNameLogger),
|
||||
).Map()
|
||||
if len(serverLoggerConfigMap) == 0 && len(serverConfigMap) > 0 {
|
||||
serverLoggerConfigMap = gconv.Map(serverConfigMap[consts.ConfigNodeNameLogger])
|
||||
}
|
||||
if len(serverLoggerConfigMap) > 0 {
|
||||
if err = server.Logger().SetConfigWithMap(serverLoggerConfigMap); err != nil {
|
||||
panic(err)
|
||||
|
||||
@ -18,6 +18,7 @@ import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gmeta"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
|
||||
// DoRequestObj does HTTP request using standard request/response object.
|
||||
@ -81,13 +82,14 @@ func (c *Client) DoRequestObj(ctx context.Context, req, res interface{}) error {
|
||||
// /user/{name} -> /order/john
|
||||
func (c *Client) handlePathForObjRequest(path string, req interface{}) string {
|
||||
if gstr.Contains(path, "{") {
|
||||
requestParamsMap := gconv.MapStrStr(req)
|
||||
requestParamsMap := gconv.Map(req)
|
||||
if len(requestParamsMap) > 0 {
|
||||
path, _ = gregex.ReplaceStringFuncMatch(`\{(\w+)\}`, path, func(match []string) string {
|
||||
if v, ok := requestParamsMap[match[1]]; ok {
|
||||
return v
|
||||
foundKey, foundValue := gutil.MapPossibleItemByKey(requestParamsMap, match[1])
|
||||
if foundKey != "" {
|
||||
return gconv.String(foundValue)
|
||||
}
|
||||
return match[1]
|
||||
return match[0]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
package gclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
@ -69,6 +70,13 @@ func (r *Response) ReadAllString() string {
|
||||
return string(r.ReadAll())
|
||||
}
|
||||
|
||||
// SetBodyContent overwrites response content with custom one.
|
||||
func (r *Response) SetBodyContent(content []byte) {
|
||||
buffer := bytes.NewBuffer(content)
|
||||
r.Body = ioutil.NopCloser(buffer)
|
||||
r.ContentLength = int64(buffer.Len())
|
||||
}
|
||||
|
||||
// Close closes the response when it will never be used.
|
||||
func (r *Response) Close() error {
|
||||
if r == nil || r.Response == nil {
|
||||
|
||||
@ -27,7 +27,8 @@ func Test_Client_DoRequestObj(t *testing.T) {
|
||||
Id int
|
||||
}
|
||||
type UserQueryReq struct {
|
||||
g.Meta `path:"/user" method:"get"`
|
||||
g.Meta `path:"/user/{id}" method:"get"`
|
||||
Id int
|
||||
}
|
||||
type UserQueryRes struct {
|
||||
Id int
|
||||
@ -36,8 +37,8 @@ func Test_Client_DoRequestObj(t *testing.T) {
|
||||
p, _ := gtcp.GetFreePort()
|
||||
s := g.Server(p)
|
||||
s.Group("/user", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/", func(r *ghttp.Request) {
|
||||
r.Response.WriteJson(g.Map{"id": 1, "name": "john"})
|
||||
group.GET("/{id}", func(r *ghttp.Request) {
|
||||
r.Response.WriteJson(g.Map{"id": r.Get("id").Int(), "name": "john"})
|
||||
})
|
||||
group.POST("/", func(r *ghttp.Request) {
|
||||
r.Response.WriteJson(g.Map{"id": r.Get("Id")})
|
||||
@ -68,7 +69,9 @@ func Test_Client_DoRequestObj(t *testing.T) {
|
||||
client := g.Client().SetPrefix(url).ContentJson()
|
||||
var (
|
||||
queryRes *UserQueryRes
|
||||
queryReq = UserQueryReq{}
|
||||
queryReq = UserQueryReq{
|
||||
Id: 1,
|
||||
}
|
||||
)
|
||||
err := client.DoRequestObj(ctx, queryReq, &queryRes)
|
||||
t.AssertNil(err)
|
||||
|
||||
@ -640,3 +640,27 @@ func TestClient_RequestVar(t *testing.T) {
|
||||
t.AssertNE(users, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClient_SetBodyContent(t *testing.T) {
|
||||
p, _ := gtcp.GetFreePort()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("hello")
|
||||
})
|
||||
s.SetPort(p)
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
c := g.Client()
|
||||
c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
|
||||
res, err := c.Get(ctx, "/")
|
||||
t.AssertNil(err)
|
||||
defer res.Close()
|
||||
t.Assert(res.ReadAllString(), "hello")
|
||||
res.SetBodyContent([]byte("world"))
|
||||
t.Assert(res.ReadAllString(), "world")
|
||||
})
|
||||
}
|
||||
|
||||
@ -117,21 +117,22 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
supportedHttpMethods = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
|
||||
defaultMethod = "ALL"
|
||||
exceptionExit = "exit"
|
||||
exceptionExitAll = "exit_all"
|
||||
exceptionExitHook = "exit_hook"
|
||||
routeCacheDuration = time.Hour
|
||||
ctxKeyForRequest = "gHttpRequestObject"
|
||||
contentTypeXml = "text/xml"
|
||||
contentTypeHtml = "text/html"
|
||||
contentTypeJson = "application/json"
|
||||
swaggerUIPackedPath = "/goframe/swaggerui"
|
||||
responseTraceIDHeader = "Trace-ID"
|
||||
specialMethodNameInit = "Init"
|
||||
specialMethodNameShut = "Shut"
|
||||
specialMethodNameIndex = "Index"
|
||||
supportedHttpMethods = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
|
||||
defaultMethod = "ALL"
|
||||
exceptionExit = "exit"
|
||||
exceptionExitAll = "exit_all"
|
||||
exceptionExitHook = "exit_hook"
|
||||
routeCacheDuration = time.Hour
|
||||
ctxKeyForRequest = "gHttpRequestObject"
|
||||
contentTypeXml = "text/xml"
|
||||
contentTypeHtml = "text/html"
|
||||
contentTypeJson = "application/json"
|
||||
swaggerUIPackedPath = "/goframe/swaggerui"
|
||||
responseTraceIDHeader = "Trace-ID"
|
||||
specialMethodNameInit = "Init"
|
||||
specialMethodNameShut = "Shut"
|
||||
specialMethodNameIndex = "Index"
|
||||
gracefulShutdownTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@ -215,7 +215,9 @@ func (s *gracefulServer) shutdown(ctx context.Context) {
|
||||
if s.status == ServerStatusStopped {
|
||||
return
|
||||
}
|
||||
if err := s.httpServer.Shutdown(context.Background()); err != nil {
|
||||
timeoutCtx, cancelFunc := context.WithTimeout(ctx, gracefulShutdownTimeout)
|
||||
defer cancelFunc()
|
||||
if err := s.httpServer.Shutdown(timeoutCtx); err != nil {
|
||||
s.server.Logger().Errorf(
|
||||
ctx,
|
||||
"%d: %s server [%s] shutdown error: %v",
|
||||
|
||||
@ -196,7 +196,13 @@ func GetFreePort() (port int, err error) {
|
||||
)
|
||||
}
|
||||
port = l.Addr().(*net.TCPAddr).Port
|
||||
err = l.Close()
|
||||
if err = l.Close(); err != nil {
|
||||
err = gerror.Wrapf(
|
||||
err,
|
||||
`close listening failed for network "%s", address "%s", port "%d"`,
|
||||
network, resolvedAddr.String(), port,
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -24,9 +24,10 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
helpOptionName = "help"
|
||||
helpOptionNameShort = "h"
|
||||
maxLineChars = 120
|
||||
helpOptionName = "help"
|
||||
helpOptionNameShort = "h"
|
||||
maxLineChars = 120
|
||||
tracingInstrumentName = "github.com/gogf/gf/v2/os/gcmd.Command"
|
||||
)
|
||||
|
||||
// Init does custom initialization.
|
||||
|
||||
@ -11,12 +11,19 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
// Print prints help info to stdout for current command.
|
||||
func (c *Command) Print() {
|
||||
c.PrintTo(os.Stdout)
|
||||
}
|
||||
|
||||
// PrintTo prints help info to custom io.Writer.
|
||||
func (c *Command) PrintTo(writer io.Writer) {
|
||||
var (
|
||||
prefix = gstr.Repeat(" ", 4)
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
@ -191,7 +198,7 @@ func (c *Command) Print() {
|
||||
}
|
||||
content := buffer.String()
|
||||
content = gstr.Replace(content, "\t", " ")
|
||||
fmt.Println(content)
|
||||
_, _ = writer.Write([]byte(content))
|
||||
}
|
||||
|
||||
type printLineBriefInput struct {
|
||||
|
||||
@ -8,16 +8,24 @@
|
||||
package gcmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/gogf/gf/v2"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/gtrace"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
"github.com/gogf/gf/v2/os/genv"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// Run calls custom function that bound to this command.
|
||||
@ -34,18 +42,23 @@ func (c *Command) RunWithValue(ctx context.Context) (value interface{}) {
|
||||
var (
|
||||
code = gerror.Code(err)
|
||||
detail = code.Detail()
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
)
|
||||
if code.Code() == gcode.CodeNotFound.Code() {
|
||||
fmt.Printf("ERROR: %s\n", gstr.Trim(err.Error()))
|
||||
buffer.WriteString(fmt.Sprintf("ERROR: %s\n", gstr.Trim(err.Error())))
|
||||
if lastCmd, ok := detail.(*Command); ok {
|
||||
lastCmd.Print()
|
||||
lastCmd.PrintTo(buffer)
|
||||
} else {
|
||||
c.Print()
|
||||
c.PrintTo(buffer)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("%+v\n", err)
|
||||
buffer.WriteString(fmt.Sprintf("%+v\n", err))
|
||||
}
|
||||
os.Exit(1)
|
||||
if gtrace.GetTraceID(ctx) == "" {
|
||||
fmt.Println(buffer.String())
|
||||
os.Exit(1)
|
||||
}
|
||||
glog.Stack(false).Fatal(ctx, buffer.String())
|
||||
}
|
||||
return value
|
||||
}
|
||||
@ -107,6 +120,24 @@ func (c *Command) doRun(ctx context.Context, parser *Parser) (value interface{},
|
||||
}
|
||||
return nil, c.defaultHelpFunc(ctx, parser)
|
||||
}
|
||||
// OpenTelemetry for command.
|
||||
var (
|
||||
span trace.Span
|
||||
tr = otel.GetTracerProvider().Tracer(
|
||||
tracingInstrumentName,
|
||||
trace.WithInstrumentationVersion(gf.VERSION),
|
||||
)
|
||||
)
|
||||
ctx, span = tr.Start(
|
||||
otel.GetTextMapPropagator().Extract(
|
||||
ctx,
|
||||
propagation.MapCarrier(genv.Map()),
|
||||
),
|
||||
gstr.Join(os.Args, " "),
|
||||
trace.WithSpanKind(trace.SpanKindServer),
|
||||
)
|
||||
defer span.End()
|
||||
span.SetAttributes(gtrace.CommonLabels()...)
|
||||
// Reparse the arguments for current command configuration.
|
||||
parser, err = c.reParse(ctx, parser)
|
||||
if err != nil {
|
||||
@ -126,7 +157,7 @@ func (c *Command) doRun(ctx context.Context, parser *Parser) (value interface{},
|
||||
return nil, c.defaultHelpFunc(ctx, parser)
|
||||
}
|
||||
|
||||
// reParse re-parses the arguments using option configuration of current command.
|
||||
// reParse parses the arguments using option configuration of current command.
|
||||
func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error) {
|
||||
if len(c.Arguments) == 0 {
|
||||
return parser, nil
|
||||
|
||||
@ -9,8 +9,12 @@ package gctx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/net/gtrace"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -18,13 +22,36 @@ type (
|
||||
StrKey string // StrKey is a type for warps basic type string as context key.
|
||||
)
|
||||
|
||||
var (
|
||||
// processCtx is the context initialized from process environment.
|
||||
processCtx context.Context
|
||||
)
|
||||
|
||||
func init() {
|
||||
// All environment key-value pairs.
|
||||
m := make(map[string]string)
|
||||
i := 0
|
||||
for _, s := range os.Environ() {
|
||||
i = strings.IndexByte(s, '=')
|
||||
m[s[0:i]] = s[i+1:]
|
||||
}
|
||||
// OpenTelemetry from environments.
|
||||
processCtx = otel.GetTextMapPropagator().Extract(
|
||||
context.Background(),
|
||||
propagation.MapCarrier(m),
|
||||
)
|
||||
}
|
||||
|
||||
// New creates and returns a context which contains context id.
|
||||
func New() context.Context {
|
||||
return WithCtx(context.Background())
|
||||
return WithCtx(processCtx)
|
||||
}
|
||||
|
||||
// WithCtx creates and returns a context containing context id upon given parent context `ctx`.
|
||||
func WithCtx(ctx context.Context) context.Context {
|
||||
if CtxId(ctx) != "" {
|
||||
return ctx
|
||||
}
|
||||
if gtrace.IsUsingDefaultProvider() {
|
||||
var span *gtrace.Span
|
||||
ctx, span = gtrace.NewSpan(ctx, "gctx.WithCtx")
|
||||
|
||||
@ -10,6 +10,8 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/command"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/os/gcache"
|
||||
@ -17,22 +19,28 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
defaultCacheExpire = "1m" // defaultCacheExpire is the expire time for file content caching in seconds.
|
||||
defaultCacheDuration = "1m" // defaultCacheExpire is the expire time for file content caching in seconds.
|
||||
commandEnvKeyForCache = "gf.gfile.cache" // commandEnvKeyForCache is the configuration key for command argument or environment configuring cache expire duration.
|
||||
)
|
||||
|
||||
var (
|
||||
// Default expire time for file content caching.
|
||||
cacheExpire = getCacheExpire()
|
||||
cacheDuration = getCacheDuration()
|
||||
|
||||
// internalCache is the memory cache for internal usage.
|
||||
internalCache = gcache.New()
|
||||
)
|
||||
|
||||
func getCacheExpire() time.Duration {
|
||||
d, err := time.ParseDuration(command.GetOptWithEnv(commandEnvKeyForCache, defaultCacheExpire))
|
||||
func getCacheDuration() time.Duration {
|
||||
cacheDurationConfigured := command.GetOptWithEnv(commandEnvKeyForCache, defaultCacheDuration)
|
||||
d, err := time.ParseDuration(cacheDurationConfigured)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
panic(gerror.WrapCodef(
|
||||
gcode.CodeInvalidConfiguration,
|
||||
err,
|
||||
`error parsing string "%s" to time duration`,
|
||||
cacheDurationConfigured,
|
||||
))
|
||||
}
|
||||
return d
|
||||
}
|
||||
@ -50,7 +58,7 @@ func GetContentsWithCache(path string, duration ...time.Duration) string {
|
||||
func GetBytesWithCache(path string, duration ...time.Duration) []byte {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
expire = cacheExpire
|
||||
expire = cacheDuration
|
||||
cacheKey = commandEnvKeyForCache + path
|
||||
)
|
||||
|
||||
|
||||
@ -120,7 +120,7 @@ func (w *Watcher) eventLoop() {
|
||||
|
||||
}
|
||||
// Calling the callbacks in order.
|
||||
for _, v := range callbacks {
|
||||
for _, callback := range callbacks {
|
||||
go func(callback *Callback) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
@ -133,7 +133,7 @@ func (w *Watcher) eventLoop() {
|
||||
}
|
||||
}()
|
||||
callback.Func(event)
|
||||
}(v)
|
||||
}(callback)
|
||||
}
|
||||
} else {
|
||||
break
|
||||
|
||||
@ -8,8 +8,9 @@
|
||||
package glog
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/internal/command"
|
||||
"github.com/gogf/gf/v2/os/grpool"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -30,7 +31,7 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
defaultDebug = gcmd.GetOptWithEnv(commandEnvKeyForDebug, true).Bool()
|
||||
defaultDebug = gconv.Bool(command.GetOptWithEnv(commandEnvKeyForDebug, "true"))
|
||||
SetDebug(defaultDebug)
|
||||
}
|
||||
|
||||
|
||||
@ -14,15 +14,15 @@ import (
|
||||
|
||||
// HandlerOutputJson is the structure outputting logging content as single json.
|
||||
type HandlerOutputJson struct {
|
||||
Time string // Formatted time string, like "2016-01-09 12:00:00".
|
||||
TraceId string // Trace id, only available if tracing is enabled.
|
||||
CtxStr string // The retrieved context value string from context, only available if Config.CtxKeys configured.
|
||||
Level string // Formatted level string, like "DEBU", "ERRO", etc. Eg: ERRO
|
||||
CallerFunc string // The source function name that calls logging, only available if F_CALLER_FN set.
|
||||
CallerPath string // The source file path and its line number that calls logging, only available if F_FILE_SHORT or F_FILE_LONG set.
|
||||
Prefix string // Custom prefix string for logging content.
|
||||
Content string // Content is the main logging content, containing error stack string produced by logger.
|
||||
Stack string // Stack string produced by logger, only available if Config.StStatus configured.
|
||||
Time string `json:""` // Formatted time string, like "2016-01-09 12:00:00".
|
||||
TraceId string `json:",omitempty"` // Trace id, only available if tracing is enabled.
|
||||
CtxStr string `json:",omitempty"` // The retrieved context value string from context, only available if Config.CtxKeys configured.
|
||||
Level string `json:""` // Formatted level string, like "DEBU", "ERRO", etc. Eg: ERRO
|
||||
CallerFunc string `json:",omitempty"` // The source function name that calls logging, only available if F_CALLER_FN set.
|
||||
CallerPath string `json:",omitempty"` // The source file path and its line number that calls logging, only available if F_FILE_SHORT or F_FILE_LONG set.
|
||||
Prefix string `json:",omitempty"` // Custom prefix string for logging content.
|
||||
Content string `json:""` // Content is the main logging content, containing error stack string produced by logger.
|
||||
Stack string `json:",omitempty"` // Stack string produced by logger, only available if Config.StStatus configured.
|
||||
}
|
||||
|
||||
// HandlerJson is a handler for output logging content as a single json string.
|
||||
@ -43,5 +43,6 @@ func HandlerJson(ctx context.Context, in *HandlerInput) {
|
||||
panic(err)
|
||||
}
|
||||
in.Buffer.Write(jsonBytes)
|
||||
in.Buffer.Write([]byte("\n"))
|
||||
in.Next(ctx)
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ func ParseTag(tag string) map[string]string {
|
||||
tag = tag[i+1:]
|
||||
value, err := strconv.Unquote(quotedValue)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
panic(gerror.WrapCodef(gcode.CodeInvalidParameter, err, `error parsing tag "%s"`, tag))
|
||||
}
|
||||
data[key] = gtag.Parse(value)
|
||||
}
|
||||
|
||||
@ -25,6 +25,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gtype"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/command"
|
||||
)
|
||||
|
||||
@ -58,9 +60,13 @@ var (
|
||||
)
|
||||
|
||||
func getDefaultInterval() time.Duration {
|
||||
n, err := strconv.Atoi(command.GetOptWithEnv(commandEnvKeyForInterval, defaultTimerInterval))
|
||||
interval := command.GetOptWithEnv(commandEnvKeyForInterval, defaultTimerInterval)
|
||||
n, err := strconv.Atoi(interval)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
panic(gerror.WrapCodef(
|
||||
gcode.CodeInvalidConfiguration, err, `error converting string "%s" to int number`,
|
||||
interval,
|
||||
))
|
||||
}
|
||||
return time.Duration(n) * time.Millisecond
|
||||
}
|
||||
|
||||
@ -8,6 +8,9 @@ package grand
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -33,7 +36,7 @@ func asyncProducingRandomBufferBytesLoop() {
|
||||
for {
|
||||
buffer := make([]byte, 1024)
|
||||
if n, err := rand.Read(buffer); err != nil {
|
||||
panic(err)
|
||||
panic(gerror.WrapCode(gcode.CodeInternalError, err, `error reading random buffer from system`))
|
||||
} else {
|
||||
// The random buffer from system is very expensive,
|
||||
// so fully reuse the random buffer by changing
|
||||
|
||||
Reference in New Issue
Block a user