Skip to content
This repository has been archived by the owner on Sep 13, 2023. It is now read-only.

Commit

Permalink
Merge pull request #18 from palavrapasse/14-feat-allow-clients-to-spe…
Browse files Browse the repository at this point in the history
…cify-logging-levels-to-enable

feat: allow clients to specify logging levels to enable
  • Loading branch information
rutesantos4 authored Feb 11, 2023
2 parents 0a1e51a + dd620e7 commit c23da16
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 34 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This repository is configured with client-side Git hooks which you need to insta
- Log to console
- Log to file
- Log to Telegram chat
- Log only for specific levels


## Usage
Expand Down Expand Up @@ -44,14 +45,14 @@ import (
)

func main() {
fileClient, err := aspirador.NewFileClient("filename.log")
fileClient, err := aspirador.NewFileClient("filename.log") // Will print all Levels (TRACE, INFO, WARNING, ERROR) logs
if err != nil {
return
}

consoleClient := aspirador.NewConsoleClient()
consoleClient := aspirador.NewConsoleClient(aspirador.WARNING, aspirador.ERROR) // Will only print Warning and Error logs

telegramClient := aspirador.NewTelegramClient("telegram_bot_token", "chat_id")
telegramClient := aspirador.NewTelegramClient("telegram_bot_token", "chat_id", aspirador.ERROR) // Will only print Error logs

clients := []aspirador.Client{fileClient, consoleClient, telegramClient}

Expand Down
6 changes: 4 additions & 2 deletions pkg/aspirador.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ func (as Aspirador) log(lvl Level, msg string) {
Message: msg,
}

for _, v := range as.clients {
v.Write(record)
for _, c := range as.clients {
if c.SupportsLevel(lvl) {
c.Write(record)
}
}

}
1 change: 1 addition & 0 deletions pkg/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ package pkg

type Client interface {
Write(ar Record)
SupportsLevel(l Level) bool
}
23 changes: 14 additions & 9 deletions pkg/consoleclient.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
package pkg

import (
"log"
"os"
)

type ConsoleClient struct {
loggers []*log.Logger
loggers LevelLogger
}

func NewConsoleClient() ConsoleClient {
loggers := make([]*log.Logger, len(levelPrefix))

for i, v := range levelPrefix {
loggers[i] = log.New(os.Stdout, v, defaultLoggerFlag)
}
func NewConsoleClient(levels ...Level) ConsoleClient {
loggers := NewLevelLogger(os.Stdout, defaultLoggerFlag, levels)

return ConsoleClient{
loggers: loggers,
}
}

func (cc ConsoleClient) Write(ar Record) {
cc.loggers[ar.Level].Println(ar.Message)
logger, exists := cc.loggers[ar.Level]

if !exists {
return
}

logger.Println(ar.Message)
}

func (cc ConsoleClient) SupportsLevel(l Level) bool {
return cc.loggers.ContainsLevel(l)
}
23 changes: 14 additions & 9 deletions pkg/fileclient.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
package pkg

import (
"log"
"os"
)

type FileClient struct {
loggers []*log.Logger
loggers LevelLogger
}

func NewFileClient(fp string) (FileClient, error) {
func NewFileClient(fp string, levels ...Level) (FileClient, error) {
file, err := os.OpenFile(fp, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0770)

if err != nil {
return FileClient{}, err
}

loggers := make([]*log.Logger, len(levelPrefix))

for i, v := range levelPrefix {
loggers[i] = log.New(file, v, defaultLoggerFlag)
}
loggers := NewLevelLogger(file, defaultLoggerFlag, levels)

return FileClient{
loggers: loggers,
}, nil
}

func (fc FileClient) Write(ar Record) {
fc.loggers[ar.Level].Println(ar.Message)
logger, exists := fc.loggers[ar.Level]

if !exists {
return
}

logger.Println(ar.Message)
}

func (fc FileClient) SupportsLevel(l Level) bool {
return fc.loggers.ContainsLevel(l)
}
30 changes: 30 additions & 0 deletions pkg/levellogger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package pkg

import (
"io"
"log"
)

type LevelLogger map[Level]*log.Logger

func NewLevelLogger(out io.Writer, flag int, levels []Level) LevelLogger {
size := len(levels)

if size == 0 {
levels = []Level{TRACE, INFO, WARNING, ERROR}
size = len(levels)
}

result := make(map[Level]*log.Logger, size)

for _, v := range levels {
result[v] = log.New(out, levelPrefix[v], flag)
}

return result
}

func (ll LevelLogger) ContainsLevel(l Level) bool {
_, exists := ll[l]
return exists
}
150 changes: 150 additions & 0 deletions pkg/levellogger_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package pkg

import (
"os"
"testing"
)

func TestNewLevelLoggerWithoutLevelsReturnsLevelLoggerWithLenght4(t *testing.T) {

result := NewLevelLogger(os.Stdout, defaultLoggerFlag, []Level{})
size := len(result)

if size != 4 {
t.Fatalf("No levels provided so it should return a map with 4 elements, but it has %d", size)
}
}

func TestNewLevelLoggerWithTRACELevelReturnsLevelLoggerWithTRACELevel(t *testing.T) {

result := NewLevelLogger(os.Stdout, defaultLoggerFlag, []Level{TRACE})

_, ok := result[TRACE]

if !ok {
t.Fatalf("No levels provided so it should return a map with TRACE level")
}
}

func TestNewLevelLoggerWithTRACELevelReturnsLevelLoggerWithLength1(t *testing.T) {

result := NewLevelLogger(os.Stdout, defaultLoggerFlag, []Level{TRACE})
size := len(result)

if size != 1 {
t.Fatalf("One level provided so it should return a map with 1 elements, but it has %d", size)
}
}

func TestNewLevelLoggerWithINFOLevelReturnsLevelLoggerWithINFOLevel(t *testing.T) {

result := NewLevelLogger(os.Stdout, defaultLoggerFlag, []Level{INFO})

_, ok := result[INFO]

if !ok {
t.Fatalf("No levels provided so it should return a map with INFO level")
}
}

func TestNewLevelLoggerWithINFOLevelReturnsLevelLoggerWithLength1(t *testing.T) {

result := NewLevelLogger(os.Stdout, defaultLoggerFlag, []Level{INFO})
size := len(result)

if size != 1 {
t.Fatalf("One level provided so it should return a map with 1 elements, but it has %d", size)
}
}

func TestNewLevelLoggerWithoutLevelsReturnsLevelLoggerWithWARNINGLevel(t *testing.T) {

result := NewLevelLogger(os.Stdout, defaultLoggerFlag, []Level{WARNING})

_, ok := result[WARNING]

if !ok {
t.Fatalf("No levels provided so it should return a map with WARNING level")
}
}

func TestNewLevelLoggerWithWARNINGLevelReturnsLevelLoggerWithLenght1(t *testing.T) {

result := NewLevelLogger(os.Stdout, defaultLoggerFlag, []Level{WARNING})
size := len(result)

if size != 1 {
t.Fatalf("One level provided so it should return a map with 1 elements, but it has %d", size)
}
}

func TestNewLevelLoggerWithERRORLevelReturnsLevelLoggerWithERRORLevel(t *testing.T) {

result := NewLevelLogger(os.Stdout, defaultLoggerFlag, []Level{ERROR})

_, ok := result[ERROR]

if !ok {
t.Fatalf("No levels provided so it should return a map with ERROR level")
}
}

func TestNewLevelLoggerWithERRORLevelReturnsLevelLoggerWithLenght1(t *testing.T) {

result := NewLevelLogger(os.Stdout, defaultLoggerFlag, []Level{TRACE})
size := len(result)

if size != 1 {
t.Fatalf("One level provided so it should return a map with 1 elements, but it has %d", size)
}
}

func TestNewLevelLoggerWithMultipleLevelsReturnsLevelLoggerWithTheSameLenghtAsTheLevels(t *testing.T) {

levels := []Level{TRACE, WARNING}
result := NewLevelLogger(os.Stdout, defaultLoggerFlag, levels)

expected := len(levels)
size := len(result)

if size != expected {
t.Fatalf("%d levels provided so it should return a map with %d elements, but it has %d", expected, expected, size)
}
}

func TestNewLevelLoggerWithMultipleLevelsReturnsLevelLoggerWithTheLevelsProvided(t *testing.T) {

levels := []Level{TRACE, WARNING}
result := NewLevelLogger(os.Stdout, defaultLoggerFlag, levels)

for _, v := range levels {
_, ok := result[v]

if !ok {
t.Fatalf("No levels provided so it should return a map with %d level", v)
}

}
}

func TestContaisLevelWithLevelPresentReturnsTrue(t *testing.T) {

levels := []Level{TRACE}
ll := NewLevelLogger(os.Stdout, defaultLoggerFlag, levels)
result := ll.ContainsLevel(TRACE)

if !result {
t.Fatalf("Level is present in LevelLogger so it should return true")
}
}

func TestContaisLevelWithLevelNotPresentReturnsFalse(t *testing.T) {

levels := []Level{TRACE}
ll := NewLevelLogger(os.Stdout, defaultLoggerFlag, levels)
result := ll.ContainsLevel(ERROR)

if result {
t.Fatalf("Level is not present in LevelLogger so it should return false")
}
}
18 changes: 7 additions & 11 deletions pkg/telegramclient.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
package pkg

import (
"log"
)

const messageType = "application/json"

type TelegramClient struct {
loggers []*log.Logger
loggers LevelLogger
}

func NewTelegramClient(botToken, chatId string) TelegramClient {
func NewTelegramClient(botToken, chatId string, levels ...Level) TelegramClient {
tw := TelegramWriter{
botToken: botToken,
chatId: chatId,
}

loggers := make([]*log.Logger, len(levelPrefix))

for i, v := range levelPrefix {
loggers[i] = log.New(tw, v, defaultLoggerFlag)
}
loggers := NewLevelLogger(tw, defaultLoggerFlag, levels)

return TelegramClient{
loggers: loggers,
Expand All @@ -30,3 +22,7 @@ func NewTelegramClient(botToken, chatId string) TelegramClient {
func (tc TelegramClient) Write(ar Record) {
tc.loggers[ar.Level].Println(ar.Message)
}

func (tc TelegramClient) SupportsLevel(l Level) bool {
return tc.loggers.ContainsLevel(l)
}

0 comments on commit c23da16

Please sign in to comment.