Skip to content

Commit

Permalink
Add log component (#69)
Browse files Browse the repository at this point in the history
  • Loading branch information
omerzi authored Jul 17, 2024
1 parent 577296f commit 6ce8b51
Show file tree
Hide file tree
Showing 4 changed files with 262 additions and 0 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/jfrog/gofrog
go 1.22

require (
github.com/gookit/color v1.5.4
github.com/jfrog/archiver/v3 v3.6.0
github.com/minio/sha256-simd v1.0.1
github.com/pkg/errors v0.9.1
Expand All @@ -25,6 +26,7 @@ require (
github.com/rivo/uniseg v0.4.7 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
golang.org/x/sync v0.6.0
golang.org/x/sys v0.17.0 // indirect
golang.org/x/term v0.17.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5Jflh
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/jfrog/archiver/v3 v3.6.0 h1:OVZ50vudkIQmKMgA8mmFF9S0gA47lcag22N13iV3F1w=
github.com/jfrog/archiver/v3 v3.6.0/go.mod h1:fCAof46C3rAXgZurS8kNRNdSVMKBbZs+bNNhPYxLldI=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
Expand Down Expand Up @@ -45,6 +47,8 @@ github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8=
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand Down
189 changes: 189 additions & 0 deletions log/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package log

import (
"fmt"
"io"
"log"
"os"
"strings"
"sync"

"github.com/gookit/color"
)

const (
_logLevelEnv = "JFROG_LOG_LEVEL"
)

type Log interface {
Debug(a ...interface{})
Info(a ...interface{})
Warn(a ...interface{})
Error(a ...interface{})
Output(a ...interface{})
GetLogLevel() LevelType
}

var (
// The logger instance
_logger *Logger
// Used to ensure _logger is initialized only once
once sync.Once
)

func GetLogger() *Logger {
once.Do(func() {
_logger = NewLogger(getLogLevel())
})
return _logger
}

type LevelType int

const (
ERROR LevelType = iota
WARN
INFO
DEBUG
)

func getLogLevel() LevelType {
switch strings.ToUpper(os.Getenv(_logLevelEnv)) {
case "ERROR":
return ERROR
case "WARN":
return WARN
case "DEBUG":
return DEBUG
default:
return INFO
}
}

type Logger struct {
LogLevel LevelType
OutputLog *log.Logger
DebugLog *log.Logger
InfoLog *log.Logger
WarnLog *log.Logger
ErrorLog *log.Logger
// Mutex to protect access to the logger
mu sync.Mutex
}

func NewLogger(logLevel LevelType) *Logger {
logger := new(Logger)
logger.SetLogLevel(logLevel)
logger.SetOutputWriter()
logger.SetLogsWriter()
return logger
}

func (logger *Logger) SetLogLevel(levelEnum LevelType) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.LogLevel = levelEnum
}

func (logger *Logger) SetOutputWriter() {
logger.OutputLog = log.New(io.Writer(os.Stdout), "", 0)
}

func (logger *Logger) SetLogsWriter() {
stdErrWriter := io.Writer(os.Stderr)
logger.DebugLog = log.New(stdErrWriter, getLogPrefix(DEBUG), 0)
logger.InfoLog = log.New(stdErrWriter, getLogPrefix(INFO), 0)
logger.WarnLog = log.New(stdErrWriter, getLogPrefix(WARN), 0)
logger.ErrorLog = log.New(stdErrWriter, getLogPrefix(ERROR), 0)
}

var prefixStyles = map[LevelType]struct {
logLevel string
color color.Color
}{
DEBUG: {logLevel: "Debug", color: color.Cyan},
INFO: {logLevel: "Info", color: color.Blue},
WARN: {logLevel: "Warn", color: color.Yellow},
ERROR: {logLevel: "Error", color: color.Red},
}

func getLogPrefix(logType LevelType) string {
if logPrefixStyle, ok := prefixStyles[logType]; ok {
return fmt.Sprintf("[%s] ", logPrefixStyle.logLevel)
}
return ""
}

func Debug(a ...interface{}) {
GetLogger().Debug(a...)
}

func Debugf(format string, a ...interface{}) {
GetLogger().Debug(fmt.Sprintf(format, a...))
}

func Info(a ...interface{}) {
GetLogger().Info(a...)
}

func Infof(format string, a ...interface{}) {
GetLogger().Info(fmt.Sprintf(format, a...))
}

func Warn(a ...interface{}) {
GetLogger().Warn(a...)
}

func Error(a ...interface{}) {
GetLogger().Error(a...)
}

func Output(a ...interface{}) {
GetLogger().Output(a...)
}

func (logger *Logger) GetLogLevel() LevelType {
return logger.LogLevel
}

func (logger *Logger) Debug(a ...interface{}) {
logger.mu.Lock()
defer logger.mu.Unlock()
if logger.GetLogLevel() >= DEBUG {
logger.Println(logger.DebugLog, a...)
}
}

func (logger *Logger) Info(a ...interface{}) {
logger.mu.Lock()
defer logger.mu.Unlock()
if logger.GetLogLevel() >= INFO {
logger.Println(logger.InfoLog, a...)
}
}

func (logger *Logger) Warn(a ...interface{}) {
logger.mu.Lock()
defer logger.mu.Unlock()
if logger.GetLogLevel() >= WARN {
logger.Println(logger.WarnLog, a...)
}
}

func (logger *Logger) Error(a ...interface{}) {
logger.mu.Lock()
defer logger.mu.Unlock()
if logger.GetLogLevel() >= ERROR {
logger.Println(logger.ErrorLog, a...)
}
}

func (logger *Logger) Output(a ...interface{}) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Println(logger.OutputLog, a...)
}

func (logger *Logger) Println(log *log.Logger, values ...interface{}) {
log.Println(values...)
}
67 changes: 67 additions & 0 deletions log/logger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package log

import (
"os"
"testing"

"github.com/stretchr/testify/assert"
)

func SetEnvironmentVariableForLogLevel(t *testing.T, level string) {
assert.NoError(t, os.Setenv(_logLevelEnv, level))
}

func ResetEnvironmentVariableForLogLevel(t *testing.T) {
assert.NoError(t, os.Unsetenv(_logLevelEnv))
}

func TestLogger_WithDefaultInfoLogLevel_LogsInfoAndAbove(t *testing.T) {
// Ensure default INFO level
SetEnvironmentVariableForLogLevel(t, "")
defer ResetEnvironmentVariableForLogLevel(t)

logger := NewLogger(getLogLevel())

assert.Equal(t, INFO, logger.GetLogLevel())
}

func TestLogger_WithEnvironmentVariableSetToDebug_LogsAllLevels(t *testing.T) {
SetEnvironmentVariableForLogLevel(t, "DEBUG")
defer ResetEnvironmentVariableForLogLevel(t)

logger := NewLogger(getLogLevel())

assert.Equal(t, DEBUG, logger.GetLogLevel())
}

func TestLogger_WithEnvironmentVariableSetToError_LogsOnlyErrors(t *testing.T) {
SetEnvironmentVariableForLogLevel(t, "ERROR")
defer ResetEnvironmentVariableForLogLevel(t)

logger := NewLogger(getLogLevel())

assert.Equal(t, ERROR, logger.GetLogLevel())
}

func TestLogger_SetLogLevelChangesLogLevelAtRuntime(t *testing.T) {
logger := NewLogger(INFO)
logger.SetLogLevel(DEBUG)

assert.Equal(t, DEBUG, logger.GetLogLevel())
}

func TestLogger_ConcurrentAccessToSetLogLevel_DoesNotPanic(t *testing.T) {
logger := NewLogger(INFO)

done := make(chan bool)
for i := range 10 {
go func() {
logger.SetLogLevel(LevelType(i % 4))
done <- true
}()
}

for range 10 {
<-done
}
}

0 comments on commit 6ce8b51

Please sign in to comment.