Skip to content

Commit

Permalink
feat: [#462] Custom Log Channel cannot take values ​​from some functi…
Browse files Browse the repository at this point in the history
…ons (#640)

* add methods to entry

* chore: update mocks

* add test cases for log

---------

Co-authored-by: kkumar-gcc <[email protected]>
  • Loading branch information
kkumar-gcc and kkumar-gcc authored Sep 14, 2024
1 parent 551f30f commit f5c6941
Show file tree
Hide file tree
Showing 5 changed files with 546 additions and 6 deletions.
16 changes: 16 additions & 0 deletions contracts/log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,20 @@ type Entry interface {
Time() time.Time
// Message returns the message of the entry.
Message() string
// Code returns the associated code.
Code() string
// With returns additional context data.
With() map[string]any
// User returns the user information.
User() any
// Tags returns the list of tags.
Tags() []string
// Owner returns the log's owner.
Owner() any
// Request returns the request data.
Request() map[string]any
// Response returns the response data.
Response() map[string]any
// Trace returns the stack trace or trace data.
Trace() map[string]any
}
48 changes: 44 additions & 4 deletions log/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,18 @@ import (
)

type Entry struct {
ctx context.Context
level log.Level
time time.Time
message string
ctx context.Context
level log.Level
time time.Time
message string
code string
user any
tags []string
owner any
request map[string]any
response map[string]any
with map[string]any
stacktrace map[string]any
}

func (r *Entry) Context() context.Context {
Expand All @@ -29,3 +37,35 @@ func (r *Entry) Time() time.Time {
func (r *Entry) Message() string {
return r.message
}

func (r *Entry) Code() string {
return r.code
}

func (r *Entry) With() map[string]any {
return r.with
}

func (r *Entry) User() any {
return r.user
}

func (r *Entry) Tags() []string {
return r.tags
}

func (r *Entry) Owner() any {
return r.owner
}

func (r *Entry) Request() map[string]any {
return r.request
}

func (r *Entry) Response() map[string]any {
return r.response
}

func (r *Entry) Trace() map[string]any {
return r.stacktrace
}
43 changes: 41 additions & 2 deletions log/logrus_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/rotisserie/eris"
"github.com/sirupsen/logrus"
"github.com/spf13/cast"

"github.com/goravel/framework/contracts/config"
"github.com/goravel/framework/contracts/foundation"
Expand Down Expand Up @@ -365,10 +366,48 @@ func (h *Hook) Levels() []logrus.Level {
}

func (h *Hook) Fire(entry *logrus.Entry) error {
return h.instance.Fire(&Entry{
e := &Entry{
ctx: entry.Context,
level: log.Level(entry.Level),
time: entry.Time,
message: entry.Message,
})
}

data := entry.Data
if len(data) > 0 {
root, err := cast.ToStringMapE(data["root"])
if err != nil {
return err
}

if code, ok := cast.ToStringE(root["code"]); ok == nil {
e.code = code
}

e.user = root["user"]

if tags, ok := cast.ToStringSliceE(root["tags"]); ok == nil {
e.tags = tags
}

e.owner = root["owner"]

if req, err := cast.ToStringMapE(root["tags"]); err == nil {
e.request = req
}

if res, err := cast.ToStringMapE(root["tags"]); err == nil {
e.response = res
}

if context, ok := cast.ToStringMapE(root["context"]); ok == nil {
e.with = context
}

if stacktrace, ok := cast.ToStringMapE(root["stacktrace"]); ok == nil {
e.stacktrace = stacktrace
}
}

return h.instance.Fire(e)
}
71 changes: 71 additions & 0 deletions log/logrus_writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ import (
"os"
"os/exec"
"reflect"
"strings"
"testing"

"github.com/spf13/cast"
"github.com/stretchr/testify/assert"

"github.com/goravel/framework/contracts/filesystem"
contractshttp "github.com/goravel/framework/contracts/http"
logcontracts "github.com/goravel/framework/contracts/log"
contractsession "github.com/goravel/framework/contracts/session"
"github.com/goravel/framework/contracts/validation"
"github.com/goravel/framework/foundation/json"
Expand Down Expand Up @@ -390,6 +393,30 @@ func TestLogrus(t *testing.T) {
_ = file.Remove("storage")
}

func TestLogrusWithCustomLogger(t *testing.T) {
mockConfig := &configmock.Config{}
mockConfig.On("GetString", "logging.default").Return("customLogger").Once()
mockConfig.On("GetString", "logging.channels.customLogger.driver").Return("custom").Twice()
mockConfig.On("Get", "logging.channels.customLogger.via").Return(&CustomLogger{}).Twice()
mockConfig.On("GetString", "app.timezone").Return("UTC")
mockConfig.On("GetString", "app.env").Return("test")

filename := "custom.log"

logger := NewApplication(mockConfig, json.NewJson())
logger.Channel("customLogger").
WithTrace().
With(map[string]any{"filename": filename}).
User(map[string]any{"name": "kkumar-gcc"}).
Owner("[email protected]").
Code("code").Info("Goravel")

expectedContent := "info: Goravel\ncustom_code: code\ncustom_user: map[name:kkumar-gcc]\n"
assert.True(t, file.Contain(filename, expectedContent), "Log file content does not match expected output")

assert.Nil(t, file.Remove(filename))
}

func TestLogrus_Fatal(t *testing.T) {
mockConfig := initMockConfig()
mockDriverConfig(mockConfig)
Expand Down Expand Up @@ -521,6 +548,50 @@ func mockDriverConfig(mockConfig *configmock.Config) {
mockConfig.On("GetString", "app.env").Return("test")
}

type CustomLogger struct {
}

func (logger *CustomLogger) Handle(channel string) (logcontracts.Hook, error) {
return &CustomHook{}, nil
}

type CustomHook struct {
}

func (h *CustomHook) Levels() []logcontracts.Level {
return []logcontracts.Level{
logcontracts.InfoLevel,
}
}

func (h *CustomHook) Fire(entry logcontracts.Entry) error {
with := entry.With()
filename, ok := with["filename"]
if ok {
var builder strings.Builder
message := entry.Message()
if len(message) > 0 {
builder.WriteString(fmt.Sprintf("%s: %v\n", entry.Level(), message))
}

code := entry.Code()
if len(code) > 0 {
builder.WriteString(fmt.Sprintf("custom_code: %v\n", code))
}

user := entry.User()
if user != nil {
builder.WriteString(fmt.Sprintf("custom_user: %v\n", user))
}

err := file.Create(cast.ToString(filename), builder.String())
if err != nil {
return err
}
}
return nil
}

type TestRequest struct{}

func (r *TestRequest) Header(key string, defaultValue ...string) string {
Expand Down
Loading

0 comments on commit f5c6941

Please sign in to comment.