Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

加入 log level #272

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ type Config struct {
MailDriver string
}

var logger = logging.NewLogger()

func NewDefaultConfig() (*Config, error) {
return NewConfig("./conf/config_default.toml", "config.toml")
}
Expand All @@ -28,6 +26,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 @@ -48,6 +48,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 @@ -141,6 +144,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