diff --git a/api/docs.go b/api/docs.go index b52680b..206db6e 100644 --- a/api/docs.go +++ b/api/docs.go @@ -621,6 +621,43 @@ const docTemplate = `{ } } } + }, + "/test/tracing": { + "get": { + "description": "Test tracing to Tumblebug", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Test] Utility" + ], + "summary": "Test tracing to Tumblebug", + "parameters": [ + { + "type": "string", + "description": "Custom request ID (NOTE: It will be used as a trace ID.)", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.SimpleMessage" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/common.SimpleMessage" + } + } + } + } } }, "definitions": { diff --git a/api/swagger.json b/api/swagger.json index 8a8a0fd..18c51b8 100644 --- a/api/swagger.json +++ b/api/swagger.json @@ -614,6 +614,43 @@ } } } + }, + "/test/tracing": { + "get": { + "description": "Test tracing to Tumblebug", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "[Test] Utility" + ], + "summary": "Test tracing to Tumblebug", + "parameters": [ + { + "type": "string", + "description": "Custom request ID (NOTE: It will be used as a trace ID.)", + "name": "x-request-id", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/common.SimpleMessage" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/common.SimpleMessage" + } + } + } + } } }, "definitions": { diff --git a/api/swagger.yaml b/api/swagger.yaml index 0ded38d..9b4872e 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -845,6 +845,30 @@ paths: summary: Update a user tags: - '[Sample API] Users' + /test/tracing: + get: + consumes: + - application/json + description: Test tracing to Tumblebug + parameters: + - description: 'Custom request ID (NOTE: It will be used as a trace ID.)' + in: header + name: x-request-id + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/common.SimpleMessage' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/common.SimpleMessage' + summary: Test tracing to Tumblebug + tags: + - '[Test] Utility' securityDefinitions: BasicAuth: type: basic diff --git a/go.work.sum b/go.work.sum index b5a8a8c..4a5ce63 100644 --- a/go.work.sum +++ b/go.work.sum @@ -350,6 +350,7 @@ github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdW github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= diff --git a/pkg/api/rest/common/utility.go b/pkg/api/rest/common/utility.go index 62a12ad..3bb6227 100644 --- a/pkg/api/rest/common/utility.go +++ b/pkg/api/rest/common/utility.go @@ -15,13 +15,18 @@ limitations under the License. package common import ( + "fmt" "net/http" "github.com/go-playground/validator/v10" + "github.com/go-resty/resty/v2" "github.com/labstack/echo/v4" "github.com/rs/zerolog/log" + "github.com/cloud-barista/cb-tumblebug/src/core/model" + "github.com/cloud-barista/cm-beetle/pkg/config" "github.com/cloud-barista/cm-beetle/pkg/core/common" + "github.com/cloud-barista/cm-beetle/pkg/logger" ) var validate *validator.Validate @@ -116,6 +121,67 @@ func RestCheckHTTPVersion(c echo.Context) error { return c.JSON(http.StatusOK, &okMessage) } +// RestGetTestTracingToTumblebug godoc +// @Summary Test tracing to Tumblebug +// @Description Test tracing to Tumblebug +// @Tags [Test] Utility +// @Accept json +// @Produce json +// @Param x-request-id header string false "Custom request ID (NOTE: It will be used as a trace ID.)" +// @Success 200 {object} SimpleMessage +// @Failure 503 {object} SimpleMessage +// @Router /test/tracing [get] +func RestGetTestTracing(c echo.Context) error { + + ctx := c.Request().Context() // Get context + log.Ctx(ctx).Info().Msg("RestGetReadyz called") // Log ctx to trace + + // Initialize resty client with basic auth + client := resty.New() + apiUser := config.Tumblebug.API.Username + apiPass := config.Tumblebug.API.Password + client.SetBasicAuth(apiUser, apiPass) + + // set tumblebug rest url + epTumblebug := config.Tumblebug.RestUrl + + // Search and set a target VM spec + method := "GET" + url := fmt.Sprintf("%s/readyz", epTumblebug) + + // Headers + headers := map[string]string{ + "x-request-id": ctx.Value(logger.TraceIdKey).(string), + } + + // Request body + tbReqt := common.NoBody + + // Response body + tbResp := model.SimpleMsg{} + + err := common.ExecuteHttpRequest( + client, + method, + url, + headers, + common.SetUseBody(tbReqt), + &tbReqt, + &tbResp, + common.VeryShortDuration, + ) + + resp := SimpleMessage{} + if err != nil { + log.Err(err).Msg("") + return c.JSON(http.StatusInternalServerError, resp) + } + + resp.Message = tbResp.Message + + return c.JSON(http.StatusOK, resp) +} + // /* // // RestGetSwagger func is to get API document web. // // RestGetSwagger godoc diff --git a/pkg/api/rest/middlewares/trancing.go b/pkg/api/rest/middlewares/trancing.go index 926850a..091fcf9 100644 --- a/pkg/api/rest/middlewares/trancing.go +++ b/pkg/api/rest/middlewares/trancing.go @@ -38,20 +38,30 @@ func TracingMiddleware(next echo.HandlerFunc) echo.HandlerFunc { ctx = context.WithValue(ctx, logger.SpanIdKey, spanId) // Create a logger with trace_id and span_id and store it in the context - logger := log.With().Str(string(logger.TraceIdKey), traceId).Str(string(logger.SpanIdKey), spanId).Logger() - ctx = logger.WithContext(ctx) + childLogger := log.With().Str(string(logger.TraceIdKey), traceId).Str(string(logger.SpanIdKey), spanId).Logger() + ctx = childLogger.WithContext(ctx) // Set the context in the request c.SetRequest(c.Request().WithContext(ctx)) // [Tracing log] when the request is received - log.Ctx(ctx).Info().Msg("[tracing] receive request") + traceLogger := logger.GetTraceLogger() + + traceLogger.Trace(). + Str(string(logger.TraceIdKey), traceId). + Str(string(logger.SpanIdKey), spanId). + Str("URI", c.Request().RequestURI). + Msg("[tracing] receive request") // [Tracing log] before the response is sent // Hooks: Before Response c.Response().Before(func() { // Log the request details - log.Ctx(ctx).Info().Msg("[tracing] send response") + traceLogger.Trace(). + Str(string(logger.TraceIdKey), traceId). + Str(string(logger.SpanIdKey), spanId). + Str("URI", c.Request().RequestURI). + Msg("[tracing] send response") }) // Call the next handler diff --git a/pkg/api/rest/server.go b/pkg/api/rest/server.go index 7ae7225..439ad56 100644 --- a/pkg/api/rest/server.go +++ b/pkg/api/rest/server.go @@ -205,6 +205,9 @@ func RunServer(port string) { gBeetle.GET("/readyz", rest_common.RestGetReadyz) gBeetle.GET("/httpVersion", rest_common.RestCheckHTTPVersion) + // Test utility APIs + gBeetle.GET("/test/tracing", rest_common.RestGetTestTracing) + // Namespace API group // gNamespace := gBeetle.Group("/ns") // gNamespace.POST("", controller.RestPostNs) diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index f4f495c..f7a96ba 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -40,6 +40,7 @@ func (h TracingHook) Run(e *zerolog.Event, level zerolog.Level, msg string) { var ( sharedLogFile *lumberjack.Logger once sync.Once + traceLogger zerolog.Logger ) type Config struct { @@ -82,7 +83,7 @@ func NewLogger(config Config) *zerolog.Logger { config.LogFilePath = "./log/app.log" } if config.MaxSize == 0 { - config.MaxSize = 100 // in MB + config.MaxSize = 1000 // in MB } if config.MaxBackups == 0 { config.MaxBackups = 3 @@ -115,6 +116,10 @@ func NewLogger(config Config) *zerolog.Logger { if err := os.Chmod(config.LogFilePath, 0644); err != nil { log.Fatal().Msgf("Failed to change file permissions: %v", err) } + + // traceLogger = zerolog.New(sharedLogFile).Level(zerolog.TraceLevel).With().Timestamp().Caller().Logger() + traceLogger = zerolog.New(sharedLogFile).Level(zerolog.TraceLevel).With().Timestamp().Logger() + traceLogger.Hook(TracingHook{}) }) level := getLogLevel(config.LogLevel) @@ -131,6 +136,11 @@ func NewLogger(config Config) *zerolog.Logger { return logger } +// GetTraceLogger returns the trace logger +func GetTraceLogger() *zerolog.Logger { + return &traceLogger +} + // getLogLevel returns the zerolog.Level based on the string level func getLogLevel(logLevel string) zerolog.Level { switch logLevel {