This is the 13th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

introduce

Through a complete example, implement distributed log tracking based on Echo framework.

What is API log tracing?

An API request spans multiple microservices, and we want to retrieve logs for the entire link with a unique ID.

We will use RK-boot to start the Echo framework microservice.

Please visit the following address for the full tutorial:

  • rkdocs.netlify.app/cn

The installation

go get github.com/rookie-ninja/rk-boot
Copy the code

Quick start

We created /v1/ Greeter apis for validation, and enabled logging, Meta, and tracing middleware to achieve this.

1. Create boota. yaml & Servera. go

ServerA listens on port 1949 and sends a request to ServerB.

We through rkechoctx InjectSpanToNewContext () method of the Tracing information into Context, sent to ServerB.

---
echo:
  - name: greeter                   # Required
    port: 1949                      # Required
    enabled: true                   # Required
    interceptors:
      loggingZap:
        enabled: true               # Optional, enable logging interceptor
      meta:
        enabled: true               # Optional, enable meta interceptor
      tracingTelemetry:
        enabled: true               # Optional, enable tracing interceptor
Copy the code
// 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/labstack/echo/v4"
	"github.com/rookie-ninja/rk-boot"
	"github.com/rookie-ninja/rk-echo/interceptor/context"
	"net/http"
)

// Application entrance.
func main(a) {
	// Create a new boot instance.
	boot := rkboot.NewBoot(rkboot.WithBootConfigPath("bootA.yaml"))

	// Register handler
	boot.GetEchoEntry("greeter").Echo.GET("/v1/greeter", GreeterA)

	// Bootstrap
	boot.Bootstrap(context.Background())

	// Wait for shutdown sig
	boot.WaitForShutdownSig(context.Background())
}

// GreeterA will add trace info into context and call serverB
func GreeterA(ctx echo.Context) error {
	// Call serverB at 2008
	req, _ := http.NewRequest(http.MethodGet, "http://localhost:2008/v1/greeter".nil)

	// Inject current trace information into context
	rkechoctx.InjectSpanToHttpRequest(ctx, req)

	// Call server
	http.DefaultClient.Do(req)

	// Respond to request
	return ctx.String(http.StatusOK, "Hello from serverA!")}Copy the code

2. Create bootb.yaml & SerPreb.go

ServerB listens on port 2008.

---
echo:
  - name: greeter                   # Required
    port: 2008                      # Required
    enabled: true                   # Required
    interceptors:
      loggingZap:
        enabled: true               # Optional, enable logging interceptor
      meta:
        enabled: true               # Optional, enable meta interceptor
      tracingTelemetry:
        enabled: true               # Optional, enable tracing interceptor
Copy the code
// 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/labstack/echo/v4"
	"github.com/rookie-ninja/rk-boot"
	"net/http"
)

// Application entrance.
func main(a) {
	// Create a new boot instance.
	boot := rkboot.NewBoot(rkboot.WithBootConfigPath("bootB.yaml"))

	// Register handler
	boot.GetEchoEntry("greeter").Echo.GET("/v1/greeter", GreeterB)

	// Bootstrap
	boot.Bootstrap(context.Background())

	// Wait for shutdown sig
	boot.WaitForShutdownSig(context.Background())
}

// GreeterB will add trace info into context and call serverB
func GreeterB(ctx echo.Context) error {
	// Respond to request
	return ctx.String(http.StatusOK, "Hello from serverB!")}Copy the code

3. Folder structure

.├ ── ─ Go.go ├── Go.go ├── Go.go ├── go.go ├── let directories directories directories, 6 filesCopy the code

4. Start ServerA & ServerB

$ go run serverA.go
$ go run serverB.go
Copy the code

5. Send a request to ServerA

$ curl localhost:1949/v1/greeter
Hello from serverA!
Copy the code

6. Verify logs

The logs of the two services have the same traceId but different requestId.

We can trace RPC by grep traceId.

  • ServerA
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- endTime = 2021-11-19 T23:56:47. 681644 + 08:00... ids={"eventId":"e2670cdb-9a3c-42e9-ae8f-e01de3d8fbfa","requestId":"e2670cdb-9a3c-42e9-ae8f-e01de3d8fbfa","traceId":"eb46 6c6e0c46538027d8b8c2efc08baa"} ... operation=/v1/greeter resCode=200 eventStatus=Ended EOECopy the code
  • ServerB
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- endTime = 2021-11-19 T23:56:47. 681362 + 08:00... ids={"eventId":"3c72b929-78bd-4ff1-b48c-3ad699429c45","requestId":"3c72b929-78bd-4ff1-b48c-3ad699429c45","traceId":"eb46 6c6e0c46538027d8b8c2efc08baa"} ... operation=/v1/greeter resCode=200 eventStatus=Ended EOECopy the code

concept

When we are not calling chain services such as Jaeger, we want to keep track of RPC requests in a distributed system through logging.

The MIDDLEWARE of RK-Boot writes traceId to the log through the openTelemetry library to trace the RPC.

When the logging middleware, raw data middleware and call chain middleware are started, the middleware will write the following three ids in the log.

EventId

When the logging middleware is started, EventId is automatically generated.

---
echo:
  - name: greeter                   # Required
    port: 1949                      # Required
    enabled: true                   # Required
    interceptors:
      loggingZap:
        enabled: true
Copy the code
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --... ids={"eventId":"cd617f0c-2d93-45e1-bef0-95c89972530d"} ...Copy the code

RequestId

When the logging middleware and raw data middleware are enabled, the RequestId and EventId ids are automatically generated and the two ids are consistent.

---
echo:
  - name: greeter                   # Required
    port: 1949                      # Required
    enabled: true                   # Required
    interceptors:
      loggingZap:
        enabled: true
      meta:
        enabled: true
Copy the code
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --... ids={"eventId":"8226ba9b-424e-4e19-ba63-d37ca69028b3","requestId":"8226ba9b-424e-4e19-ba63-d37ca69028b3"} ...Copy the code

EventId remains consistent even if the user overrides RequestId.

rkechoctx.AddHeaderToClient(ctx, rkechoctx.RequestIdKey, "overridden-request-id")
Copy the code
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --... ids={"eventId":"overridden-request-id","requestId":"overridden-request-id"} ...Copy the code

TraceId

When the call chain middleware is enabled, traceId is automatically generated.

---
echo:
  - name: greeter                   # Required
    port: 1949                      # Required
    enabled: true                   # Required
    interceptors:
      loggingZap:
        enabled: true
      meta:
        enabled: true
      tracingTelemetry:
        enabled: true
Copy the code
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --... ids={"eventId":"dd19cf9a-c7be-486c-b29d-7af777a78ebe","requestId":"dd19cf9a-c7be-486c-b29d-7af777a78ebe","traceId":"316a 7b475ff500a76bfcd6147036951c"} ...Copy the code