From 04528f7d818c27459a7a0d280777e10aab4e230e Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Fri, 5 Jul 2024 02:53:36 -0400 Subject: [PATCH] v3: Updates to fiberlog benchmarks and documentation (#3059) * Add missing benchmarks for fiberlog. Rewrite docs * Update log.md --- docs/api/log.md | 55 ++++++++----- log/default_test.go | 2 +- log/fiberlog_test.go | 144 +++++++++++++++++++++++++++++++++++ middleware/cors/cors_test.go | 24 +++--- 4 files changed, 195 insertions(+), 30 deletions(-) diff --git a/docs/api/log.md b/docs/api/log.md index e53d6d4b0a..9289967d66 100644 --- a/docs/api/log.md +++ b/docs/api/log.md @@ -5,11 +5,9 @@ description: Fiber's built-in log package sidebar_position: 6 --- -We can use logs to observe program behavior, diagnose problems, or configure corresponding alarms. -And defining a well structured log can improve search efficiency and facilitate handling of problems. +Logs serve as an essential tool for observing program behavior, diagnosing issues, and setting up corresponding alerts. Well-structured logs can significantly enhance search efficiency and streamline the troubleshooting process. -Fiber provides a default way to print logs in the standard output. -It also provides several global functions, such as `log.Info`, `log.Errorf`, `log.Warnw`, etc. +Fiber offers a default mechanism for logging to standard output. Additionally, it provides several global functions, including `log.Info`, `log.Errorf`, `log.Warnw`, among others, to facilitate comprehensive logging capabilities. ## Log levels @@ -44,8 +42,10 @@ type AllLogger interface { ``` ## Print log -Note: The method of calling the Fatal level will interrupt the program running after printing the log, please use it with caution. -Directly print logs of different levels, which will be entered into messageKey, the default is msg. +Note: The Fatal level method will terminate the program after printing the log message. Please use it with caution. + +### Basic Logging +Logs of different levels can be directly printed. These will be entered into `messageKey`, with the default key being `msg`. ```go log.Info("Hello, World!") @@ -56,7 +56,9 @@ log.Error("Houston, we have a problem.") log.Fatal("So Long, and Thanks for All the Fislog.") log.Panic("The system is down.") ``` -Format and print logs of different levels, all methods end with f + +### Formatted Logging +Logs of different levels can be formatted before printing. All such methods end with an `f`. ```go log.Debugf("Hello %s", "boy") @@ -66,7 +68,8 @@ log.Errorf("%s, we have a problem.", "Master Shifu") log.Fatalf("So Long, and Thanks for All the %s.", "banana") ``` -Print a message with the key and value, or `KEYVALS UNPAIRED` if the key and value are not a pair. +### Key-Value Logging +Print a message with key-value pairs. If the key and value are not paired correctly, the log will output `KEYVALS UNPAIRED`. ```go log.Debugw("", "Hello", "boy") @@ -77,7 +80,7 @@ log.Fatalw("", "fruit", "banana") ``` ## Global log -If you are in a project and just want to use a simple log function that can be printed at any time in the global, we provide a global log. +For projects that require a simple, global logging function to print messages at any time, Fiber provides a global log. ```go import "github.com/gofiber/fiber/v3/log" @@ -86,8 +89,11 @@ log.Info("info") log.Warn("warn") ``` -The above is using the default `log.DefaultLogger` standard output. -You can also find an already implemented adaptation under contrib, or use your own implemented Logger and use `log.SetLogger` to set the global log logger. +These global log functions allow you to log messages conveniently throughout your project. + +The above example uses the default `log.DefaultLogger` for standard output. You can also find various pre-implemented adapters under the [contrib](https://github.com/gofiber/contrib) package such as `fiberzap` and `fiberzerolog`, or you can implement your own logger and set it as the global logger using `log.SetLogger`.This flexibility allows you to tailor the logging behavior to suit your project's needs. + +Here's an example using a custom logger: ```go import ( @@ -107,8 +113,7 @@ fiberlog.SetLogger(customLogger) ``` ## Set Level -`log.SetLevel` sets the level of logs below which logs will not be output. -The default logger is LevelTrace. +`log.SetLevel` sets the minimum level of logs that will be output. The default log level is `LevelTrace`. Note that this method is not **concurrent-safe**. @@ -117,9 +122,14 @@ import "github.com/gofiber/fiber/v3/log" log.SetLevel(log.LevelInfo) ``` + +Setting the log level allows you to control the verbosity of the logs, filtering out messages below the specified level. + ## Set output -`log.SetOutput` sets the output destination of the logger. The default logger types the log in the console. +`log.SetOutput` sets the output destination of the logger. By default, the logger outputs logs to the console. + +### Writing logs to stderr ```go var logger AllLogger = &defaultLogger{ @@ -128,7 +138,11 @@ var logger AllLogger = &defaultLogger{ } ``` -Set the output destination to the file. +This allows you to customize where the logs are written, such as to a file, an external logging service, or any other desired destination. + +### Writing logs to a file + +Set the output destination to the file, in this case `test.log`: ```go // Output to ./test.log file @@ -138,7 +152,10 @@ if err != nil { } log.SetOutput(f) ``` -Set the output destination to the console and file. + +### Writing logs to both console and file + +The following example will write the logs to both `test.log` and `stdout`: ```go // Output to ./test.log file @@ -146,10 +163,14 @@ file, _ := os.OpenFile("test.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) iw := io.MultiWriter(os.Stdout, file) log.SetOutput(iw) ``` + ## Bind context -Set the context, using the following method will return a `CommonLogger` instance bound to the specified context + +To bind a logger to a specific context, use the following method. This will return a `CommonLogger` instance that is bound to the specified context. + ```go commonLogger := log.WithContext(ctx) commonLogger.Info("info") ``` +Binding the logger to a context allows you to include context-specific information in your logs, improving traceability and debugging. diff --git a/log/default_test.go b/log/default_test.go index 0f57d2009f..2d2e4f8fa3 100644 --- a/log/default_test.go +++ b/log/default_test.go @@ -365,7 +365,7 @@ func Benchmark_LogfKeyAndValues(b *testing.B) { } } -func Benchmark_LogfKeyAndValuesParallel(b *testing.B) { +func Benchmark_LogfKeyAndValues_Parallel(b *testing.B) { tests := []struct { name string level Level diff --git a/log/fiberlog_test.go b/log/fiberlog_test.go index 315afe7290..a6fbd193c8 100644 --- a/log/fiberlog_test.go +++ b/log/fiberlog_test.go @@ -69,3 +69,147 @@ func Test_Fiberlog_SetLevel(t *testing.T) { }) } } + +func Benchmark_DefaultSystemLogger(b *testing.B) { + b.ResetTimer() + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _ = DefaultLogger() + } +} + +func Benchmark_SetLogger(b *testing.B) { + setLog := &defaultLogger{ + stdlog: log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), + depth: 6, + } + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + SetLogger(setLog) + } +} + +func Benchmark_Fiberlog_SetLevel(b *testing.B) { + mockLogger := &defaultLogger{} + SetLogger(mockLogger) + + // Test cases + testCases := []struct { + name string + level Level + expected Level + }{ + { + name: "Test case 1", + level: LevelDebug, + expected: LevelDebug, + }, + { + name: "Test case 2", + level: LevelInfo, + expected: LevelInfo, + }, + { + name: "Test case 3", + level: LevelWarn, + expected: LevelWarn, + }, + { + name: "Test case 4", + level: LevelError, + expected: LevelError, + }, + { + name: "Test case 5", + level: LevelFatal, + expected: LevelFatal, + }, + } + + for _, tc := range testCases { + b.ReportAllocs() + b.ResetTimer() + b.Run(tc.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + SetLevel(tc.level) + } + }) + } +} + +func Benchmark_DefaultSystemLogger_Parallel(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + _ = DefaultLogger() + } + }) +} + +func Benchmark_SetLogger_Parallel(b *testing.B) { + setLog := &defaultLogger{ + stdlog: log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), + depth: 6, + } + + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + SetLogger(setLog) + } + }) +} + +func Benchmark_Fiberlog_SetLevel_Parallel(b *testing.B) { + mockLogger := &defaultLogger{} + SetLogger(mockLogger) + + // Test cases + testCases := []struct { + name string + level Level + expected Level + }{ + { + name: "Test case 1", + level: LevelDebug, + expected: LevelDebug, + }, + { + name: "Test case 2", + level: LevelInfo, + expected: LevelInfo, + }, + { + name: "Test case 3", + level: LevelWarn, + expected: LevelWarn, + }, + { + name: "Test case 4", + level: LevelError, + expected: LevelError, + }, + { + name: "Test case 5", + level: LevelFatal, + expected: LevelFatal, + }, + } + + for _, tc := range testCases { + b.Run(tc.name+"_Parallel", func(bb *testing.B) { + bb.ReportAllocs() + bb.ResetTimer() + bb.RunParallel(func(pb *testing.PB) { + for pb.Next() { + SetLevel(tc.level) + } + }) + }) + } +} diff --git a/middleware/cors/cors_test.go b/middleware/cors/cors_test.go index fc542e948a..d95c0f5313 100644 --- a/middleware/cors/cors_test.go +++ b/middleware/cors/cors_test.go @@ -1060,8 +1060,8 @@ func Benchmark_CORS_NewHandler(b *testing.B) { } } -// go test -v -run=^$ -bench=Benchmark_CORS_NewHandlerParallel -benchmem -count=4 -func Benchmark_CORS_NewHandlerParallel(b *testing.B) { +// go test -v -run=^$ -bench=Benchmark_CORS_NewHandler_Parallel -benchmem -count=4 +func Benchmark_CORS_NewHandler_Parallel(b *testing.B) { app := fiber.New() c := New(Config{ AllowOrigins: []string{"http://localhost", "http://example.com"}, @@ -1133,8 +1133,8 @@ func Benchmark_CORS_NewHandlerSingleOrigin(b *testing.B) { } } -// go test -v -run=^$ -bench=Benchmark_CORS_NewHandlerSingleOriginParallel -benchmem -count=4 -func Benchmark_CORS_NewHandlerSingleOriginParallel(b *testing.B) { +// go test -v -run=^$ -bench=Benchmark_CORS_NewHandlerSingleOrigin_Parallel -benchmem -count=4 +func Benchmark_CORS_NewHandlerSingleOrigin_Parallel(b *testing.B) { app := fiber.New() c := New(Config{ AllowOrigins: []string{"http://example.com"}, @@ -1205,8 +1205,8 @@ func Benchmark_CORS_NewHandlerWildcard(b *testing.B) { } } -// go test -v -run=^$ -bench=Benchmark_CORS_NewHandlerWildcardParallel -benchmem -count=4 -func Benchmark_CORS_NewHandlerWildcardParallel(b *testing.B) { +// go test -v -run=^$ -bench=Benchmark_CORS_NewHandlerWildcard_Parallel -benchmem -count=4 +func Benchmark_CORS_NewHandlerWildcard_Parallel(b *testing.B) { app := fiber.New() c := New(Config{ AllowMethods: []string{fiber.MethodGet, fiber.MethodPost, fiber.MethodPut, fiber.MethodDelete}, @@ -1279,8 +1279,8 @@ func Benchmark_CORS_NewHandlerPreflight(b *testing.B) { } } -// go test -v -run=^$ -bench=Benchmark_CORS_NewHandlerPreflightParallel -benchmem -count=4 -func Benchmark_CORS_NewHandlerPreflightParallel(b *testing.B) { +// go test -v -run=^$ -bench=Benchmark_CORS_NewHandlerPreflight_Parallel -benchmem -count=4 +func Benchmark_CORS_NewHandlerPreflight_Parallel(b *testing.B) { app := fiber.New() c := New(Config{ AllowOrigins: []string{"http://localhost", "http://example.com"}, @@ -1354,8 +1354,8 @@ func Benchmark_CORS_NewHandlerPreflightSingleOrigin(b *testing.B) { } } -// go test -v -run=^$ -bench=Benchmark_CORS_NewHandlerPreflightSingleOriginParallel -benchmem -count=4 -func Benchmark_CORS_NewHandlerPreflightSingleOriginParallel(b *testing.B) { +// go test -v -run=^$ -bench=Benchmark_CORS_NewHandlerPreflightSingleOrigin_Parallel -benchmem -count=4 +func Benchmark_CORS_NewHandlerPreflightSingleOrigin_Parallel(b *testing.B) { app := fiber.New() c := New(Config{ AllowOrigins: []string{"http://example.com"}, @@ -1428,8 +1428,8 @@ func Benchmark_CORS_NewHandlerPreflightWildcard(b *testing.B) { } } -// go test -v -run=^$ -bench=Benchmark_CORS_NewHandlerPreflightWildcardParallel -benchmem -count=4 -func Benchmark_CORS_NewHandlerPreflightWildcardParallel(b *testing.B) { +// go test -v -run=^$ -bench=Benchmark_CORS_NewHandlerPreflightWildcard_Parallel -benchmem -count=4 +func Benchmark_CORS_NewHandlerPreflightWildcard_Parallel(b *testing.B) { app := fiber.New() c := New(Config{ AllowMethods: []string{fiber.MethodGet, fiber.MethodPost, fiber.MethodPut, fiber.MethodDelete},