Source file src/log/slog/example_custom_levels_test.go

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package slog_test
     6  
     7  import (
     8  	"context"
     9  	"log/slog"
    10  	"os"
    11  )
    12  
    13  // This example demonstrates using custom log levels and custom log level names.
    14  // In addition to the default log levels, it introduces Trace, Notice, and
    15  // Emergency levels. The ReplaceAttr changes the way levels are printed for both
    16  // the standard log levels and the custom log levels.
    17  func ExampleHandlerOptions_customLevels() {
    18  	// Exported constants from a custom logging package.
    19  	const (
    20  		LevelTrace     = slog.Level(-8)
    21  		LevelDebug     = slog.LevelDebug
    22  		LevelInfo      = slog.LevelInfo
    23  		LevelNotice    = slog.Level(2)
    24  		LevelWarning   = slog.LevelWarn
    25  		LevelError     = slog.LevelError
    26  		LevelEmergency = slog.Level(12)
    27  	)
    28  
    29  	th := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
    30  		// Set a custom level to show all log output. The default value is
    31  		// LevelInfo, which would drop Debug and Trace logs.
    32  		Level: LevelTrace,
    33  
    34  		ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
    35  			// Remove time from the output for predictable test output.
    36  			if a.Key == slog.TimeKey {
    37  				return slog.Attr{}
    38  			}
    39  
    40  			// Customize the name of the level key and the output string, including
    41  			// custom level values.
    42  			if a.Key == slog.LevelKey {
    43  				// Rename the level key from "level" to "sev".
    44  				a.Key = "sev"
    45  
    46  				// Handle custom level values.
    47  				level := a.Value.Any().(slog.Level)
    48  
    49  				// This could also look up the name from a map or other structure, but
    50  				// this demonstrates using a switch statement to rename levels. For
    51  				// maximum performance, the string values should be constants, but this
    52  				// example uses the raw strings for readability.
    53  				switch {
    54  				case level < LevelDebug:
    55  					a.Value = slog.StringValue("TRACE")
    56  				case level < LevelInfo:
    57  					a.Value = slog.StringValue("DEBUG")
    58  				case level < LevelNotice:
    59  					a.Value = slog.StringValue("INFO")
    60  				case level < LevelWarning:
    61  					a.Value = slog.StringValue("NOTICE")
    62  				case level < LevelError:
    63  					a.Value = slog.StringValue("WARNING")
    64  				case level < LevelEmergency:
    65  					a.Value = slog.StringValue("ERROR")
    66  				default:
    67  					a.Value = slog.StringValue("EMERGENCY")
    68  				}
    69  			}
    70  
    71  			return a
    72  		},
    73  	})
    74  
    75  	logger := slog.New(th)
    76  	ctx := context.Background()
    77  	logger.Log(ctx, LevelEmergency, "missing pilots")
    78  	logger.Error("failed to start engines", "err", "missing fuel")
    79  	logger.Warn("falling back to default value")
    80  	logger.Log(ctx, LevelNotice, "all systems are running")
    81  	logger.Info("initiating launch")
    82  	logger.Debug("starting background job")
    83  	logger.Log(ctx, LevelTrace, "button clicked")
    84  
    85  	// Output:
    86  	// sev=EMERGENCY msg="missing pilots"
    87  	// sev=ERROR msg="failed to start engines" err="missing fuel"
    88  	// sev=WARNING msg="falling back to default value"
    89  	// sev=NOTICE msg="all systems are running"
    90  	// sev=INFO msg="initiating launch"
    91  	// sev=DEBUG msg="starting background job"
    92  	// sev=TRACE msg="button clicked"
    93  }
    94  

View as plain text