github.com/gogf/gf/v2@v2.7.4/os/glog/glog_logger_handler.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package glog
     8  
     9  import (
    10  	"bytes"
    11  	"context"
    12  	"time"
    13  
    14  	"github.com/gogf/gf/v2/util/gconv"
    15  )
    16  
    17  // Handler is function handler for custom logging content outputs.
    18  type Handler func(ctx context.Context, in *HandlerInput)
    19  
    20  // HandlerInput is the input parameter struct for logging Handler.
    21  //
    22  // The logging content is consisted in:
    23  // TimeFormat [LevelFormat] {TraceId} {CtxStr} Prefix CallerFunc CallerPath Content Values Stack
    24  //
    25  // The header in the logging content is:
    26  // TimeFormat [LevelFormat] {TraceId} {CtxStr} Prefix CallerFunc CallerPath
    27  type HandlerInput struct {
    28  	internalHandlerInfo
    29  
    30  	// Current Logger object.
    31  	Logger *Logger
    32  
    33  	// Buffer for logging content outputs.
    34  	Buffer *bytes.Buffer
    35  
    36  	// (ReadOnly) Logging time, which is the time that logging triggers.
    37  	Time time.Time
    38  
    39  	// Formatted time string for output, like "2016-01-09 12:00:00".
    40  	TimeFormat string
    41  
    42  	// (ReadOnly) Using color constant value, like COLOR_RED, COLOR_BLUE, etc.
    43  	// Example: 34
    44  	Color int
    45  
    46  	// (ReadOnly) Using level, like LEVEL_INFO, LEVEL_ERRO, etc.
    47  	// Example: 256
    48  	Level int
    49  
    50  	// Formatted level string for output, like "DEBU", "ERRO", etc.
    51  	// Example: ERRO
    52  	LevelFormat string
    53  
    54  	// The source function name that calls logging, only available if F_CALLER_FN set.
    55  	CallerFunc string
    56  
    57  	// The source file path and its line number that calls logging,
    58  	// only available if F_FILE_SHORT or F_FILE_LONG set.
    59  	CallerPath string
    60  
    61  	// The retrieved context value string from context, only available if Config.CtxKeys configured.
    62  	// It's empty if no Config.CtxKeys configured.
    63  	CtxStr string
    64  
    65  	// Trace id, only available if OpenTelemetry is enabled, or else it's an empty string.
    66  	TraceId string
    67  
    68  	// Custom prefix string in logging content header part.
    69  	// Note that, it takes no effect if HeaderPrint is disabled.
    70  	Prefix string
    71  
    72  	// Custom logging content for logging.
    73  	Content string
    74  
    75  	// The passed un-formatted values array to logger.
    76  	Values []any
    77  
    78  	// Stack string produced by logger, only available if Config.StStatus configured.
    79  	// Note that there are usually multiple lines in stack content.
    80  	Stack string
    81  
    82  	// IsAsync marks it is in asynchronous logging.
    83  	IsAsync bool
    84  }
    85  
    86  type internalHandlerInfo struct {
    87  	index    int       // Middleware handling index for internal usage.
    88  	handlers []Handler // Handler array calling bu index.
    89  }
    90  
    91  // defaultHandler is the default handler for package.
    92  var defaultHandler Handler
    93  
    94  // doFinalPrint is a handler for logging content printing.
    95  // This handler outputs logging content to file/stdout/write if any of them configured.
    96  func doFinalPrint(ctx context.Context, in *HandlerInput) {
    97  	buffer := in.Logger.doFinalPrint(ctx, in)
    98  	if in.Buffer.Len() == 0 {
    99  		in.Buffer = buffer
   100  	}
   101  }
   102  
   103  // SetDefaultHandler sets default handler for package.
   104  func SetDefaultHandler(handler Handler) {
   105  	defaultHandler = handler
   106  }
   107  
   108  // GetDefaultHandler returns the default handler of package.
   109  func GetDefaultHandler() Handler {
   110  	return defaultHandler
   111  }
   112  
   113  // Next calls the next logging handler in middleware way.
   114  func (in *HandlerInput) Next(ctx context.Context) {
   115  	in.index++
   116  	if in.index < len(in.handlers) {
   117  		in.handlers[in.index](ctx, in)
   118  	}
   119  }
   120  
   121  // String returns the logging content formatted by default logging handler.
   122  func (in *HandlerInput) String(withColor ...bool) string {
   123  	formatWithColor := false
   124  	if len(withColor) > 0 {
   125  		formatWithColor = withColor[0]
   126  	}
   127  	return in.getDefaultBuffer(formatWithColor).String()
   128  }
   129  
   130  // ValuesContent converts and returns values as string content.
   131  func (in *HandlerInput) ValuesContent() string {
   132  	var (
   133  		buffer       = bytes.NewBuffer(nil)
   134  		valueContent string
   135  	)
   136  	for _, v := range in.Values {
   137  		valueContent = gconv.String(v)
   138  		if len(valueContent) == 0 {
   139  			continue
   140  		}
   141  		if buffer.Len() == 0 {
   142  			buffer.WriteString(valueContent)
   143  			continue
   144  		}
   145  		if buffer.Bytes()[buffer.Len()-1] != '\n' {
   146  			buffer.WriteString(" " + valueContent)
   147  			continue
   148  		}
   149  		// Remove one blank line(\n\n).
   150  		if valueContent[0] == '\n' {
   151  			valueContent = valueContent[1:]
   152  		}
   153  		buffer.WriteString(valueContent)
   154  	}
   155  	return buffer.String()
   156  }
   157  
   158  func (in *HandlerInput) getDefaultBuffer(withColor bool) *bytes.Buffer {
   159  	buffer := bytes.NewBuffer(nil)
   160  	if in.Logger.config.HeaderPrint {
   161  		if in.TimeFormat != "" {
   162  			buffer.WriteString(in.TimeFormat)
   163  		}
   164  		if in.Logger.config.LevelPrint && in.LevelFormat != "" {
   165  			var levelStr = "[" + in.LevelFormat + "]"
   166  			if withColor {
   167  				in.addStringToBuffer(buffer, in.Logger.getColoredStr(
   168  					in.Logger.getColorByLevel(in.Level), levelStr,
   169  				))
   170  			} else {
   171  				in.addStringToBuffer(buffer, levelStr)
   172  			}
   173  		}
   174  	}
   175  	if in.TraceId != "" {
   176  		in.addStringToBuffer(buffer, "{"+in.TraceId+"}")
   177  	}
   178  	if in.CtxStr != "" {
   179  		in.addStringToBuffer(buffer, "{"+in.CtxStr+"}")
   180  	}
   181  	if in.Logger.config.HeaderPrint {
   182  		if in.Prefix != "" {
   183  			in.addStringToBuffer(buffer, in.Prefix)
   184  		}
   185  		if in.CallerFunc != "" {
   186  			in.addStringToBuffer(buffer, in.CallerFunc)
   187  		}
   188  		if in.CallerPath != "" {
   189  			in.addStringToBuffer(buffer, in.CallerPath)
   190  		}
   191  	}
   192  
   193  	if in.Content != "" {
   194  		in.addStringToBuffer(buffer, in.Content)
   195  	}
   196  
   197  	if len(in.Values) > 0 {
   198  		in.addStringToBuffer(buffer, in.ValuesContent())
   199  	}
   200  
   201  	if in.Stack != "" {
   202  		in.addStringToBuffer(buffer, "\nStack:\n"+in.Stack)
   203  	}
   204  	// avoid a single space at the end of a line.
   205  	buffer.WriteString("\n")
   206  	return buffer
   207  }
   208  
   209  func (in *HandlerInput) getRealBuffer(withColor bool) *bytes.Buffer {
   210  	if in.Buffer.Len() > 0 {
   211  		return in.Buffer
   212  	}
   213  	return in.getDefaultBuffer(withColor)
   214  }
   215  
   216  func (in *HandlerInput) addStringToBuffer(buffer *bytes.Buffer, strings ...string) {
   217  	for _, s := range strings {
   218  		if buffer.Len() > 0 {
   219  			buffer.WriteByte(' ')
   220  		}
   221  		buffer.WriteString(s)
   222  	}
   223  }