github.com/searKing/golang/go@v1.2.117/log/slog/glog_handler.go (about)

     1  // Copyright 2023 The searKing Author. 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
     6  
     7  import (
     8  	"context"
     9  	"io"
    10  	"log/slog"
    11  	"sync"
    12  )
    13  
    14  var _ slog.Handler = (*GlogHandler)(nil)
    15  
    16  type GlogHandler struct {
    17  	*commonHandler
    18  }
    19  
    20  // NewGlogHandler creates a GlogHandler that writes to w,
    21  // using the given options.
    22  // If opts is nil, the default options are used.
    23  // # LOG LINE PREFIX FORMAT
    24  //
    25  // Log lines have this form:
    26  //
    27  //	Lyyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg...
    28  //
    29  // where the fields are defined as follows:
    30  //
    31  //	L                A single character, representing the log level
    32  //	                 (eg 'I' for INFO)
    33  //	yyyy             The year
    34  //	mm               The month (zero padded; ie May is '05')
    35  //	dd               The day (zero padded)
    36  //	hh:mm:ss.uuuuuu  Time in hours, minutes and fractional seconds
    37  //	threadid         The space-padded thread ID as returned by GetTID()
    38  //	                 (this matches the PID on Linux)
    39  //	file             The file name
    40  //	line             The line number
    41  //	msg              The user-supplied message
    42  //
    43  // Example:
    44  //
    45  //	I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog
    46  //	I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395
    47  func NewGlogHandler(w io.Writer, opts *slog.HandlerOptions) *GlogHandler {
    48  	if opts == nil {
    49  		opts = &slog.HandlerOptions{
    50  			AddSource: true,
    51  		}
    52  	}
    53  	return &GlogHandler{
    54  		&commonHandler{
    55  			ReplaceLevelString: func(l slog.Level) string {
    56  				switch {
    57  				case l < slog.LevelInfo:
    58  					return "D"
    59  				case l < slog.LevelWarn:
    60  					return "I"
    61  				case l < slog.LevelError:
    62  					return "W"
    63  				default:
    64  					return "E"
    65  				}
    66  			},
    67  			opts:           *opts,
    68  			AttrSep:        ", ",
    69  			DisableQuote:   true,
    70  			SourcePrettier: ShortSource,
    71  			sharedVar:      &sharedVar{once: &sync.Once{}},
    72  			mu:             &sync.Mutex{},
    73  			w:              w,
    74  		},
    75  	}
    76  }
    77  
    78  // NewGlogHumanHandler creates a human-readable GlogHandler that writes to w,
    79  // using the given options.
    80  // If opts is nil, the default options are used.
    81  // # LOG LINE PREFIX FORMAT
    82  //
    83  // Log lines have this form:
    84  //
    85  //	[LLLLL] [yyyymmdd hh:mm:ss.uuuuuu] [threadid] [file:line(func)] msg...
    86  //
    87  // where the fields are defined as follows:
    88  //
    89  //	LLLLL            Five characters, representing the log level
    90  //	                 (eg 'INFO ' for INFO)
    91  //	yyyy             The year
    92  //	mm               The month (zero padded; ie May is '05')
    93  //	dd               The day (zero padded)
    94  //	hh:mm:ss.uuuuuu  Time in hours, minutes and fractional seconds
    95  //	threadid         The space-padded thread ID as returned by GetTID()
    96  //	                 (this matches the PID on Linux)
    97  //	file             The file name
    98  //	line             The line number
    99  //	func             The func name
   100  //	msg              The user-supplied message
   101  //
   102  // Example:
   103  //
   104  //	[INFO ] [20081103 11:57:31.739339] [24395] [google.cc:2341](main) Command line: ./some_prog
   105  //	[INFO ] [20081103 11:57:31.739403] [24395] [google.cc:2342](main) Process id 24395
   106  func NewGlogHumanHandler(w io.Writer, opts *slog.HandlerOptions) *GlogHandler {
   107  	if opts == nil {
   108  		opts = &slog.HandlerOptions{
   109  			AddSource: true,
   110  		}
   111  	}
   112  	return &GlogHandler{
   113  		&commonHandler{
   114  			opts:           *opts,
   115  			AttrSep:        ", ",
   116  			DisableQuote:   true,
   117  			PadLevelText:   true,
   118  			HumanReadable:  true,
   119  			SourcePrettier: ShortSource,
   120  			WithFuncName:   true,
   121  			sharedVar:      &sharedVar{once: &sync.Once{}},
   122  			mu:             &sync.Mutex{},
   123  			w:              w,
   124  		},
   125  	}
   126  }
   127  
   128  // Enabled reports whether the handler handles records at the given level.
   129  // The handler ignores records whose level is lower.
   130  func (h *GlogHandler) Enabled(_ context.Context, level slog.Level) bool {
   131  	return h.commonHandler.enabled(level)
   132  }
   133  
   134  // WithAttrs returns a new GlogHandler whose attributes consists
   135  // of h's attributes followed by attrs.
   136  func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
   137  	return &GlogHandler{commonHandler: h.commonHandler.withAttrs(attrs)}
   138  }
   139  
   140  func (h *GlogHandler) WithGroup(name string) slog.Handler {
   141  	return &GlogHandler{commonHandler: h.commonHandler.withGroup(name)}
   142  }
   143  
   144  // Handle formats its argument Record as a JSON object on a single line.
   145  //
   146  // If the Record's time is zero, the time is omitted.
   147  // Otherwise, the key is "time"
   148  // and the value is output as with GlogDate.
   149  //
   150  // If the Record's level is zero, the level is omitted.
   151  // Otherwise, the key is "level"
   152  // and the value of [Level.String] is output.
   153  //
   154  // If the AddSource option is set and source information is available,
   155  // the key is "source", and the value is a record of type [Source].
   156  //
   157  // The message's key is "msg".
   158  //
   159  // To modify these or other attributes, or remove them from the output, use
   160  // [HandlerOptions.ReplaceAttr].
   161  //
   162  // Values are formatted as with an [encoding/json.Encoder] with SetEscapeHTML(false),
   163  // with two exceptions.
   164  //
   165  // First, an Attr whose Value is of type error is formatted as a string, by
   166  // calling its Error method. Only errors in Attrs receive this special treatment,
   167  // not errors embedded in structs, slices, maps or other data structures that
   168  // are processed by the encoding/json package.
   169  //
   170  // Second, an encoding failure does not cause Handle to return an error.
   171  // Instead, the error message is formatted as a string.
   172  //
   173  // Each call to Handle results in a single serialized call to io.Writer.Write.
   174  //
   175  // Header formats a log header as defined by the C++ implementation.
   176  // It returns a buffer containing the formatted header and the user's file and line number.
   177  // The depth specifies how many stack frames above lives the source line to be identified in the log message.
   178  //
   179  // # LOG LINE PREFIX FORMAT
   180  //
   181  // Log lines have this form:
   182  //
   183  //	Lyyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg...
   184  //
   185  // where the fields are defined as follows:
   186  //
   187  //	L                A single character, representing the log level
   188  //	                 (eg 'I' for INFO)
   189  //	yyyy             The year
   190  //	mm               The month (zero padded; ie May is '05')
   191  //	dd               The day (zero padded)
   192  //	hh:mm:ss.uuuuuu  Time in hours, minutes and fractional seconds
   193  //	threadid         The space-padded thread ID as returned by GetTID()
   194  //	                 (this matches the PID on Linux)
   195  //	file             The file name
   196  //	line             The line number
   197  //	msg              The user-supplied message
   198  //
   199  // Example:
   200  //
   201  //	I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog
   202  //	I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395
   203  //
   204  // NOTE: although the microseconds are useful for comparing events on
   205  // a single machine, clocks on different machines may not be well
   206  // synchronized.  Hence, use caution when comparing the low bits of
   207  // timestamps from different machines.
   208  func (h *GlogHandler) Handle(_ context.Context, r slog.Record) error {
   209  	return h.commonHandler.handle(r)
   210  }