introduce
Through a complete example, based on gorilla/mux Add tracing middleware to microservices.
What is tracing middleware?
The Tracing middleware will record the Tracing data for each API request, which can be viewed by users using tools like Jaeger.
We will use rk-boot To start gorilla/mux Microservices.
rk-boot Is a framework that can start a variety of Web services through YAML. Please refer to the last chapter of this article for details rk-boot Details.
Please visit the following address for a complete tutorial: https://github.com/rookie-ninja/rk-mux
install
go get github.com/rookie-ninja/rk-boot/mux
Quick start
rk-boot By default OpenTelemetry-CNCF To handle Tracing.
1. Create boot yaml
To verify, we launched the following options:
- commonService: commonService contains a series of general API s. details
- jaeger exporter: gorilla/mux The service sends data to the local jaeger agent.
--- mux: - name: greeter # Required port: 8080 # Required enabled: true # Required commonService: enabled: true # Optional, default: false interceptors: tracingTelemetry: enabled: true # Optional, Enable tracing interceptor/middleware exporter: jaeger: agent: enabled: true # Optional, Export to jaeger agent
2. Create main go
Add / v1/greeter API.
// Copyright (c) 2021 rookie-ninja // // Use of this source code is governed by an Apache-style // license that can be found in the LICENSE file. package main import ( "context" "fmt" "github.com/rookie-ninja/rk-boot" "github.com/rookie-ninja/rk-boot/mux" "github.com/rookie-ninja/rk-mux/interceptor" "github.com/rookie-ninja/rk-mux/interceptor/context" "net/http" ) func main() { // Create a new boot instance. boot := rkboot.NewBoot() // Register handler entry := rkbootmux.GetMuxEntry("greeter") entry.Router.NewRoute().Methods(http.MethodGet).Path("/v1/greeter").HandlerFunc(Greeter) // Bootstrap boot.Bootstrap(context.TODO()) boot.WaitForShutdownSig(context.TODO()) } func Greeter(writer http.ResponseWriter, request *http.Request) { rkmuxinter.WriteJson(writer, http.StatusOK, &GreeterResponse{ Message: fmt.Sprintf("Hello %s!", request.URL.Query().Get("name")), }) } type GreeterResponse struct { Message string }
3. Folder structure
$ tree . ├── boot.yaml ├── go.mod ├── go.sum └── main.go 0 directories, 4 files
4. Start jaeger locally
$ docker run -d --name jaeger \ -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ -p 5775:5775/udp \ -p 6831:6831/udp \ -p 6832:6832/udp \ -p 5778:5778 \ -p 16686:16686 \ -p 14268:14268 \ -p 14250:14250 \ -p 9411:9411 \ jaegertracing/all-in-one:1.23
5. Start main go
$ go run main.go
6. Verification
- Send the request to the / rk / V1 / health API in CommonService.
$ curl -X GET localhost:8080/rk/v1/healthy {"healthy":true}
- Send request to / v1/greeter API.
$ curl -X GET "localhost:8080/v1/greeter?name=rk-dev" {"Message":"Hello rk-dev!"}
- Visit jaeger home page: http://localhost:16686/
Not through rkentry GlobalAppCtx. GetAppInfoEntry(). Appnamewhen you specify an AppName, rk is used as the AppName by default.
Output to Stdout
You can modify boot Yaml file to modify the output path, such as STDOUT.
- boot.yaml
--- mux: - name: greeter # Required port: 8080 # Required enabled: true # Required commonService: enabled: true # Optional, default: false interceptors: tracingTelemetry: enabled: true # Optional, Enable tracing interceptor/middleware exporter: file: enabled: true outputPath: "stdout" # Optional, Output to stdout
output to a file
You can modify boot Yaml file to save Tracing information to a file.
- boot.yaml
--- mux: - name: greeter # Required port: 8080 # Required enabled: true # Required commonService: enabled: true # Optional, default: false interceptors: tracingTelemetry: enabled: true # Optional, Enable tracing interceptor/middleware exporter: file: enabled: true outputPath: "logs/tracing.log" # Optional, Log to files
YAML options
name | describe | type | Default value |
---|---|---|---|
mux.interceptors.tracingTelemetry.enabled | Start call chain interceptor | boolean | false |
mux.interceptors.tracingTelemetry.exporter.file.enabled | Start file output | boolean | false |
mux.interceptors.tracingTelemetry.exporter.file.outputPath | Output file path | string | stdout |
mux.interceptors.tracingTelemetry.exporter.jaeger.agent.enabled | jaeger agent as data output | boolean | false |
mux.interceptors.tracingTelemetry.exporter.jaeger.agent.host | jaeger agent address | string | localhost |
mux.interceptors.tracingTelemetry.exporter.jaeger.agent.port | jaeger agent port | int | 6831 |
mux.interceptors.tracingTelemetry.exporter.jaeger.collector.enabled | jaeger collector as data output | boolean | false |
mux.interceptors.tracingTelemetry.exporter.jaeger.collector.endpoint | jaeger collector address | string | http://localhost:16368/api/trace |
mux.interceptors.tracingTelemetry.exporter.jaeger.collector.username | jaeger collector user name | string | "" |
mux.interceptors.tracingTelemetry.exporter.jaeger.collector.password | jaeger collector password | string | "" |
Introduction to rk boot
rk-boot Is a framework that can start a variety of Web services through YAML.
It is similar to Spring boot. By integrating rk XXX series libraries, you can start a variety of Web frameworks. Of course, users can also customize the RK XXX library and integrate it into rk boot.
Rk boot highlights
Launch different Web frameworks through YAML files in the same format.
For example, we can start grpc, gin, echo and goframe frameworks in one process through the following files. Unify the layout of micro services within the team.
- Dependent installation
go get github.com/rookie-ninja/rk-boot/grpc go get github.com/rookie-ninja/rk-boot/gin go get github.com/rookie-ninja/rk-boot/echo go get github.com/rookie-ninja/rk-boot/gf
- boot.yaml
--- grpc: - name: grpc-server port: 8080 enabled: true commonService: enabled: true gin: - name: gin-server port: 8081 enabled: true commonService: enabled: true echo: - name: echo-server port: 8082 enabled: true commonService: enabled: true gf: - name: gf-server port: 8083 enabled: true commonService: enabled: true
- main.go
// Copyright (c) 2021 rookie-ninja // // Use of this source code is governed by an Apache-style // license that can be found in the LICENSE file. package main import ( "context" "github.com/rookie-ninja/rk-boot" _ "github.com/rookie-ninja/rk-boot/echo" _ "github.com/rookie-ninja/rk-boot/gf" _ "github.com/rookie-ninja/rk-boot/gin" _ "github.com/rookie-ninja/rk-boot/grpc" ) // Application entrance. func main() { // Create a new boot instance. boot := rkboot.NewBoot() // Bootstrap boot.Bootstrap(context.Background()) // Wait for shutdown sig boot.WaitForShutdownSig(context.Background()) }
- verification
# gRPC throuth grpc-gateway $ curl localhost:8080/rk/v1/healthy {"healthy":true} # Gin $ curl localhost:8081/rk/v1/healthy {"healthy":true} # Echo $ curl localhost:8082/rk/v1/healthy {"healthy":true} # GoFrame $ curl localhost:8083/rk/v1/healthy {"healthy":true}
Web framework supported by rk boot
Welcome to contribute a new Web framework to the RK boot series.
reference resources docs & rk-gin As an example.
frame | Development status | install | rely on |
---|---|---|---|
Stable | go get github.com/rookie-ninja/rk-boot/gin | ||
Stable | go get github.com/rookie-ninja/rk-boot/grpc | ||
Stable | go get github.com/rookie-ninja/rk-boot/echo | ||
Stable | go get github.com/rookie-ninja/rk-boot/gf | ||
Testing | go get github.com/rookie-ninja/rk-boot/fiber | ||
Testing | go get github.com/rookie-ninja/rk-boot/zero | ||
Testing | go get github.com/rookie-ninja/rk-boot/mux |
Introduction to rk MUX
rk-mux Used to launch through YAML gorilla/mux Web services.
Supported functions
According to the following example of YAML file initialization, if it is external, it will maintain the native usage.
example | introduce |
---|---|
mux.Router | Primordial gorilla/mux |
Config | Primordial spf13/viper Parameter instance |
Logger | Primordial uber-go/zap Log instance |
EventLogger | Used to record RPC request logs, using rk-query |
Credential | Used to pull Credential from a remote service, such as ETCD |
Cert | Obtain TLS/SSL certificate from remote service (ETCD, etc.) and start SSL/TLS |
Prometheus | Start the Prometheus client and push it to as needed pushgateway |
Swagger | Launch Swagger UI locally |
CommonService | Expose common API s |
TV | TV web page, showing the basic information of micro services |
StaticFileHandler | Start the static file download service in the form of Web, and the background storage supports the local file system and pkger |
Supported Middleware
Rk MUX will initialize the middleware according to the YAML file.
Middleware | Description |
---|---|
Metrics | Collect RPC Metrics and start prometheus |
Log | use rk-query Record each RPC log |
Trace | Collect RPC call chain and send data to stdout, local file or jaeger open-telemetry/opentelemetry-go. |
Panic | Recover from panic for RPC requests and log it. |
Meta | Collect the service meta information and add it to the return Header |
Auth | Middleware supporting basic auth & API key authentication |
RateLimit | RPC speed limiting Middleware |
Timeout | RPC timeout Middleware |
CORS | CORS Middleware |
JWT | JWT verification |
Secure | Server side security middleware |
CSRF | CSRF Middleware |
Mux full YAML configuration
--- #app: # description: "this is description" # Optional, default: "" # keywords: ["rk", "golang"] # Optional, default: [] # homeUrl: "http://example.com" # Optional, default: "" # iconUrl: "http://example.com" # Optional, default: "" # docsUrl: ["http://example.com"] # Optional, default: [] # maintainers: ["rk-dev"] # Optional, default: [] #zapLogger: # - name: zap-logger # Required # description: "Description of entry" # Optional #eventLogger: # - name: event-logger # Required # description: "Description of entry" # Optional #cred: # - name: "local-cred" # Required # provider: "localFs" # Required, etcd, consul, localFs, remoteFs are supported options # description: "Description of entry" # Optional # locale: "*::*::*::*" # Optional, default: *::*::*::* # paths: # Optional # - "example/boot/full/cred.yaml" #cert: # - name: "local-cert" # Required # provider: "localFs" # Required, etcd, consul, localFs, remoteFs are supported options # description: "Description of entry" # Optional # locale: "*::*::*::*" # Optional, default: *::*::*::* # serverCertPath: "example/boot/full/server.pem" # Optional, default: "", path of certificate on local FS # serverKeyPath: "example/boot/full/server-key.pem" # Optional, default: "", path of certificate on local FS # clientCertPath: "example/client.pem" # Optional, default: "", path of certificate on local FS # clientKeyPath: "example/client.pem" # Optional, default: "", path of certificate on local FS #config: # - name: rk-main # Required # path: "example/boot/full/config.yaml" # Required # locale: "*::*::*::*" # Required, default: *::*::*::* # description: "Description of entry" # Optional mux: - name: greeter # Required port: 8080 # Required enabled: true # Required # description: "greeter server" # Optional, default: "" # cert: # ref: "local-cert" # Optional, default: "", reference of cert entry declared above # sw: # enabled: true # Optional, default: false # path: "sw" # Optional, default: "sw" # jsonPath: "" # Optional # headers: ["sw:rk"] # Optional, default: [] # commonService: # enabled: true # Optional, default: false # static: # enabled: true # Optional, default: false # path: "/rk/v1/static" # Optional, default: /rk/v1/static # sourceType: local # Required, options: pkger, local # sourcePath: "." # Required, full path of source directory # tv: # enabled: true # Optional, default: false # prom: # enabled: true # Optional, default: false # path: "" # Optional, default: "metrics" # pusher: # enabled: false # Optional, default: false # jobName: "greeter-pusher" # Required # remoteAddress: "localhost:9091" # Required # basicAuth: "user:pass" # Optional, default: "" # intervalMs: 10000 # Optional, default: 1000 # cert: # Optional # ref: "local-test" # Optional, default: "", reference of cert entry declared above # logger: # zapLogger: # ref: zap-logger # Optional, default: logger of STDOUT, reference of logger entry declared above # eventLogger: # ref: event-logger # Optional, default: logger of STDOUT, reference of logger entry declared above # interceptors: # loggingZap: # enabled: true # Optional, default: false # zapLoggerEncoding: "json" # Optional, default: "console" # zapLoggerOutputPaths: ["logs/app.log"] # Optional, default: ["stdout"] # eventLoggerEncoding: "json" # Optional, default: "console" # eventLoggerOutputPaths: ["logs/event.log"] # Optional, default: ["stdout"] # metricsProm: # enabled: true # Optional, default: false # auth: # enabled: true # Optional, default: false # basic: # - "user:pass" # Optional, default: [] # ignorePrefix: # - "/rk/v1" # Optional, default: [] # apiKey: # - "keys" # Optional, default: [] # meta: # enabled: true # Optional, default: false # prefix: "rk" # Optional, default: "rk" # tracingTelemetry: # enabled: true # Optional, default: false # exporter: # Optional, default will create a stdout exporter # file: # enabled: true # Optional, default: false # outputPath: "logs/trace.log" # Optional, default: stdout # jaeger: # agent: # enabled: false # Optional, default: false # host: "" # Optional, default: localhost # port: 0 # Optional, default: 6831 # collector: # enabled: true # Optional, default: false # endpoint: "" # Optional, default: http://localhost:14268/api/traces # username: "" # Optional, default: "" # password: "" # Optional, default: "" # rateLimit: # enabled: false # Optional, default: false # algorithm: "leakyBucket" # Optional, default: "tokenBucket" # reqPerSec: 100 # Optional, default: 1000000 # paths: # - path: "/rk/v1/healthy" # Optional, default: "" # reqPerSec: 0 # Optional, default: 1000000 # jwt: # enabled: true # Optional, default: false # signingKey: "my-secret" # Required # ignorePrefix: # Optional, default: [] # - "/rk/v1/tv" # - "/sw" # - "/rk/v1/assets" # signingKeys: # Optional # - "key:value" # signingAlgo: "" # Optional, default: "HS256" # tokenLookup: "header:<name>" # Optional, default: "header:Authorization" # authScheme: "Bearer" # Optional, default: "Bearer" # secure: # enabled: true # Optional, default: false # xssProtection: "" # Optional, default: "1; mode=block" # contentTypeNosniff: "" # Optional, default: nosniff # xFrameOptions: "" # Optional, default: SAMEORIGIN # hstsMaxAge: 0 # Optional, default: 0 # hstsExcludeSubdomains: false # Optional, default: false # hstsPreloadEnabled: false # Optional, default: false # contentSecurityPolicy: "" # Optional, default: "" # cspReportOnly: false # Optional, default: false # referrerPolicy: "" # Optional, default: "" # ignorePrefix: [] # Optional, default: [] # csrf: # enabled: true # tokenLength: 32 # Optional, default: 32 # tokenLookup: "header:X-CSRF-Token" # Optional, default: "header:X-CSRF-Token" # cookieName: "_csrf" # Optional, default: _csrf # cookieDomain: "" # Optional, default: "" # cookiePath: "" # Optional, default: "" # cookieMaxAge: 86400 # Optional, default: 86400 # cookieHttpOnly: false # Optional, default: false # cookieSameSite: "default" # Optional, default: "default", options: lax, strict, none, default # ignorePrefix: [] # Optional, default: []