From 778df1af0fc3160de89627c7ba64768674e38376 Mon Sep 17 00:00:00 2001 From: Toby Chui Date: Wed, 24 Sep 2025 20:31:53 +0800 Subject: [PATCH] Updated #411 - Added support for human readable units in -logrotate flag --- src/def.go | 2 +- src/mod/utils/conv.go | 66 ++++++++++++++++++++++++++++++++++++++ src/mod/utils/conv_test.go | 41 +++++++++++++++++++++++ src/start.go | 15 +++++++-- 4 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 src/mod/utils/conv_test.go diff --git a/src/def.go b/src/def.go index 99f3122..8f7e0cb 100644 --- a/src/def.go +++ b/src/def.go @@ -97,7 +97,7 @@ var ( /* Logging Configuration Flags */ enableLog = flag.Bool("enablelog", true, "Enable system wide logging, set to false for writing log to STDOUT only") enableLogCompression = flag.Bool("enablelogcompress", true, "Enable log compression for rotated log files") - logRotate = flag.Int("logrotate", 0, "Enable log rotation and set the maximum log file size in KB (e.g. 25 for 25KB), set to 0 for disable") + logRotate = flag.String("logrotate", "0", "Enable log rotation and set the maximum log file size in KB, also support K, M, G suffix (e.g. 200M), set to 0 to disable") /* Default Configuration Flags */ defaultInboundPort = flag.Int("default_inbound_port", 443, "Default web server listening port") diff --git a/src/mod/utils/conv.go b/src/mod/utils/conv.go index 6adf753..d84cfd8 100644 --- a/src/mod/utils/conv.go +++ b/src/mod/utils/conv.go @@ -22,6 +22,72 @@ func Int64ToString(number int64) string { return convedNumber } +func SizeStringToBytes(sizeStr string) (int64, error) { + sizeStr = strings.TrimSpace(sizeStr) + if len(sizeStr) == 0 { + return 0, nil + } + // Extract unit (1 or 2 characters) from the end of the string + var unit string + var sizeValue string + + sizeStrLower := strings.ToLower(sizeStr) + if len(sizeStrLower) > 2 && (strings.HasSuffix(sizeStrLower, "kb") || strings.HasSuffix(sizeStrLower, "mb") || strings.HasSuffix(sizeStrLower, "gb") || strings.HasSuffix(sizeStrLower, "tb") || strings.HasSuffix(sizeStrLower, "pb")) { + unit = sizeStrLower[len(sizeStrLower)-2:] + sizeValue = sizeStrLower[:len(sizeStrLower)-2] + } else if len(sizeStrLower) > 1 && (strings.HasSuffix(sizeStrLower, "k") || strings.HasSuffix(sizeStrLower, "m") || strings.HasSuffix(sizeStrLower, "g") || strings.HasSuffix(sizeStrLower, "t") || strings.HasSuffix(sizeStrLower, "p")) { + unit = sizeStrLower[len(sizeStrLower)-1:] + sizeValue = sizeStrLower[:len(sizeStrLower)-1] + } else { + unit = "" + sizeValue = sizeStrLower + } + + size, err := strconv.ParseFloat(sizeValue, 64) + if err != nil { + return 0, err + } + switch unit { + case "k", "kb": + size *= 1024 + case "m", "mb": + size *= 1024 * 1024 + case "g", "gb": + size *= 1024 * 1024 * 1024 + case "t", "tb": + size *= 1024 * 1024 * 1024 * 1024 + case "p", "pb": + size *= 1024 * 1024 * 1024 * 1024 * 1024 + case "": + // No unit, size is already in bytes + default: + return 0, nil // Unknown unit + } + return int64(size), nil +} + +func BytesToHumanReadable(bytes int64) string { + const ( + KB = 1024 + MB = KB * 1024 + GB = MB * 1024 + TB = GB * 1024 + ) + + switch { + case bytes >= TB: + return strconv.FormatFloat(float64(bytes)/float64(TB), 'f', 2, 64) + " TB" + case bytes >= GB: + return strconv.FormatFloat(float64(bytes)/float64(GB), 'f', 2, 64) + " GB" + case bytes >= MB: + return strconv.FormatFloat(float64(bytes)/float64(MB), 'f', 2, 64) + " MB" + case bytes >= KB: + return strconv.FormatFloat(float64(bytes)/float64(KB), 'f', 2, 64) + " KB" + default: + return strconv.FormatInt(bytes, 10) + " Bytes" + } +} + func ReplaceSpecialCharacters(filename string) string { replacements := map[string]string{ "#": "%pound%", diff --git a/src/mod/utils/conv_test.go b/src/mod/utils/conv_test.go new file mode 100644 index 0000000..1abdf0c --- /dev/null +++ b/src/mod/utils/conv_test.go @@ -0,0 +1,41 @@ +package utils_test + +import ( + "testing" + + "imuslab.com/zoraxy/mod/utils" + + "github.com/stretchr/testify/assert" +) + +func TestSizeStringToBytes(t *testing.T) { + tests := []struct { + input string + expected int64 + hasError bool + }{ + {"1024", 1024, false}, + {"1k", 1024, false}, + {"1K", 1024, false}, + {"2kb", 2 * 1024, false}, + {"1m", 1024 * 1024, false}, + {"3mb", 3 * 1024 * 1024, false}, + {"1g", 1024 * 1024 * 1024, false}, + {"2gb", 2 * 1024 * 1024 * 1024, false}, + {"", 0, false}, + {" 5mb ", 5 * 1024 * 1024, false}, + {"invalid", 0, true}, + {"1tb", 1099511627776, false}, // Unknown unit returns 0, nil + {"1.5mb", int64(1.5 * 1024 * 1024), false}, + } + + for _, tt := range tests { + got, err := utils.SizeStringToBytes(tt.input) + if tt.hasError { + assert.Error(t, err, "input: %s", tt.input) + } else { + assert.NoError(t, err, "input: %s", tt.input) + assert.Equal(t, tt.expected, got, "input: %s", tt.input) + } + } +} diff --git a/src/start.go b/src/start.go index d1afd93..b2fb0cf 100644 --- a/src/start.go +++ b/src/start.go @@ -12,6 +12,7 @@ import ( "imuslab.com/zoraxy/mod/auth/sso/oauth2" "imuslab.com/zoraxy/mod/eventsystem" + "imuslab.com/zoraxy/mod/utils" "github.com/gorilla/csrf" "imuslab.com/zoraxy/mod/access" @@ -76,14 +77,24 @@ func startupSequence() { SystemWideLogger = l SystemWideLogger.Println("System wide logging is disabled, all logs will be printed to STDOUT only") } else { + logRotateSize, err := utils.SizeStringToBytes(*logRotate) + if err != nil { + //Default disable + logRotateSize = 0 + } l.SetRotateOption(&logger.RotateOption{ - Enabled: *logRotate != 0, - MaxSize: int64(*logRotate) * 1024, //Convert to bytes + Enabled: logRotateSize != 0, + MaxSize: int64(logRotateSize), MaxBackups: 10, Compress: *enableLogCompression, BackupDir: "", }) SystemWideLogger = l + if logRotateSize == 0 { + SystemWideLogger.Println("Log rotation is disabled") + } else { + SystemWideLogger.Println("Log rotation is enabled, max log file size " + utils.BytesToHumanReadable(int64(logRotateSize))) + } SystemWideLogger.Println("System wide logging is enabled") }