From 003870922fbb303e7cf7de5b83f535de444e872e Mon Sep 17 00:00:00 2001
From: Tucker Gary Siegel <tgsiegel@terpmail.umd.edu>
Date: Wed, 18 Aug 2021 15:12:34 -0400
Subject: [PATCH] custom logging

---
 config/local                      |   3 +-
 errors/dawn_errors.go             |  43 +++++++++++--
 logger/logger.go                  | 103 ++++++++++++++++++++++++++++++
 main.go                           |  36 ++++++++---
 models/csv.go                     |   8 ---
 services/data_download_service.go |   2 +-
 6 files changed, 169 insertions(+), 26 deletions(-)
 create mode 100644 logger/logger.go

diff --git a/config/local b/config/local
index 87ecead..a0d3588 100644
--- a/config/local
+++ b/config/local
@@ -1,5 +1,6 @@
 app:
   name: dawn-server
+  # logType: json
 
 server:
   host: "localhost"
@@ -8,4 +9,4 @@ server:
 
 db:
   uri: "mongodb://127.0.0.1:27017/"
-  database: "weather-service"
\ No newline at end of file
+  database: "weather-service"
diff --git a/errors/dawn_errors.go b/errors/dawn_errors.go
index a20d95d..adbb0c3 100644
--- a/errors/dawn_errors.go
+++ b/errors/dawn_errors.go
@@ -1,8 +1,8 @@
 package errors
 
 import (
+	"encoding/json"
 	"fmt"
-	"log"
 	"os"
 	"strconv"
 
@@ -17,7 +17,7 @@ type BaseError interface {
 type DawnError struct {
 	Name        string `json:"name"`
 	Description string `json:"description"`
-	LogDetails  string `json:"log_details,omitempty"`
+	LogDetails  string `json:"log_details"`
 	Code        int    `json:"code"`
 }
 
@@ -33,7 +33,11 @@ type StandardError struct {
 }
 
 func (err *DawnError) Error() string {
-	return err.Name + ": " + err.Description
+	str := err.Name + ": " + err.Description
+	if err.LogDetails != "" {
+		str += " - " + err.LogDetails
+	}
+	return str
 }
 
 func (err *DawnError) BuildStandardError(ctx *fiber.Ctx) StandardError {
@@ -47,13 +51,27 @@ func (err *DawnError) AddLogDetails(logDetails string) *DawnError {
 	return err
 }
 
-func (err *StandardError) LogJson() {
-	log.Println(err)
+func Build(err error) *DawnError {
+	return &DawnError{
+		Name:        "INTERNAL_SERVER_ERROR",
+		Description: err.Error(),
+		Code:        500,
+	}
+}
+
+func (err *DawnError) LogJson(c *fiber.Ctx) {
+	jsonErrBytes, _ := json.Marshal(err)
+	fmt.Println(string(jsonErrBytes))
 }
 
 func (err *DawnError) LogString(c *fiber.Ctx) {
 	requestId := c.Locals("requestId")
-	output := strconv.Itoa(os.Getpid()) + " " + fmt.Sprintf("%s", requestId) + " " + strconv.Itoa(err.Code) + " - " + c.Method() + " " + c.Route().Path + " - " + err.Error() + " - " + err.LogDetails
+	// requestBody := c.Request()
+	// requestBodyStr, _ := json.Marshal(requestBody)
+	output := strconv.Itoa(os.Getpid()) + " " + fmt.Sprintf("%s", requestId) + " " + strconv.Itoa(err.Code) + " - " + c.Method() + " " + c.Route().Path + " - " + err.Error()
+	if err.LogDetails != "" {
+		output += " - " + err.LogDetails
+	}
 	fmt.Println(output)
 }
 
@@ -78,8 +96,21 @@ var NO_DATA_FOUND = &DawnError{
 }
 
 // 500s
+
+var INTERNAL_SERVER_STANDARD_ERROR = &DawnError{
+	Name:        "INTERNAL_SERVER_ERROR",
+	Description: "Unkown internal server error occurred",
+	Code:        500,
+}
+
 var DATE_PARSE_FAILURE = &DawnError{
 	Name:        "DATE_PARSE_FAILURE",
 	Description: "Date parse failure",
 	Code:        500,
 }
+
+var FILE_CREATION_ERROR = &DawnError{
+	Name:        "FILE_CREATION_ERROR",
+	Description: "Could not create file",
+	Code:        500,
+}
diff --git a/logger/logger.go b/logger/logger.go
new file mode 100644
index 0000000..883308d
--- /dev/null
+++ b/logger/logger.go
@@ -0,0 +1,103 @@
+package logger
+
+import (
+	"dawn-weather/errors"
+	"encoding/json"
+	"fmt"
+	"os"
+	"strconv"
+	"time"
+
+	"github.com/gofiber/fiber/v2"
+	"github.com/spf13/viper"
+	"github.com/valyala/fasthttp"
+)
+
+type LogMessage struct {
+	Date       string
+	PID        string
+	RequestId  string
+	Error      *errors.DawnError
+	StatusCode string
+	Method     string
+	Path       string
+}
+
+type Request struct {
+	Headers fasthttp.RequestHeader
+}
+
+func cleanRequest(c *fiber.Ctx, r *fasthttp.Request) Request {
+	headers := fasthttp.AcquireRequest().Header
+	r.Header.CopyTo(&headers)
+	fmt.Println(headers.String())
+	return Request{
+		Headers: headers,
+	}
+}
+
+func BuildMessage(c *fiber.Ctx) LogMessage {
+	const layout = "2006-01-02 03:04:05"
+	requestId := c.Locals("requestId")
+
+	message := LogMessage{
+		Date:       time.Now().UTC().Format(layout),
+		RequestId:  fmt.Sprintf("%s", requestId),
+		StatusCode: strconv.Itoa(c.Response().StatusCode()),
+		Method:     c.Method(),
+		Path:       c.Route().Path,
+		PID:        strconv.Itoa(os.Getpid()),
+	}
+	return message
+}
+
+func Log(message LogMessage) {
+	logString := ""
+	if viper.GetString("app.logType") == "json" {
+		tempLogString, _ := json.MarshalIndent(message, "", "  ")
+		logString = string(tempLogString)
+	} else {
+		logString = fmt.Sprintf("%s %s %s %s - %s %s", message.Date, message.PID, message.RequestId, message.StatusCode, message.Method, message.Path) //strconv.Itoa(os.Getpid()) + " " + fmt.Sprintf("%s", requestId) + " " + strconv.Itoa(err.Code) + " - " + c.Method() + " " + c.Route().Path + " - " + err.Error()
+		if message.Error != nil {
+			logString += " - " + message.Error.Error()
+		}
+	}
+
+	fmt.Println(logString)
+}
+
+func New() fiber.Handler {
+
+	return func(c *fiber.Ctx) error {
+		errHandler := c.App().Config().ErrorHandler
+		chainErr := c.Next()
+
+		message := BuildMessage(c)
+
+		if chainErr != nil {
+			dawnError := ErrorHandler(c, chainErr)
+			message.Error = dawnError
+		}
+
+		Log(message)
+
+		if chainErr != nil {
+			if err := errHandler(c, chainErr); err != nil {
+				_ = c.SendStatus(fiber.StatusInternalServerError)
+			}
+		}
+
+		return nil
+	}
+}
+
+func ErrorHandler(ctx *fiber.Ctx, err error) *errors.DawnError {
+	var returnError *errors.DawnError
+	if e, ok := err.(*errors.DawnError); ok {
+		returnError = e
+	} else {
+		returnError = errors.Build(err)
+	}
+
+	return returnError
+}
diff --git a/main.go b/main.go
index af3dade..8ae99a5 100644
--- a/main.go
+++ b/main.go
@@ -3,14 +3,14 @@ package main
 import (
 	"dawn-weather/config"
 	"dawn-weather/errors"
+	"dawn-weather/logger"
 	"dawn-weather/persistence"
-	"fmt"
+	"strconv"
 
 	"github.com/ansrivas/fiberprometheus/v2"
 	swagger "github.com/arsmn/fiber-swagger/v2"
 	"github.com/gofiber/fiber/v2"
 	"github.com/gofiber/fiber/v2/middleware/cors"
-	"github.com/gofiber/fiber/v2/middleware/logger"
 	"github.com/gofiber/fiber/v2/middleware/recover"
 	"github.com/gofiber/fiber/v2/middleware/requestid"
 	"github.com/gofiber/fiber/v2/utils"
@@ -46,9 +46,17 @@ func registerLogging(app *fiber.App) {
 		ContextKey: "requestId",
 	}))
 
-	app.Use(logger.New(logger.Config{
-		Format: "${pid} ${locals:requestId} ${status} - ${method} ${path}\n",
-	}))
+	// app.Use(logger.New(logger.Config{
+	// 	Format: "${pid} ${locals:requestId} ${status} - ${method} ${path}\n",
+	// }))
+
+	// app.Use(func(c *fiber.Ctx) error {
+	// 	fmt.Println(c.Response().StatusCode())
+	// 	fmt.Println("hey!")
+	// 	return c.Next()
+	// })
+
+	app.Use(logger.New())
 }
 
 func registerPrometheus(app *fiber.App) {
@@ -62,17 +70,25 @@ func createFiberConfig() fiber.Config {
 		ErrorHandler: func(ctx *fiber.Ctx, err error) error {
 
 			code := fiber.StatusInternalServerError
-			message := errors.StandardError{Source: viper.GetString("app.name"), ErrorCode: "UNKNOWN_ERROR",
-				Description: "Unknown error occurred", Details: errors.ErrorDetails{RequestId: ""}}
+			message := errors.StandardError{Source: viper.GetString("app.name"), ErrorCode: "INTERNAL_SERVER",
+				Description: "Internal Server Error Occurred", Details: errors.ErrorDetails{RequestId: ""}}
 
 			if e, ok := err.(*errors.DawnError); ok {
 				code = e.Code
 				message = err.(*errors.DawnError).BuildStandardError(ctx)
-				err.(*errors.DawnError).LogString(ctx)
 			} else {
-				fmt.Println(err)
+				err = errors.Build(err)
+			}
+
+			logMessage := logger.BuildMessage(ctx)
+			logMessage.Error = err.(*errors.DawnError)
+			logMessage.StatusCode = strconv.Itoa(code)
+
+			logger.Log(logMessage)
+
+			if code == 500 {
+				message = errors.INTERNAL_SERVER_STANDARD_ERROR.BuildStandardError(ctx)
 			}
-			// message.LogJson()
 
 			err = ctx.Status(code).JSON(message)
 
diff --git a/models/csv.go b/models/csv.go
index a71ec0a..de0d5ba 100644
--- a/models/csv.go
+++ b/models/csv.go
@@ -107,11 +107,3 @@ func (r CSVRequest) Build(c *fiber.Ctx) CSVRequest {
 
 	return newRequest
 }
-
-// func (r GddRequest) BuildLocation() entities.Location {
-// 	l := entities.Location{
-// 		Type:        "Point",
-// 		Coordinates: []float64{r.Longitude, r.Latitude},
-// 	}
-// 	return l
-// }
diff --git a/services/data_download_service.go b/services/data_download_service.go
index c18dfd8..5ccf021 100644
--- a/services/data_download_service.go
+++ b/services/data_download_service.go
@@ -430,7 +430,7 @@ func GetDataDownload(request models.CSVRequest) string {
 	f, err := os.Create(fileId.String() + ".csv")
 
 	if err != nil {
-		panic(errors.BAD_REQUEST)
+		panic(errors.FILE_CREATION_ERROR.AddLogDetails("Could not create file"))
 	}
 
 	w := csv.NewWriter(f)
-- 
GitLab