diff options
| author | Craig Jennings <c@cjennings.net> | 2024-04-07 13:41:34 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2024-04-07 13:41:34 -0500 |
| commit | 754bbf7a25a8dda49b5d08ef0d0443bbf5af0e36 (patch) | |
| tree | f1190704f78f04a2b0b4c977d20fe96a828377f1 /devdocs/go/log%2Fslog%2Findex.html | |
new repository
Diffstat (limited to 'devdocs/go/log%2Fslog%2Findex.html')
| -rw-r--r-- | devdocs/go/log%2Fslog%2Findex.html | 931 |
1 files changed, 931 insertions, 0 deletions
diff --git a/devdocs/go/log%2Fslog%2Findex.html b/devdocs/go/log%2Fslog%2Findex.html new file mode 100644 index 00000000..4c81a471 --- /dev/null +++ b/devdocs/go/log%2Fslog%2Findex.html @@ -0,0 +1,931 @@ +<h1> Package slog </h1> <ul id="short-nav"> +<li><code>import "log/slog"</code></li> +<li><a href="#pkg-overview" class="overviewLink">Overview</a></li> +<li><a href="#pkg-index" class="indexLink">Index</a></li> +<li><a href="#pkg-examples" class="examplesLink">Examples</a></li> +<li><a href="#pkg-subdirectories">Subdirectories</a></li> +</ul> <h2 id="pkg-overview">Overview </h2> <p>Package slog provides structured logging, in which log records include a message, a severity level, and various other attributes expressed as key-value pairs. </p> +<p>It defines a type, <a href="#Logger">Logger</a>, which provides several methods (such as <a href="#Logger.Info">Logger.Info</a> and <a href="#Logger.Error">Logger.Error</a>) for reporting events of interest. </p> +<p>Each Logger is associated with a <a href="#Handler">Handler</a>. A Logger output method creates a <a href="#Record">Record</a> from the method arguments and passes it to the Handler, which decides how to handle it. There is a default Logger accessible through top-level functions (such as <a href="#Info">Info</a> and <a href="#Error">Error</a>) that call the corresponding Logger methods. </p> +<p>A log record consists of a time, a level, a message, and a set of key-value pairs, where the keys are strings and the values may be of any type. As an example, </p> +<pre data-language="go">slog.Info("hello", "count", 3) +</pre> <p>creates a record containing the time of the call, a level of Info, the message "hello", and a single pair with key "count" and value 3. </p> +<p>The <a href="#Info">Info</a> top-level function calls the <a href="#Logger.Info">Logger.Info</a> method on the default Logger. In addition to <a href="#Logger.Info">Logger.Info</a>, there are methods for Debug, Warn and Error levels. Besides these convenience methods for common levels, there is also a <a href="#Logger.Log">Logger.Log</a> method which takes the level as an argument. Each of these methods has a corresponding top-level function that uses the default logger. </p> +<p>The default handler formats the log record's message, time, level, and attributes as a string and passes it to the <span>log</span> package. </p> +<pre data-language="go">2022/11/08 15:28:26 INFO hello count=3 +</pre> <p>For more control over the output format, create a logger with a different handler. This statement uses <a href="#New">New</a> to create a new logger with a <a href="#TextHandler">TextHandler</a> that writes structured records in text form to standard error: </p> +<pre data-language="go">logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) +</pre> <p><a href="#TextHandler">TextHandler</a> output is a sequence of key=value pairs, easily and unambiguously parsed by machine. This statement: </p> +<pre data-language="go">logger.Info("hello", "count", 3) +</pre> <p>produces this output: </p> +<pre data-language="go">time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3 +</pre> <p>The package also provides <a href="#JSONHandler">JSONHandler</a>, whose output is line-delimited JSON: </p> +<pre data-language="go">logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) +logger.Info("hello", "count", 3) +</pre> <p>produces this output: </p> +<pre data-language="go">{"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3} +</pre> <p>Both <a href="#TextHandler">TextHandler</a> and <a href="#JSONHandler">JSONHandler</a> can be configured with <a href="#HandlerOptions">HandlerOptions</a>. There are options for setting the minimum level (see Levels, below), displaying the source file and line of the log call, and modifying attributes before they are logged. </p> +<p>Setting a logger as the default with </p> +<pre data-language="go">slog.SetDefault(logger) +</pre> <p>will cause the top-level functions like <a href="#Info">Info</a> to use it. <a href="#SetDefault">SetDefault</a> also updates the default logger used by the <span>log</span> package, so that existing applications that use <span>log.Printf</span> and related functions will send log records to the logger's handler without needing to be rewritten. </p> +<p>Some attributes are common to many log calls. For example, you may wish to include the URL or trace identifier of a server request with all log events arising from the request. Rather than repeat the attribute with every log call, you can use <a href="#Logger.With">Logger.With</a> to construct a new Logger containing the attributes: </p> +<pre data-language="go">logger2 := logger.With("url", r.URL) +</pre> <p>The arguments to With are the same key-value pairs used in <a href="#Logger.Info">Logger.Info</a>. The result is a new Logger with the same handler as the original, but additional attributes that will appear in the output of every call. </p> +<h3 id="hdr-Levels">Levels</h3> <p>A <a href="#Level">Level</a> is an integer representing the importance or severity of a log event. The higher the level, the more severe the event. This package defines constants for the most common levels, but any int can be used as a level. </p> +<p>In an application, you may wish to log messages only at a certain level or greater. One common configuration is to log messages at Info or higher levels, suppressing debug logging until it is needed. The built-in handlers can be configured with the minimum level to output by setting [HandlerOptions.Level]. The program's `main` function typically does this. The default value is LevelInfo. </p> +<p>Setting the [HandlerOptions.Level] field to a <a href="#Level">Level</a> value fixes the handler's minimum level throughout its lifetime. Setting it to a <a href="#LevelVar">LevelVar</a> allows the level to be varied dynamically. A LevelVar holds a Level and is safe to read or write from multiple goroutines. To vary the level dynamically for an entire program, first initialize a global LevelVar: </p> +<pre data-language="go">var programLevel = new(slog.LevelVar) // Info by default +</pre> <p>Then use the LevelVar to construct a handler, and make it the default: </p> +<pre data-language="go">h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}) +slog.SetDefault(slog.New(h)) +</pre> <p>Now the program can change its logging level with a single statement: </p> +<pre data-language="go">programLevel.Set(slog.LevelDebug) +</pre> <h3 id="hdr-Groups">Groups</h3> <p>Attributes can be collected into groups. A group has a name that is used to qualify the names of its attributes. How this qualification is displayed depends on the handler. <a href="#TextHandler">TextHandler</a> separates the group and attribute names with a dot. <a href="#JSONHandler">JSONHandler</a> treats each group as a separate JSON object, with the group name as the key. </p> +<p>Use <a href="#Group">Group</a> to create a Group attribute from a name and a list of key-value pairs: </p> +<pre data-language="go">slog.Group("request", + "method", r.Method, + "url", r.URL) +</pre> <p>TextHandler would display this group as </p> +<pre data-language="go">request.method=GET request.url=http://example.com +</pre> <p>JSONHandler would display it as </p> +<pre data-language="go">"request":{"method":"GET","url":"http://example.com"} +</pre> <p>Use <a href="#Logger.WithGroup">Logger.WithGroup</a> to qualify all of a Logger's output with a group name. Calling WithGroup on a Logger results in a new Logger with the same Handler as the original, but with all its attributes qualified by the group name. </p> +<p>This can help prevent duplicate attribute keys in large systems, where subsystems might use the same keys. Pass each subsystem a different Logger with its own group name so that potential duplicates are qualified: </p> +<pre data-language="go">logger := slog.Default().With("id", systemID) +parserLogger := logger.WithGroup("parser") +parseInput(input, parserLogger) +</pre> <p>When parseInput logs with parserLogger, its keys will be qualified with "parser", so even if it uses the common key "id", the log line will have distinct keys. </p> +<h3 id="hdr-Contexts">Contexts</h3> <p>Some handlers may wish to include information from the <span>context.Context</span> that is available at the call site. One example of such information is the identifier for the current span when tracing is enabled. </p> +<p>The <a href="#Logger.Log">Logger.Log</a> and <a href="#Logger.LogAttrs">Logger.LogAttrs</a> methods take a context as a first argument, as do their corresponding top-level functions. </p> +<p>Although the convenience methods on Logger (Info and so on) and the corresponding top-level functions do not take a context, the alternatives ending in "Context" do. For example, </p> +<pre data-language="go">slog.InfoContext(ctx, "message") +</pre> <p>It is recommended to pass a context to an output method if one is available. </p> +<h3 id="hdr-Attrs_and_Values">Attrs and Values</h3> <p>An <a href="#Attr">Attr</a> is a key-value pair. The Logger output methods accept Attrs as well as alternating keys and values. The statement </p> +<pre data-language="go">slog.Info("hello", slog.Int("count", 3)) +</pre> <p>behaves the same as </p> +<pre data-language="go">slog.Info("hello", "count", 3) +</pre> <p>There are convenience constructors for <a href="#Attr">Attr</a> such as <a href="#Int">Int</a>, <a href="#String">String</a>, and <a href="#Bool">Bool</a> for common types, as well as the function <a href="#Any">Any</a> for constructing Attrs of any type. </p> +<p>The value part of an Attr is a type called <a href="#Value">Value</a>. Like an [any], a Value can hold any Go value, but it can represent typical values, including all numbers and strings, without an allocation. </p> +<p>For the most efficient log output, use <a href="#Logger.LogAttrs">Logger.LogAttrs</a>. It is similar to <a href="#Logger.Log">Logger.Log</a> but accepts only Attrs, not alternating keys and values; this allows it, too, to avoid allocation. </p> +<p>The call </p> +<pre data-language="go">logger.LogAttrs(ctx, slog.LevelInfo, "hello", slog.Int("count", 3)) +</pre> <p>is the most efficient way to achieve the same output as </p> +<pre data-language="go">slog.InfoContext(ctx, "hello", "count", 3) +</pre> <h3 id="hdr-Customizing_a_type_s_logging_behavior">Customizing a type's logging behavior</h3> <p>If a type implements the <a href="#LogValuer">LogValuer</a> interface, the <a href="#Value">Value</a> returned from its LogValue method is used for logging. You can use this to control how values of the type appear in logs. For example, you can redact secret information like passwords, or gather a struct's fields in a Group. See the examples under <a href="#LogValuer">LogValuer</a> for details. </p> +<p>A LogValue method may return a Value that itself implements <a href="#LogValuer">LogValuer</a>. The <a href="#Value.Resolve">Value.Resolve</a> method handles these cases carefully, avoiding infinite loops and unbounded recursion. Handler authors and others may wish to use <a href="#Value.Resolve">Value.Resolve</a> instead of calling LogValue directly. </p> +<h3 id="hdr-Wrapping_output_methods">Wrapping output methods</h3> <p>The logger functions use reflection over the call stack to find the file name and line number of the logging call within the application. This can produce incorrect source information for functions that wrap slog. For instance, if you define this function in file mylog.go: </p> +<pre data-language="go">func Infof(logger *slog.Logger, format string, args ...any) { + logger.Info(fmt.Sprintf(format, args...)) +} +</pre> <p>and you call it like this in main.go: </p> +<pre data-language="go">Infof(slog.Default(), "hello, %s", "world") +</pre> <p>then slog will report the source file as mylog.go, not main.go. </p> +<p>A correct implementation of Infof will obtain the source location (pc) and pass it to NewRecord. The Infof function in the package-level example called "wrapping" demonstrates how to do this. </p> +<h3 id="hdr-Working_with_Records">Working with Records</h3> <p>Sometimes a Handler will need to modify a Record before passing it on to another Handler or backend. A Record contains a mixture of simple public fields (e.g. Time, Level, Message) and hidden fields that refer to state (such as attributes) indirectly. This means that modifying a simple copy of a Record (e.g. by calling <a href="#Record.Add">Record.Add</a> or <a href="#Record.AddAttrs">Record.AddAttrs</a> to add attributes) may have unexpected effects on the original. Before modifying a Record, use <a href="#Record.Clone">Record.Clone</a> to create a copy that shares no state with the original, or create a new Record with <a href="#NewRecord">NewRecord</a> and build up its Attrs by traversing the old ones with <a href="#Record.Attrs">Record.Attrs</a>. </p> +<h3 id="hdr-Performance_considerations">Performance considerations</h3> <p>If profiling your application demonstrates that logging is taking significant time, the following suggestions may help. </p> +<p>If many log lines have a common attribute, use <a href="#Logger.With">Logger.With</a> to create a Logger with that attribute. The built-in handlers will format that attribute only once, at the call to <a href="#Logger.With">Logger.With</a>. The <a href="#Handler">Handler</a> interface is designed to allow that optimization, and a well-written Handler should take advantage of it. </p> +<p>The arguments to a log call are always evaluated, even if the log event is discarded. If possible, defer computation so that it happens only if the value is actually logged. For example, consider the call </p> +<pre data-language="go">slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily +</pre> <p>The URL.String method will be called even if the logger discards Info-level events. Instead, pass the URL directly: </p> +<pre data-language="go">slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed +</pre> <p>The built-in <a href="#TextHandler">TextHandler</a> will call its String method, but only if the log event is enabled. Avoiding the call to String also preserves the structure of the underlying value. For example <a href="#JSONHandler">JSONHandler</a> emits the components of the parsed URL as a JSON object. If you want to avoid eagerly paying the cost of the String call without causing the handler to potentially inspect the structure of the value, wrap the value in a fmt.Stringer implementation that hides its Marshal methods. </p> +<p>You can also use the <a href="#LogValuer">LogValuer</a> interface to avoid unnecessary work in disabled log calls. Say you need to log some expensive value: </p> +<pre data-language="go">slog.Debug("frobbing", "value", computeExpensiveValue(arg)) +</pre> <p>Even if this line is disabled, computeExpensiveValue will be called. To avoid that, define a type implementing LogValuer: </p> +<pre data-language="go">type expensive struct { arg int } + +func (e expensive) LogValue() slog.Value { + return slog.AnyValue(computeExpensiveValue(e.arg)) +} +</pre> <p>Then use a value of that type in log calls: </p> +<pre data-language="go">slog.Debug("frobbing", "value", expensive{arg}) +</pre> <p>Now computeExpensiveValue will only be called when the line is enabled. </p> +<p>The built-in handlers acquire a lock before calling <span>io.Writer.Write</span> to ensure that each record is written in one piece. User-defined handlers are responsible for their own locking. </p> +<h3 id="hdr-Writing_a_handler">Writing a handler</h3> <p>For a guide to writing a custom handler, see <a href="https://golang.org/s/slog-handler-guide">https://golang.org/s/slog-handler-guide</a>. </p> <h4 id="example__wrapping"> <span class="text">Example (Wrapping)</span> +</h4> <p>Code:</p> <pre class="code" data-language="go">package slog_test + +import ( + "context" + "fmt" + "log/slog" + "os" + "path/filepath" + "runtime" + "time" +) + +// Infof is an example of a user-defined logging function that wraps slog. +// The log record contains the source position of the caller of Infof. +func Infof(logger *slog.Logger, format string, args ...any) { + if !logger.Enabled(context.Background(), slog.LevelInfo) { + return + } + var pcs [1]uintptr + runtime.Callers(2, pcs[:]) // skip [Callers, Infof] + r := slog.NewRecord(time.Now(), slog.LevelInfo, fmt.Sprintf(format, args...), pcs[0]) + _ = logger.Handler().Handle(context.Background(), r) +} + +func Example_wrapping() { + replace := func(groups []string, a slog.Attr) slog.Attr { + // Remove time. + if a.Key == slog.TimeKey && len(groups) == 0 { + return slog.Attr{} + } + // Remove the directory from the source's filename. + if a.Key == slog.SourceKey { + source := a.Value.Any().(*slog.Source) + source.File = filepath.Base(source.File) + } + return a + } + logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{AddSource: true, ReplaceAttr: replace})) + Infof(logger, "message, %s", "formatted") + + // Output: + // level=INFO source=example_wrap_test.go:43 msg="message, formatted" +} +</pre> <h2 id="pkg-index">Index </h2> <ul id="manual-nav"> +<li><a href="#pkg-constants">Constants</a></li> +<li><a href="#Debug">func Debug(msg string, args ...any)</a></li> +<li><a href="#DebugContext">func DebugContext(ctx context.Context, msg string, args ...any)</a></li> +<li><a href="#Error">func Error(msg string, args ...any)</a></li> +<li><a href="#ErrorContext">func ErrorContext(ctx context.Context, msg string, args ...any)</a></li> +<li><a href="#Info">func Info(msg string, args ...any)</a></li> +<li><a href="#InfoContext">func InfoContext(ctx context.Context, msg string, args ...any)</a></li> +<li><a href="#Log">func Log(ctx context.Context, level Level, msg string, args ...any)</a></li> +<li><a href="#LogAttrs">func LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr)</a></li> +<li><a href="#NewLogLogger">func NewLogLogger(h Handler, level Level) *log.Logger</a></li> +<li><a href="#SetDefault">func SetDefault(l *Logger)</a></li> +<li><a href="#Warn">func Warn(msg string, args ...any)</a></li> +<li><a href="#WarnContext">func WarnContext(ctx context.Context, msg string, args ...any)</a></li> +<li><a href="#Attr">type Attr</a></li> +<li> <a href="#Any">func Any(key string, value any) Attr</a> +</li> +<li> <a href="#Bool">func Bool(key string, v bool) Attr</a> +</li> +<li> <a href="#Duration">func Duration(key string, v time.Duration) Attr</a> +</li> +<li> <a href="#Float64">func Float64(key string, v float64) Attr</a> +</li> +<li> <a href="#Group">func Group(key string, args ...any) Attr</a> +</li> +<li> <a href="#Int">func Int(key string, value int) Attr</a> +</li> +<li> <a href="#Int64">func Int64(key string, value int64) Attr</a> +</li> +<li> <a href="#String">func String(key, value string) Attr</a> +</li> +<li> <a href="#Time">func Time(key string, v time.Time) Attr</a> +</li> +<li> <a href="#Uint64">func Uint64(key string, v uint64) Attr</a> +</li> +<li> <a href="#Attr.Equal">func (a Attr) Equal(b Attr) bool</a> +</li> +<li> <a href="#Attr.String">func (a Attr) String() string</a> +</li> +<li><a href="#Handler">type Handler</a></li> +<li><a href="#HandlerOptions">type HandlerOptions</a></li> +<li><a href="#JSONHandler">type JSONHandler</a></li> +<li> <a href="#NewJSONHandler">func NewJSONHandler(w io.Writer, opts *HandlerOptions) *JSONHandler</a> +</li> +<li> <a href="#JSONHandler.Enabled">func (h *JSONHandler) Enabled(_ context.Context, level Level) bool</a> +</li> +<li> <a href="#JSONHandler.Handle">func (h *JSONHandler) Handle(_ context.Context, r Record) error</a> +</li> +<li> <a href="#JSONHandler.WithAttrs">func (h *JSONHandler) WithAttrs(attrs []Attr) Handler</a> +</li> +<li> <a href="#JSONHandler.WithGroup">func (h *JSONHandler) WithGroup(name string) Handler</a> +</li> +<li><a href="#Kind">type Kind</a></li> +<li> <a href="#Kind.String">func (k Kind) String() string</a> +</li> +<li><a href="#Level">type Level</a></li> +<li> <a href="#SetLogLoggerLevel">func SetLogLoggerLevel(level Level) (oldLevel Level)</a> +</li> +<li> <a href="#Level.Level">func (l Level) Level() Level</a> +</li> +<li> <a href="#Level.MarshalJSON">func (l Level) MarshalJSON() ([]byte, error)</a> +</li> +<li> <a href="#Level.MarshalText">func (l Level) MarshalText() ([]byte, error)</a> +</li> +<li> <a href="#Level.String">func (l Level) String() string</a> +</li> +<li> <a href="#Level.UnmarshalJSON">func (l *Level) UnmarshalJSON(data []byte) error</a> +</li> +<li> <a href="#Level.UnmarshalText">func (l *Level) UnmarshalText(data []byte) error</a> +</li> +<li><a href="#LevelVar">type LevelVar</a></li> +<li> <a href="#LevelVar.Level">func (v *LevelVar) Level() Level</a> +</li> +<li> <a href="#LevelVar.MarshalText">func (v *LevelVar) MarshalText() ([]byte, error)</a> +</li> +<li> <a href="#LevelVar.Set">func (v *LevelVar) Set(l Level)</a> +</li> +<li> <a href="#LevelVar.String">func (v *LevelVar) String() string</a> +</li> +<li> <a href="#LevelVar.UnmarshalText">func (v *LevelVar) UnmarshalText(data []byte) error</a> +</li> +<li><a href="#Leveler">type Leveler</a></li> +<li><a href="#LogValuer">type LogValuer</a></li> +<li><a href="#Logger">type Logger</a></li> +<li> <a href="#Default">func Default() *Logger</a> +</li> +<li> <a href="#New">func New(h Handler) *Logger</a> +</li> +<li> <a href="#With">func With(args ...any) *Logger</a> +</li> +<li> <a href="#Logger.Debug">func (l *Logger) Debug(msg string, args ...any)</a> +</li> +<li> <a href="#Logger.DebugContext">func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any)</a> +</li> +<li> <a href="#Logger.Enabled">func (l *Logger) Enabled(ctx context.Context, level Level) bool</a> +</li> +<li> <a href="#Logger.Error">func (l *Logger) Error(msg string, args ...any)</a> +</li> +<li> <a href="#Logger.ErrorContext">func (l *Logger) ErrorContext(ctx context.Context, msg string, args ...any)</a> +</li> +<li> <a href="#Logger.Handler">func (l *Logger) Handler() Handler</a> +</li> +<li> <a href="#Logger.Info">func (l *Logger) Info(msg string, args ...any)</a> +</li> +<li> <a href="#Logger.InfoContext">func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any)</a> +</li> +<li> <a href="#Logger.Log">func (l *Logger) Log(ctx context.Context, level Level, msg string, args ...any)</a> +</li> +<li> <a href="#Logger.LogAttrs">func (l *Logger) LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr)</a> +</li> +<li> <a href="#Logger.Warn">func (l *Logger) Warn(msg string, args ...any)</a> +</li> +<li> <a href="#Logger.WarnContext">func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any)</a> +</li> +<li> <a href="#Logger.With">func (l *Logger) With(args ...any) *Logger</a> +</li> +<li> <a href="#Logger.WithGroup">func (l *Logger) WithGroup(name string) *Logger</a> +</li> +<li><a href="#Record">type Record</a></li> +<li> <a href="#NewRecord">func NewRecord(t time.Time, level Level, msg string, pc uintptr) Record</a> +</li> +<li> <a href="#Record.Add">func (r *Record) Add(args ...any)</a> +</li> +<li> <a href="#Record.AddAttrs">func (r *Record) AddAttrs(attrs ...Attr)</a> +</li> +<li> <a href="#Record.Attrs">func (r Record) Attrs(f func(Attr) bool)</a> +</li> +<li> <a href="#Record.Clone">func (r Record) Clone() Record</a> +</li> +<li> <a href="#Record.NumAttrs">func (r Record) NumAttrs() int</a> +</li> +<li><a href="#Source">type Source</a></li> +<li><a href="#TextHandler">type TextHandler</a></li> +<li> <a href="#NewTextHandler">func NewTextHandler(w io.Writer, opts *HandlerOptions) *TextHandler</a> +</li> +<li> <a href="#TextHandler.Enabled">func (h *TextHandler) Enabled(_ context.Context, level Level) bool</a> +</li> +<li> <a href="#TextHandler.Handle">func (h *TextHandler) Handle(_ context.Context, r Record) error</a> +</li> +<li> <a href="#TextHandler.WithAttrs">func (h *TextHandler) WithAttrs(attrs []Attr) Handler</a> +</li> +<li> <a href="#TextHandler.WithGroup">func (h *TextHandler) WithGroup(name string) Handler</a> +</li> +<li><a href="#Value">type Value</a></li> +<li> <a href="#AnyValue">func AnyValue(v any) Value</a> +</li> +<li> <a href="#BoolValue">func BoolValue(v bool) Value</a> +</li> +<li> <a href="#DurationValue">func DurationValue(v time.Duration) Value</a> +</li> +<li> <a href="#Float64Value">func Float64Value(v float64) Value</a> +</li> +<li> <a href="#GroupValue">func GroupValue(as ...Attr) Value</a> +</li> +<li> <a href="#Int64Value">func Int64Value(v int64) Value</a> +</li> +<li> <a href="#IntValue">func IntValue(v int) Value</a> +</li> +<li> <a href="#StringValue">func StringValue(value string) Value</a> +</li> +<li> <a href="#TimeValue">func TimeValue(v time.Time) Value</a> +</li> +<li> <a href="#Uint64Value">func Uint64Value(v uint64) Value</a> +</li> +<li> <a href="#Value.Any">func (v Value) Any() any</a> +</li> +<li> <a href="#Value.Bool">func (v Value) Bool() bool</a> +</li> +<li> <a href="#Value.Duration">func (v Value) Duration() time.Duration</a> +</li> +<li> <a href="#Value.Equal">func (v Value) Equal(w Value) bool</a> +</li> +<li> <a href="#Value.Float64">func (v Value) Float64() float64</a> +</li> +<li> <a href="#Value.Group">func (v Value) Group() []Attr</a> +</li> +<li> <a href="#Value.Int64">func (v Value) Int64() int64</a> +</li> +<li> <a href="#Value.Kind">func (v Value) Kind() Kind</a> +</li> +<li> <a href="#Value.LogValuer">func (v Value) LogValuer() LogValuer</a> +</li> +<li> <a href="#Value.Resolve">func (v Value) Resolve() (rv Value)</a> +</li> +<li> <a href="#Value.String">func (v Value) String() string</a> +</li> +<li> <a href="#Value.Time">func (v Value) Time() time.Time</a> +</li> +<li> <a href="#Value.Uint64">func (v Value) Uint64() uint64</a> +</li> +</ul> <div id="pkg-examples"> <h3>Examples</h3> <dl> <dd><a class="exampleLink" href="#example_Group">Group</a></dd> <dd><a class="exampleLink" href="#example_HandlerOptions_customLevels">HandlerOptions (CustomLevels)</a></dd> <dd><a class="exampleLink" href="#example_Handler_levelHandler">Handler (LevelHandler)</a></dd> <dd><a class="exampleLink" href="#example_LogValuer_group">LogValuer (Group)</a></dd> <dd><a class="exampleLink" href="#example_LogValuer_secret">LogValuer (Secret)</a></dd> <dd><a class="exampleLink" href="#example_SetLogLoggerLevel_log">SetLogLoggerLevel (Log)</a></dd> <dd><a class="exampleLink" href="#example_SetLogLoggerLevel_slog">SetLogLoggerLevel (Slog)</a></dd> <dd><a class="exampleLink" href="#example__wrapping">Package (Wrapping)</a></dd> </dl> </div> <h3>Package files</h3> <p> <span>attr.go</span> <span>doc.go</span> <span>handler.go</span> <span>json_handler.go</span> <span>level.go</span> <span>logger.go</span> <span>record.go</span> <span>text_handler.go</span> <span>value.go</span> </p> <h2 id="pkg-constants">Constants</h2> <p>Keys for "built-in" attributes. </p> +<pre data-language="go">const ( + // TimeKey is the key used by the built-in handlers for the time + // when the log method is called. The associated Value is a [time.Time]. + TimeKey = "time" + // LevelKey is the key used by the built-in handlers for the level + // of the log call. The associated value is a [Level]. + LevelKey = "level" + // MessageKey is the key used by the built-in handlers for the + // message of the log call. The associated value is a string. + MessageKey = "msg" + // SourceKey is the key used by the built-in handlers for the source file + // and line of the log call. The associated value is a *[Source]. + SourceKey = "source" +)</pre> <h2 id="Debug">func <span>Debug</span> <span title="Added in Go 1.21">1.21</span> </h2> <pre data-language="go">func Debug(msg string, args ...any)</pre> <p>Debug calls <a href="#Logger.Debug">Logger.Debug</a> on the default logger. </p> +<h2 id="DebugContext">func <span>DebugContext</span> <span title="Added in Go 1.21">1.21</span> </h2> <pre data-language="go">func DebugContext(ctx context.Context, msg string, args ...any)</pre> <p>DebugContext calls <a href="#Logger.DebugContext">Logger.DebugContext</a> on the default logger. </p> +<h2 id="Error">func <span>Error</span> <span title="Added in Go 1.21">1.21</span> </h2> <pre data-language="go">func Error(msg string, args ...any)</pre> <p>Error calls <a href="#Logger.Error">Logger.Error</a> on the default logger. </p> +<h2 id="ErrorContext">func <span>ErrorContext</span> <span title="Added in Go 1.21">1.21</span> </h2> <pre data-language="go">func ErrorContext(ctx context.Context, msg string, args ...any)</pre> <p>ErrorContext calls <a href="#Logger.ErrorContext">Logger.ErrorContext</a> on the default logger. </p> +<h2 id="Info">func <span>Info</span> <span title="Added in Go 1.21">1.21</span> </h2> <pre data-language="go">func Info(msg string, args ...any)</pre> <p>Info calls <a href="#Logger.Info">Logger.Info</a> on the default logger. </p> +<h2 id="InfoContext">func <span>InfoContext</span> <span title="Added in Go 1.21">1.21</span> </h2> <pre data-language="go">func InfoContext(ctx context.Context, msg string, args ...any)</pre> <p>InfoContext calls <a href="#Logger.InfoContext">Logger.InfoContext</a> on the default logger. </p> +<h2 id="Log">func <span>Log</span> <span title="Added in Go 1.21">1.21</span> </h2> <pre data-language="go">func Log(ctx context.Context, level Level, msg string, args ...any)</pre> <p>Log calls <a href="#Logger.Log">Logger.Log</a> on the default logger. </p> +<h2 id="LogAttrs">func <span>LogAttrs</span> <span title="Added in Go 1.21">1.21</span> </h2> <pre data-language="go">func LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr)</pre> <p>LogAttrs calls <a href="#Logger.LogAttrs">Logger.LogAttrs</a> on the default logger. </p> +<h2 id="NewLogLogger">func <span>NewLogLogger</span> <span title="Added in Go 1.21">1.21</span> </h2> <pre data-language="go">func NewLogLogger(h Handler, level Level) *log.Logger</pre> <p>NewLogLogger returns a new <span>log.Logger</span> such that each call to its Output method dispatches a Record to the specified handler. The logger acts as a bridge from the older log API to newer structured logging handlers. </p> +<h2 id="SetDefault">func <span>SetDefault</span> <span title="Added in Go 1.21">1.21</span> </h2> <pre data-language="go">func SetDefault(l *Logger)</pre> <p>SetDefault makes l the default <a href="#Logger">Logger</a>, which is used by the top-level functions <a href="#Info">Info</a>, <a href="#Debug">Debug</a> and so on. After this call, output from the log package's default Logger (as with <span>log.Print</span>, etc.) will be logged using l's Handler, at a level controlled by <a href="#SetLogLoggerLevel">SetLogLoggerLevel</a>. </p> +<h2 id="Warn">func <span>Warn</span> <span title="Added in Go 1.21">1.21</span> </h2> <pre data-language="go">func Warn(msg string, args ...any)</pre> <p>Warn calls <a href="#Logger.Warn">Logger.Warn</a> on the default logger. </p> +<h2 id="WarnContext">func <span>WarnContext</span> <span title="Added in Go 1.21">1.21</span> </h2> <pre data-language="go">func WarnContext(ctx context.Context, msg string, args ...any)</pre> <p>WarnContext calls <a href="#Logger.WarnContext">Logger.WarnContext</a> on the default logger. </p> +<h2 id="Attr">type <span>Attr</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>An Attr is a key-value pair. </p> +<pre data-language="go">type Attr struct { + Key string + Value Value +} +</pre> <h3 id="Any">func <span>Any</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Any(key string, value any) Attr</pre> <p>Any returns an Attr for the supplied value. See <a href="#AnyValue">AnyValue</a> for how values are treated. </p> +<h3 id="Bool">func <span>Bool</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Bool(key string, v bool) Attr</pre> <p>Bool returns an Attr for a bool. </p> +<h3 id="Duration">func <span>Duration</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Duration(key string, v time.Duration) Attr</pre> <p>Duration returns an Attr for a <span>time.Duration</span>. </p> +<h3 id="Float64">func <span>Float64</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Float64(key string, v float64) Attr</pre> <p>Float64 returns an Attr for a floating-point number. </p> +<h3 id="Group">func <span>Group</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Group(key string, args ...any) Attr</pre> <p>Group returns an Attr for a Group <a href="#Value">Value</a>. The first argument is the key; the remaining arguments are converted to Attrs as in <a href="#Logger.Log">Logger.Log</a>. </p> +<p>Use Group to collect several key-value pairs under a single key on a log line, or as the result of LogValue in order to log a single value as multiple Attrs. </p> <h4 id="example_Group"> <span class="text">Example</span> +</h4> <p>Code:</p> <pre class="code" data-language="go">r, _ := http.NewRequest("GET", "localhost", nil) +// ... + +logger := slog.New( + slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ + ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { + if a.Key == slog.TimeKey && len(groups) == 0 { + return slog.Attr{} + } + return a + }, + }), +) +logger.Info("finished", + slog.Group("req", + slog.String("method", r.Method), + slog.String("url", r.URL.String())), + slog.Int("status", http.StatusOK), + slog.Duration("duration", time.Second)) + +</pre> <p>Output:</p> <pre class="output" data-language="go">level=INFO msg=finished req.method=GET req.url=localhost status=200 duration=1s +</pre> <h3 id="Int">func <span>Int</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Int(key string, value int) Attr</pre> <p>Int converts an int to an int64 and returns an Attr with that value. </p> +<h3 id="Int64">func <span>Int64</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Int64(key string, value int64) Attr</pre> <p>Int64 returns an Attr for an int64. </p> +<h3 id="String">func <span>String</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func String(key, value string) Attr</pre> <p>String returns an Attr for a string value. </p> +<h3 id="Time">func <span>Time</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Time(key string, v time.Time) Attr</pre> <p>Time returns an Attr for a <span>time.Time</span>. It discards the monotonic portion. </p> +<h3 id="Uint64">func <span>Uint64</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Uint64(key string, v uint64) Attr</pre> <p>Uint64 returns an Attr for a uint64. </p> +<h3 id="Attr.Equal">func (Attr) <span>Equal</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (a Attr) Equal(b Attr) bool</pre> <p>Equal reports whether a and b have equal keys and values. </p> +<h3 id="Attr.String">func (Attr) <span>String</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (a Attr) String() string</pre> <h2 id="Handler">type <span>Handler</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>A Handler handles log records produced by a Logger. </p> +<p>A typical handler may print log records to standard error, or write them to a file or database, or perhaps augment them with additional attributes and pass them on to another handler. </p> +<p>Any of the Handler's methods may be called concurrently with itself or with other methods. It is the responsibility of the Handler to manage this concurrency. </p> +<p>Users of the slog package should not invoke Handler methods directly. They should use the methods of <a href="#Logger">Logger</a> instead. </p> +<pre data-language="go">type Handler interface { + // Enabled reports whether the handler handles records at the given level. + // The handler ignores records whose level is lower. + // It is called early, before any arguments are processed, + // to save effort if the log event should be discarded. + // If called from a Logger method, the first argument is the context + // passed to that method, or context.Background() if nil was passed + // or the method does not take a context. + // The context is passed so Enabled can use its values + // to make a decision. + Enabled(context.Context, Level) bool + + // Handle handles the Record. + // It will only be called when Enabled returns true. + // The Context argument is as for Enabled. + // It is present solely to provide Handlers access to the context's values. + // Canceling the context should not affect record processing. + // (Among other things, log messages may be necessary to debug a + // cancellation-related problem.) + // + // Handle methods that produce output should observe the following rules: + // - If r.Time is the zero time, ignore the time. + // - If r.PC is zero, ignore it. + // - Attr's values should be resolved. + // - If an Attr's key and value are both the zero value, ignore the Attr. + // This can be tested with attr.Equal(Attr{}). + // - If a group's key is empty, inline the group's Attrs. + // - If a group has no Attrs (even if it has a non-empty key), + // ignore it. + Handle(context.Context, Record) error + + // WithAttrs returns a new Handler whose attributes consist of + // both the receiver's attributes and the arguments. + // The Handler owns the slice: it may retain, modify or discard it. + WithAttrs(attrs []Attr) Handler + + // WithGroup returns a new Handler with the given group appended to + // the receiver's existing groups. + // The keys of all subsequent attributes, whether added by With or in a + // Record, should be qualified by the sequence of group names. + // + // How this qualification happens is up to the Handler, so long as + // this Handler's attribute keys differ from those of another Handler + // with a different sequence of group names. + // + // A Handler should treat WithGroup as starting a Group of Attrs that ends + // at the end of the log event. That is, + // + // logger.WithGroup("s").LogAttrs(ctx, level, msg, slog.Int("a", 1), slog.Int("b", 2)) + // + // should behave like + // + // logger.LogAttrs(ctx, level, msg, slog.Group("s", slog.Int("a", 1), slog.Int("b", 2))) + // + // If the name is empty, WithGroup returns the receiver. + WithGroup(name string) Handler +}</pre> <h4 id="example_Handler_levelHandler"> <span class="text">Example (LevelHandler)</span> +</h4> <p>This example shows how to Use a LevelHandler to change the level of an existing Handler while preserving its other behavior. This example demonstrates increasing the log level to reduce a logger's output. Another typical use would be to decrease the log level (to LevelDebug, say) during a part of the program that was suspected of containing a bug. </p> <p>Code:</p> <pre class="code" data-language="go">package slog_test + +import ( + "context" + "log/slog" + "log/slog/internal/slogtest" + "os" +) + +// A LevelHandler wraps a Handler with an Enabled method +// that returns false for levels below a minimum. +type LevelHandler struct { + level slog.Leveler + handler slog.Handler +} + +// NewLevelHandler returns a LevelHandler with the given level. +// All methods except Enabled delegate to h. +func NewLevelHandler(level slog.Leveler, h slog.Handler) *LevelHandler { + // Optimization: avoid chains of LevelHandlers. + if lh, ok := h.(*LevelHandler); ok { + h = lh.Handler() + } + return &LevelHandler{level, h} +} + +// Enabled implements Handler.Enabled by reporting whether +// level is at least as large as h's level. +func (h *LevelHandler) Enabled(_ context.Context, level slog.Level) bool { + return level >= h.level.Level() +} + +// Handle implements Handler.Handle. +func (h *LevelHandler) Handle(ctx context.Context, r slog.Record) error { + return h.handler.Handle(ctx, r) +} + +// WithAttrs implements Handler.WithAttrs. +func (h *LevelHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + return NewLevelHandler(h.level, h.handler.WithAttrs(attrs)) +} + +// WithGroup implements Handler.WithGroup. +func (h *LevelHandler) WithGroup(name string) slog.Handler { + return NewLevelHandler(h.level, h.handler.WithGroup(name)) +} + +// Handler returns the Handler wrapped by h. +func (h *LevelHandler) Handler() slog.Handler { + return h.handler +} + +// This example shows how to Use a LevelHandler to change the level of an +// existing Handler while preserving its other behavior. +// +// This example demonstrates increasing the log level to reduce a logger's +// output. +// +// Another typical use would be to decrease the log level (to LevelDebug, say) +// during a part of the program that was suspected of containing a bug. +func ExampleHandler_levelHandler() { + th := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ReplaceAttr: slogtest.RemoveTime}) + logger := slog.New(NewLevelHandler(slog.LevelWarn, th)) + logger.Info("not printed") + logger.Warn("printed") + + // Output: + // level=WARN msg=printed +} +</pre> <h2 id="HandlerOptions">type <span>HandlerOptions</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>HandlerOptions are options for a <a href="#TextHandler">TextHandler</a> or <a href="#JSONHandler">JSONHandler</a>. A zero HandlerOptions consists entirely of default values. </p> +<pre data-language="go">type HandlerOptions struct { + // AddSource causes the handler to compute the source code position + // of the log statement and add a SourceKey attribute to the output. + AddSource bool + + // Level reports the minimum record level that will be logged. + // The handler discards records with lower levels. + // If Level is nil, the handler assumes LevelInfo. + // The handler calls Level.Level for each record processed; + // to adjust the minimum level dynamically, use a LevelVar. + Level Leveler + + // ReplaceAttr is called to rewrite each non-group attribute before it is logged. + // The attribute's value has been resolved (see [Value.Resolve]). + // If ReplaceAttr returns a zero Attr, the attribute is discarded. + // + // The built-in attributes with keys "time", "level", "source", and "msg" + // are passed to this function, except that time is omitted + // if zero, and source is omitted if AddSource is false. + // + // The first argument is a list of currently open groups that contain the + // Attr. It must not be retained or modified. ReplaceAttr is never called + // for Group attributes, only their contents. For example, the attribute + // list + // + // Int("a", 1), Group("g", Int("b", 2)), Int("c", 3) + // + // results in consecutive calls to ReplaceAttr with the following arguments: + // + // nil, Int("a", 1) + // []string{"g"}, Int("b", 2) + // nil, Int("c", 3) + // + // ReplaceAttr can be used to change the default keys of the built-in + // attributes, convert types (for example, to replace a `time.Time` with the + // integer seconds since the Unix epoch), sanitize personal information, or + // remove attributes from the output. + ReplaceAttr func(groups []string, a Attr) Attr +} +</pre> <h4 id="example_HandlerOptions_customLevels"> <span class="text">Example (CustomLevels)</span> +</h4> <p>This example demonstrates using custom log levels and custom log level names. In addition to the default log levels, it introduces Trace, Notice, and Emergency levels. The ReplaceAttr changes the way levels are printed for both the standard log levels and the custom log levels. </p> <p>Code:</p> <pre class="code" data-language="go">// Exported constants from a custom logging package. +const ( + LevelTrace = slog.Level(-8) + LevelDebug = slog.LevelDebug + LevelInfo = slog.LevelInfo + LevelNotice = slog.Level(2) + LevelWarning = slog.LevelWarn + LevelError = slog.LevelError + LevelEmergency = slog.Level(12) +) + +th := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ + // Set a custom level to show all log output. The default value is + // LevelInfo, which would drop Debug and Trace logs. + Level: LevelTrace, + + ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { + // Remove time from the output for predictable test output. + if a.Key == slog.TimeKey { + return slog.Attr{} + } + + // Customize the name of the level key and the output string, including + // custom level values. + if a.Key == slog.LevelKey { + // Rename the level key from "level" to "sev". + a.Key = "sev" + + // Handle custom level values. + level := a.Value.Any().(slog.Level) + + // This could also look up the name from a map or other structure, but + // this demonstrates using a switch statement to rename levels. For + // maximum performance, the string values should be constants, but this + // example uses the raw strings for readability. + switch { + case level < LevelDebug: + a.Value = slog.StringValue("TRACE") + case level < LevelInfo: + a.Value = slog.StringValue("DEBUG") + case level < LevelNotice: + a.Value = slog.StringValue("INFO") + case level < LevelWarning: + a.Value = slog.StringValue("NOTICE") + case level < LevelError: + a.Value = slog.StringValue("WARNING") + case level < LevelEmergency: + a.Value = slog.StringValue("ERROR") + default: + a.Value = slog.StringValue("EMERGENCY") + } + } + + return a + }, +}) + +logger := slog.New(th) +ctx := context.Background() +logger.Log(ctx, LevelEmergency, "missing pilots") +logger.Error("failed to start engines", "err", "missing fuel") +logger.Warn("falling back to default value") +logger.Log(ctx, LevelNotice, "all systems are running") +logger.Info("initiating launch") +logger.Debug("starting background job") +logger.Log(ctx, LevelTrace, "button clicked") + +</pre> <p>Output:</p> <pre class="output" data-language="go">sev=EMERGENCY msg="missing pilots" +sev=ERROR msg="failed to start engines" err="missing fuel" +sev=WARNING msg="falling back to default value" +sev=NOTICE msg="all systems are running" +sev=INFO msg="initiating launch" +sev=DEBUG msg="starting background job" +sev=TRACE msg="button clicked" +</pre> <h2 id="JSONHandler">type <span>JSONHandler</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>JSONHandler is a <a href="#Handler">Handler</a> that writes Records to an <span>io.Writer</span> as line-delimited JSON objects. </p> +<pre data-language="go">type JSONHandler struct { + // contains filtered or unexported fields +} +</pre> <h3 id="NewJSONHandler">func <span>NewJSONHandler</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func NewJSONHandler(w io.Writer, opts *HandlerOptions) *JSONHandler</pre> <p>NewJSONHandler creates a <a href="#JSONHandler">JSONHandler</a> that writes to w, using the given options. If opts is nil, the default options are used. </p> +<h3 id="JSONHandler.Enabled">func (*JSONHandler) <span>Enabled</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (h *JSONHandler) Enabled(_ context.Context, level Level) bool</pre> <p>Enabled reports whether the handler handles records at the given level. The handler ignores records whose level is lower. </p> +<h3 id="JSONHandler.Handle">func (*JSONHandler) <span>Handle</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (h *JSONHandler) Handle(_ context.Context, r Record) error</pre> <p>Handle formats its argument <a href="#Record">Record</a> as a JSON object on a single line. </p> +<p>If the Record's time is zero, the time is omitted. Otherwise, the key is "time" and the value is output as with json.Marshal. </p> +<p>If the Record's level is zero, the level is omitted. Otherwise, the key is "level" and the value of <a href="#Level.String">Level.String</a> is output. </p> +<p>If the AddSource option is set and source information is available, the key is "source", and the value is a record of type <a href="#Source">Source</a>. </p> +<p>The message's key is "msg". </p> +<p>To modify these or other attributes, or remove them from the output, use [HandlerOptions.ReplaceAttr]. </p> +<p>Values are formatted as with an <span>encoding/json.Encoder</span> with SetEscapeHTML(false), with two exceptions. </p> +<p>First, an Attr whose Value is of type error is formatted as a string, by calling its Error method. Only errors in Attrs receive this special treatment, not errors embedded in structs, slices, maps or other data structures that are processed by the <span>encoding/json</span> package. </p> +<p>Second, an encoding failure does not cause Handle to return an error. Instead, the error message is formatted as a string. </p> +<p>Each call to Handle results in a single serialized call to io.Writer.Write. </p> +<h3 id="JSONHandler.WithAttrs">func (*JSONHandler) <span>WithAttrs</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (h *JSONHandler) WithAttrs(attrs []Attr) Handler</pre> <p>WithAttrs returns a new <a href="#JSONHandler">JSONHandler</a> whose attributes consists of h's attributes followed by attrs. </p> +<h3 id="JSONHandler.WithGroup">func (*JSONHandler) <span>WithGroup</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (h *JSONHandler) WithGroup(name string) Handler</pre> <h2 id="Kind">type <span>Kind</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>Kind is the kind of a <a href="#Value">Value</a>. </p> +<pre data-language="go">type Kind int</pre> <pre data-language="go">const ( + KindAny Kind = iota + KindBool + KindDuration + KindFloat64 + KindInt64 + KindString + KindTime + KindUint64 + KindGroup + KindLogValuer +)</pre> <h3 id="Kind.String">func (Kind) <span>String</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (k Kind) String() string</pre> <h2 id="Level">type <span>Level</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>A Level is the importance or severity of a log event. The higher the level, the more important or severe the event. </p> +<pre data-language="go">type Level int</pre> <p>Names for common levels. </p> +<p>Level numbers are inherently arbitrary, but we picked them to satisfy three constraints. Any system can map them to another numbering scheme if it wishes. </p> +<p>First, we wanted the default level to be Info, Since Levels are ints, Info is the default value for int, zero. </p> +<p>Second, we wanted to make it easy to use levels to specify logger verbosity. Since a larger level means a more severe event, a logger that accepts events with smaller (or more negative) level means a more verbose logger. Logger verbosity is thus the negation of event severity, and the default verbosity of 0 accepts all events at least as severe as INFO. </p> +<p>Third, we wanted some room between levels to accommodate schemes with named levels between ours. For example, Google Cloud Logging defines a Notice level between Info and Warn. Since there are only a few of these intermediate levels, the gap between the numbers need not be large. Our gap of 4 matches OpenTelemetry's mapping. Subtracting 9 from an OpenTelemetry level in the DEBUG, INFO, WARN and ERROR ranges converts it to the corresponding slog Level range. OpenTelemetry also has the names TRACE and FATAL, which slog does not. But those OpenTelemetry levels can still be represented as slog Levels by using the appropriate integers. </p> +<pre data-language="go">const ( + LevelDebug Level = -4 + LevelInfo Level = 0 + LevelWarn Level = 4 + LevelError Level = 8 +)</pre> <h3 id="SetLogLoggerLevel">func <span>SetLogLoggerLevel</span> <span title="Added in Go 1.22">1.22</span> </h3> <pre data-language="go">func SetLogLoggerLevel(level Level) (oldLevel Level)</pre> <p>SetLogLoggerLevel controls the level for the bridge to the <span>log</span> package. </p> +<p>Before <a href="#SetDefault">SetDefault</a> is called, slog top-level logging functions call the default <span>log.Logger</span>. In that mode, SetLogLoggerLevel sets the minimum level for those calls. By default, the minimum level is Info, so calls to <a href="#Debug">Debug</a> (as well as top-level logging calls at lower levels) will not be passed to the log.Logger. After calling </p> +<pre data-language="go">slog.SetLogLoggerLevel(slog.LevelDebug) +</pre> <p>calls to <a href="#Debug">Debug</a> will be passed to the log.Logger. </p> +<p>After <a href="#SetDefault">SetDefault</a> is called, calls to the default <span>log.Logger</span> are passed to the slog default handler. In that mode, SetLogLoggerLevel sets the level at which those calls are logged. That is, after calling </p> +<pre data-language="go">slog.SetLogLoggerLevel(slog.LevelDebug) +</pre> <p>A call to <span>log.Printf</span> will result in output at level <a href="#LevelDebug">LevelDebug</a>. </p> +<p>SetLogLoggerLevel returns the previous value. </p> <h4 id="example_SetLogLoggerLevel_log"> <span class="text">Example (Log)</span> +</h4> <p>This example shows how to use slog.SetLogLoggerLevel to change the minimal level of the internal default handler for slog package before calling slog.SetDefault. </p> <p>Code:</p> <pre class="code" data-language="go">defer log.SetFlags(log.Flags()) // revert changes after the example +log.SetFlags(0) +defer log.SetOutput(log.Writer()) // revert changes after the example +log.SetOutput(os.Stdout) + +// Default logging level is slog.LevelInfo. +log.Print("log debug") // log debug +slog.Debug("debug") // no output +slog.Info("info") // INFO info + +// Set the default logging level to slog.LevelDebug. +currentLogLevel := slog.SetLogLoggerLevel(slog.LevelDebug) +defer slog.SetLogLoggerLevel(currentLogLevel) // revert changes after the example + +log.Print("log debug") // log debug +slog.Debug("debug") // DEBUG debug +slog.Info("info") // INFO info + +</pre> <p>Output:</p> <pre class="output" data-language="go">log debug +INFO info +log debug +DEBUG debug +INFO info +</pre> <h4 id="example_SetLogLoggerLevel_slog"> <span class="text">Example (Slog)</span> +</h4> <p>This example shows how to use slog.SetLogLoggerLevel to change the minimal level of the internal writer that uses the custom handler for log package after calling slog.SetDefault. </p> <p>Code:</p> <pre class="code" data-language="go">// Set the default logging level to slog.LevelError. +currentLogLevel := slog.SetLogLoggerLevel(slog.LevelError) +defer slog.SetLogLoggerLevel(currentLogLevel) // revert changes after the example + +defer slog.SetDefault(slog.Default()) // revert changes after the example +slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ReplaceAttr: slogtest.RemoveTime}))) + +log.Print("error") // level=ERROR msg=error + +</pre> <p>Output:</p> <pre class="output" data-language="go">level=ERROR msg=error +</pre> <h3 id="Level.Level">func (Level) <span>Level</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l Level) Level() Level</pre> <p>Level returns the receiver. It implements <a href="#Leveler">Leveler</a>. </p> +<h3 id="Level.MarshalJSON">func (Level) <span>MarshalJSON</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l Level) MarshalJSON() ([]byte, error)</pre> <p>MarshalJSON implements <span>encoding/json.Marshaler</span> by quoting the output of <a href="#Level.String">Level.String</a>. </p> +<h3 id="Level.MarshalText">func (Level) <span>MarshalText</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l Level) MarshalText() ([]byte, error)</pre> <p>MarshalText implements <span>encoding.TextMarshaler</span> by calling <a href="#Level.String">Level.String</a>. </p> +<h3 id="Level.String">func (Level) <span>String</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l Level) String() string</pre> <p>String returns a name for the level. If the level has a name, then that name in uppercase is returned. If the level is between named values, then an integer is appended to the uppercased name. Examples: </p> +<pre data-language="go">LevelWarn.String() => "WARN" +(LevelInfo+2).String() => "INFO+2" +</pre> <h3 id="Level.UnmarshalJSON">func (*Level) <span>UnmarshalJSON</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Level) UnmarshalJSON(data []byte) error</pre> <p>UnmarshalJSON implements <span>encoding/json.Unmarshaler</span> It accepts any string produced by <a href="#Level.MarshalJSON">Level.MarshalJSON</a>, ignoring case. It also accepts numeric offsets that would result in a different string on output. For example, "Error-8" would marshal as "INFO". </p> +<h3 id="Level.UnmarshalText">func (*Level) <span>UnmarshalText</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Level) UnmarshalText(data []byte) error</pre> <p>UnmarshalText implements <span>encoding.TextUnmarshaler</span>. It accepts any string produced by <a href="#Level.MarshalText">Level.MarshalText</a>, ignoring case. It also accepts numeric offsets that would result in a different string on output. For example, "Error-8" would marshal as "INFO". </p> +<h2 id="LevelVar">type <span>LevelVar</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>A LevelVar is a <a href="#Level">Level</a> variable, to allow a <a href="#Handler">Handler</a> level to change dynamically. It implements <a href="#Leveler">Leveler</a> as well as a Set method, and it is safe for use by multiple goroutines. The zero LevelVar corresponds to <a href="#LevelInfo">LevelInfo</a>. </p> +<pre data-language="go">type LevelVar struct { + // contains filtered or unexported fields +} +</pre> <h3 id="LevelVar.Level">func (*LevelVar) <span>Level</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v *LevelVar) Level() Level</pre> <p>Level returns v's level. </p> +<h3 id="LevelVar.MarshalText">func (*LevelVar) <span>MarshalText</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v *LevelVar) MarshalText() ([]byte, error)</pre> <p>MarshalText implements <span>encoding.TextMarshaler</span> by calling <a href="#Level.MarshalText">Level.MarshalText</a>. </p> +<h3 id="LevelVar.Set">func (*LevelVar) <span>Set</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v *LevelVar) Set(l Level)</pre> <p>Set sets v's level to l. </p> +<h3 id="LevelVar.String">func (*LevelVar) <span>String</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v *LevelVar) String() string</pre> <h3 id="LevelVar.UnmarshalText">func (*LevelVar) <span>UnmarshalText</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v *LevelVar) UnmarshalText(data []byte) error</pre> <p>UnmarshalText implements <span>encoding.TextUnmarshaler</span> by calling <a href="#Level.UnmarshalText">Level.UnmarshalText</a>. </p> +<h2 id="Leveler">type <span>Leveler</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>A Leveler provides a <a href="#Level">Level</a> value. </p> +<p>As Level itself implements Leveler, clients typically supply a Level value wherever a Leveler is needed, such as in <a href="#HandlerOptions">HandlerOptions</a>. Clients who need to vary the level dynamically can provide a more complex Leveler implementation such as *<a href="#LevelVar">LevelVar</a>. </p> +<pre data-language="go">type Leveler interface { + Level() Level +}</pre> <h2 id="LogValuer">type <span>LogValuer</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>A LogValuer is any Go value that can convert itself into a Value for logging. </p> +<p>This mechanism may be used to defer expensive operations until they are needed, or to expand a single value into a sequence of components. </p> +<pre data-language="go">type LogValuer interface { + LogValue() Value +}</pre> <h4 id="example_LogValuer_group"> <span class="text">Example (Group)</span> +</h4> <p>Code:</p> <pre class="code" data-language="go">package slog_test + +import "log/slog" + +type Name struct { + First, Last string +} + +// LogValue implements slog.LogValuer. +// It returns a group containing the fields of +// the Name, so that they appear together in the log output. +func (n Name) LogValue() slog.Value { + return slog.GroupValue( + slog.String("first", n.First), + slog.String("last", n.Last)) +} + +func ExampleLogValuer_group() { + n := Name{"Perry", "Platypus"} + slog.Info("mission accomplished", "agent", n) + + // JSON Output would look in part like: + // { + // ... + // "msg": "mission accomplished", + // "agent": { + // "first": "Perry", + // "last": "Platypus" + // } + // } +} +</pre> <h4 id="example_LogValuer_secret"> <span class="text">Example (Secret)</span> +</h4> <p>This example demonstrates a Value that replaces itself with an alternative representation to avoid revealing secrets. </p> <p>Code:</p> <pre class="code" data-language="go">package slog_test + +import ( + "log/slog" + "log/slog/internal/slogtest" + "os" +) + +// A token is a secret value that grants permissions. +type Token string + +// LogValue implements slog.LogValuer. +// It avoids revealing the token. +func (Token) LogValue() slog.Value { + return slog.StringValue("REDACTED_TOKEN") +} + +// This example demonstrates a Value that replaces itself +// with an alternative representation to avoid revealing secrets. +func ExampleLogValuer_secret() { + t := Token("shhhh!") + logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ReplaceAttr: slogtest.RemoveTime})) + logger.Info("permission granted", "user", "Perry", "token", t) + + // Output: + // level=INFO msg="permission granted" user=Perry token=REDACTED_TOKEN +} +</pre> <h2 id="Logger">type <span>Logger</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>A Logger records structured information about each call to its Log, Debug, Info, Warn, and Error methods. For each call, it creates a <a href="#Record">Record</a> and passes it to a <a href="#Handler">Handler</a>. </p> +<p>To create a new Logger, call <a href="#New">New</a> or a Logger method that begins "With". </p> +<pre data-language="go">type Logger struct { + // contains filtered or unexported fields +} +</pre> <h3 id="Default">func <span>Default</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Default() *Logger</pre> <p>Default returns the default <a href="#Logger">Logger</a>. </p> +<h3 id="New">func <span>New</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func New(h Handler) *Logger</pre> <p>New creates a new Logger with the given non-nil Handler. </p> +<h3 id="With">func <span>With</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func With(args ...any) *Logger</pre> <p>With calls <a href="#Logger.With">Logger.With</a> on the default logger. </p> +<h3 id="Logger.Debug">func (*Logger) <span>Debug</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) Debug(msg string, args ...any)</pre> <p>Debug logs at <a href="#LevelDebug">LevelDebug</a>. </p> +<h3 id="Logger.DebugContext">func (*Logger) <span>DebugContext</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any)</pre> <p>DebugContext logs at <a href="#LevelDebug">LevelDebug</a> with the given context. </p> +<h3 id="Logger.Enabled">func (*Logger) <span>Enabled</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) Enabled(ctx context.Context, level Level) bool</pre> <p>Enabled reports whether l emits log records at the given context and level. </p> +<h3 id="Logger.Error">func (*Logger) <span>Error</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) Error(msg string, args ...any)</pre> <p>Error logs at <a href="#LevelError">LevelError</a>. </p> +<h3 id="Logger.ErrorContext">func (*Logger) <span>ErrorContext</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) ErrorContext(ctx context.Context, msg string, args ...any)</pre> <p>ErrorContext logs at <a href="#LevelError">LevelError</a> with the given context. </p> +<h3 id="Logger.Handler">func (*Logger) <span>Handler</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) Handler() Handler</pre> <p>Handler returns l's Handler. </p> +<h3 id="Logger.Info">func (*Logger) <span>Info</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) Info(msg string, args ...any)</pre> <p>Info logs at <a href="#LevelInfo">LevelInfo</a>. </p> +<h3 id="Logger.InfoContext">func (*Logger) <span>InfoContext</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any)</pre> <p>InfoContext logs at <a href="#LevelInfo">LevelInfo</a> with the given context. </p> +<h3 id="Logger.Log">func (*Logger) <span>Log</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) Log(ctx context.Context, level Level, msg string, args ...any)</pre> <p>Log emits a log record with the current time and the given level and message. The Record's Attrs consist of the Logger's attributes followed by the Attrs specified by args. </p> +<p>The attribute arguments are processed as follows: </p> +<ul> <li>If an argument is an Attr, it is used as is. </li> +<li>If an argument is a string and this is not the last argument, the following argument is treated as the value and the two are combined into an Attr. </li> +<li>Otherwise, the argument is treated as a value with key "!BADKEY". </li> +</ul> <h3 id="Logger.LogAttrs">func (*Logger) <span>LogAttrs</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr)</pre> <p>LogAttrs is a more efficient version of <a href="#Logger.Log">Logger.Log</a> that accepts only Attrs. </p> +<h3 id="Logger.Warn">func (*Logger) <span>Warn</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) Warn(msg string, args ...any)</pre> <p>Warn logs at <a href="#LevelWarn">LevelWarn</a>. </p> +<h3 id="Logger.WarnContext">func (*Logger) <span>WarnContext</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any)</pre> <p>WarnContext logs at <a href="#LevelWarn">LevelWarn</a> with the given context. </p> +<h3 id="Logger.With">func (*Logger) <span>With</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) With(args ...any) *Logger</pre> <p>With returns a Logger that includes the given attributes in each output operation. Arguments are converted to attributes as if by <a href="#Logger.Log">Logger.Log</a>. </p> +<h3 id="Logger.WithGroup">func (*Logger) <span>WithGroup</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (l *Logger) WithGroup(name string) *Logger</pre> <p>WithGroup returns a Logger that starts a group, if name is non-empty. The keys of all attributes added to the Logger will be qualified by the given name. (How that qualification happens depends on the [Handler.WithGroup] method of the Logger's Handler.) </p> +<p>If name is empty, WithGroup returns the receiver. </p> +<h2 id="Record">type <span>Record</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>A Record holds information about a log event. Copies of a Record share state. Do not modify a Record after handing out a copy to it. Call <a href="#NewRecord">NewRecord</a> to create a new Record. Use <a href="#Record.Clone">Record.Clone</a> to create a copy with no shared state. </p> +<pre data-language="go">type Record struct { + // The time at which the output method (Log, Info, etc.) was called. + Time time.Time + + // The log message. + Message string + + // The level of the event. + Level Level + + // The program counter at the time the record was constructed, as determined + // by runtime.Callers. If zero, no program counter is available. + // + // The only valid use for this value is as an argument to + // [runtime.CallersFrames]. In particular, it must not be passed to + // [runtime.FuncForPC]. + PC uintptr + // contains filtered or unexported fields +} +</pre> <h3 id="NewRecord">func <span>NewRecord</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func NewRecord(t time.Time, level Level, msg string, pc uintptr) Record</pre> <p>NewRecord creates a <a href="#Record">Record</a> from the given arguments. Use <a href="#Record.AddAttrs">Record.AddAttrs</a> to add attributes to the Record. </p> +<p>NewRecord is intended for logging APIs that want to support a <a href="#Handler">Handler</a> as a backend. </p> +<h3 id="Record.Add">func (*Record) <span>Add</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (r *Record) Add(args ...any)</pre> <p>Add converts the args to Attrs as described in <a href="#Logger.Log">Logger.Log</a>, then appends the Attrs to the <a href="#Record">Record</a>'s list of Attrs. It omits empty groups. </p> +<h3 id="Record.AddAttrs">func (*Record) <span>AddAttrs</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (r *Record) AddAttrs(attrs ...Attr)</pre> <p>AddAttrs appends the given Attrs to the <a href="#Record">Record</a>'s list of Attrs. It omits empty groups. </p> +<h3 id="Record.Attrs">func (Record) <span>Attrs</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (r Record) Attrs(f func(Attr) bool)</pre> <p>Attrs calls f on each Attr in the <a href="#Record">Record</a>. Iteration stops if f returns false. </p> +<h3 id="Record.Clone">func (Record) <span>Clone</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (r Record) Clone() Record</pre> <p>Clone returns a copy of the record with no shared state. The original record and the clone can both be modified without interfering with each other. </p> +<h3 id="Record.NumAttrs">func (Record) <span>NumAttrs</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (r Record) NumAttrs() int</pre> <p>NumAttrs returns the number of attributes in the <a href="#Record">Record</a>. </p> +<h2 id="Source">type <span>Source</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>Source describes the location of a line of source code. </p> +<pre data-language="go">type Source struct { + // Function is the package path-qualified function name containing the + // source line. If non-empty, this string uniquely identifies a single + // function in the program. This may be the empty string if not known. + Function string `json:"function"` + // File and Line are the file name and line number (1-based) of the source + // line. These may be the empty string and zero, respectively, if not known. + File string `json:"file"` + Line int `json:"line"` +} +</pre> <h2 id="TextHandler">type <span>TextHandler</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>TextHandler is a <a href="#Handler">Handler</a> that writes Records to an <span>io.Writer</span> as a sequence of key=value pairs separated by spaces and followed by a newline. </p> +<pre data-language="go">type TextHandler struct { + // contains filtered or unexported fields +} +</pre> <h3 id="NewTextHandler">func <span>NewTextHandler</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func NewTextHandler(w io.Writer, opts *HandlerOptions) *TextHandler</pre> <p>NewTextHandler creates a <a href="#TextHandler">TextHandler</a> that writes to w, using the given options. If opts is nil, the default options are used. </p> +<h3 id="TextHandler.Enabled">func (*TextHandler) <span>Enabled</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (h *TextHandler) Enabled(_ context.Context, level Level) bool</pre> <p>Enabled reports whether the handler handles records at the given level. The handler ignores records whose level is lower. </p> +<h3 id="TextHandler.Handle">func (*TextHandler) <span>Handle</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (h *TextHandler) Handle(_ context.Context, r Record) error</pre> <p>Handle formats its argument <a href="#Record">Record</a> as a single line of space-separated key=value items. </p> +<p>If the Record's time is zero, the time is omitted. Otherwise, the key is "time" and the value is output in RFC3339 format with millisecond precision. </p> +<p>If the Record's level is zero, the level is omitted. Otherwise, the key is "level" and the value of <a href="#Level.String">Level.String</a> is output. </p> +<p>If the AddSource option is set and source information is available, the key is "source" and the value is output as FILE:LINE. </p> +<p>The message's key is "msg". </p> +<p>To modify these or other attributes, or remove them from the output, use [HandlerOptions.ReplaceAttr]. </p> +<p>If a value implements <span>encoding.TextMarshaler</span>, the result of MarshalText is written. Otherwise, the result of <span>fmt.Sprint</span> is written. </p> +<p>Keys and values are quoted with <span>strconv.Quote</span> if they contain Unicode space characters, non-printing characters, '"' or '='. </p> +<p>Keys inside groups consist of components (keys or group names) separated by dots. No further escaping is performed. Thus there is no way to determine from the key "a.b.c" whether there are two groups "a" and "b" and a key "c", or a single group "a.b" and a key "c", or single group "a" and a key "b.c". If it is necessary to reconstruct the group structure of a key even in the presence of dots inside components, use [HandlerOptions.ReplaceAttr] to encode that information in the key. </p> +<p>Each call to Handle results in a single serialized call to io.Writer.Write. </p> +<h3 id="TextHandler.WithAttrs">func (*TextHandler) <span>WithAttrs</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (h *TextHandler) WithAttrs(attrs []Attr) Handler</pre> <p>WithAttrs returns a new <a href="#TextHandler">TextHandler</a> whose attributes consists of h's attributes followed by attrs. </p> +<h3 id="TextHandler.WithGroup">func (*TextHandler) <span>WithGroup</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (h *TextHandler) WithGroup(name string) Handler</pre> <h2 id="Value">type <span>Value</span> <span title="Added in Go 1.21">1.21</span> </h2> <p>A Value can represent any Go value, but unlike type any, it can represent most small values without an allocation. The zero Value corresponds to nil. </p> +<pre data-language="go">type Value struct { + // contains filtered or unexported fields +} +</pre> <h3 id="AnyValue">func <span>AnyValue</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func AnyValue(v any) Value</pre> <p>AnyValue returns a <a href="#Value">Value</a> for the supplied value. </p> +<p>If the supplied value is of type Value, it is returned unmodified. </p> +<p>Given a value of one of Go's predeclared string, bool, or (non-complex) numeric types, AnyValue returns a Value of kind <a href="#KindString">KindString</a>, <a href="#KindBool">KindBool</a>, <a href="#KindUint64">KindUint64</a>, <a href="#KindInt64">KindInt64</a>, or <a href="#KindFloat64">KindFloat64</a>. The width of the original numeric type is not preserved. </p> +<p>Given a <span>time.Time</span> or <span>time.Duration</span> value, AnyValue returns a Value of kind <a href="#KindTime">KindTime</a> or <a href="#KindDuration">KindDuration</a>. The monotonic time is not preserved. </p> +<p>For nil, or values of all other types, including named types whose underlying type is numeric, AnyValue returns a value of kind <a href="#KindAny">KindAny</a>. </p> +<h3 id="BoolValue">func <span>BoolValue</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func BoolValue(v bool) Value</pre> <p>BoolValue returns a <a href="#Value">Value</a> for a bool. </p> +<h3 id="DurationValue">func <span>DurationValue</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func DurationValue(v time.Duration) Value</pre> <p>DurationValue returns a <a href="#Value">Value</a> for a <span>time.Duration</span>. </p> +<h3 id="Float64Value">func <span>Float64Value</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Float64Value(v float64) Value</pre> <p>Float64Value returns a <a href="#Value">Value</a> for a floating-point number. </p> +<h3 id="GroupValue">func <span>GroupValue</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func GroupValue(as ...Attr) Value</pre> <p>GroupValue returns a new <a href="#Value">Value</a> for a list of Attrs. The caller must not subsequently mutate the argument slice. </p> +<h3 id="Int64Value">func <span>Int64Value</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Int64Value(v int64) Value</pre> <p>Int64Value returns a <a href="#Value">Value</a> for an int64. </p> +<h3 id="IntValue">func <span>IntValue</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func IntValue(v int) Value</pre> <p>IntValue returns a <a href="#Value">Value</a> for an int. </p> +<h3 id="StringValue">func <span>StringValue</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func StringValue(value string) Value</pre> <p>StringValue returns a new <a href="#Value">Value</a> for a string. </p> +<h3 id="TimeValue">func <span>TimeValue</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func TimeValue(v time.Time) Value</pre> <p>TimeValue returns a <a href="#Value">Value</a> for a <span>time.Time</span>. It discards the monotonic portion. </p> +<h3 id="Uint64Value">func <span>Uint64Value</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func Uint64Value(v uint64) Value</pre> <p>Uint64Value returns a <a href="#Value">Value</a> for a uint64. </p> +<h3 id="Value.Any">func (Value) <span>Any</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) Any() any</pre> <p>Any returns v's value as an any. </p> +<h3 id="Value.Bool">func (Value) <span>Bool</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) Bool() bool</pre> <p>Bool returns v's value as a bool. It panics if v is not a bool. </p> +<h3 id="Value.Duration">func (Value) <span>Duration</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) Duration() time.Duration</pre> <p>Duration returns v's value as a <span>time.Duration</span>. It panics if v is not a time.Duration. </p> +<h3 id="Value.Equal">func (Value) <span>Equal</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) Equal(w Value) bool</pre> <p>Equal reports whether v and w represent the same Go value. </p> +<h3 id="Value.Float64">func (Value) <span>Float64</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) Float64() float64</pre> <p>Float64 returns v's value as a float64. It panics if v is not a float64. </p> +<h3 id="Value.Group">func (Value) <span>Group</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) Group() []Attr</pre> <p>Group returns v's value as a []Attr. It panics if v's <a href="#Kind">Kind</a> is not <a href="#KindGroup">KindGroup</a>. </p> +<h3 id="Value.Int64">func (Value) <span>Int64</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) Int64() int64</pre> <p>Int64 returns v's value as an int64. It panics if v is not a signed integer. </p> +<h3 id="Value.Kind">func (Value) <span>Kind</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) Kind() Kind</pre> <p>Kind returns v's Kind. </p> +<h3 id="Value.LogValuer">func (Value) <span>LogValuer</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) LogValuer() LogValuer</pre> <p>LogValuer returns v's value as a LogValuer. It panics if v is not a LogValuer. </p> +<h3 id="Value.Resolve">func (Value) <span>Resolve</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) Resolve() (rv Value)</pre> <p>Resolve repeatedly calls LogValue on v while it implements <a href="#LogValuer">LogValuer</a>, and returns the result. If v resolves to a group, the group's attributes' values are not recursively resolved. If the number of LogValue calls exceeds a threshold, a Value containing an error is returned. Resolve's return value is guaranteed not to be of Kind <a href="#KindLogValuer">KindLogValuer</a>. </p> +<h3 id="Value.String">func (Value) <span>String</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) String() string</pre> <p>String returns Value's value as a string, formatted like <span>fmt.Sprint</span>. Unlike the methods Int64, Float64, and so on, which panic if v is of the wrong kind, String never panics. </p> +<h3 id="Value.Time">func (Value) <span>Time</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) Time() time.Time</pre> <p>Time returns v's value as a <span>time.Time</span>. It panics if v is not a time.Time. </p> +<h3 id="Value.Uint64">func (Value) <span>Uint64</span> <span title="Added in Go 1.21">1.21</span> </h3> <pre data-language="go">func (v Value) Uint64() uint64</pre> <p>Uint64 returns v's value as a uint64. It panics if v is not an unsigned integer. </p> +<h2 id="pkg-subdirectories">Subdirectories</h2> <div class="pkg-dir"> <table> <tr> <th class="pkg-name">Name</th> <th class="pkg-synopsis">Synopsis</th> </tr> <tr> <td colspan="2"><a href="../index">..</a></td> </tr> </table> </div><div class="_attribution"> + <p class="_attribution-p"> + © Google, Inc.<br>Licensed under the Creative Commons Attribution License 3.0.<br> + <a href="http://golang.org/pkg/log/slog/" class="_attribution-link">http://golang.org/pkg/log/slog/</a> + </p> +</div> |
