mirror of
https://github.com/zhufuyi/sponge.git
synced 2025-09-26 20:51:14 +08:00
docs: update document
This commit is contained in:
@@ -106,8 +106,8 @@ func HandlerPbCommand() *cobra.Command {
|
||||
using help:
|
||||
1. move the folders "api" and "internal" to your project code folder.
|
||||
2. open a terminal and execute the command: make proto
|
||||
3. compile and run service: make run
|
||||
4. visit http://localhost:8080/apis/swagger/index.html in your browser, and test the http CRUD api.
|
||||
3. compile and run server: make run
|
||||
4. access http://localhost:8080/apis/swagger/index.html in your browser, and test the http CRUD api.
|
||||
|
||||
`)
|
||||
fmt.Printf("generate \"handler-pb\" code successfully, out = %s\n", outPath)
|
||||
|
@@ -103,8 +103,8 @@ func HandlerCommand() *cobra.Command {
|
||||
using help:
|
||||
1. move the folder "internal" to your project code folder.
|
||||
2. open a terminal and execute the command: make docs
|
||||
3. compile and run service: make run
|
||||
4. visit http://localhost:8080/swagger/index.html in your browser, and test the CRUD api interface.
|
||||
3. compile and run server: make run
|
||||
4. access http://localhost:8080/swagger/index.html in your browser, and test the CRUD api interface.
|
||||
|
||||
`)
|
||||
fmt.Printf("generate \"handler\" code successfully, out = %s\n", outPath)
|
||||
|
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/go-dev-frame/sponge/pkg/replacer"
|
||||
)
|
||||
|
||||
// HTTPPbCommand generate web service code based on protobuf file
|
||||
// HTTPPbCommand generate web server code based on protobuf file
|
||||
func HTTPPbCommand() *cobra.Command {
|
||||
var (
|
||||
moduleName string // module name for go.mod
|
||||
@@ -26,15 +26,15 @@ func HTTPPbCommand() *cobra.Command {
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "http-pb",
|
||||
Short: "Generate web service code based on protobuf file",
|
||||
Long: "Generate web service code based on protobuf file.",
|
||||
Example: color.HiBlackString(` # Generate web service code.
|
||||
Short: "Generate web server code based on protobuf file",
|
||||
Long: "Generate web server code based on protobuf file.",
|
||||
Example: color.HiBlackString(` # Generate web server code.
|
||||
sponge web http-pb --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --protobuf-file=./test.proto
|
||||
|
||||
# Generate web service code and specify the output directory, Note: code generation will be canceled when the latest generated file already exists.
|
||||
# Generate web server code and specify the output directory, Note: code generation will be canceled when the latest generated file already exists.
|
||||
sponge web http-pb --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --protobuf-file=./test.proto --out=./yourServerDir
|
||||
|
||||
# Generate web service code and specify the docker image repository address.
|
||||
# Generate web server code and specify the docker image repository address.
|
||||
sponge web http-pb --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --repo-addr=192.168.3.37:9443/user-name --protobuf-file=./test.proto
|
||||
|
||||
# If you want the generated code to suited to mono-repo, you need to set the parameter --suited-mono-repo=true`),
|
||||
@@ -173,12 +173,12 @@ func (g *httpPbGenerator) generateCode() (string, error) {
|
||||
using help:
|
||||
1. open a terminal and execute the command to generate code: make proto
|
||||
2. open file internal/handler/xxx.go, replace panic("implement me") according to template code example.
|
||||
3. compile and run service: make run
|
||||
4. visit http://localhost:8080/apis/swagger/index.html in your browser, and test the http api.
|
||||
3. compile and run server: make run
|
||||
4. access http://localhost:8080/apis/swagger/index.html in your browser, and test the http api.
|
||||
|
||||
`)
|
||||
outpath := r.GetOutputDir()
|
||||
fmt.Printf("generate %s's web service code successfully, out = %s\n", g.serverName, outpath)
|
||||
fmt.Printf("generate %s's web server code successfully, out = %s\n", g.serverName, outpath)
|
||||
return outpath, nil
|
||||
}
|
||||
|
||||
|
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/go-dev-frame/sponge/pkg/sql2code/parser"
|
||||
)
|
||||
|
||||
// HTTPCommand generate web service code
|
||||
// HTTPCommand generate web server code
|
||||
func HTTPCommand() *cobra.Command {
|
||||
var (
|
||||
moduleName string // module name for go.mod
|
||||
@@ -36,21 +36,21 @@ func HTTPCommand() *cobra.Command {
|
||||
//nolint
|
||||
cmd := &cobra.Command{
|
||||
Use: "http",
|
||||
Short: "Generate web service code based on sql",
|
||||
Long: "Generate web service code based on sql.",
|
||||
Example: color.HiBlackString(` # Generate web service code.
|
||||
Short: "Generate web server code based on sql",
|
||||
Long: "Generate web server code based on sql.",
|
||||
Example: color.HiBlackString(` # Generate web server code.
|
||||
sponge web http --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --db-driver=mysql --db-dsn=root:123456@(192.168.3.37:3306)/test --db-table=user
|
||||
|
||||
# Generate web service code with multiple table names.
|
||||
# Generate web server code with multiple table names.
|
||||
sponge web http --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --db-driver=mysql --db-dsn=root:123456@(192.168.3.37:3306)/test --db-table=t1,t2
|
||||
|
||||
# Generate web service code with extended api.
|
||||
# Generate web server code with extended api.
|
||||
sponge web http --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --db-driver=mysql --db-dsn=root:123456@(192.168.3.37:3306)/test --db-table=user --extended-api=true
|
||||
|
||||
# Generate web service code and specify the output directory, Note: code generation will be canceled when the latest generated file already exists.
|
||||
# Generate web server code and specify the output directory, Note: code generation will be canceled when the latest generated file already exists.
|
||||
sponge web http --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --db-driver=mysql --db-dsn=root:123456@(192.168.3.37:3306)/test --db-table=user --out=./yourServerDir
|
||||
|
||||
# Generate web service code and specify the docker image repository address.
|
||||
# Generate web server code and specify the docker image repository address.
|
||||
sponge web http --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --repo-addr=192.168.3.37:9443/user-name --db-driver=mysql --db-dsn=root:123456@(192.168.3.37:3306)/test --db-table=user
|
||||
|
||||
# If you want the generated code to suited to mono-repo, you need to set the parameter --suited-mono-repo=true`),
|
||||
@@ -135,11 +135,11 @@ func HTTPCommand() *cobra.Command {
|
||||
fmt.Printf(`
|
||||
using help:
|
||||
1. open a terminal and execute the command to generate the swagger documentation: make docs
|
||||
2. compile and run service: make run
|
||||
3. visit http://localhost:8080/swagger/index.html in your browser, and test the http CRUD api.
|
||||
2. compile and run server: make run
|
||||
3. access http://localhost:8080/swagger/index.html in your browser, and test the http CRUD api.
|
||||
|
||||
`)
|
||||
fmt.Printf("generate %s's web service code successfully, out = %s\n", serverName, outPath)
|
||||
fmt.Printf("generate %s's web server code successfully, out = %s\n", serverName, outPath)
|
||||
|
||||
_ = generateConfigmap(serverName, outPath)
|
||||
return nil
|
||||
|
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/go-dev-frame/sponge/pkg/replacer"
|
||||
)
|
||||
|
||||
// RPCGwPbCommand generate grpc gateway service code base on protobuf file
|
||||
// RPCGwPbCommand generate grpc gateway server code base on protobuf file
|
||||
func RPCGwPbCommand() *cobra.Command {
|
||||
var (
|
||||
moduleName string // module name for go.mod
|
||||
@@ -26,15 +26,15 @@ func RPCGwPbCommand() *cobra.Command {
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "rpc-gw-pb",
|
||||
Short: "Generate grpc gateway service code based on protobuf file",
|
||||
Long: "Generate grpc gateway service code based on protobuf file.",
|
||||
Example: color.HiBlackString(` # Generate grpc gateway service code.
|
||||
Short: "Generate grpc gateway server code based on protobuf file",
|
||||
Long: "Generate grpc gateway server code based on protobuf file.",
|
||||
Example: color.HiBlackString(` # Generate grpc gateway server code.
|
||||
sponge micro rpc-gw-pb --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --protobuf-file=./demo.proto
|
||||
|
||||
# Generate grpc gateway service code and specify the output directory, Note: code generation will be canceled when the latest generated file already exists.
|
||||
# Generate grpc gateway server code and specify the output directory, Note: code generation will be canceled when the latest generated file already exists.
|
||||
sponge micro rpc-gw-pb --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --protobuf-file=./demo.proto --out=./yourServerDir
|
||||
|
||||
# Generate grpc gateway service code and specify the docker image repository address.
|
||||
# Generate grpc gateway server code and specify the docker image repository address.
|
||||
sponge micro rpc-gw-pb --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --repo-addr=192.168.3.37:9443/user-name --protobuf-file=./demo.proto
|
||||
|
||||
# If you want the generated code to suited to mono-repo, you need to set the parameter --suited-mono-repo=true`),
|
||||
@@ -174,11 +174,11 @@ func (g *rpcGwPbGenerator) generateCode() error {
|
||||
using help:
|
||||
1. open a terminal and execute the command to generate code: make proto
|
||||
2. open internal/service/xxx.go file, replace panic("implement me") according to template code example.
|
||||
3. compile and run service: make run
|
||||
4. visit http://localhost:8080/apis/swagger/index.html in your browser, and test the http api.
|
||||
3. compile and run server: make run
|
||||
4. access http://localhost:8080/apis/swagger/index.html in your browser, and test the http api.
|
||||
|
||||
`)
|
||||
fmt.Printf("generate %s's grpc gateway service code successfully, out = %s\n", g.serverName, r.GetOutputDir())
|
||||
fmt.Printf("generate %s's grpc gateway server code successfully, out = %s\n", g.serverName, r.GetOutputDir())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/go-dev-frame/sponge/pkg/replacer"
|
||||
)
|
||||
|
||||
// RPCPbCommand generate grpc service code bash on protobuf file
|
||||
// RPCPbCommand generate grpc server code based on protobuf file
|
||||
func RPCPbCommand() *cobra.Command {
|
||||
var (
|
||||
moduleName string // module name for go.mod
|
||||
@@ -26,15 +26,15 @@ func RPCPbCommand() *cobra.Command {
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "rpc-pb",
|
||||
Short: "Generate grpc service code based on protobuf file",
|
||||
Long: "Generate grpc service code based on protobuf file.",
|
||||
Example: color.HiBlackString(` # Generate grpc service code.
|
||||
Short: "Generate grpc server code based on protobuf file",
|
||||
Long: "Generate grpc server code based on protobuf file.",
|
||||
Example: color.HiBlackString(` # Generate grpc server code.
|
||||
sponge micro rpc-pb --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --protobuf-file=./demo.proto
|
||||
|
||||
# Generate grpc service code and specify the output directory, Note: code generation will be canceled when the latest generated file already exists.
|
||||
# Generate grpc server code and specify the output directory, Note: code generation will be canceled when the latest generated file already exists.
|
||||
sponge micro rpc-pb --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --protobuf-file=./demo.proto --out=./yourServerDir
|
||||
|
||||
# Generate grpc service code and specify the docker image repository address.
|
||||
# Generate grpc server code and specify the docker image repository address.
|
||||
sponge micro rpc-pb --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --repo-addr=192.168.3.37:9443/user-name --protobuf-file=./demo.proto
|
||||
|
||||
# If you want the generated code to suited to mono-repo, you need to set the parameter --suited-mono-repo=true`),
|
||||
@@ -170,11 +170,11 @@ func (g *rpcPbGenerator) generateCode() error {
|
||||
using help:
|
||||
1. open a terminal and execute the command to generate code: make proto
|
||||
2. open file "internal/service/xxx.go", replace panic("implement me") according to template code example.
|
||||
3. compile and run service: make run
|
||||
4. open the file "internal/service/xxx_client_test.go" using Goland or VS Code, and test the grpc api.
|
||||
3. compile and run server: make run
|
||||
4. open the file "internal/service/xxx_client_test.go" using Goland or VSCode, and test the grpc api.
|
||||
|
||||
`)
|
||||
fmt.Printf("generate %s's grpc service code successfully, out = %s\n", g.serverName, r.GetOutputDir())
|
||||
fmt.Printf("generate %s's grpc server code successfully, out = %s\n", g.serverName, r.GetOutputDir())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/go-dev-frame/sponge/pkg/sql2code/parser"
|
||||
)
|
||||
|
||||
// RPCCommand generate grpc service code
|
||||
// RPCCommand generate grpc server code
|
||||
func RPCCommand() *cobra.Command {
|
||||
var (
|
||||
moduleName string // module name for go.mod
|
||||
@@ -37,21 +37,21 @@ func RPCCommand() *cobra.Command {
|
||||
//nolint
|
||||
cmd := &cobra.Command{
|
||||
Use: "rpc",
|
||||
Short: "Generate grpc service code based on sql",
|
||||
Long: "Generate grpc service code based on sql.",
|
||||
Example: color.HiBlackString(` # Generate grpc service code.
|
||||
Short: "Generate grpc server code based on sql",
|
||||
Long: "Generate grpc server code based on sql.",
|
||||
Example: color.HiBlackString(` # Generate grpc server code.
|
||||
sponge micro rpc --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --db-driver=mysql --db-dsn=root:123456@(192.168.3.37:3306)/test --db-table=user
|
||||
|
||||
# Generate grpc service code with multiple table names.
|
||||
# Generate grpc server code with multiple table names.
|
||||
sponge micro rpc --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --db-driver=mysql --db-dsn=root:123456@(192.168.3.37:3306)/test --db-table=t1,t2
|
||||
|
||||
# Generate grpc service code with extended api.
|
||||
# Generate grpc server code with extended api.
|
||||
sponge micro rpc --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --db-driver=mysql --db-dsn=root:123456@(192.168.3.37:3306)/test --db-table=user --extended-api=true
|
||||
|
||||
# Generate grpc service code and specify the output directory, Note: code generation will be canceled when the latest generated file already exists.
|
||||
# Generate grpc server code and specify the output directory, Note: code generation will be canceled when the latest generated file already exists.
|
||||
sponge micro rpc --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --db-driver=mysql --db-dsn=root:123456@(192.168.3.37:3306)/test --db-table=user --out=./yourServerDir
|
||||
|
||||
# Generate grpc service code and specify the docker image repository address.
|
||||
# Generate grpc server code and specify the docker image repository address.
|
||||
sponge micro rpc --module-name=yourModuleName --server-name=yourServerName --project-name=yourProjectName --repo-addr=192.168.3.37:9443/user-name --db-driver=mysql --db-dsn=root:123456@(192.168.3.37:3306)/test --db-table=user
|
||||
|
||||
# If you want the generated code to suited to mono-repo, you need to set the parameter --suited-mono-repo=true`),
|
||||
@@ -135,11 +135,11 @@ func RPCCommand() *cobra.Command {
|
||||
fmt.Printf(`
|
||||
using help:
|
||||
1. open a terminal and execute the command to generate code: make proto
|
||||
2. compile and run service: make run
|
||||
3. open the file internal/service/xxx_client_test.go using Goland or VS Code, and test the grpc CRUD api.
|
||||
2. compile and run server: make run
|
||||
3. open the file internal/service/xxx_client_test.go using Goland or VSCode, and test the grpc CRUD api.
|
||||
|
||||
`)
|
||||
fmt.Printf("generate %s's grpc service code successfully, out = %s\n", serverName, outPath)
|
||||
fmt.Printf("generate %s's grpc server code successfully, out = %s\n", serverName, outPath)
|
||||
|
||||
_ = generateConfigmap(serverName, outPath)
|
||||
return nil
|
||||
|
@@ -106,9 +106,9 @@ func ServiceAndHandlerCRUDCommand() *cobra.Command {
|
||||
using help:
|
||||
1. move the folders "api" and "internal" to your project code folder.
|
||||
2. open a terminal and execute the command to generate code: make proto
|
||||
3. compile and run service: make run
|
||||
4. visit http://localhost:8080/apis/swagger/index.html in your browser, and test the http CRUD api.
|
||||
open the file "internal/service/xxx_client_test.go" using Goland or VS Code, and test the grpc CRUD api.
|
||||
3. compile and run server: make run
|
||||
4. access http://localhost:8080/apis/swagger/index.html in your browser, and test the http CRUD api.
|
||||
open the file "internal/service/xxx_client_test.go" using Goland or VSCode, and test the grpc CRUD api.
|
||||
|
||||
`)
|
||||
fmt.Printf("generate \"service-http\" code successfully, out = %s\n", outPath)
|
||||
|
@@ -105,8 +105,8 @@ func ServiceCommand() *cobra.Command {
|
||||
using help:
|
||||
1. move the folders "api" and "internal" to your project code folder.
|
||||
2. open a terminal and execute the command to generate code: make proto
|
||||
3. compile and run service: make run
|
||||
4. open the file internal/service/xxx_client_test.go using Goland or VS Code, and test the grpc CRUD api.
|
||||
3. compile and run server: make run
|
||||
4. open the file internal/service/xxx_client_test.go using Goland or VSCode, and test the grpc CRUD api.
|
||||
|
||||
`)
|
||||
fmt.Printf("generate \"service\" code successfully, out = %s\n", outPath)
|
||||
|
@@ -27,6 +27,7 @@ func GenMicroCommand() *cobra.Command {
|
||||
generate.RPCPbCommand(),
|
||||
generate.GRPCConnectionCommand(),
|
||||
generate.ConvertSwagJSONCommand("micro"),
|
||||
generate.GRPCAndHTTPCommand(),
|
||||
generate.GRPCAndHTTPPbCommand(),
|
||||
generate.ServiceAndHandlerCRUDCommand(),
|
||||
)
|
||||
|
@@ -25,8 +25,8 @@ func OpenUICommand() *cobra.Command {
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "Run code generation UI service",
|
||||
Long: "Run code generation UI service.",
|
||||
Short: "Run code generation engine service, generate code in UI interface",
|
||||
Long: "Run code generation engine service, generate code in UI interface.",
|
||||
Example: color.HiBlackString(` # Running ui service, local browser access only.
|
||||
sponge run
|
||||
|
||||
@@ -43,7 +43,7 @@ func OpenUICommand() *cobra.Command {
|
||||
return err
|
||||
}
|
||||
}
|
||||
fmt.Printf("The code generation service has started, version = %s, please visit %s in your browser.\n",
|
||||
fmt.Printf("The code generation engine service is already running, version = %s, access the url %s in your browser.\n",
|
||||
getVersion(), color.HiCyanString(spongeAddr))
|
||||
go func() {
|
||||
_ = open(spongeAddr)
|
||||
|
@@ -56,7 +56,7 @@ func runUpgrade(targetVersion string) (string, error) {
|
||||
p.LoopPrint(runningTip)
|
||||
err := runUpgradeCommand(targetVersion)
|
||||
if err != nil {
|
||||
p.StopPrint(failTip)
|
||||
p.StopPrint(failTip + "\nError: " + err.Error())
|
||||
return "", err
|
||||
}
|
||||
p.StopPrint(finishTip)
|
||||
@@ -68,7 +68,7 @@ func runUpgrade(targetVersion string) (string, error) {
|
||||
p.LoopPrint(runningTip)
|
||||
ver, err := copyToTempDir(targetVersion)
|
||||
if err != nil {
|
||||
p.StopPrint(failTip)
|
||||
p.StopPrint(failTip + "\nError: " + err.Error())
|
||||
return "", err
|
||||
}
|
||||
p.StopPrint(finishTip)
|
||||
@@ -80,7 +80,7 @@ func runUpgrade(targetVersion string) (string, error) {
|
||||
p.LoopPrint(runningTip)
|
||||
err = updateSpongeInternalPlugin(ver)
|
||||
if err != nil {
|
||||
p.StopPrint(failTip)
|
||||
p.StopPrint(failTip + "\nError: " + err.Error())
|
||||
return "", err
|
||||
}
|
||||
p.StopPrint(finishTip)
|
||||
|
@@ -193,7 +193,12 @@ func handleGenerateCode(c *gin.Context, outPath string, arg string) {
|
||||
}
|
||||
|
||||
zipFile := out + ".zip"
|
||||
err := CompressPathToZip(out, zipFile)
|
||||
var err error
|
||||
if gofile.IsWindows() {
|
||||
err = AdaptToWindowsZip(out, zipFile)
|
||||
} else {
|
||||
err = CompressPathToZip(out, zipFile)
|
||||
}
|
||||
if err != nil {
|
||||
responseErr(c, err, errcode.InternalServerError)
|
||||
return
|
||||
@@ -424,6 +429,56 @@ func compress(file *os.File, prefix string, zw *zip.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func AdaptToWindowsZip(outPath, targetFile string) error {
|
||||
d, err := os.Create(targetFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
w := zip.NewWriter(d)
|
||||
defer w.Close()
|
||||
|
||||
baseDir := filepath.Dir(outPath)
|
||||
|
||||
return filepath.Walk(outPath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
header, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
relPath, err := filepath.Rel(baseDir, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
header.Name = filepath.ToSlash(relPath) // convert to slash path
|
||||
|
||||
if info.IsDir() {
|
||||
header.Name += "/"
|
||||
_, err = w.CreateHeader(header)
|
||||
return err
|
||||
}
|
||||
|
||||
writer, err := w.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = io.Copy(writer, file)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func getSpongeDir() string {
|
||||
dir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
|
2
doc.go
2
doc.go
@@ -26,7 +26,7 @@
|
||||
//
|
||||
// plugins Managing sponge dependency plugins
|
||||
//
|
||||
// run Run code generation UI service
|
||||
// run Run code generation engine service, generate code in UI interface
|
||||
//
|
||||
// template Generate code based on custom templates
|
||||
//
|
||||
|
@@ -11,34 +11,39 @@ Common gin middleware libraries.
|
||||
You can set the maximum length for printing, add a request id field, ignore print path, customize [zap](go.uber.org/zap) log.
|
||||
|
||||
```go
|
||||
import "github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
)
|
||||
|
||||
func NewRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
// ......
|
||||
|
||||
// Print input parameters and return results
|
||||
// case 1:
|
||||
r.Use(middleware.Logging()) // default
|
||||
// case 2:
|
||||
r.Use(middleware.Logging( // custom
|
||||
middleware.WithMaxLen(400),
|
||||
middleware.WithRequestIDFromHeader(),
|
||||
//middleware.WithRequestIDFromContext(),
|
||||
//middleware.WithLog(log), // custom zap log
|
||||
//middleware.WithIgnoreRoutes("/hello"),
|
||||
))
|
||||
// Case 1: default
|
||||
{
|
||||
r.Use(middleware.Logging()
|
||||
}
|
||||
// Case 2: custom
|
||||
{
|
||||
r.Use(middleware.Logging(
|
||||
middleware.WithLog(logger.Get()))
|
||||
middleware.WithMaxLen(400),
|
||||
middleware.WithRequestIDFromHeader(),
|
||||
//middleware.WithRequestIDFromContext(),
|
||||
//middleware.WithIgnoreRoutes("/hello"),
|
||||
))
|
||||
}
|
||||
|
||||
// ----------------------------------------
|
||||
/*******************************************
|
||||
TIP: You can use middleware.SimpleLog instead of
|
||||
middleware.Logging, it only prints return results
|
||||
*******************************************/
|
||||
|
||||
// Print only return results
|
||||
// case 1:
|
||||
r.Use(middleware.SimpleLog()) // default
|
||||
// case 2:
|
||||
r.Use(middleware.SimpleLog( // custom
|
||||
middleware.WithRequestIDFromHeader(),
|
||||
//middleware.WithRequestIDFromContext(),
|
||||
//middleware.WithLog(log), // custom zap log
|
||||
//middleware.WithIgnoreRoutes("/hello"),
|
||||
))
|
||||
// ......
|
||||
return r
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
@@ -46,10 +51,20 @@ You can set the maximum length for printing, add a request id field, ignore prin
|
||||
### Allow cross-domain requests middleware
|
||||
|
||||
```go
|
||||
import "github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
)
|
||||
|
||||
func NewRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
// ......
|
||||
|
||||
r.Use(middleware.Cors())
|
||||
|
||||
// ......
|
||||
return r
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
@@ -59,20 +74,29 @@ You can set the maximum length for printing, add a request id field, ignore prin
|
||||
Adaptive flow limitation based on hardware resources.
|
||||
|
||||
```go
|
||||
import "github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
)
|
||||
|
||||
func NewRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
// ......
|
||||
|
||||
// case 1: default
|
||||
// Case 1: default
|
||||
r.Use(middleware.RateLimit())
|
||||
|
||||
// case 2: custom
|
||||
// Case 2: custom
|
||||
r.Use(middleware.RateLimit(
|
||||
middleware.WithWindow(time.Second*10),
|
||||
middleware.WithBucket(1000),
|
||||
middleware.WithCPUThreshold(100),
|
||||
middleware.WithCPUQuota(0.5),
|
||||
))
|
||||
|
||||
// ......
|
||||
return r
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
@@ -80,13 +104,23 @@ Adaptive flow limitation based on hardware resources.
|
||||
### Circuit Breaker middleware
|
||||
|
||||
```go
|
||||
import "github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
)
|
||||
|
||||
func NewRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
// ......
|
||||
|
||||
r.Use(middleware.CircuitBreaker(
|
||||
//middleware.WithValidCode(http.StatusRequestTimeout), // add error code 408 for circuit breaker
|
||||
//middleware.WithDegradeHandler(handler), // add custom degrade handler
|
||||
))
|
||||
|
||||
// ......
|
||||
return r
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
@@ -97,14 +131,14 @@ Adaptive flow limitation based on hardware resources.
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
"github.com/go-dev-frame/sponge/pkg/gin/response"
|
||||
"github.com/go-dev-frame/sponge/pkg/jwt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func web() {
|
||||
func main() {
|
||||
r := gin.Default()
|
||||
|
||||
// Case 1: default jwt options, signKey, signMethod(HS256), expiry time(24 hour)
|
||||
@@ -195,8 +229,11 @@ func extraVerifyFn(claims *jwt.Claims, c *gin.Context) error {
|
||||
### Tracing middleware
|
||||
|
||||
```go
|
||||
import "github.com/go-dev-frame/sponge/pkg/tracer"
|
||||
import "github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
"github.com/go-dev-frame/sponge/pkg/tracer"
|
||||
)
|
||||
|
||||
func InitTrace(serviceName string) {
|
||||
exporter, err := tracer.NewJaegerAgentExporter("192.168.3.37", "6831")
|
||||
@@ -213,15 +250,18 @@ func InitTrace(serviceName string) {
|
||||
tracer.Init(exporter, resource) // collect all by default
|
||||
}
|
||||
|
||||
func NewRouter(
|
||||
func NewRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
// ......
|
||||
|
||||
r.Use(middleware.Tracing("your-service-name"))
|
||||
|
||||
// ......
|
||||
)
|
||||
return r
|
||||
}
|
||||
|
||||
// if necessary, you can create a span in the program
|
||||
func SpanDemo(serviceName string, spanName string, ctx context.Context) {
|
||||
func CreateSpanDemo(serviceName string, spanName string, ctx context.Context) {
|
||||
_, span := otel.Tracer(serviceName).Start(
|
||||
ctx, spanName,
|
||||
trace.WithAttributes(attribute.String(spanName, time.Now().String())),
|
||||
@@ -237,9 +277,15 @@ func SpanDemo(serviceName string, spanName string, ctx context.Context) {
|
||||
### Metrics middleware
|
||||
|
||||
```go
|
||||
import "github.com/go-dev-frame/sponge/pkg/gin/middleware/metrics"
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
"github.com/go-dev-frame/sponge/pkg/gin/middleware/metrics"
|
||||
)
|
||||
|
||||
func NewRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
// ......
|
||||
|
||||
r.Use(metrics.Metrics(r,
|
||||
//metrics.WithMetricsPath("/demo/metrics"), // default is /metrics
|
||||
@@ -247,6 +293,9 @@ func SpanDemo(serviceName string, spanName string, ctx context.Context) {
|
||||
//metrics.WithIgnoreRequestMethods(http.MethodHead), // ignore request methods
|
||||
//metrics.WithIgnoreRequestPaths("/ping", "/health"), // ignore request paths
|
||||
))
|
||||
|
||||
// ......
|
||||
return r
|
||||
```
|
||||
|
||||
<br>
|
||||
@@ -254,25 +303,33 @@ func SpanDemo(serviceName string, spanName string, ctx context.Context) {
|
||||
### Request id
|
||||
|
||||
```go
|
||||
import "github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
)
|
||||
|
||||
// Default request id
|
||||
func NewRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
r.Use(middleware.RequestID())
|
||||
// ......
|
||||
|
||||
// --- or ---
|
||||
// Case 1: default request id
|
||||
{
|
||||
r.Use(middleware.RequestID())
|
||||
}
|
||||
// Case 2: custom request id key
|
||||
{
|
||||
//r.User(middleware.RequestID(
|
||||
// middleware.WithContextRequestIDKey("your ctx request id key"), // default is request_id
|
||||
// middleware.WithHeaderRequestIDKey("your header request id key"), // default is X-Request-Id
|
||||
//))
|
||||
// If you change the ContextRequestIDKey, you have to set the same key name if you want to print the request id in the mysql logs as well.
|
||||
// example:
|
||||
// db, err := mysql.Init(dsn,mysql.WithLogRequestIDKey("your ctx request id key")) // print request_id
|
||||
}
|
||||
|
||||
// Customized request id key
|
||||
//r.User(middleware.RequestID(
|
||||
// middleware.WithContextRequestIDKey("your ctx request id key"), // default is request_id
|
||||
// middleware.WithHeaderRequestIDKey("your header request id key"), // default is X-Request-Id
|
||||
//))
|
||||
// If you change the ContextRequestIDKey, you have to set the same key name if you want to print the request id in the mysql logs as well.
|
||||
// example:
|
||||
// db, err := mysql.Init(dsn,
|
||||
// mysql.WithLogRequestIDKey("your ctx request id key"), // print request_id
|
||||
// ...
|
||||
// )
|
||||
// ......
|
||||
return r
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
@@ -280,17 +337,30 @@ func SpanDemo(serviceName string, spanName string, ctx context.Context) {
|
||||
### Timeout
|
||||
|
||||
```go
|
||||
import "github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-dev-frame/sponge/pkg/gin/middleware"
|
||||
)
|
||||
|
||||
func NewRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
// ......
|
||||
|
||||
// way1: global set timeout
|
||||
r.Use(middleware.Timeout(time.Second*5))
|
||||
|
||||
// --- or ---
|
||||
|
||||
// way2: router set timeout
|
||||
r.GET("/userExample/:id", middleware.Timeout(time.Second*3), h.GetByID)
|
||||
|
||||
// Case 1: global set timeout
|
||||
{
|
||||
r.Use(middleware.Timeout(time.Second*5))
|
||||
}
|
||||
// Case 2: set timeout for specifyed router
|
||||
{
|
||||
r.GET("/userExample/:id", middleware.Timeout(time.Second*3), GetByID)
|
||||
}
|
||||
// Note: If timeout is set both globally and in the router, the minimum timeout prevails
|
||||
|
||||
// ......
|
||||
return r
|
||||
}
|
||||
|
||||
func GetByID(c *gin.Context) {
|
||||
// do something
|
||||
}
|
||||
```
|
||||
|
@@ -24,23 +24,28 @@ All import paths are "github.com/go-dev-frame/sponge/pkg/grpc/interceptor".
|
||||
**gRPC server side**
|
||||
|
||||
```go
|
||||
// set unary server logging
|
||||
func getServerOptions() []grpc.ServerOption {
|
||||
var options []grpc.ServerOption
|
||||
|
||||
option := grpc.ChainUnaryInterceptor(
|
||||
// if you don't want to log reply data, you can use interceptor.StreamServerSimpleLog instead of interceptor.UnaryServerLog,
|
||||
interceptor.UnaryServerLog(
|
||||
logger.Get(),
|
||||
interceptor.WithReplaceGRPCLogger(),
|
||||
//interceptor.WithMarshalFn(fn), // customised marshal function, default is jsonpb.Marshal
|
||||
//interceptor.WithLogIgnoreMethods(fullMethodNames), // ignore methods logging
|
||||
//interceptor.WithMaxLen(400), // logging max length, default 300
|
||||
),
|
||||
)
|
||||
options = append(options, option)
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"github.com/go-dev-frame/sponge/pkg/logger"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
return options
|
||||
func setServerOptions() []grpc.ServerOption {
|
||||
var options []grpc.ServerOption
|
||||
|
||||
option := grpc.ChainUnaryInterceptor(
|
||||
// if you don't want to log reply data, you can use interceptor.StreamServerSimpleLog instead of interceptor.UnaryServerLog,
|
||||
interceptor.UnaryServerLog( // set unary server logging
|
||||
logger.Get(),
|
||||
interceptor.WithReplaceGRPCLogger(),
|
||||
//interceptor.WithMarshalFn(fn), // customised marshal function, default is jsonpb.Marshal
|
||||
//interceptor.WithLogIgnoreMethods(fullMethodNames), // ignore methods logging
|
||||
//interceptor.WithMaxLen(400), // logging max length, default 300
|
||||
),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
|
||||
@@ -50,19 +55,23 @@ func getServerOptions() []grpc.ServerOption {
|
||||
**gRPC client side**
|
||||
|
||||
```go
|
||||
// set unary client logging
|
||||
func getDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
option := grpc.WithChainUnaryInterceptor(
|
||||
interceptor.UnaryClientLog(
|
||||
logger.Get(),
|
||||
interceptor.WithReplaceGRPCLogger(),
|
||||
),
|
||||
)
|
||||
options = append(options, option)
|
||||
func setDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
|
||||
return options
|
||||
option := grpc.WithChainUnaryInterceptor(
|
||||
interceptor.UnaryClientLog( // set unary client logging
|
||||
logger.Get(),
|
||||
interceptor.WithReplaceGRPCLogger(),
|
||||
),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
// you can also set stream client logging
|
||||
@@ -75,30 +84,40 @@ func getDialOptions() []grpc.DialOption {
|
||||
**gRPC server side**
|
||||
|
||||
```go
|
||||
func getServerOptions() []grpc.ServerOption {
|
||||
var options []grpc.ServerOption
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
option := grpc.ChainUnaryInterceptor(
|
||||
interceptor.UnaryServerRecovery(),
|
||||
)
|
||||
options = append(options, option)
|
||||
func setServerOptions() []grpc.ServerOption {
|
||||
var options []grpc.ServerOption
|
||||
|
||||
return options
|
||||
option := grpc.ChainUnaryInterceptor(
|
||||
interceptor.UnaryServerRecovery(),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
```
|
||||
|
||||
**gRPC client side**
|
||||
|
||||
```go
|
||||
func getDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
option := grpc.WithChainUnaryInterceptor(
|
||||
interceptor.UnaryClientRecovery(),
|
||||
)
|
||||
options = append(options, option)
|
||||
func setDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
|
||||
return options
|
||||
option := grpc.WithChainUnaryInterceptor(
|
||||
interceptor.UnaryClientRecovery(),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
```
|
||||
|
||||
@@ -109,77 +128,94 @@ func getDialOptions() []grpc.DialOption {
|
||||
**gRPC client side**
|
||||
|
||||
```go
|
||||
func getDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// use insecure transfer
|
||||
options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
func setDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
|
||||
// retry
|
||||
option := grpc.WithChainUnaryInterceptor(
|
||||
interceptor.UnaryClientRetry(
|
||||
//middleware.WithRetryTimes(5), // modify the default number of retries to 3 by default
|
||||
//middleware.WithRetryInterval(100*time.Millisecond), // modify the default retry interval, default 50 milliseconds
|
||||
//middleware.WithRetryErrCodes(), // add trigger retry error code, default is codes.Internal, codes.DeadlineExceeded, codes.Unavailable
|
||||
),
|
||||
)
|
||||
options = append(options, option)
|
||||
// use insecure transfer
|
||||
options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
|
||||
return options
|
||||
// retry
|
||||
option := grpc.WithChainUnaryInterceptor(
|
||||
interceptor.UnaryClientRetry(
|
||||
//interceptor.WithRetryTimes(5), // modify the default number of retries to 3 by default
|
||||
//interceptor.WithRetryInterval(100*time.Millisecond), // modify the default retry interval, default 50 milliseconds
|
||||
//interceptor.WithRetryErrCodes(), // add trigger retry error code, default is codes.Internal, codes.DeadlineExceeded, codes.Unavailable
|
||||
),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
#### Adaptive rate limiter interceptor
|
||||
#### Rate limiter interceptor
|
||||
|
||||
Adaptive flow limitation based on hardware resources.
|
||||
|
||||
**gRPC server side**
|
||||
|
||||
```go
|
||||
func getDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// use insecure transfer
|
||||
options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
func setDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
|
||||
// rate limiter
|
||||
option := grpc.ChainUnaryInterceptor(
|
||||
interceptor.UnaryServerRateLimit(
|
||||
//interceptor.WithWindow(time.Second*5),
|
||||
//interceptor.WithBucket(200),
|
||||
//interceptor.WithCPUThreshold(600),
|
||||
//interceptor.WithCPUQuota(0),
|
||||
),
|
||||
)
|
||||
options = append(options, option)
|
||||
// use insecure transfer
|
||||
options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
|
||||
return options
|
||||
// rate limiter
|
||||
option := grpc.ChainUnaryInterceptor(
|
||||
interceptor.UnaryServerRateLimit(
|
||||
//interceptor.WithWindow(time.Second*5),
|
||||
//interceptor.WithBucket(200),
|
||||
//interceptor.WithCPUThreshold(600),
|
||||
//interceptor.WithCPUQuota(0),
|
||||
),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
#### Adaptive circuit breaker interceptor
|
||||
#### Circuit breaker interceptor
|
||||
|
||||
**gRPC server side**
|
||||
|
||||
```go
|
||||
func getDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// use insecure transfer
|
||||
options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
func setDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
|
||||
// circuit breaker
|
||||
option := grpc.ChainUnaryInterceptor(
|
||||
interceptor.UnaryServerCircuitBreaker(
|
||||
//interceptor.WithValidCode(codes.DeadlineExceeded), // add error code 4 for circuit breaker
|
||||
//interceptor.WithUnaryServerDegradeHandler(handler), // add custom degrade handler
|
||||
),
|
||||
)
|
||||
options = append(options, option)
|
||||
// use insecure transfer
|
||||
options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
|
||||
return options
|
||||
// circuit breaker
|
||||
option := grpc.ChainUnaryInterceptor(
|
||||
interceptor.UnaryServerCircuitBreaker(
|
||||
//interceptor.WithValidCode(codes.DeadlineExceeded), // add error code for circuit breaker
|
||||
//interceptor.WithUnaryServerDegradeHandler(handler), // add custom degrade handler
|
||||
),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
```
|
||||
|
||||
@@ -190,19 +226,23 @@ func getDialOptions() []grpc.DialOption {
|
||||
**gRPC client side**
|
||||
|
||||
```go
|
||||
func getDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// use insecure transfer
|
||||
options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
func setDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
|
||||
// timeout
|
||||
option := grpc.WithChainUnaryInterceptor(
|
||||
interceptor.UnaryClientTimeout(time.Second), // set timeout
|
||||
)
|
||||
options = append(options, option)
|
||||
// use insecure transfer
|
||||
options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
|
||||
return options
|
||||
option := grpc.WithChainUnaryInterceptor(
|
||||
interceptor.UnaryClientTimeout(time.Second), // set timeout
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
```
|
||||
|
||||
@@ -210,63 +250,84 @@ func getDialOptions() []grpc.DialOption {
|
||||
|
||||
#### Tracing interceptor
|
||||
|
||||
**gRPC server side**
|
||||
**Initialize tracing**
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/tracer"
|
||||
"go.opentelemetry.io/otel"
|
||||
)
|
||||
|
||||
// initialize tracing
|
||||
func InitTrace(serviceName string) {
|
||||
exporter, err := tracer.NewJaegerAgentExporter("192.168.3.37", "6831")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
exporter, err := tracer.NewJaegerAgentExporter("192.168.3.37", "6831")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
resource := tracer.NewResource(
|
||||
tracer.WithServiceName(serviceName),
|
||||
tracer.WithEnvironment("dev"),
|
||||
tracer.WithServiceVersion("demo"),
|
||||
)
|
||||
resource := tracer.NewResource(
|
||||
tracer.WithServiceName(serviceName),
|
||||
tracer.WithEnvironment("dev"),
|
||||
tracer.WithServiceVersion("demo"),
|
||||
)
|
||||
|
||||
tracer.Init(exporter, resource) // collect all by default
|
||||
}
|
||||
|
||||
// set up trace on the client side
|
||||
func getDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
|
||||
// use insecure transfer
|
||||
options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
|
||||
// use tracing
|
||||
option := grpc.WithUnaryInterceptor(
|
||||
interceptor.UnaryClientTracing(),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
// set up trace on the server side
|
||||
func getServerOptions() []grpc.ServerOption {
|
||||
var options []grpc.ServerOption
|
||||
|
||||
// use tracing
|
||||
option := grpc.UnaryInterceptor(
|
||||
interceptor.UnaryServerTracing(),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
tracer.Init(exporter, resource) // collect all by default
|
||||
}
|
||||
|
||||
// if necessary, you can create a span in the program
|
||||
func SpanDemo(serviceName string, spanName string, ctx context.Context) {
|
||||
_, span := otel.Tracer(serviceName).Start(
|
||||
ctx, spanName,
|
||||
trace.WithAttributes(attribute.String(spanName, time.Now().String())), // customised attributes
|
||||
)
|
||||
defer span.End()
|
||||
_, span := otel.Tracer(serviceName).Start(
|
||||
ctx, spanName,
|
||||
trace.WithAttributes(attribute.String(spanName, time.Now().String())), // customised attributes
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
// ......
|
||||
// ......
|
||||
}
|
||||
```
|
||||
|
||||
**gRPC server side**
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func setServerOptions() []grpc.ServerOption {
|
||||
var options []grpc.ServerOption
|
||||
|
||||
// use tracing
|
||||
option := grpc.UnaryInterceptor(
|
||||
interceptor.UnaryServerTracing(),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
```
|
||||
|
||||
**gRPC client side**
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func setDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
|
||||
// use insecure transfer
|
||||
options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
|
||||
// use tracing
|
||||
option := grpc.WithUnaryInterceptor(
|
||||
interceptor.UnaryClientTracing(),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
```
|
||||
|
||||
@@ -283,15 +344,20 @@ Click to view [metrics examples](../metrics/README.md).
|
||||
**gRPC server side**
|
||||
|
||||
```go
|
||||
func getServerOptions() []grpc.ServerOption {
|
||||
var options []grpc.ServerOption
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
option := grpc.ChainUnaryInterceptor(
|
||||
interceptor.UnaryServerRequestID(),
|
||||
)
|
||||
options = append(options, option)
|
||||
func setServerOptions() []grpc.ServerOption {
|
||||
var options []grpc.ServerOption
|
||||
|
||||
return options
|
||||
option := grpc.ChainUnaryInterceptor(
|
||||
interceptor.UnaryServerRequestID(),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
```
|
||||
|
||||
@@ -300,18 +366,23 @@ func getServerOptions() []grpc.ServerOption {
|
||||
**gRPC client side**
|
||||
|
||||
```go
|
||||
func getDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
import (
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// use insecure transfer
|
||||
options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
func setDialOptions() []grpc.DialOption {
|
||||
var options []grpc.DialOption
|
||||
|
||||
option := grpc.WithChainUnaryInterceptor(
|
||||
interceptor.UnaryClientRequestID(),
|
||||
)
|
||||
options = append(options, option)
|
||||
// use insecure transfer
|
||||
options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
|
||||
return options
|
||||
option := grpc.WithChainUnaryInterceptor(
|
||||
interceptor.UnaryClientRequestID(),
|
||||
)
|
||||
options = append(options, option)
|
||||
|
||||
return options
|
||||
}
|
||||
```
|
||||
|
||||
@@ -325,101 +396,101 @@ func getDialOptions() []grpc.DialOption {
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"github.com/go-dev-frame/sponge/pkg/jwt"
|
||||
"google.golang.org/grpc"
|
||||
"net"
|
||||
"time"
|
||||
userV1 "user/api/user/v1"
|
||||
"context"
|
||||
"net"
|
||||
"time"
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
"github.com/go-dev-frame/sponge/pkg/jwt"
|
||||
"google.golang.org/grpc"
|
||||
userV1 "user/api/user/v1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
list, err := net.Listen("tcp", ":8282")
|
||||
server := grpc.NewServer(getUnaryServerOptions()...)
|
||||
userV1.RegisterUserServer(server, &user{})
|
||||
server.Serve(list)
|
||||
select {}
|
||||
list, err := net.Listen("tcp", ":8282")
|
||||
server := grpc.NewServer(getUnaryServerOptions()...)
|
||||
userV1.RegisterUserServer(server, &user{})
|
||||
server.Serve(list)
|
||||
select {}
|
||||
}
|
||||
|
||||
func getUnaryServerOptions() []grpc.ServerOption {
|
||||
var options []grpc.ServerOption
|
||||
var options []grpc.ServerOption
|
||||
|
||||
// Case1: default options
|
||||
{
|
||||
options = append(options, grpc.UnaryInterceptor(
|
||||
interceptor.UnaryServerJwtAuth(),
|
||||
))
|
||||
}
|
||||
// Case1: default options
|
||||
{
|
||||
options = append(options, grpc.UnaryInterceptor(
|
||||
interceptor.UnaryServerJwtAuth(),
|
||||
))
|
||||
}
|
||||
|
||||
// Case 2: custom options, signKey, extra verify function, rpc method
|
||||
{
|
||||
options = append(options, grpc.UnaryInterceptor(
|
||||
interceptor.UnaryServerJwtAuth(
|
||||
interceptor.WithSignKey([]byte("your_secret_key")),
|
||||
interceptor.WithExtraVerify(extraVerifyFn),
|
||||
interceptor.WithAuthIgnoreMethods(// specify the gRPC API to ignore token verification(full path)
|
||||
"/api.user.v1.User/Register",
|
||||
"/api.user.v1.User/Login",
|
||||
),
|
||||
),
|
||||
))
|
||||
}
|
||||
// Case 2: custom options, signKey, extra verify function, rpc method
|
||||
{
|
||||
options = append(options, grpc.UnaryInterceptor(
|
||||
interceptor.UnaryServerJwtAuth(
|
||||
interceptor.WithSignKey([]byte("your_secret_key")),
|
||||
interceptor.WithExtraVerify(extraVerifyFn),
|
||||
interceptor.WithAuthIgnoreMethods(// specify the gRPC API to ignore token verification(full path)
|
||||
"/api.user.v1.User/Register",
|
||||
"/api.user.v1.User/Login",
|
||||
),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
return options
|
||||
return options
|
||||
}
|
||||
|
||||
type user struct {
|
||||
userV1.UnimplementedUserServer
|
||||
userV1.UnimplementedUserServer
|
||||
}
|
||||
|
||||
// Login ...
|
||||
func (s *user) Login(ctx context.Context, req *userV1.LoginRequest) (*userV1.LoginReply, error) {
|
||||
// check user and password success
|
||||
// check user and password success
|
||||
|
||||
uid := "100"
|
||||
fields := map[string]interface{}{"name": "bob","age": 10,"is_vip": true}
|
||||
uid := "100"
|
||||
fields := map[string]interface{}{"name": "bob","age": 10,"is_vip": true}
|
||||
|
||||
// Case 1: default jwt options, signKey, signMethod(HS256), expiry time(24 hour)
|
||||
{
|
||||
_, token, err := jwt.GenerateToken("100")
|
||||
}
|
||||
// Case 1: default jwt options, signKey, signMethod(HS256), expiry time(24 hour)
|
||||
{
|
||||
_, token, err := jwt.GenerateToken("100")
|
||||
}
|
||||
|
||||
// Case 2: custom jwt options, signKey, signMethod(HS512), expiry time(12 hour), fields, claims
|
||||
{
|
||||
_, token, err := jwt.GenerateToken(
|
||||
uid,
|
||||
jwt.WithGenerateTokenSignKey([]byte("your_secret_key")),
|
||||
jwt.WithGenerateTokenSignMethod(jwt.HS384),
|
||||
jwt.WithGenerateTokenFields(fields),
|
||||
jwt.WithGenerateTokenClaims([]jwt.RegisteredClaimsOption{
|
||||
jwt.WithExpires(time.Hour * 12),
|
||||
//jwt.WithIssuedAt(now),
|
||||
// jwt.WithSubject("123"),
|
||||
// jwt.WithIssuer("https://auth.example.com"),
|
||||
// jwt.WithAudience("https://api.example.com"),
|
||||
// jwt.WithNotBefore(now),
|
||||
// jwt.WithJwtID("abc1234xxx"),
|
||||
}...),
|
||||
)
|
||||
}
|
||||
// Case 2: custom jwt options, signKey, signMethod(HS512), expiry time(12 hour), fields, claims
|
||||
{
|
||||
_, token, err := jwt.GenerateToken(
|
||||
uid,
|
||||
jwt.WithGenerateTokenSignKey([]byte("your_secret_key")),
|
||||
jwt.WithGenerateTokenSignMethod(jwt.HS384),
|
||||
jwt.WithGenerateTokenFields(fields),
|
||||
jwt.WithGenerateTokenClaims([]jwt.RegisteredClaimsOption{
|
||||
jwt.WithExpires(time.Hour * 12),
|
||||
// jwt.WithIssuedAt(now),
|
||||
// jwt.WithSubject("123"),
|
||||
// jwt.WithIssuer("https://auth.example.com"),
|
||||
// jwt.WithAudience("https://api.example.com"),
|
||||
// jwt.WithNotBefore(now),
|
||||
// jwt.WithJwtID("abc1234xxx"),
|
||||
}...),
|
||||
)
|
||||
}
|
||||
|
||||
return &userV1.LoginReply{Token: token}, nil
|
||||
return &userV1.LoginReply{Token: token}, nil
|
||||
}
|
||||
|
||||
func extraVerifyFn(ctx context.Context, claims *jwt.Claims) error {
|
||||
// judge whether the user is disabled, query whether jwt id exists from the blacklist
|
||||
//if CheckBlackList(uid, claims.ID) {
|
||||
// return errors.New("user is disabled")
|
||||
//}
|
||||
// judge whether the user is disabled, query whether jwt id exists from the blacklist
|
||||
//if CheckBlackList(uid, claims.ID) {
|
||||
// return errors.New("user is disabled")
|
||||
//}
|
||||
|
||||
// get fields from claims
|
||||
//uid := claims.UID
|
||||
//name, _ := claims.GetString("name")
|
||||
//age, _ := claims.GetInt("age")
|
||||
//isVip, _ := claims.GetBool("is_vip")
|
||||
// get fields from claims
|
||||
//uid := claims.UID
|
||||
//name, _ := claims.GetString("name")
|
||||
//age, _ := claims.GetInt("age")
|
||||
//isVip, _ := claims.GetBool("is_vip")
|
||||
|
||||
return nil
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
@@ -429,31 +500,30 @@ func extraVerifyFn(ctx context.Context, claims *jwt.Claims) error {
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/grpccli"
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
userV1 "user/api/user/v1"
|
||||
"context"
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/grpccli"
|
||||
"github.com/go-dev-frame/sponge/pkg/grpc/interceptor"
|
||||
userV1 "user/api/user/v1"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conn, _ := grpccli.NewClient("127.0.0.1:8282")
|
||||
cli := userV1.NewUserClient(conn)
|
||||
conn, _ := grpccli.NewClient("127.0.0.1:8282")
|
||||
cli := userV1.NewUserClient(conn)
|
||||
|
||||
uid := "100"
|
||||
ctx := context.Background()
|
||||
uid := "100"
|
||||
ctx := context.Background()
|
||||
|
||||
// Case 1: get authorization from header key is "authorization", value is "Bearer xxx"
|
||||
{
|
||||
ctx = interceptor.SetAuthToCtx(ctx, authorization)
|
||||
}
|
||||
// Case 2: get token from grpc server response result
|
||||
{
|
||||
ctx = interceptor.SetJwtTokenToCtx(ctx, token)
|
||||
}
|
||||
// Case 1: get authorization from header key is "authorization", value is "Bearer xxx"
|
||||
{
|
||||
ctx = interceptor.SetAuthToCtx(ctx, authorization)
|
||||
}
|
||||
// Case 2: get token from grpc server response result
|
||||
{
|
||||
ctx = interceptor.SetJwtTokenToCtx(ctx, token)
|
||||
}
|
||||
|
||||
cli.GetByID(ctx, &userV1.GetUserByIDRequest{Id: 100})
|
||||
cli.GetByID(ctx, &userV1.GetUserByIDRequest{Id: 100})
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
<br>
|
||||
|
@@ -160,7 +160,7 @@ func TestGenerateError(t *testing.T) {
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func Test_getOptions(t *testing.T) {
|
||||
func Test_setOptions(t *testing.T) {
|
||||
a := &Args{
|
||||
Package: "Package",
|
||||
GormType: true,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
|
||||
### 启动jaeger和elasticsearch服务
|
||||
|
||||
链路跟踪使用jaeger,存储使用elasticsearch,在本地使用[docker-compose](https://github.com/docker/compose/releases)启动两个服务。
|
||||
链路追踪使用jaeger,存储使用elasticsearch,在本地使用[docker-compose](https://github.com/docker/compose/releases)启动两个服务。
|
||||
|
||||
**(1) elasticsearch服务**
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
|
||||
<br>
|
||||
|
||||
### 单服务链路跟踪示例
|
||||
### 单服务链路追踪示例
|
||||
|
||||
以`⓵基于sql创建web服务`代码为例,修改配置文件`configs/user.yml`,开启链路跟踪功能(字段enableTrace),并且填写jaeger配置信息。
|
||||
以`⓵基于sql创建web服务`代码为例,修改配置文件`configs/user.yml`,开启链路追踪功能(字段enableTrace),并且填写jaeger配置信息。
|
||||
|
||||
如果想跟踪redis,启用redis缓存,把yaml配置文件里的缓存类型字段**cacheType**值改为redis,并配置redis地址,同时在本地使用docker启动redis服务,这是[redis服务启动脚本](https://github.com/go-dev-frame/sponge/tree/main/test/server/redis)。
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
make run
|
||||
```
|
||||
|
||||
复制 [http://localhost:8080/swagger/index.html](http://localhost:8080/apis/swagger/index.html) 到浏览器访问swagger主页,以请求get查询为例,连续请求同一个id两次,链路跟踪如下图所示。
|
||||
复制 [http://localhost:8080/swagger/index.html](http://localhost:8080/apis/swagger/index.html) 到浏览器访问swagger主页,以请求get查询为例,连续请求同一个id两次,链路追踪如下图所示。
|
||||
|
||||

|
||||
|
||||
@@ -68,13 +68,13 @@ defer span.End()
|
||||
|
||||
<br>
|
||||
|
||||
### 多服务链路跟踪示例
|
||||
### 多服务链路追踪示例
|
||||
|
||||
以一个极简版的电商微服务集群为例,点击查看[源码](https://github.com/go-dev-frame/sponge_examples/tree/main/6_micro-cluster),一个共四个服务**shopgw**、**product**、**inventory**、**comment**,分别修改4个服务yaml配置(在configs目录下),开启链路跟踪功能,并且填写jaeger配置信息。
|
||||
以一个极简版的电商微服务集群为例,点击查看[源码](https://github.com/go-dev-frame/sponge_examples/tree/main/6_micro-cluster),一个共四个服务**shopgw**、**product**、**inventory**、**comment**,分别修改4个服务yaml配置(在configs目录下),开启链路追踪功能,并且填写jaeger配置信息。
|
||||
|
||||
在 **product**、**inventory**、**comment** 三个服务的**internal/service**目录下找到模板文件,填充代码替代`panic("implement me")`,使得代码可以正常执行,并且手动添加一个**span**,添加随机延时。
|
||||
|
||||
启动 **shopgw**、**product**、**inventory**、**comment** 四个服务,在浏览器访问 [http://localhost:8080/apis/swagger/index.html](http://localhost:8080/apis/swagger/index.html) ,执行get请求,链路跟踪界面如下图所示。
|
||||
启动 **shopgw**、**product**、**inventory**、**comment** 四个服务,在浏览器访问 [http://localhost:8080/apis/swagger/index.html](http://localhost:8080/apis/swagger/index.html) ,执行get请求,链路追踪界面如下图所示。
|
||||
|
||||

|
||||
|
||||
|
Reference in New Issue
Block a user