docs: update document

This commit is contained in:
zhuyasen
2025-03-13 21:51:10 +08:00
parent 09a0e7049a
commit 7eee3570f4
18 changed files with 574 additions and 378 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -27,6 +27,7 @@ func GenMicroCommand() *cobra.Command {
generate.RPCPbCommand(),
generate.GRPCConnectionCommand(),
generate.ConvertSwagJSONCommand("micro"),
generate.GRPCAndHTTPCommand(),
generate.GRPCAndHTTPPbCommand(),
generate.ServiceAndHandlerCRUDCommand(),
)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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
View File

@@ -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
//

View File

@@ -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
}
```

View File

@@ -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>

View File

@@ -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,

View File

@@ -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两次链路踪如下图所示。
![one-server-trace](https://raw.githubusercontent.com/go-dev-frame/sponge_examples/main/assets/one-server-trace.jpg)
@@ -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请求链路踪界面如下图所示。
![multi-servers-trace](https://raw.githubusercontent.com/go-dev-frame/sponge_examples/main/assets/multi-servers-trace.jpg)