github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/pkg/logger/logger_test.go (about)

     1  package logger
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/redis/go-redis/v9"
    11  	"github.com/sirupsen/logrus"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/mock"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  type hookMock struct {
    18  	mock.Mock
    19  }
    20  
    21  func newHookMock(t *testing.T) *hookMock {
    22  	m := new(hookMock)
    23  	m.Test(t)
    24  
    25  	t.Cleanup(func() { m.AssertExpectations(t) })
    26  
    27  	return m
    28  }
    29  
    30  func (m *hookMock) Levels() []logrus.Level {
    31  	return logrus.AllLevels
    32  }
    33  
    34  func (m *hookMock) Fire(entry *logrus.Entry) error {
    35  	return m.Called(entry.String()).Error(0)
    36  }
    37  
    38  func TestImplementation(t *testing.T) {
    39  	assert.Implements(t, (*Logger)(nil), new(Entry))
    40  }
    41  
    42  func TestLogger(t *testing.T) {
    43  	t.Run("DebugDomain", func(t *testing.T) {
    44  		buf := new(bytes.Buffer)
    45  		err := Init(Options{
    46  			Level:  "info",
    47  			Output: buf,
    48  		})
    49  		assert.NoError(t, err)
    50  
    51  		debugLogger.SetFormatter(&logrus.TextFormatter{
    52  			DisableColors:    true,
    53  			DisableTimestamp: true,
    54  		})
    55  
    56  		err = AddDebugDomain("foo.bar", 24*time.Hour)
    57  		assert.NoError(t, err)
    58  
    59  		WithDomain("foo.bar").Debug("debug1")
    60  
    61  		debugTimeout := DebugExpiration("foo.bar")
    62  		assert.WithinDuration(t, time.Now().Add(24*time.Hour), *debugTimeout, time.Second)
    63  
    64  		err = RemoveDebugDomain("foo.bar")
    65  		assert.NoError(t, err)
    66  
    67  		WithDomain("foo.bar").Debug("debug2")
    68  
    69  		assert.Equal(t, "level=debug msg=debug1 domain=foo.bar\n", buf.String())
    70  	})
    71  
    72  	t.Run("DebugDomain with expired debug", func(t *testing.T) {
    73  		buf := new(bytes.Buffer)
    74  
    75  		err := Init(Options{
    76  			Level:  "info",
    77  			Output: buf,
    78  		})
    79  		assert.NoError(t, err)
    80  
    81  		debugLogger.SetFormatter(&logrus.TextFormatter{
    82  			DisableColors:    true,
    83  			DisableTimestamp: true,
    84  		})
    85  
    86  		err = AddDebugDomain("foo.bar", 5*time.Millisecond)
    87  		assert.NoError(t, err)
    88  
    89  		WithDomain("foo.bar").Debug("debug1")
    90  
    91  		// Let the rule about the domain expire.
    92  		time.Sleep(6 * time.Millisecond)
    93  
    94  		// Should not be logged as the debug mode has expired
    95  		WithDomain("foo.bar").Debug("debug2")
    96  
    97  		debugTimeout := DebugExpiration("foo.bar")
    98  		assert.Nil(t, debugTimeout)
    99  
   100  		assert.Equal(t, "level=debug msg=debug1 domain=foo.bar\n", buf.String())
   101  	})
   102  
   103  	t.Run("DebugDomainWithRedis", func(t *testing.T) {
   104  		if testing.Short() {
   105  			t.Skip("an instance is required for this test: test skipped due to the use of --short flag")
   106  		}
   107  
   108  		opt, err := redis.ParseURL("redis://localhost:6379/0")
   109  		assert.NoError(t, err)
   110  		err = Init(Options{
   111  			Level: "info",
   112  			Redis: redis.NewClient(opt),
   113  		})
   114  		assert.NoError(t, err)
   115  
   116  		buf := new(bytes.Buffer)
   117  		debugLogger.SetFormatter(&logrus.TextFormatter{
   118  			DisableColors:    true,
   119  			DisableTimestamp: true,
   120  		})
   121  		debugLogger.SetOutput(buf)
   122  
   123  		time.Sleep(100 * time.Millisecond)
   124  
   125  		err = AddDebugDomain("foo.bar.redis", 24*time.Hour)
   126  		assert.NoError(t, err)
   127  		err = AddDebugDomain("foo.bar.redis", 24*time.Hour)
   128  		assert.NoError(t, err)
   129  
   130  		time.Sleep(100 * time.Millisecond)
   131  
   132  		WithDomain("foo.bar.redis").Debug("debug1")
   133  
   134  		err = RemoveDebugDomain("foo.bar.redis")
   135  		assert.NoError(t, err)
   136  
   137  		time.Sleep(100 * time.Millisecond)
   138  
   139  		WithDomain("foo.bar.redis").Debug("debug2")
   140  
   141  		assert.Equal(t, "level=debug msg=debug1 domain=foo.bar.redis\n", buf.String())
   142  	})
   143  
   144  	t.Run("Hooks are triggered", func(t *testing.T) {
   145  		hook := newHookMock(t)
   146  
   147  		err := Init(Options{
   148  			Level:  "info",
   149  			Hooks:  []logrus.Hook{hook},
   150  			Output: io.Discard,
   151  		})
   152  		require.NoError(t, err)
   153  
   154  		logrus.StandardLogger().SetFormatter(&logrus.TextFormatter{
   155  			DisableColors:    true,
   156  			DisableTimestamp: true,
   157  		})
   158  
   159  		hook.On("Fire", "level=warning msg=warn1 domain=foo.bar\n", nil).Once().Return(nil)
   160  
   161  		WithDomain("foo.bar").Warnf("warn%d", 1)
   162  	})
   163  
   164  	t.Run("Fallback to Info if level is not set", func(t *testing.T) {
   165  		err := Init(Options{})
   166  		require.NoError(t, err)
   167  
   168  		assert.Equal(t, logrus.InfoLevel, logrus.StandardLogger().Level)
   169  	})
   170  
   171  	t.Run("Init fail in case of an invalid level", func(t *testing.T) {
   172  		err := Init(Options{Level: "invalid level"})
   173  
   174  		require.EqualError(t, err, "not a valid logrus Level: \"invalid level\"")
   175  	})
   176  
   177  	t.Run("Truncate log line if too long", func(t *testing.T) {
   178  		buf := new(bytes.Buffer)
   179  
   180  		err := Init(Options{
   181  			Level:  "info",
   182  			Output: buf,
   183  		})
   184  		require.NoError(t, err)
   185  
   186  		debugLogger.SetFormatter(&logrus.TextFormatter{
   187  			DisableColors:    true,
   188  			DisableTimestamp: true,
   189  		})
   190  
   191  		// input == "foo" + ' ' * 3000 + "bar"
   192  		WithDomain("test").Error(fmt.Sprintf("%-3000sbar", "foo"))
   193  
   194  		assert.Equal(t, fmt.Sprintf("level=error msg=\"%-1988s [TRUNCATED]\" domain=test\n", "foo"), buf.String())
   195  	})
   196  }