github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/ekalog/integrator_common_private.go (about)

     1  // Copyright © 2020. All rights reserved.
     2  // Author: Ilya Stroy.
     3  // Contacts: iyuryevich@pm.me, https://github.com/qioalice
     4  // License: https://opensource.org/licenses/MIT
     5  
     6  package ekalog
     7  
     8  import (
     9  	"io"
    10  	"os"
    11  	"unsafe"
    12  
    13  	"github.com/qioalice/ekago/v3/internal/ekaclike"
    14  	"github.com/qioalice/ekago/v3/internal/ekasys"
    15  )
    16  
    17  //noinspection GoSnakeCaseUsage
    18  type (
    19  	// _CI_Output is a CommonIntegrator part that contains encoder
    20  	// and destination io.Writer set, encoded Entry will be written to.
    21  	//
    22  	// It used at the CommonIntegrator building procedure.
    23  	_CI_Output struct {
    24  		minLevel           Level       // minimum level log entry should have to be processed
    25  		stacktraceMinLevel Level       // minimum level starting with stacktrace must be added to the entry
    26  		encoder            CI_Encoder  // func that encoders Entry object to []byte
    27  		writers            []io.Writer // slice of io.Writer, log entry will be written to
    28  		preEncodedFields   []byte      // raw data of pre-encoded fields
    29  	}
    30  )
    31  
    32  // assertNil panics if current CommonIntegrator is nil.
    33  func (ci *CommonIntegrator) assertNil() {
    34  	if ci == nil {
    35  		panic("CommonIntegrator is nil object")
    36  	}
    37  }
    38  
    39  // assertWithLock calls assertNil(), locks then CommonIntegrator and checks,
    40  // whether current CommonIntegrator is not registered before and has at least 1
    41  // valid io.Writer.
    42  // The caller must take a responsibility about unlocking CommonIntegrator.
    43  func (ci *CommonIntegrator) assertWithLock() {
    44  	ci.assertNil()
    45  	ci.mu.Lock()
    46  	switch {
    47  	case ci.isRegistered:
    48  		panic("Failed to build CommonIntegrator. It has already registered.")
    49  	}
    50  }
    51  
    52  // build tries to prepare CommonIntegrator to be used with Logger:
    53  //  - Drops last not fully registered _CI_Output object,
    54  //  - Calculates lowest levels of all _CI_Output.
    55  //
    56  // Requirements:
    57  //  - Integrator must not be nil (even typed nil), panic otherwise;
    58  //  - If Integrator is CommonIntegrator
    59  //    it must not be registered with some Logger before, panic otherwise;
    60  //  - If Integrator is CommonIntegrator
    61  //    it must have at least 1 registered io.Writer, panic otherwise.
    62  func (ci *CommonIntegrator) build() {
    63  
    64  	// build() cannot be called if CommonIntegrator is nil.
    65  	// So, another one nil check is redundant.
    66  
    67  	ci.assertWithLock()
    68  	defer ci.mu.Unlock()
    69  
    70  	if len(ci.output) == 0 {
    71  		panic("Failed to build CommonIntegrator. There is no valid io.Writer.")
    72  	}
    73  
    74  	// Use stdout (synced) as writer for last encoder if user forgot/omit
    75  	// to specify it explicitly AND if it has not been specified yet.
    76  
    77  	if len(ci.output[ci.idx].writers) == 0 {
    78  
    79  		// Try to find stdout in the previous writers.
    80  
    81  		stdoutNormal := unsafe.Pointer(os.Stdout)
    82  		stdoutSynced := unsafe.Pointer(ekasys.Stdout)
    83  
    84  		found := false
    85  
    86  		for i := 0; i < ci.idx && !found; i++ {
    87  			for j, n := 0, len(ci.output[i].writers); j < n && !found; j++ {
    88  				writerPtr := ekaclike.TakeRealAddr(ci.output[i].writers[j])
    89  				found = writerPtr == stdoutNormal || writerPtr == stdoutSynced
    90  			}
    91  		}
    92  
    93  		if found {
    94  			// If stdout was used already, drop the last encoder.
    95  			ci.output = ci.output[:ci.idx]
    96  		} else {
    97  			ci.output[ci.idx].writers = append(ci.output[ci.idx].writers, ekasys.Stdout)
    98  		}
    99  	}
   100  
   101  	ci.oll = LEVEL_WARNING
   102  	ci.stll = LEVEL_WARNING
   103  
   104  	for _, output := range ci.output {
   105  		if output.minLevel > ci.oll {
   106  			ci.oll = output.minLevel
   107  		}
   108  		if output.stacktraceMinLevel > ci.stll {
   109  			ci.stll = output.stacktraceMinLevel
   110  		}
   111  	}
   112  
   113  	ci.isRegistered = true
   114  }