From f1d7123596f0b3f67643c01db742adaa3e8dd265 Mon Sep 17 00:00:00 2001 From: Sung <8265228+sungwoncho@users.noreply.github.com> Date: Sat, 1 Nov 2025 14:06:33 -0700 Subject: [PATCH] Fix log level (#712) --- README.md | 10 +++- pkg/server/database/database.go | 4 +- pkg/server/database/database_test.go | 70 ++++++++++++++++++++++++++++ pkg/server/log/log.go | 46 +++++++++++------- pkg/server/log/log_test.go | 44 +++++++++++++++++ scripts/license.sh | 16 +++---- 6 files changed, 160 insertions(+), 30 deletions(-) create mode 100644 pkg/server/database/database_test.go diff --git a/README.md b/README.md index fbe46e26..7ab0063f 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,9 @@ Or [download binary](https://github.com/dnote/dnote/releases). ## Server (Optional) -Just run a binary. No database setup required. +Server is a binary with SQLite embedded. No database setup is required. -Run with Docker Compose using [compose.yml](./host/docker/compose.yml): +If using docker, create a compose.yml: ```yaml services: @@ -51,6 +51,12 @@ services: restart: unless-stopped ``` +Then run: + +```bash +docker-compose up -d +``` + Or see the [guide](https://www.getdnote.com/docs/server/manual) for binary installation. ## Documentation diff --git a/pkg/server/database/database.go b/pkg/server/database/database.go index cfb18ab7..bd7869bc 100644 --- a/pkg/server/database/database.go +++ b/pkg/server/database/database.go @@ -38,13 +38,13 @@ func getDBLogLevel(level string) logger.LogLevel { case log.LevelDebug: return logger.Info case log.LevelInfo: - return logger.Info + return logger.Silent case log.LevelWarn: return logger.Warn case log.LevelError: return logger.Error default: - return logger.Error + return logger.Silent } } diff --git a/pkg/server/database/database_test.go b/pkg/server/database/database_test.go new file mode 100644 index 00000000..3d3f5b92 --- /dev/null +++ b/pkg/server/database/database_test.go @@ -0,0 +1,70 @@ +/* Copyright 2025 Dnote Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package database + +import ( + "testing" + + "github.com/dnote/dnote/pkg/assert" + "github.com/dnote/dnote/pkg/server/log" + "gorm.io/gorm/logger" +) + +func TestGetDBLogLevel(t *testing.T) { + testCases := []struct { + name string + level string + expected logger.LogLevel + }{ + { + name: "debug level maps to Info", + level: log.LevelDebug, + expected: logger.Info, + }, + { + name: "info level maps to Silent", + level: log.LevelInfo, + expected: logger.Silent, + }, + { + name: "warn level maps to Warn", + level: log.LevelWarn, + expected: logger.Warn, + }, + { + name: "error level maps to Error", + level: log.LevelError, + expected: logger.Error, + }, + { + name: "unknown level maps to Silent", + level: "unknown", + expected: logger.Silent, + }, + { + name: "empty string maps to Silent", + level: "", + expected: logger.Silent, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := getDBLogLevel(tc.level) + assert.Equal(t, result, tc.expected, "log level mismatch") + }) + } +} diff --git a/pkg/server/log/log.go b/pkg/server/log/log.go index d8b43c8b..172255ba 100644 --- a/pkg/server/log/log.go +++ b/pkg/server/log/log.go @@ -75,25 +75,35 @@ func GetLevel() string { return currentLevel } -// levelPriority returns a numeric priority for comparison -func levelPriority(level string) int { - switch level { - case LevelDebug: - return 0 - case LevelInfo: - return 1 - case LevelWarn: - return 2 - case LevelError: - return 3 - default: - return 1 - } -} - -// shouldLog returns true if the given level should be logged based on currentLevel +// shouldLog returns true if the given level should be logged based on currentLevel. +// +// Log level behavior (hierarchical): +// - LevelDebug: shows all messages (debug, info, warn, error) +// - LevelInfo: shows info, warn, and error messages +// - LevelWarn: shows warn and error messages +// - LevelError: shows only error messages func shouldLog(level string) bool { - return levelPriority(level) >= levelPriority(currentLevel) + // Debug level shows everything + if currentLevel == LevelDebug { + return true + } + + // Info level shows info + warn + error + if currentLevel == LevelInfo { + return level == LevelInfo || level == LevelWarn || level == LevelError + } + + // Warn level shows warn + error + if currentLevel == LevelWarn { + return level == LevelWarn || level == LevelError + } + + // Error level shows only error + if currentLevel == LevelError { + return level == LevelError + } + + return false } // Debug logs the given entry at a debug level diff --git a/pkg/server/log/log_test.go b/pkg/server/log/log_test.go index 488e3725..dd98c685 100644 --- a/pkg/server/log/log_test.go +++ b/pkg/server/log/log_test.go @@ -33,3 +33,47 @@ func TestSetLevel(t *testing.T) { t.Errorf("Expected level %s, got %s", LevelError, currentLevel) } } + +func TestShouldLog(t *testing.T) { + // Reset to default after test + defer SetLevel(LevelInfo) + + testCases := []struct { + currentLevel string + logLevel string + expected bool + description string + }{ + // Debug level shows everything + {LevelDebug, LevelDebug, true, "debug level should show debug"}, + {LevelDebug, LevelInfo, true, "debug level should show info"}, + {LevelDebug, LevelWarn, true, "debug level should show warn"}, + {LevelDebug, LevelError, true, "debug level should show error"}, + + // Info level shows info + warn + error + {LevelInfo, LevelDebug, false, "info level should not show debug"}, + {LevelInfo, LevelInfo, true, "info level should show info"}, + {LevelInfo, LevelWarn, true, "info level should show warn"}, + {LevelInfo, LevelError, true, "info level should show error"}, + + // Warn level shows warn + error + {LevelWarn, LevelDebug, false, "warn level should not show debug"}, + {LevelWarn, LevelInfo, false, "warn level should not show info"}, + {LevelWarn, LevelWarn, true, "warn level should show warn"}, + {LevelWarn, LevelError, true, "warn level should show error"}, + + // Error level shows only error + {LevelError, LevelDebug, false, "error level should not show debug"}, + {LevelError, LevelInfo, false, "error level should not show info"}, + {LevelError, LevelWarn, false, "error level should not show warn"}, + {LevelError, LevelError, true, "error level should show error"}, + } + + for _, tc := range testCases { + SetLevel(tc.currentLevel) + result := shouldLog(tc.logLevel) + if result != tc.expected { + t.Errorf("%s: expected %v, got %v", tc.description, tc.expected, result) + } + } +} diff --git a/scripts/license.sh b/scripts/license.sh index 4f96780c..4f7788e4 100755 --- a/scripts/license.sh +++ b/scripts/license.sh @@ -1,11 +1,9 @@ #!/usr/bin/env bash set -eux -function remove_notice { - # Remove old copyright notice - matches /* Copyright ... */ including the trailing newline - # The 's' flag makes . match newlines, allowing multi-line matching - # The \n? matches an optional newline after the closing */ - perl -i -0pe 's/\/\* Copyright.*?\*\/\n?//s' "$1" +function has_license { + # Check if file already has a copyright notice + grep -q "Copyright.*Dnote Authors" "$1" } function add_notice { @@ -18,7 +16,8 @@ q END } -license="/* Copyright 2025 Dnote Authors +year=$(date +%Y) +license="/* Copyright $year Dnote Authors * * Licensed under the Apache License, Version 2.0 (the \"License\"); * you may not use this file except in compliance with the License. @@ -41,6 +40,7 @@ pkgPath="$basedir/pkg" allFiles=$(find "$pkgPath" -type f \( -name "*.go" -o -name "*.js" -o -name "*.ts" -o -name "*.tsx" -o -name "*.scss" -o -name "*.css" \) ! -path "**/vendor/*" ! -path "**/node_modules/*" ! -path "**/dist/*") for file in $allFiles; do - remove_notice "$file" - add_notice "$file" "$license" + if ! has_license "$file"; then + add_notice "$file" "$license" + fi done