gorilla/mux framework (RK boot): add tracing Middleware

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: []

Keywords: Go Microservices Middleware

Added by graham on Mon, 14 Feb 2022 10:42:41 +0200