github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/goutils/logger/logger_test.go (about)

     1  /*
     2   * Copyright (c) 2020-present unTill Pro, Ltd.
     3   * @author Maxim Geraskin
     4   *
     5   * This source code is licensed under the MIT license found in the
     6   * LICENSE file in the root directory of this source tree.
     7   */
     8  
     9  package logger_test
    10  
    11  import (
    12  	"bytes"
    13  	"io"
    14  	"os"
    15  	"strconv"
    16  	"strings"
    17  	"sync"
    18  	"testing"
    19  
    20  	"github.com/stretchr/testify/require"
    21  	"github.com/voedger/voedger/pkg/goutils/logger"
    22  	"github.com/voedger/voedger/pkg/goutils/testingu"
    23  )
    24  
    25  func Test_BasicUsage(t *testing.T) {
    26  
    27  	// "Hello world"
    28  	{
    29  		logger.Error("Error", "arg1", "arg2")
    30  		logger.Warning("My warning")
    31  		logger.Info("My info")
    32  
    33  		// IsVerbose() is used to avoid unnecessary calculations
    34  		if logger.IsVerbose() {
    35  			logger.Verbose("!!! You should NOT see this verbose message since default level is INFO")
    36  		}
    37  
    38  		// IsTrace() is used to avoid unnecessary calculations
    39  		if logger.IsTrace() {
    40  			logger.Trace("!!! You should NOT see this trace message since default level is INFO")
    41  		}
    42  	}
    43  
    44  	// Changing LogLevel
    45  	{
    46  		logger.SetLogLevel(logger.LogLevelTrace)
    47  		if logger.IsTrace() {
    48  			logger.Trace("Now you should see my Trace")
    49  		}
    50  		if logger.IsVerbose() {
    51  			logger.Verbose("Now you should see my Verbose")
    52  		}
    53  		logger.SetLogLevel(logger.LogLevelError)
    54  		logger.Trace("!!! You should NOT see my Trace")
    55  		logger.Warning("!!! You should NOT see my warning")
    56  		logger.SetLogLevel(logger.LogLevelInfo)
    57  		logger.Warning("You should see my warning")
    58  		logger.Warning("You should see my info")
    59  	}
    60  
    61  	// Let see how it looks when using from methods
    62  	{
    63  		m := mystruct{}
    64  		m.iWantToLog()
    65  	}
    66  }
    67  
    68  func loggerHelperWithSkipStackFrames(skipStackFrames int, msg string) error {
    69  	logger.Log(skipStackFrames, logger.LogLevelTrace, "myStunningPrefix:", msg)
    70  	return nil
    71  }
    72  
    73  func Test_BasicUsage_SkipStackFrames(t *testing.T) {
    74  
    75  	logger.SetLogLevel(logger.LogLevelTrace)
    76  
    77  	// [logger_test.loggerHelperWithSkipStackFrames:...]: myStunningPrefix: hello
    78  	_ = loggerHelperWithSkipStackFrames(0, "hello")
    79  
    80  	// logger_test.Test_SkipStackFrames:...]: myStunningPrefix: hello
    81  	_ = loggerHelperWithSkipStackFrames(1, "hello")
    82  }
    83  
    84  func Test_BasicUsage_CustomPrintLine(t *testing.T) {
    85  
    86  	require := require.New(t)
    87  
    88  	// Define myPrintLine
    89  	myPrintLine := func(level logger.TLogLevel, line string) {
    90  		line += "myPrintLine"
    91  		logger.DefaultPrintLine(level, line)
    92  	}
    93  
    94  	// Use myPrintLine as logger.PrintLine
    95  
    96  	logger.PrintLine = myPrintLine
    97  	defer func() {
    98  		logger.PrintLine = logger.DefaultPrintLine
    99  	}()
   100  
   101  	{
   102  		logger.SetLogLevel(logger.LogLevelTrace)
   103  		strStdout, strStderr, err := testingu.CaptureStdoutStderr(func() error {
   104  			logger.Trace("hello")
   105  			return nil
   106  		})
   107  		require.NoError(err)
   108  		require.Equal("", strStderr)
   109  		require.Contains(strStdout, "myPrintLine")
   110  	}
   111  
   112  }
   113  
   114  func Test_SkipStackFrames(t *testing.T) {
   115  
   116  	require := require.New(t)
   117  	logger.SetLogLevel(logger.LogLevelTrace)
   118  
   119  	const funcNamePattern = "loggerHelperWithSkipStackFrames"
   120  
   121  	{
   122  		// [logger_test.loggerHelperSkip0StackFrames:69]: myStunningPrefix: hello
   123  		strStdout, strStderr, err := testingu.CaptureStdoutStderr(func() error {
   124  			return loggerHelperWithSkipStackFrames(0, "hello")
   125  		})
   126  		require.NoError(err)
   127  		require.Equal("", strStderr)
   128  		require.Contains(strStdout, funcNamePattern)
   129  	}
   130  
   131  	{
   132  		// logger_test.Test_SkipStackFrames:80]: myStunningPrefix: hello
   133  		strStdout, strStderr, err := testingu.CaptureStdoutStderr(func() error {
   134  			return loggerHelperWithSkipStackFrames(1, "hello")
   135  		})
   136  		require.NoError(err)
   137  		require.Equal("", strStderr)
   138  		require.NotContains(strStdout, funcNamePattern)
   139  	}
   140  
   141  }
   142  
   143  func Test_StdoutStderr_LogLevel(t *testing.T) {
   144  
   145  	require := require.New(t)
   146  
   147  	// LogLevelError
   148  	{
   149  		logger.SetLogLevel(logger.LogLevelError)
   150  		strStdout, strStderr, err := testingu.CaptureStdoutStderr(func() error {
   151  			logger.Error("Error", "arg1", "arg2")
   152  			logger.Warning("My warning")
   153  			return nil
   154  		})
   155  		require.NoError(err)
   156  		require.Contains(strStderr, "Error arg1 arg2")
   157  		require.Equal("", strStdout)
   158  	}
   159  
   160  	// LogLevelWarning
   161  	{
   162  		logger.SetLogLevel(logger.LogLevelWarning)
   163  		strStdout, strStderr, err := testingu.CaptureStdoutStderr(func() error {
   164  			logger.Error("Error", "arg1", "arg2")
   165  			logger.Warning("My warning")
   166  			return nil
   167  		})
   168  		require.NoError(err)
   169  		require.Contains(strStderr, "Error arg1 arg2")
   170  		require.Contains(strStdout, "My warning")
   171  	}
   172  
   173  }
   174  
   175  func Test_CheckSetLevels(t *testing.T) {
   176  
   177  	require := require.New(t)
   178  
   179  	logger.SetLogLevel(logger.LogLevelNone)
   180  	require.False(logger.IsError())
   181  	require.False(logger.IsWarning())
   182  	require.False(logger.IsInfo())
   183  	require.False(logger.IsVerbose())
   184  	require.False(logger.IsTrace())
   185  
   186  	logger.SetLogLevel(logger.LogLevelError)
   187  	require.True(logger.IsError())
   188  	require.False(logger.IsWarning())
   189  	require.False(logger.IsInfo())
   190  	require.False(logger.IsVerbose())
   191  	require.False(logger.IsTrace())
   192  
   193  	logger.SetLogLevel(logger.LogLevelWarning)
   194  	require.True(logger.IsError())
   195  	require.True(logger.IsWarning())
   196  	require.False(logger.IsInfo())
   197  	require.False(logger.IsVerbose())
   198  	require.False(logger.IsTrace())
   199  
   200  	logger.SetLogLevel(logger.LogLevelInfo)
   201  	require.True(logger.IsError())
   202  	require.True(logger.IsWarning())
   203  	require.True(logger.IsInfo())
   204  	require.False(logger.IsVerbose())
   205  	require.False(logger.IsTrace())
   206  
   207  	logger.SetLogLevel(logger.LogLevelVerbose)
   208  	require.True(logger.IsError())
   209  	require.True(logger.IsWarning())
   210  	require.True(logger.IsInfo())
   211  	require.True(logger.IsVerbose())
   212  	require.False(logger.IsTrace())
   213  
   214  	logger.SetLogLevel(logger.LogLevelTrace)
   215  	require.True(logger.IsError())
   216  	require.True(logger.IsWarning())
   217  	require.True(logger.IsInfo())
   218  	require.True(logger.IsVerbose())
   219  	require.True(logger.IsTrace())
   220  
   221  }
   222  
   223  type mystruct struct {
   224  }
   225  
   226  func (m *mystruct) iWantToLog() {
   227  	logger.Error("OOPS")
   228  }
   229  
   230  func TestMultithread(t *testing.T) {
   231  	require := require.New(t)
   232  	r, w, err := os.Pipe()
   233  	require.NoError(err)
   234  	oldStdout := os.Stdout
   235  	defer func() { os.Stdout = oldStdout }()
   236  	os.Stdout = w
   237  	wg := sync.WaitGroup{}
   238  	wg.Add(1000)
   239  
   240  	toLog := []string{}
   241  	for i := 0; i < 100; i++ {
   242  		toLog = append(toLog, strings.Repeat(strconv.Itoa(i), 10))
   243  	}
   244  
   245  	for i := 0; i < 1000; i++ {
   246  		go func() {
   247  			for i := 0; i < 100; i++ {
   248  				logger.Info(toLog[i])
   249  			}
   250  			wg.Done()
   251  		}()
   252  	}
   253  
   254  	stdout := ""
   255  	wait := make(chan struct{})
   256  	go func() {
   257  		buf := bytes.NewBuffer(nil)
   258  		_, err := io.Copy(buf, r)
   259  		require.NoError(err)
   260  		stdout = buf.String()
   261  		close(wait)
   262  	}()
   263  	wg.Wait()
   264  	w.Close()
   265  	<-wait
   266  
   267  	logged := strings.Split(stdout, "\n")
   268  outer:
   269  	for _, loggedActual := range logged {
   270  		if len(loggedActual) == 0 {
   271  			continue
   272  		}
   273  		for _, loggedExpected := range toLog {
   274  			if strings.Contains(loggedActual, loggedExpected) {
   275  				continue outer
   276  			}
   277  		}
   278  		t.Fatal(loggedActual)
   279  	}
   280  }