Repository: casbin/casbin
Pull request #644 (2020-11-20 05:34:55)

fix: refactor log
Signed-off-by: Zixuan Liu <nodeces@gmail.com>


Patch:
diff --git a/enforcer.go b/enforcer.go
index 5e77459..ed18fe3 100644
--- a/enforcer.go
+++ b/enforcer.go
@@ -17,8 +17,6 @@ package casbin
 import (
 	"errors"
 	"fmt"
-	"strings"
-
 	"github.com/Knetic/govaluate"
 	"github.com/casbin/casbin/v2/effect"
 	"github.com/casbin/casbin/v2/log"
@@ -538,7 +536,6 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac
 		parameters.pVals = make([]string, len(parameters.pTokens))
 
 		result, err := expression.Eval(parameters)
-		// log.LogPrint("Result: ", result)
 
 		if err != nil {
 			return false, err
@@ -551,51 +548,21 @@ func (e *Enforcer) enforce(matcher string, explains *[]string, rvals ...interfac
 		}
 	}
 
-	// log.LogPrint("Rule Results: ", policyEffects)
-
 	result, explainIndex, err := e.eft.MergeEffects(e.model["e"]["e"].Value, policyEffects, matcherResults)
 	if err != nil {
 		return false, err
 	}
 
+	var logExplains [][]string
+
 	if explains != nil {
+		logExplains = append(logExplains, *explains)
 		if explainIndex != -1 && len(e.model["p"]["p"].Policy) > explainIndex {
 			*explains = e.model["p"]["p"].Policy[explainIndex]
 		}
 	}
 
-	// Log request.
-	if e.logger.IsEnabled() {
-		var reqStr strings.Builder
-		reqStr.WriteString("Request: ")
-		for i, rval := range rvals {
-			if i != len(rvals)-1 {
-				reqStr.WriteString(fmt.Sprintf("%v, ", rval))
-			} else {
-				reqStr.WriteString(fmt.Sprintf("%v", rval))
-			}
-		}
-		reqStr.WriteString(fmt.Sprintf(" ---> %t\n", result))
-
-		if explains != nil {
-			reqStr.WriteString("Hit Policy: ")
-			for i, pval := range *explains {
-				if i != len(*explains)-1 {
-					reqStr.WriteString(fmt.Sprintf("%v, ", pval))
-				} else {
-					reqStr.WriteString(fmt.Sprintf("%v \n", pval))
-				}
-			}
-
-		}
-
-		logType := log.LogTypeGrantedAccessRequest
-		if !result {
-			logType = log.LogTypeRejectedAccessRequest
-		}
-
-		e.logger.LogEnforce(logType, reqStr.String(), &rvals, explains, &[]interface{}{result})
-	}
+	e.logger.LogEnforce(expString, rvals, result, logExplains)
 
 	return result, nil
 }
diff --git a/enforcer_synced.go b/enforcer_synced.go
index 552a77c..4b75de8 100644
--- a/enforcer_synced.go
+++ b/enforcer_synced.go
@@ -20,7 +20,6 @@ import (
 	"time"
 
 	"github.com/Knetic/govaluate"
-	"github.com/casbin/casbin/v2/log"
 	"github.com/casbin/casbin/v2/persist"
 )
 
@@ -65,7 +64,6 @@ func (e *SyncedEnforcer) StartAutoLoadPolicy(d time.Duration) {
 			atomic.StoreInt32(&(e.autoLoadRunning), int32(0))
 		}()
 		n := 1
-		e.logger.LogPolicy(log.LogTypeLoadPolicy, "Start automatically load policy", nil, nil, nil, nil)
 		for {
 			select {
 			case <-ticker.C:
@@ -75,7 +73,6 @@ func (e *SyncedEnforcer) StartAutoLoadPolicy(d time.Duration) {
 				// log.Print("Load policy for time: ", n)
 				n++
 			case <-e.stopAutoLoad:
-				e.logger.LogPolicy(log.LogTypeLoadPolicy, "Stop automatically load policy", nil, nil, nil, nil)
 				return
 			}
 		}
diff --git a/go.mod b/go.mod
index c6c765a..62fe536 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,8 @@
 module github.com/casbin/casbin/v2
 
-require github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible
+require (
+	github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible
+	github.com/golang/mock v1.4.4
+)
 
 go 1.13
diff --git a/go.sum b/go.sum
index d1c7c35..8563487 100644
--- a/go.sum
+++ b/go.sum
@@ -1,2 +1,10 @@
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
diff --git a/log/default_logger.go b/log/default_logger.go
index 9ecf324..650704c 100644
--- a/log/default_logger.go
+++ b/log/default_logger.go
@@ -14,7 +14,11 @@
 
 package log
 
-import "log"
+import (
+	"fmt"
+	"log"
+	"strings"
+)
 
 // DefaultLogger is the implementation for a Logger using golang log.
 type DefaultLogger struct {
@@ -29,54 +33,65 @@ func (l *DefaultLogger) IsEnabled() bool {
 	return l.enabled
 }
 
-func (l *DefaultLogger) LogModel(event int, line []string, model [][]string) {
+func (l *DefaultLogger) LogModel(model [][]string) {
 	if !l.enabled {
 		return
 	}
-
-	for _, v := range line {
-		log.Print(v)
+	var str strings.Builder
+	str.WriteString("Model: ")
+	for _, v := range model {
+		str.WriteString(fmt.Sprintf("%v\n", v))
 	}
-}
 
-func (l *DefaultLogger) LogEnforce(event int, line string, request *[]interface{}, policies *[]string, result *[]interface{}) {
-	if !l.enabled {
-		return
-	}
-
-	log.Print(line)
+	log.Println(str.String())
 }
 
-func (l *DefaultLogger) LogPolicy(event int, line string, pPolicyFormat []string, gPolicyFormat []string, pPolicy *[]interface{}, gPolicy *[]interface{}) {
+func (l *DefaultLogger) LogEnforce(matcher string, request []interface{}, result bool, explains [][]string) {
 	if !l.enabled {
 		return
 	}
 
-	log.Print(line)
-	if pPolicy != nil {
-		for k, v := range *pPolicy {
-			log.Print("p: ", pPolicyFormat[k], ": ", v)
+	var reqStr strings.Builder
+	reqStr.WriteString("Request: ")
+	for i, rval := range request {
+		if i != len(request)-1 {
+			reqStr.WriteString(fmt.Sprintf("%v, ", rval))
+		} else {
+			reqStr.WriteString(fmt.Sprintf("%v", rval))
 		}
 	}
-	if gPolicy != nil {
-		for k, v := range *gPolicy {
-			log.Print("g: ", gPolicyFormat[k], ": ", v)
+	reqStr.WriteString(fmt.Sprintf(" ---> %t\n", result))
+
+	reqStr.WriteString("Hit Policy: ")
+	for i, pval := range explains {
+		if i != len(explains)-1 {
+			reqStr.WriteString(fmt.Sprintf("%v, ", pval))
+		} else {
+			reqStr.WriteString(fmt.Sprintf("%v \n", pval))
 		}
 	}
+
+	log.Println(reqStr.String())
 }
 
-func (l *DefaultLogger) LogRole(event int, line string, role []string) {
+func (l *DefaultLogger) LogPolicy(policy map[string][][]string) {
 	if !l.enabled {
 		return
 	}
 
-	log.Print(line)
+	var str strings.Builder
+	str.WriteString("Policy: ")
+	for k, v := range policy {
+		str.WriteString(fmt.Sprintf("%s : %v\n", k, v))
+	}
+
+	log.Println(str.String())
 }
 
-/*
-func (l *DefaultLogger) Printf(format string, v ...interface{}) {
-	if l.IsEnabled() {
-		log.Printf(format, v...)
+func (l *DefaultLogger) LogRole(roles []string) {
+	if !l.enabled {
+		return
 	}
+
+	log.Println("Roles: ", roles)
 }
-*/
diff --git a/log/log_util.go b/log/log_util.go
index f789ae6..191c817 100644
--- a/log/log_util.go
+++ b/log/log_util.go
@@ -26,34 +26,22 @@ func GetLogger() Logger {
 	return logger
 }
 
-/*
-// LogPrint prints the log.
-func LogPrint(v ...interface{}) {
-	logger.Print(v...)
-}
-
-// LogPrintf prints the log with the format.
-func LogPrintf(format string, v ...interface{}) {
-	logger.Printf(format, v...)
-}
-*/
-
 // LogModel logs the model information.
-func LogModel(event int, line []string, model [][]string) {
-	logger.LogModel(event, line, model)
+func LogModel(model [][]string) {
+	logger.LogModel(model)
 }
 
 // LogEnforce logs the enforcer information.
-func LogEnforce(event int, line string, request *[]interface{}, policies *[]string, result *[]interface{}) {
-	logger.LogEnforce(event, line, request, policies, result)
+func LogEnforce(matcher string, request []interface{}, result bool, explains [][]string) {
+	logger.LogEnforce(matcher, request, result, explains)
 }
 
-// LogRole logs the role information.
-func LogRole(event int, line string, role []string) {
-	logger.LogRole(event, line, role)
+// LogRole log info related to role.
+func LogRole(roles []string) {
+	logger.LogRole(roles)
 }
 
 // LogPolicy logs the policy information.
-func LogPolicy(event int, line string, pPolicyFormat []string, gPolicyFormat []string, pPolicy *[]interface{}, gPolicy *[]interface{}) {
-	logger.LogPolicy(event, line, pPolicyFormat, gPolicyFormat, pPolicy, gPolicy)
+func LogPolicy(policy map[string][][]string) {
+	logger.LogPolicy(policy)
 }
diff --git a/log/logger.go b/log/logger.go
index 6f7c40e..c60e07a 100644
--- a/log/logger.go
+++ b/log/logger.go
@@ -14,39 +14,25 @@
 
 package log
 
-const (
-	LogTypeGrantedAccessRequest = iota
-	LogTypeRejectedAccessRequest
-	LogTypeLoadPolicy
-	LogTypePrintModel
-	LogTypePrintPolicy
-	LogTypePrintRole
-	LogTypeLinkRole
-)
+//go:generate mockgen -destination=./mocks/mock_logger.go -package=mocks github.com/casbin/casbin/v2/log Logger
 
 // Logger is the logging interface implementation.
 type Logger interface {
-	//EnableLog controls whether print the message.
+	// EnableLog controls whether print the message.
 	EnableLog(bool)
 
-	//IsEnabled returns if logger is enabled.
+	// IsEnabled returns if logger is enabled.
 	IsEnabled() bool
 
-	//Print formats using the default formats for its operands and logs the message.
-	//Print(...interface{})
-
-	//Printf formats according to a format specifier and logs the message.
-	//Printf(string, ...interface{})
-
 	// LogModel log info related to model.
-	LogModel(event int, line []string, model [][]string)
+	LogModel(model [][]string)
 
 	// LogEnforce log info related to enforce.
-	LogEnforce(event int, line string, request *[]interface{}, policies *[]string, result *[]interface{})
+	LogEnforce(matcher string, request []interface{}, result bool, explains [][]string)
 
 	// LogRole log info related to role.
-	LogRole(event int, line string, role []string)
+	LogRole(roles []string)
 
 	// LogPolicy log info related to policy.
-	LogPolicy(event int, line string, pPolicyFormat []string, gPolicyFormat []string, pPolicy *[]interface{}, gPolicy *[]interface{})
+	LogPolicy(policy map[string][][]string)
 }
diff --git a/log/mocks/mock_logger.go b/log/mocks/mock_logger.go
new file mode 100644
index 0000000..49d5347
--- /dev/null
+++ b/log/mocks/mock_logger.go
@@ -0,0 +1,107 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: github.com/casbin/casbin/v2/log (interfaces: Logger)
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	gomock "github.com/golang/mock/gomock"
+	reflect "reflect"
+)
+
+// MockLogger is a mock of Logger interface
+type MockLogger struct {
+	ctrl     *gomock.Controller
+	recorder *MockLoggerMockRecorder
+}
+
+// MockLoggerMockRecorder is the mock recorder for MockLogger
+type MockLoggerMockRecorder struct {
+	mock *MockLogger
+}
+
+// NewMockLogger creates a new mock instance
+func NewMockLogger(ctrl *gomock.Controller) *MockLogger {
+	mock := &MockLogger{ctrl: ctrl}
+	mock.recorder = &MockLoggerMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use
+func (m *MockLogger) EXPECT() *MockLoggerMockRecorder {
+	return m.recorder
+}
+
+// EnableLog mocks base method
+func (m *MockLogger) EnableLog(arg0 bool) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "EnableLog", arg0)
+}
+
+// EnableLog indicates an expected call of EnableLog
+func (mr *MockLoggerMockRecorder) EnableLog(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnableLog", reflect.TypeOf((*MockLogger)(nil).EnableLog), arg0)
+}
+
+// IsEnabled mocks base method
+func (m *MockLogger) IsEnabled() bool {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "IsEnabled")
+	ret0, _ := ret[0].(bool)
+	return ret0
+}
+
+// IsEnabled indicates an expected call of IsEnabled
+func (mr *MockLoggerMockRecorder) IsEnabled() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsEnabled", reflect.TypeOf((*MockLogger)(nil).IsEnabled))
+}
+
+// LogEnforce mocks base method
+func (m *MockLogger) LogEnforce(arg0 string, arg1 []interface{}, arg2 bool, arg3 [][]string) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "LogEnforce", arg0, arg1, arg2, arg3)
+}
+
+// LogEnforce indicates an expected call of LogEnforce
+func (mr *MockLoggerMockRecorder) LogEnforce(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LogEnforce", reflect.TypeOf((*MockLogger)(nil).LogEnforce), arg0, arg1, arg2, arg3)
+}
+
+// LogModel mocks base method
+func (m *MockLogger) LogModel(arg0 [][]string) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "LogModel", arg0)
+}
+
+// LogModel indicates an expected call of LogModel
+func (mr *MockLoggerMockRecorder) LogModel(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LogModel", reflect.TypeOf((*MockLogger)(nil).LogModel), arg0)
+}
+
+// LogPolicy mocks base method
+func (m *MockLogger) LogPolicy(arg0 map[string][][]string) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "LogPolicy", arg0)
+}
+
+// LogPolicy indicates an expected call of LogPolicy
+func (mr *MockLoggerMockRecorder) LogPolicy(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LogPolicy", reflect.TypeOf((*MockLogger)(nil).LogPolicy), arg0)
+}
+
+// LogRole mocks base method
+func (m *MockLogger) LogRole(arg0 []string) {
+	m.ctrl.T.Helper()
+	m.ctrl.Call(m, "LogRole", arg0)
+}
+
+// LogRole indicates an expected call of LogRole
+func (mr *MockLoggerMockRecorder) LogRole(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LogRole", reflect.TypeOf((*MockLogger)(nil).LogRole), arg0)
+}
diff --git a/model/assertion.go b/model/assertion.go
index e22b856..5ff4ca4 100644
--- a/model/assertion.go
+++ b/model/assertion.go
@@ -32,7 +32,7 @@ type Assertion struct {
 	PolicyMap map[string]int
 	RM        rbac.RoleManager
 
-	logger *log.Logger
+	logger log.Logger
 }
 
 func (ast *Assertion) buildIncrementalRoleLinks(rm rbac.RoleManager, op PolicyOp, rules [][]string) error {
@@ -85,11 +85,9 @@ func (ast *Assertion) buildRoleLinks(rm rbac.RoleManager) error {
 		}
 	}
 
-	(*ast.logger).LogRole(log.LogTypeLinkRole, "Role links for: "+ast.Key, []string{ast.Key})
-
-	return ast.RM.PrintRoles()
+	return nil
 }
 
 func (ast *Assertion) setLogger(logger log.Logger) {
-	ast.logger = &logger
+	ast.logger = logger
 }
diff --git a/model/model.go b/model/model.go
index b0a3770..c297f48 100644
--- a/model/model.go
+++ b/model/model.go
@@ -99,15 +99,15 @@ func loadSection(model Model, cfg config.ConfigInterface, sec string) {
 func (model Model) SetLogger(logger log.Logger) {
 	for _, astMap := range model {
 		for _, ast := range astMap {
-			ast.logger = &logger
+			ast.logger = logger
 		}
 	}
-	model["logger"] = AssertionMap{"logger": &Assertion{logger: &logger}}
+	model["logger"] = AssertionMap{"logger": &Assertion{logger: logger}}
 }
 
 // GetLogger returns the model's logger.
 func (model Model) GetLogger() log.Logger {
-	return *model["logger"]["logger"].logger
+	return model["logger"]["logger"].logger
 }
 
 // NewModel creates an empty model.
@@ -189,7 +189,6 @@ func (model Model) PrintModel() {
 		return
 	}
 
-	logInfo := []string{"Model: "}
 	var modelInfo [][]string
 	for k, v := range model {
 		if k == "logger" {
@@ -198,9 +197,8 @@ func (model Model) PrintModel() {
 
 		for i, j := range v {
 			modelInfo = append(modelInfo, []string{k, i, j.Value})
-			logInfo = append(logInfo, fmt.Sprintf("%s.%s: %s", k, i, j.Value))
 		}
 	}
 
-	model.GetLogger().LogModel(log.LogTypePrintModel, logInfo, modelInfo)
+	model.GetLogger().LogModel(modelInfo)
 }
diff --git a/model/policy.go b/model/policy.go
index 3e15c88..6b70b41 100644
--- a/model/policy.go
+++ b/model/policy.go
@@ -17,7 +17,6 @@ package model
 import (
 	"strings"
 
-	"github.com/casbin/casbin/v2/log"
 	"github.com/casbin/casbin/v2/rbac"
 	"github.com/casbin/casbin/v2/util"
 )
@@ -60,24 +59,29 @@ func (model Model) PrintPolicy() {
 		return
 	}
 
-	var (
-		pPolicy       []interface{} // or [][][]string
-		gPolicy       []interface{}
-		pPolicyFormat []string
-		gPolicyFormat []string
-	)
+	policy := make(map[string][][]string)
 
-	for _, ast := range model["p"] {
-		pPolicyFormat = append(pPolicyFormat, ast.Value)
-		pPolicy = append(pPolicy, ast.Policy)
+	for key, ast := range model["p"] {
+		value, found := policy[key]
+		if found {
+			value = append(value, ast.Policy...)
+			policy[key] = value
+		} else {
+			policy[key] = ast.Policy
+		}
 	}
 
-	for _, ast := range model["g"] {
-		gPolicyFormat = append(gPolicyFormat, ast.Value)
-		gPolicy = append(gPolicy, ast.Policy)
+	for key, ast := range model["g"] {
+		value, found := policy[key]
+		if found {
+			value = append(value, ast.Policy...)
+			policy[key] = value
+		} else {
+			policy[key] = ast.Policy
+		}
 	}
 
-	model.GetLogger().LogPolicy(log.LogTypePrintPolicy, "Policy: ", pPolicyFormat, gPolicyFormat, &pPolicy, &gPolicy)
+	model.GetLogger().LogPolicy(policy)
 }
 
 // ClearPolicy clears all current policy.
diff --git a/rbac/default-role-manager/role_manager.go b/rbac/default-role-manager/role_manager.go
index 9621b4a..b46381b 100644
--- a/rbac/default-role-manager/role_manager.go
+++ b/rbac/default-role-manager/role_manager.go
@@ -36,7 +36,7 @@ type RoleManager struct {
 	hasDomainPattern   bool
 	domainMatchingFunc MatchingFunc
 
-	logger *log.Logger
+	logger log.Logger
 }
 
 // NewRoleManager is the constructor for creating an instance of the
@@ -68,7 +68,7 @@ func (rm *RoleManager) AddDomainMatchingFunc(name string, fn MatchingFunc) {
 
 // SetLogger sets role manager's logger.
 func (rm *RoleManager) SetLogger(logger log.Logger) {
-	rm.logger = &logger
+	rm.logger = logger
 }
 
 func (rm *RoleManager) generateTempRoles(domain string) *Roles {
@@ -237,22 +237,15 @@ func (rm *RoleManager) GetUsers(name string, domain ...string) ([]string, error)
 
 // PrintRoles prints all the roles to log.
 func (rm *RoleManager) PrintRoles() error {
-	if !(*rm.logger).IsEnabled() {
+	if !(rm.logger).IsEnabled() {
 		return nil
 	}
 
-	var sb strings.Builder
 	var roles []string
 	rm.allDomains.Range(func(_, value interface{}) bool {
 		value.(*Roles).Range(func(_, value interface{}) bool {
 			if text := value.(*Role).toString(); text != "" {
-				if sb.Len() == 0 {
-					sb.WriteString(text)
-				} else {
-					roles = append(roles, text)
-					sb.WriteString(", ")
-					sb.WriteString(text)
-				}
+				roles = append(roles, text)
 			}
 			return true
 		})
@@ -260,7 +253,7 @@ func (rm *RoleManager) PrintRoles() error {
 		return true
 	})
 
-	(*rm.logger).LogRole(log.LogTypePrintRole, sb.String(), roles)
+	rm.logger.LogRole(roles)
 	return nil
 }
 


Test patch:
diff --git a/log/log_util_test.go b/log/log_util_test.go
index e989798..7b72b40 100644
--- a/log/log_util_test.go
+++ b/log/log_util_test.go
@@ -15,54 +15,42 @@
 package log
 
 import (
-	"reflect"
 	"testing"
-)
 
-type LoggerTester struct {
-	event       int
-	line        string
-	lastMessage []interface{}
-}
+	"github.com/casbin/casbin/v2/log/mocks"
 
-func (t *LoggerTester) EnableLog(bool)  {}
-func (t *LoggerTester) IsEnabled() bool { return true }
+	"github.com/golang/mock/gomock"
+)
 
-func (t *LoggerTester) LogModel(event int, line []string, model [][]string) {
-	t.event = event
-	t.line = ""
-	t.lastMessage = []interface{}{model}
-}
+func TestLog(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	defer ctrl.Finish()
 
-func (t *LoggerTester) LogEnforce(event int, line string, request *[]interface{}, policies *[]string, result *[]interface{}) {
-	t.event = event
-	t.line = ""
-	t.lastMessage = *request
-}
+	m := mocks.NewMockLogger(ctrl)
+	SetLogger(m)
 
-func (t *LoggerTester) LogRole(event int, line string, role []string) {
-	t.event = event
-	t.line = ""
-	t.lastMessage = []interface{}{role}
-}
+	m.EXPECT().EnableLog(true)
+	m.EXPECT().IsEnabled()
 
-func (t *LoggerTester) LogPolicy(event int, line string, pPolicyFormat []string, gPolicyFormat []string, pPolicy *[]interface{}, gPolicy *[]interface{}) {
-	t.event = event
-	t.line = ""
-	t.lastMessage = []interface{}{pPolicyFormat, gPolicyFormat, pPolicy, gPolicy}
-}
+	logger.EnableLog(true)
+	logger.IsEnabled()
 
-func TestLog(t *testing.T) {
-	lt := &LoggerTester{}
-	SetLogger(lt)
+	policy := map[string][][]string{}
+	m.EXPECT().LogPolicy(policy)
+	LogPolicy(policy)
+
+	var model [][]string
+	m.EXPECT().LogModel(model)
+	LogModel(model)
 
-	LogEnforce(1, "2", &[]interface{}{"3"}, &[]string{"4"}, &[]interface{}{true})
-	if lt.event != 1 || lt.line != "" || !reflect.DeepEqual(lt.lastMessage, []interface{}{"3"}) {
-		t.Errorf("incorrect logger message: %+v", lt.lastMessage)
-	}
+	matcher := "my_matcher"
+	request := []interface{}{"bob"}
+	result := true
+	var explains [][]string
+	m.EXPECT().LogEnforce(matcher, request, result, explains)
+	LogEnforce(matcher, request, result, explains)
 
-	LogModel(1, []string{"2"}, [][]string{{"3", "4"}})
-	if lt.event != 1 || lt.line != "" || !reflect.DeepEqual(lt.lastMessage, []interface{}{[][]string{{"3", "4"}}}) {
-		t.Errorf("incorrect logger message: %+v", lt.lastMessage)
-	}
+	var roles []string
+	m.EXPECT().LogRole(roles)
+	LogRole(roles)
 }