github.com/facebookincubator/go-belt@v0.0.0-20230703220935-39cd348f1a38/tool/logger/adapter/compact_logger.go (about)

     1  // Copyright 2022 Meta Platforms, Inc. and affiliates.
     2  //
     3  // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
     4  //
     5  // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
     6  //
     7  // 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
     8  //
     9  // 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
    10  //
    11  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    12  
    13  package adapter
    14  
    15  import (
    16  	"github.com/facebookincubator/go-belt"
    17  	"github.com/facebookincubator/go-belt/pkg/field"
    18  	"github.com/facebookincubator/go-belt/tool/logger/types"
    19  )
    20  
    21  // CompactLogger is an optimized interface of an abstract
    22  // generic structured logger. For the full interface see "Logger".
    23  //
    24  // It is easier to implement a CompactLogger and then wrap it
    25  // to an adapter.GenericSugar to get a Logger, than to implement
    26  // a full Logger.
    27  //
    28  // All methods are thread-safe.
    29  type CompactLogger interface {
    30  	belt.Tool
    31  
    32  	// Logf logs an unstructured message. Though, of course, all
    33  	// contextual structured fields will also be logged.
    34  	//
    35  	// This method exists mostly for convenience, for people who
    36  	// has not got used to proper structured logging, yet.
    37  	// See `LogFields` and `Log`. If one have variables they want to
    38  	// log, it is better for scalable observability to log them
    39  	// as structured values, instead of injecting them into a
    40  	// non-structured string.
    41  	Logf(level types.Level, format string, args ...any)
    42  
    43  	// LogFields logs structured fields with a explanation message.
    44  	//
    45  	// Anything that implements field.AbstractFields might be used
    46  	// as a collection of fields to be logged.
    47  	//
    48  	// Examples:
    49  	//
    50  	// 	l.LogFields(logger.LevelDebug, "new_request", field.Fields{{Key: "user_id", Value: userID}, {Key: "group_id", Value: groupID}})
    51  	// 	l.LogFields(logger.LevelInfo, "affected entries", field.Field{Key: "mysql_affected", Value: affectedRows})
    52  	// 	l.LogFields(logger.LevelError, "unable to fetch user info", request) // where `request` implements field.AbstractFields
    53  	//
    54  	// Sometimes it is inconvenient to manually describe each field,
    55  	// and for such cases see method `Log`.
    56  	LogFields(level types.Level, message string, fields field.AbstractFields)
    57  
    58  	// Log extracts structured fields from provided values, joins
    59  	// the rest into an unstructured message and logs the result.
    60  	//
    61  	// This function provides convenience (relatively to LogFields)
    62  	// at cost of a bit of performance.
    63  	//
    64  	// There are few ways to extract structured fields, which are
    65  	// applied for each value from `values` (in descending priority order):
    66  	// 1. If a `value` is an `*Entry` then the Entry is used (with its fields)
    67  	// 2. If a `value` implements field.AbstractFields then ForEachField method
    68  	//    is used (so it is become similar to LogFields).
    69  	// 3. If a `value` is a structure (or a pointer to a structure) then
    70  	//    fields of the structure are interpreted as structured fields
    71  	//    to be logged (see explanation below).
    72  	// 4. If a `value` is a map then fields a constructed out of this map.
    73  	//
    74  	// Everything that does not fit into any of the rules above is just
    75  	// joined into an unstructured message (and works the same way
    76  	// as `message` in LogFields).
    77  	//
    78  	// How structures are parsed:
    79  	// Structures are parsed recursively. Each field name of the path in a tree
    80  	// of structures is added to the resulting field name (for example int "struct{A struct{B int}}"
    81  	// the field name will be `A.B`).
    82  	// To enforce another name use tag `log` (for example "struct{A int `log:"anotherName"`}"),
    83  	// to prevent a field from logging use tag `log:"-"`.
    84  	//
    85  	// Examples:
    86  	//
    87  	// 	user, err := getUser()
    88  	// 	if err != nil {
    89  	// 		l.Log(logger.LevelError, err)
    90  	// 		return err
    91  	// 	}
    92  	// 	l.Log(logger.LevelDebug, "current user", user) // fields of structure "user" will be logged
    93  	// 	l.Log(logger.LevelDebug, map[string]any{"user_id": user.ID, "group_id", user.GroupID})
    94  	// 	l.Log(logger.LevelDebug, field.Fields{{Key: "user_id", Value: user.ID}, {Key: "group_id", Value: user.GroupID}})
    95  	// 	l.Log(logger.LevelDebug, "current user ID is ", user.ID, " and group ID is ", user.GroupID) // will result into message "current user ID is 1234 and group ID is 5678".
    96  	Log(level types.Level, values ...any)
    97  
    98  	// Emitter returns the Emitter (see the description of interface "Emitter").
    99  	Emitter() types.Emitter
   100  
   101  	// Level returns the current logging level (see description of "Level").
   102  	Level() types.Level
   103  
   104  	// WithLevel returns a logger with logger level set to the given argument.
   105  	//
   106  	// See also the description of type "Level".
   107  	WithLevel(types.Level) CompactLogger
   108  
   109  	// WithPreHooks returns a Logger which includes/appends pre-hooks from the arguments.
   110  	//
   111  	// See also description of "PreHook".
   112  	//
   113  	// Special case: to reset hooks use `WithHooks()` (without any arguments).
   114  	WithPreHooks(...types.PreHook) CompactLogger
   115  
   116  	// WithHooks returns a Logger which includes/appends hooks from the arguments.
   117  	//
   118  	// See also description of "Hook".
   119  	//
   120  	// Special case: to reset hooks use `WithHooks()` (without any arguments).
   121  	WithHooks(...types.Hook) CompactLogger
   122  
   123  	// WithField returns the logger with the added field (used for structured logging).
   124  	WithField(key string, value any, props ...field.Property) CompactLogger
   125  
   126  	// WithFields returns the logger with the fields added (used for structured logging).
   127  	WithFields(fields field.AbstractFields) CompactLogger
   128  
   129  	// WithMessagePrefix adds a string to all messages logged through the derived logger
   130  	WithMessagePrefix(prefix string) CompactLogger
   131  
   132  	// WithEntryProperties adds props to EntryProperties of each emitted Entry.
   133  	// This could be used only for enabling implementation-specific behavior.
   134  	WithEntryProperties(props ...types.EntryProperty) CompactLogger
   135  }