diff --git a/README.md b/README.md index 7005273..3136aec 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ To disable SSL and run Cosmium on HTTP instead, you can use the `-DisableTls` fl * **-InitialData**: Path to JSON containing initial state * **-Persist**: Saves data to the given path on application exit (When `-InitialData` argument is not supplied, it will try to load data from path supplied in `-Persist`) * **-Port**: Listen port (default 8081) +* **-Debug**: Runs application in debug mode, this provides additional logging These arguments allow you to configure various aspects of Cosmium's behavior according to your requirements. diff --git a/api/config/config.go b/api/config/config.go index 86ebd92..55f6587 100644 --- a/api/config/config.go +++ b/api/config/config.go @@ -22,6 +22,7 @@ func ParseFlags() { disableAuthentication := flag.Bool("DisableAuth", false, "Disable authentication") disableTls := flag.Bool("DisableTls", false, "Disable TLS, serve over HTTP") persistDataPath := flag.String("Persist", "", "Saves data to given path on application exit") + debug := flag.Bool("Debug", false, "Runs application in debug mode, this provides additional logging") flag.Parse() @@ -34,6 +35,7 @@ func ParseFlags() { Config.PersistDataFilePath = *persistDataPath Config.DisableAuth = *disableAuthentication Config.DisableTls = *disableTls + Config.Debug = *debug Config.DatabaseAccount = Config.Host Config.DatabaseDomain = Config.Host diff --git a/api/config/models.go b/api/config/models.go index b8098e1..5bc1310 100644 --- a/api/config/models.go +++ b/api/config/models.go @@ -15,4 +15,5 @@ type ServerConfig struct { PersistDataFilePath string DisableAuth bool DisableTls bool + Debug bool } diff --git a/api/handlers/middleware/authentication.go b/api/handlers/middleware/authentication.go index 56aa4b5..48e66dd 100644 --- a/api/handlers/middleware/authentication.go +++ b/api/handlers/middleware/authentication.go @@ -1,13 +1,13 @@ package middleware import ( - "fmt" "net/url" "strings" "github.com/gin-gonic/gin" "github.com/pikami/cosmium/api/config" "github.com/pikami/cosmium/internal/authentication" + "github.com/pikami/cosmium/internal/logger" ) func Authentication() gin.HandlerFunc { @@ -53,7 +53,7 @@ func Authentication() gin.HandlerFunc { params, _ := url.ParseQuery(decoded) clientSignature := strings.Replace(params.Get("sig"), " ", "+", -1) if clientSignature != expectedSignature { - fmt.Printf("Got wrong signature from client.\n- Expected: %s\n- Got: %s\n", expectedSignature, clientSignature) + logger.Errorf("Got wrong signature from client.\n- Expected: %s\n- Got: %s\n", expectedSignature, clientSignature) c.IndentedJSON(401, gin.H{ "code": "Unauthorized", "message": "Wrong signature.", diff --git a/api/handlers/middleware/loggers.go b/api/handlers/middleware/loggers.go index 323e4d4..45f099f 100644 --- a/api/handlers/middleware/loggers.go +++ b/api/handlers/middleware/loggers.go @@ -2,10 +2,10 @@ package middleware import ( "bytes" - "fmt" "io" "github.com/gin-gonic/gin" + "github.com/pikami/cosmium/internal/logger" ) func RequestLogger() gin.HandlerFunc { @@ -16,7 +16,7 @@ func RequestLogger() gin.HandlerFunc { bodyStr := readBody(rdr1) if bodyStr != "" { - fmt.Println(bodyStr) + logger.Debug(bodyStr) } c.Request.Body = rdr2 diff --git a/api/router.go b/api/router.go index 64aa6bf..81e0ded 100644 --- a/api/router.go +++ b/api/router.go @@ -8,12 +8,17 @@ import ( "github.com/pikami/cosmium/api/config" "github.com/pikami/cosmium/api/handlers" "github.com/pikami/cosmium/api/handlers/middleware" + "github.com/pikami/cosmium/internal/logger" + tlsprovider "github.com/pikami/cosmium/internal/tls_provider" ) func CreateRouter() *gin.Engine { router := gin.Default() - router.Use(middleware.RequestLogger()) + if config.Config.Debug { + router.Use(middleware.RequestLogger()) + } + router.Use(middleware.Authentication()) router.GET("/dbs/:databaseId/colls/:collId/pkranges", handlers.GetPartitionKeyRanges) @@ -49,6 +54,10 @@ func CreateRouter() *gin.Engine { } func StartAPI() { + if !config.Config.Debug { + gin.SetMode(gin.ReleaseMode) + } + router := CreateRouter() listenAddress := fmt.Sprintf(":%d", config.Config.Port) @@ -58,7 +67,7 @@ func StartAPI() { config.Config.TLS_CertificatePath, config.Config.TLS_CertificateKey) if err != nil { - fmt.Println("Failed to start HTTPS server:", err) + logger.Error("Failed to start HTTPS server:", err) } return @@ -68,17 +77,17 @@ func StartAPI() { router.Run(listenAddress) } - tlsConfig := config.GetDefaultTlsConfig() + tlsConfig := tlsprovider.GetDefaultTlsConfig() server := &http.Server{ Addr: listenAddress, Handler: router.Handler(), TLSConfig: tlsConfig, } - fmt.Printf("Listening and serving HTTPS on %s\n", server.Addr) + logger.Infof("Listening and serving HTTPS on %s\n", server.Addr) err := server.ListenAndServeTLS("", "") if err != nil { - fmt.Println("Failed to start HTTPS server:", err) + logger.Error("Failed to start HTTPS server:", err) } router.Run() diff --git a/internal/logger/logger.go b/internal/logger/logger.go new file mode 100644 index 0000000..01590a3 --- /dev/null +++ b/internal/logger/logger.go @@ -0,0 +1,40 @@ +package logger + +import ( + "log" + "os" + + "github.com/pikami/cosmium/api/config" +) + +var DebugLogger = log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile) +var InfoLogger = log.New(os.Stdout, "", log.Ldate|log.Ltime) +var ErrorLogger = log.New(os.Stderr, "", log.Ldate|log.Ltime|log.Lshortfile) + +func Debug(v ...any) { + if config.Config.Debug { + DebugLogger.Println(v...) + } +} + +func Debugf(format string, v ...any) { + if config.Config.Debug { + DebugLogger.Printf(format, v...) + } +} + +func Info(v ...any) { + InfoLogger.Println(v...) +} + +func Infof(format string, v ...any) { + InfoLogger.Printf(format, v...) +} + +func Error(v ...any) { + ErrorLogger.Println(v...) +} + +func Errorf(format string, v ...any) { + ErrorLogger.Printf(format, v...) +} diff --git a/internal/repositories/state.go b/internal/repositories/state.go index 4b62503..4d13846 100644 --- a/internal/repositories/state.go +++ b/internal/repositories/state.go @@ -2,12 +2,12 @@ package repositories import ( "encoding/json" - "fmt" "log" "os" "reflect" "github.com/pikami/cosmium/api/config" + "github.com/pikami/cosmium/internal/logger" repositorymodels "github.com/pikami/cosmium/internal/repository_models" ) @@ -33,7 +33,7 @@ func InitializeRepository() { } if stat.IsDir() { - fmt.Println("Argument '-Persist' must be a path to file, not a directory.") + logger.Error("Argument '-Persist' must be a path to file, not a directory.") os.Exit(1) } @@ -55,10 +55,10 @@ func LoadStateFS(filePath string) { return } - fmt.Println("Loaded state:") - fmt.Printf("Databases: %d\n", getLength(state.Databases)) - fmt.Printf("Collections: %d\n", getLength(state.Collections)) - fmt.Printf("Documents: %d\n", getLength(state.Documents)) + logger.Info("Loaded state:") + logger.Infof("Databases: %d\n", getLength(state.Databases)) + logger.Infof("Collections: %d\n", getLength(state.Collections)) + logger.Infof("Documents: %d\n", getLength(state.Documents)) storeState = state @@ -68,16 +68,16 @@ func LoadStateFS(filePath string) { func SaveStateFS(filePath string) { data, err := json.MarshalIndent(storeState, "", "\t") if err != nil { - fmt.Printf("Failed to save state: %v\n", err) + logger.Errorf("Failed to save state: %v\n", err) return } os.WriteFile(filePath, data, os.ModePerm) - fmt.Println("Saved state:") - fmt.Printf("Databases: %d\n", getLength(storeState.Databases)) - fmt.Printf("Collections: %d\n", getLength(storeState.Collections)) - fmt.Printf("Documents: %d\n", getLength(storeState.Documents)) + logger.Info("Saved state:") + logger.Infof("Databases: %d\n", getLength(storeState.Databases)) + logger.Infof("Collections: %d\n", getLength(storeState.Collections)) + logger.Infof("Documents: %d\n", getLength(storeState.Documents)) } func GetState() repositorymodels.State { diff --git a/api/config/constants.go b/internal/tls_provider/constants.go similarity index 90% rename from api/config/constants.go rename to internal/tls_provider/constants.go index c436a78..3a37733 100644 --- a/api/config/constants.go +++ b/internal/tls_provider/constants.go @@ -1,9 +1,4 @@ -package config - -import ( - "crypto/tls" - "fmt" -) +package tlsprovider const certificate = ` -----BEGIN CERTIFICATE----- @@ -64,15 +59,3 @@ ilcZlmaCS9pqIXAFK9GQ89V/xa8OibOuJUiBgShnfSQqAwQrfX1vYjtKErnjoRFs 9+zaWugLCC47Hw6QlMDa -----END PRIVATE KEY----- ` - -func GetDefaultTlsConfig() *tls.Config { - cert, err := tls.X509KeyPair([]byte(certificate), []byte(certificateKey)) - if err != nil { - fmt.Println("Failed to parse certificate and key:", err) - return &tls.Config{} - } - - return &tls.Config{ - Certificates: []tls.Certificate{cert}, - } -} diff --git a/internal/tls_provider/tls_provider.go b/internal/tls_provider/tls_provider.go new file mode 100644 index 0000000..14ba666 --- /dev/null +++ b/internal/tls_provider/tls_provider.go @@ -0,0 +1,19 @@ +package tlsprovider + +import ( + "crypto/tls" + + "github.com/pikami/cosmium/internal/logger" +) + +func GetDefaultTlsConfig() *tls.Config { + cert, err := tls.X509KeyPair([]byte(certificate), []byte(certificateKey)) + if err != nil { + logger.Error("Failed to parse certificate and key:", err) + return &tls.Config{} + } + + return &tls.Config{ + Certificates: []tls.Certificate{cert}, + } +} diff --git a/query_executors/memory_executor/array_functions.go b/query_executors/memory_executor/array_functions.go index 66928fd..2973471 100644 --- a/query_executors/memory_executor/array_functions.go +++ b/query_executors/memory_executor/array_functions.go @@ -1,9 +1,9 @@ package memoryexecutor import ( - "fmt" "reflect" + "github.com/pikami/cosmium/internal/logger" "github.com/pikami/cosmium/parsers" ) @@ -36,13 +36,13 @@ func (c memoryExecutorContext) array_Slice(arguments []interface{}, row RowType) lengthEx := c.getFieldValue(arguments[2].(parsers.SelectItem), row) if length, ok = lengthEx.(int); !ok { - fmt.Println("array_Slice - got length parameters of wrong type") + logger.Error("array_Slice - got length parameters of wrong type") return []interface{}{} } } if start, ok = startEx.(int); !ok { - fmt.Println("array_Slice - got start parameters of wrong type") + logger.Error("array_Slice - got start parameters of wrong type") return []interface{}{} } @@ -117,7 +117,7 @@ func (c memoryExecutorContext) parseArray(argument interface{}, row RowType) []i arrValue := reflect.ValueOf(ex) if arrValue.Kind() != reflect.Slice { - fmt.Println("parseArray got parameters of wrong type") + logger.Error("parseArray got parameters of wrong type") return nil } diff --git a/query_executors/memory_executor/memory_executor.go b/query_executors/memory_executor/memory_executor.go index b94c72b..3c90852 100644 --- a/query_executors/memory_executor/memory_executor.go +++ b/query_executors/memory_executor/memory_executor.go @@ -6,6 +6,7 @@ import ( "sort" "strings" + "github.com/pikami/cosmium/internal/logger" "github.com/pikami/cosmium/parsers" ) @@ -168,7 +169,7 @@ func (c memoryExecutorContext) getFieldValue(field parsers.SelectItem, row RowTy var ok bool if typedValue, ok = field.Value.(parsers.Constant); !ok { // TODO: Handle error - fmt.Println("parsers.Constant has incorrect Value type") + logger.Error("parsers.Constant has incorrect Value type") } if typedValue.Type == parsers.ConstantTypeParameterConstant && @@ -186,7 +187,7 @@ func (c memoryExecutorContext) getFieldValue(field parsers.SelectItem, row RowTy var ok bool if typedValue, ok = field.Value.(parsers.FunctionCall); !ok { // TODO: Handle error - fmt.Println("parsers.Constant has incorrect Value type") + logger.Error("parsers.Constant has incorrect Value type") } switch typedValue.Type { @@ -288,7 +289,7 @@ func (c memoryExecutorContext) getExpressionParameterValue( return c.getFieldValue(typedParameter, row) } - fmt.Println("getExpressionParameterValue - got incorrect parameter type") + logger.Error("getExpressionParameterValue - got incorrect parameter type") return nil } diff --git a/query_executors/memory_executor/string_functions.go b/query_executors/memory_executor/string_functions.go index 1d82b84..f34e995 100644 --- a/query_executors/memory_executor/string_functions.go +++ b/query_executors/memory_executor/string_functions.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/pikami/cosmium/internal/logger" "github.com/pikami/cosmium/parsers" ) @@ -118,7 +119,7 @@ func (c memoryExecutorContext) strings_Left(arguments []interface{}, row RowType lengthEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row) if length, ok = lengthEx.(int); !ok { - fmt.Println("strings_Left - got parameters of wrong type") + logger.Error("strings_Left - got parameters of wrong type") return "" } @@ -157,7 +158,7 @@ func (c memoryExecutorContext) strings_Replicate(arguments []interface{}, row Ro timesEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row) if times, ok = timesEx.(int); !ok { - fmt.Println("strings_Replicate - got parameters of wrong type") + logger.Error("strings_Replicate - got parameters of wrong type") return "" } @@ -190,7 +191,7 @@ func (c memoryExecutorContext) strings_Right(arguments []interface{}, row RowTyp lengthEx := c.getFieldValue(arguments[1].(parsers.SelectItem), row) if length, ok = lengthEx.(int); !ok { - fmt.Println("strings_Right - got parameters of wrong type") + logger.Error("strings_Right - got parameters of wrong type") return "" } @@ -219,11 +220,11 @@ func (c memoryExecutorContext) strings_Substring(arguments []interface{}, row Ro lengthEx := c.getFieldValue(arguments[2].(parsers.SelectItem), row) if startPos, ok = startPosEx.(int); !ok { - fmt.Println("strings_Substring - got start parameters of wrong type") + logger.Error("strings_Substring - got start parameters of wrong type") return "" } if length, ok = lengthEx.(int); !ok { - fmt.Println("strings_Substring - got length parameters of wrong type") + logger.Error("strings_Substring - got length parameters of wrong type") return "" } @@ -263,7 +264,7 @@ func (c memoryExecutorContext) parseString(argument interface{}, row RowType) st return str1 } - fmt.Println("StringEquals got parameters of wrong type") + logger.Error("StringEquals got parameters of wrong type") return "" }