Skip to content

Commit

Permalink
Merge pull request #272 from karta0807913/feature/#29-#debug-level
Browse files Browse the repository at this point in the history
加入 log level
  • Loading branch information
PichuChen authored Oct 3, 2021
2 parents dfa60a5 + 8ef19e0 commit bc314b6
Show file tree
Hide file tree
Showing 9 changed files with 232 additions and 30 deletions.
5 changes: 3 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ type Config struct {
MailDriver string
}

var logger = logging.NewLogger()

func NewDefaultConfig() (*Config, error) {
return NewConfig("./conf/config_default.toml", "config.toml")
}
Expand All @@ -29,6 +27,8 @@ func NewDefaultConfig() (*Config, error) {
// return error. it userPath can not be read, it will ignore userPath.
// user configuration will override default configuration.
func NewConfig(defaultPath, userPath string) (*Config, error) {
var logger = logging.NewLogger()

config := &Config{}
logger.Debugf("load default config")

Expand All @@ -49,6 +49,7 @@ func NewConfig(defaultPath, userPath string) (*Config, error) {
}

func applyConfig(config *Config, rawConfig *toml.Tree) {
var logger = logging.NewLogger()
logger.Debugf("apply rawConfig")
var s string
var i int64
Expand Down
3 changes: 0 additions & 3 deletions internal/delivery/http/route_classes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ package http

import (
"context"
// "github.com/Ptt-official-app/go-bbs"
// "github.com/Ptt-official-app/go-bbs/crypt"
// "log"
"encoding/json"
"fmt"
"net/http"
Expand Down
5 changes: 2 additions & 3 deletions internal/delivery/http/route_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package http
import (
"context"
"encoding/json"
"log"
"net/http"
"strings"

Expand Down Expand Up @@ -64,7 +63,7 @@ func (delivery *Delivery) postToken(w http.ResponseWriter, r *http.Request) {

}

log.Println("found user:", userec)
delivery.logger.Debugf("found user: %s", userec)
err = delivery.verifyPassword(userec, password)
if err != nil {
// TODO: add delay, warning, notify user
Expand Down Expand Up @@ -98,7 +97,7 @@ func (delivery *Delivery) postToken(w http.ResponseWriter, r *http.Request) {
}

func (delivery *Delivery) verifyPassword(userec bbs.UserRecord, password string) error {
log.Println("password", userec.HashedPassword())
delivery.logger.Debugf("password: %s", userec.HashedPassword())
return userec.VerifyPassword(password)
}

Expand Down
124 changes: 105 additions & 19 deletions internal/logging/logger.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,60 @@
package logging

import (
"log"
"fmt"
"os"
"strconv"
"time"
)

type LogSetting struct {
Color string
Name string
Level uint
}

// level defined in RFC 5424
var (
Emergency LogSetting = LogSetting{
Color: "\x1b[41m",
Name: "EMERGENCY",
Level: 0,
}
Alert LogSetting = LogSetting{
Color: "\x1b[30;43m",
Name: "ALERT",
Level: 1,
}
Critical LogSetting = LogSetting{
Color: "\x1b[41m",
Name: "CRITICAL",
Level: 2,
}
Error LogSetting = LogSetting{
Color: "\x1b[31;103m",
Name: "ERROR",
Level: 3,
}
Warning LogSetting = LogSetting{
Color: "\x1b[33m",
Name: "WARN",
Level: 4,
}
Notice LogSetting = LogSetting{
Color: "\x1b[32m",
Name: "NOTICE",
Level: 5,
}
Informational LogSetting = LogSetting{
Color: "\x1b[34m",
Name: "INFO",
Level: 6,
}
Debug LogSetting = LogSetting{
Color: "\x1b[32m",
Name: "DEBUG",
Level: 7,
}
)

// Logger is the interface that wraps the basic Logging methods.
Expand All @@ -24,50 +77,83 @@ type Logger interface {
Informationalf(f string, v ...interface{})
// Debug: debug-level messages
Debugf(f string, v ...interface{})
// function for apply color and output to target file
Logf(f string, setting LogSetting, v ...interface{})
}

type logger struct{}
type logger struct {
output *os.File
level uint
}

func NewLogger() Logger {
return &logger{}
level, err := strconv.Atoi(os.Getenv("LOG_LEVEL"))
if err != nil {
fmt.Println(err)
level = 7
}
return &logger{
output: os.Stderr,
level: uint(level),
}
}

// Emergencyf implements Logger.Emergencyf by printing Emergency level messages to standard output.
// Emergencyf implements Logger.Emergencyf by printing Emergency level messages to Logger.output.
func (l *logger) Emergencyf(f string, v ...interface{}) {
log.Printf(f, v...)
l.Logf(f, Emergency, v...)
}

// Alertf implements Logger.Alertf by printing Alert level messages to standard output.
// Alertf implements Logger.Alertf by printing Alert level messages to Logger.output.
func (l *logger) Alertf(f string, v ...interface{}) {
log.Printf(f, v...)
l.Logf(f, Alert, v...)
}

// Criticalf implements Logger.Criticalf by printing Critical level messages to standard output.
// Criticalf implements Logger.Criticalf by printing Critical level messages to Logger.output.
func (l *logger) Criticalf(f string, v ...interface{}) {
log.Printf(f, v...)
l.Logf(f, Critical, v...)
}

// Errorf implements Logger.Errorf by printing Error level messages to standard output.
// Errorf implements Logger.Errorf by printing Error level messages to Logger.output.
func (l *logger) Errorf(f string, v ...interface{}) {
log.Printf(f, v...)
l.Logf(f, Error, v...)
}

// Warningf implements Logger.Warningf by printing Warning level messages to standard output.
// Warningf implements Logger.Warningf by printing Warning level messages to Logger.output.
func (l *logger) Warningf(f string, v ...interface{}) {
log.Printf(f, v...)
l.Logf(f, Warning, v...)
}

// Noticef implements Logger.Noticef by printing Notice level messages to standard output.
// Noticef implements Logger.Noticef by printing Notice level messages to Logger.output.
func (l *logger) Noticef(f string, v ...interface{}) {
log.Printf(f, v...)
l.Logf(f, Notice, v...)
}

// Informationalf implements Logger.Informationalf by printing Informational level messages to standard output.
// Informationalf implements Logger.Informationalf by printing Informational level messages to Logger.output.
func (l *logger) Informationalf(f string, v ...interface{}) {
log.Printf(f, v...)
l.Logf(f, Informational, v...)
}

// Debugf implements Logger.Debugf by printing Debug level messages to standard output.
// Debugf implements Logger.Debugf by printing Debug level messages to logger.output.
func (l *logger) Debugf(f string, v ...interface{}) {
log.Printf(f, v...)
l.Logf(f, Debug, v...)
}

// Logf implements Logger.Logf by printing messages to logger.output with LogSetting.
func (l *logger) Logf(f string, setting LogSetting, v ...interface{}) {
if l.level >= setting.Level {
fileinfo, err := l.output.Stat()
outStr := time.Now().Format("2006-01-02 15:04:05")
if err != nil || (fileinfo.Mode()&os.ModeCharDevice) == 0 {
outStr += " " + setting.Name + " "
} else {
outStr += " " + setting.Color + setting.Name + "\x1b[0m "
}

outStr += fmt.Sprintf(f, v...)
outStr += "\n"
_, err = l.output.WriteString(outStr)
if err != nil {
os.Stderr.WriteString(err.Error())
}
}
}
100 changes: 100 additions & 0 deletions internal/logging/logger_test.go
Original file line number Diff line number Diff line change
@@ -1 +1,101 @@
package logging

import (
"bufio"
"io"
"io/ioutil"
"log"
"os"
"strconv"
"strings"
"testing"
)

// newFile returns a temporally file
func newFile(testName string, t *testing.T) (f *os.File) {
f, err := ioutil.TempFile(t.TempDir(), "_Ptt-backend_"+testName)
if err != nil {
t.Fatalf("TempFile %s: %s", testName, err)
}
return
}

var settingList []LogSetting = []LogSetting{
Emergency,
Alert,
Critical,
Error,
Warning,
Notice,
Informational,
Debug,
}

func testLoggerLevel(t *testing.T, targetLevel uint) {
tempFile := newFile("testing level "+strconv.Itoa(int(targetLevel)), t)
testLogger := &logger{
output: tempFile,
level: targetLevel,
}
defer func() {
tempFile.Close()
os.Remove(tempFile.Name())
}()
testLogger.Emergencyf("")
testLogger.Alertf("")
testLogger.Criticalf("")
testLogger.Errorf("")
testLogger.Warningf("")
testLogger.Noticef("")
testLogger.Informationalf("")
testLogger.Debugf("")
_, err := tempFile.Seek(0, 0)
if err != nil {
log.Fatalf("Get error %s\n", err.Error())
}
reader := bufio.NewReader(tempFile)
idx := 0
for line, _, err := reader.ReadLine(); ; line, _, err = reader.ReadLine() {
if err == io.EOF {
break
}
if err != nil {
t.Fatalf("Get error %s", err.Error())
}
result := strings.Split(string(line), " ")
// result[0]: 2006-01-02
// result[1]: 15:04:05
if idx > int(targetLevel) {
t.Fatalf("Unexpect LogLevel %s", result[2])
}
if result[2] != settingList[idx].Name {
t.Fatalf("Expect log level %s, but get %s", settingList[idx].Name, result[2])
}
idx++
}

if idx-1 != int(targetLevel) {
t.Fatalf("Missing Log Level %d: \"%s\"", idx, settingList[idx].Name)
}
}

func TestLogger(t *testing.T) {
testLoggerLevel(t, 7)
testLoggerLevel(t, 6)
testLoggerLevel(t, 5)
testLoggerLevel(t, 4)
testLoggerLevel(t, 3)
testLoggerLevel(t, 2)
testLoggerLevel(t, 1)
testLoggerLevel(t, 0)
os.Setenv("LOG_LEVEL", "4")
testLogger := NewLogger()
if testLogger.(*logger).level != 4 {
t.Fatalf("Expect logger level is 4, get %d", testLogger.(*logger).level)
}
os.Setenv("LOG_LEVEL", "")
testLogger = NewLogger()
if testLogger.(*logger).level != 7 {
t.Fatalf("Expect logger level is 7, get %d", testLogger.(*logger).level)
}
}
2 changes: 2 additions & 0 deletions internal/repository/board.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"

"github.com/Ptt-official-app/Ptt-backend/internal/logging"
"github.com/Ptt-official-app/go-bbs"
)

Expand Down Expand Up @@ -40,6 +41,7 @@ func (repo *repository) GetBoardTreasureRecords(_ context.Context, boardID strin
// }

func loadBoardFile(db *bbs.DB) ([]bbs.BoardRecord, error) {
var logger = logging.NewLogger()
boardRecords, err := db.ReadBoardRecords()
if err != nil {
logger.Errorf("get board header error: %v", err)
Expand Down
3 changes: 0 additions & 3 deletions internal/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@ import (
"context"
"fmt"

"github.com/Ptt-official-app/Ptt-backend/internal/logging"
"github.com/Ptt-official-app/go-bbs"
)

var logger = logging.NewLogger()

// Repository directly interacts with database via db handler.
type Repository interface {

Expand Down
4 changes: 4 additions & 0 deletions internal/repository/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"context"
"fmt"

"github.com/Ptt-official-app/Ptt-backend/internal/logging"
"github.com/Ptt-official-app/go-bbs"

// TODO: remove direct access pttbbs, implement it in go-bbs package
"github.com/Ptt-official-app/go-bbs/pttbbs"
)
Expand Down Expand Up @@ -63,6 +65,7 @@ func (repo *repository) GetUserArticles(_ context.Context, boardID string) ([]bb

// TODO: no required method in go-bbs and we use a mock, replace it when available
func (repo *repository) GetUserPreferences(_ context.Context, userID string) (map[string]string, error) {
var logger = logging.NewLogger()
var u bbs.UserRecord = nil
for _, it := range repo.userRecords {
if it.UserID() == userID {
Expand Down Expand Up @@ -146,6 +149,7 @@ func (repo *repository) DeleteUserDraft(_ context.Context, userID, draftID strin
}

func loadUserRecords(db *bbs.DB) ([]bbs.UserRecord, error) {
var logger = logging.NewLogger()
userRecords, err := db.ReadUserRecords()
if err != nil {
logger.Errorf("get user rec error: %v", err)
Expand Down
Loading

0 comments on commit bc314b6

Please sign in to comment.