Skip to content

Commit

Permalink
Added setting for LogLevel
Browse files Browse the repository at this point in the history
  • Loading branch information
pikami committed Jan 9, 2025
1 parent c2c9dc0 commit 8b8b087
Show file tree
Hide file tree
Showing 14 changed files with 200 additions and 84 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,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
- **-LogLevel**: Sets the logging level (one of: debug, info, error, silent) (default info)

These arguments allow you to configure various aspects of Cosmium's behavior according to your requirements.

Expand All @@ -90,7 +90,7 @@ All mentioned arguments can also be set using environment variables:
- **COSMIUM_INITIALDATA** for `-InitialData`
- **COSMIUM_PERSIST** for `-Persist`
- **COSMIUM_PORT** for `-Port`
- **COSMIUM_DEBUG** for `-Debug`
- **COSMIUM_LOGLEVEL** for `-LogLevel`

# License

Expand Down
19 changes: 16 additions & 3 deletions api/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ func ParseFlags() ServerConfig {
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")
logLevel := NewEnumValue("info", []string{"debug", "info", "error", "silent"})
flag.Var(logLevel, "LogLevel", fmt.Sprintf("Sets the logging level %s", logLevel.AllowedValuesList()))

flag.Parse()
setFlagsFromEnvironment()
Expand All @@ -41,8 +42,8 @@ func ParseFlags() ServerConfig {
config.PersistDataFilePath = *persistDataPath
config.DisableAuth = *disableAuthentication
config.DisableTls = *disableTls
config.Debug = *debug
config.AccountKey = *accountKey
config.LogLevel = logLevel.value

config.PopulateCalculatedFields()

Expand All @@ -54,7 +55,19 @@ func (c *ServerConfig) PopulateCalculatedFields() {
c.DatabaseDomain = c.Host
c.DatabaseEndpoint = fmt.Sprintf("https://%s:%d/", c.Host, c.Port)
c.ExplorerBaseUrlLocation = ExplorerBaseUrlLocation
logger.EnableDebugOutput = c.Debug

switch c.LogLevel {
case "debug":
logger.LogLevel = logger.LogLevelDebug
case "info":
logger.LogLevel = logger.LogLevelInfo
case "error":
logger.LogLevel = logger.LogLevelError
case "silent":
logger.LogLevel = logger.LogLevelSilent
default:
logger.LogLevel = logger.LogLevelInfo
}
}

func (c *ServerConfig) ApplyDefaultsToEmptyFields() {
Expand Down
36 changes: 36 additions & 0 deletions api/config/enumFlag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package config

import (
"fmt"
"strings"
)

type EnumValue struct {
allowedValues []string
value string
}

func (e *EnumValue) String() string {
return e.value
}

func (e *EnumValue) Set(v string) error {
for _, allowed := range e.allowedValues {
if v == allowed {
e.value = v
return nil
}
}
return fmt.Errorf("invalid value %q, must be one of: %s", v, strings.Join(e.allowedValues, ", "))
}

func NewEnumValue(defaultValue string, allowedValues []string) *EnumValue {
return &EnumValue{
allowedValues: allowedValues,
value: defaultValue,
}
}

func (e *EnumValue) AllowedValuesList() string {
return fmt.Sprintf("(one of: %s)", strings.Join(e.allowedValues, ", "))
}
2 changes: 1 addition & 1 deletion api/config/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ type ServerConfig struct {
PersistDataFilePath string `json:"persistDataFilePath"`
DisableAuth bool `json:"disableAuth"`
DisableTls bool `json:"disableTls"`
Debug bool `json:"debug"`
LogLevel string `json:"logLevel"`
ExplorerBaseUrlLocation string `json:"explorerBaseUrlLocation"`
}
4 changes: 2 additions & 2 deletions api/handlers/documents.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func (h *Handlers) PatchDocument(c *gin.Context) {

currentDocumentBytes, err := json.Marshal(document)
if err != nil {
logger.Error("Failed to marshal existing document:", err)
logger.ErrorLn("Failed to marshal existing document:", err)
c.JSON(http.StatusInternalServerError, gin.H{"message": "Failed to marshal existing document"})
return
}
Expand All @@ -149,7 +149,7 @@ func (h *Handlers) PatchDocument(c *gin.Context) {
var modifiedDocument map[string]interface{}
err = json.Unmarshal(modifiedDocumentBytes, &modifiedDocument)
if err != nil {
logger.Error("Failed to unmarshal modified document:", err)
logger.ErrorLn("Failed to unmarshal modified document:", err)
c.JSON(http.StatusInternalServerError, gin.H{"message": "Failed to unmarshal modified document"})
return
}
Expand Down
2 changes: 1 addition & 1 deletion api/handlers/middleware/loggers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func RequestLogger() gin.HandlerFunc {

bodyStr := readBody(rdr1)
if bodyStr != "" {
logger.Debug(bodyStr)
logger.DebugLn(bodyStr)
}

c.Request.Body = rdr2
Expand Down
17 changes: 10 additions & 7 deletions api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@ import (
func (s *ApiServer) CreateRouter(repository *repositories.DataRepository) {
routeHandlers := handlers.NewHandlers(repository, s.config)

if !s.config.Debug {
gin.DefaultWriter = logger.InfoWriter()
gin.DefaultErrorWriter = logger.ErrorWriter()

if s.config.LogLevel != "debug" {
gin.SetMode(gin.ReleaseMode)
}

router := gin.Default(func(e *gin.Engine) {
e.RedirectTrailingSlash = false
})

if s.config.Debug {
if s.config.LogLevel == "debug" {
router.Use(middleware.RequestLogger())
}

Expand Down Expand Up @@ -89,10 +92,10 @@ func (s *ApiServer) Start() {

go func() {
<-s.stopServer
logger.Info("Shutting down server...")
logger.InfoLn("Shutting down server...")
err := server.Shutdown(context.TODO())
if err != nil {
logger.Error("Failed to shutdown server:", err)
logger.ErrorLn("Failed to shutdown server:", err)
}
}()

Expand All @@ -101,7 +104,7 @@ func (s *ApiServer) Start() {
logger.Infof("Listening and serving HTTP on %s\n", server.Addr)
err := server.ListenAndServe()
if err != nil {
logger.Error("Failed to start HTTP server:", err)
logger.ErrorLn("Failed to start HTTP server:", err)
}
s.isActive = false
} else if s.config.TLS_CertificatePath != "" && s.config.TLS_CertificateKey != "" {
Expand All @@ -110,7 +113,7 @@ func (s *ApiServer) Start() {
s.config.TLS_CertificatePath,
s.config.TLS_CertificateKey)
if err != nil {
logger.Error("Failed to start HTTPS server:", err)
logger.ErrorLn("Failed to start HTTPS server:", err)
}
s.isActive = false
} else {
Expand All @@ -120,7 +123,7 @@ func (s *ApiServer) Start() {
logger.Infof("Listening and serving HTTPS on %s\n", server.Addr)
err := server.ListenAndServeTLS("", "")
if err != nil {
logger.Error("Failed to start HTTPS server:", err)
logger.ErrorLn("Failed to start HTTPS server:", err)
}
s.isActive = false
}
Expand Down
80 changes: 72 additions & 8 deletions internal/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,100 @@ import (
"os"
)

var EnableDebugOutput = false
type LogLevelType int

var (
LogLevelDebug LogLevelType = 0
LogLevelInfo LogLevelType = 1
LogLevelError LogLevelType = 2
LogLevelSilent LogLevelType = 10
)

type LogWriter struct {
WriterLevel LogLevelType
}

var LogLevel = LogLevelInfo

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 EnableDebugOutput {
func DebugLn(v ...any) {
if LogLevel <= LogLevelDebug {
DebugLogger.Println(v...)
}
}

func Debug(v ...any) {
if LogLevel <= LogLevelDebug {
DebugLogger.Print(v...)
}
}

func Debugf(format string, v ...any) {
if EnableDebugOutput {
if LogLevel <= LogLevelDebug {
DebugLogger.Printf(format, v...)
}
}

func InfoLn(v ...any) {
if LogLevel <= LogLevelInfo {
InfoLogger.Println(v...)
}
}

func Info(v ...any) {
InfoLogger.Println(v...)
if LogLevel <= LogLevelInfo {
InfoLogger.Print(v...)
}
}

func Infof(format string, v ...any) {
InfoLogger.Printf(format, v...)
if LogLevel <= LogLevelInfo {
InfoLogger.Printf(format, v...)
}
}

func ErrorLn(v ...any) {
if LogLevel <= LogLevelError {
ErrorLogger.Println(v...)
}
}

func Error(v ...any) {
ErrorLogger.Println(v...)
if LogLevel <= LogLevelError {
ErrorLogger.Print(v...)
}
}

func Errorf(format string, v ...any) {
ErrorLogger.Printf(format, v...)
if LogLevel <= LogLevelError {
ErrorLogger.Printf(format, v...)
}
}

func (lw *LogWriter) Write(p []byte) (n int, err error) {
switch lw.WriterLevel {
case LogLevelDebug:
Debug(string(p))
case LogLevelInfo:
Info(string(p))
case LogLevelError:
Error(string(p))
}

return len(p), nil
}

func ErrorWriter() *LogWriter {
return &LogWriter{WriterLevel: LogLevelError}
}

func InfoWriter() *LogWriter {
return &LogWriter{WriterLevel: LogLevelInfo}
}

func DebugWriter() *LogWriter {
return &LogWriter{WriterLevel: LogLevelDebug}
}
6 changes: 3 additions & 3 deletions internal/repositories/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (r *DataRepository) InitializeRepository() {
}

if stat.IsDir() {
logger.Error("Argument '-Persist' must be a path to file, not a directory.")
logger.ErrorLn("Argument '-Persist' must be a path to file, not a directory.")
os.Exit(1)
}

Expand Down Expand Up @@ -60,7 +60,7 @@ func (r *DataRepository) LoadStateJSON(jsonData string) error {

r.ensureStoreStateNoNullReferences()

logger.Info("Loaded state:")
logger.InfoLn("Loaded state:")
logger.Infof("Databases: %d\n", getLength(r.storeState.Databases))
logger.Infof("Collections: %d\n", getLength(r.storeState.Collections))
logger.Infof("Documents: %d\n", getLength(r.storeState.Documents))
Expand All @@ -83,7 +83,7 @@ func (r *DataRepository) SaveStateFS(filePath string) {

os.WriteFile(filePath, data, os.ModePerm)

logger.Info("Saved state:")
logger.InfoLn("Saved state:")
logger.Infof("Databases: %d\n", getLength(r.storeState.Databases))
logger.Infof("Collections: %d\n", getLength(r.storeState.Collections))
logger.Infof("Documents: %d\n", getLength(r.storeState.Documents))
Expand Down
2 changes: 1 addition & 1 deletion internal/tls_provider/tls_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
func GetDefaultTlsConfig() *tls.Config {
cert, err := tls.X509KeyPair([]byte(certificate), []byte(certificateKey))
if err != nil {
logger.Error("Failed to parse certificate and key:", err)
logger.ErrorLn("Failed to parse certificate and key:", err)
return &tls.Config{}
}

Expand Down
10 changes: 5 additions & 5 deletions query_executors/memory_executor/array_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (r rowContext) array_Contains(arguments []interface{}) bool {
if boolValue, ok := boolExpr.(bool); ok {
partialSearch = boolValue
} else {
logger.Error("array_Contains - got parameters of wrong type")
logger.ErrorLn("array_Contains - got parameters of wrong type")
return false
}
}
Expand Down Expand Up @@ -116,13 +116,13 @@ func (r rowContext) array_Slice(arguments []interface{}) []interface{} {
lengthEx := r.resolveSelectItem(arguments[2].(parsers.SelectItem))

if length, ok = lengthEx.(int); !ok {
logger.Error("array_Slice - got length parameters of wrong type")
logger.ErrorLn("array_Slice - got length parameters of wrong type")
return []interface{}{}
}
}

if start, ok = startEx.(int); !ok {
logger.Error("array_Slice - got start parameters of wrong type")
logger.ErrorLn("array_Slice - got start parameters of wrong type")
return []interface{}{}
}

Expand Down Expand Up @@ -197,7 +197,7 @@ func (r rowContext) parseArray(argument interface{}) []interface{} {

arrValue := reflect.ValueOf(ex)
if arrValue.Kind() != reflect.Slice {
logger.Error("parseArray got parameters of wrong type")
logger.ErrorLn("parseArray got parameters of wrong type")
return nil
}

Expand All @@ -215,7 +215,7 @@ func (r rowContext) partialMatch(item interface{}, exprToSearch interface{}) boo
exprValue := reflect.ValueOf(exprToSearch)

if itemValue.Kind() != reflect.Map || exprValue.Kind() != reflect.Map {
logger.Error("partialMatch got parameters of wrong type")
logger.ErrorLn("partialMatch got parameters of wrong type")
return false
}

Expand Down
Loading

0 comments on commit 8b8b087

Please sign in to comment.