Log & Error Handling
日志记录
Casbin默认使用内置的log
将日志打印到控制台,如:
2017/07/15 19:43:56 [Request: alice, data1, read ---> true]
默认情况下不启用日志记录。 您可以通过Enforcer.EnableLog()
或NewEnforcer()
的最后一个参数来切换它。
For Golang: We already support logging the model, enforce request, role, and policy in Golang. 您可以为Casbin定义自己的日志。
For Python: PyCasbin leverages the default Python logging mechanism. PyCasbin makes a call to logging.getLogger()
to set the logger. No special logging configuration is needed other than initializing the logger in the parent application. If no logging is initialized within the parent application, you will not see any log messages from PyCasbin. At the same time, when you enable logs in PyCasbin, you can specify the logging configuration through the parameter logging_config
. If no configuration is specified, it will use the default log configuration. For other PyCasbin extensions, you can refer to the Django logging docs if you are a Django user. 对于其他Python用户,您应参考Python日志文档来配置记录器。
Use different loggers for different enforcers
Every enforcer can have its own logger to log information, and it can be changed at runtime.
And you can use a proper logger via the last parameter of NewEnforcer()
. If you are using this way to initialize your enforcer, you don't need to use the enabled parameter because the priority of the enabled field in the logger is higher.
// Set a default logger as enforcer e1's logger.
// This operation can also be seen as changing the logger of e1 at runtime.
e1.SetLogger(&Log.DefaultLogger{})
// Set another logger as enforcer e2's logger.
e2.SetLogger(&YouOwnLogger)
// Set your logger when initializing enforcer e3.
e3, _ := casbin.NewEnforcer("examples/rbac_model.conf", a, logger)
Supported loggers
We provide some loggers to help you log information.
- Go
- PHP
Logger | Author | Description |
---|---|---|
Default logger (built-in) | Casbin | The default logger using golang log. |
Zap logger | Casbin | Using zap, provide json encoded log and you can customize more with your own zap-logger. |
Logger | Author | 描述 |
---|---|---|
psr3-bridge logger | Casbin | Provides a PSR-3 compliant bridge. |
How to write a logger
Your logger should implement the Logger interface.
Method | Type | Description |
---|---|---|
EnableLog() | mandatory | Control whether to print the message. |
IsEnabled() | mandatory | Show the current logger's enabled status. |
LogModel() | mandatory | Log info related to the model. |
LogEnforce() | mandatory | Log info related to enforcing. |
LogRole() | mandatory | Log info related to the role. |
LogPolicy() | mandatory | Log info related to the policy. |
You can pass your custom logger
to Enforcer.SetLogger()
.
Here is an example of how to customize a logger for Golang:
import (
"fmt"
"log"
"strings"
)
// DefaultLogger is the implementation for a Logger using golang log.
type DefaultLogger struct {
enabled bool
}
func (l *DefaultLogger) EnableLog(enable bool) {
l.enabled = enable
}
func (l *DefaultLogger) IsEnabled() bool {
return l.enabled
}
func (l *DefaultLogger) LogModel(model [][]string) {
if !l.enabled {
return
}
var str strings.Builder
str.WriteString("Model: ")
for _, v := range model {
str.WriteString(fmt.Sprintf("%v\n", v))
}
log.Println(str.String())
}
func (l *DefaultLogger) LogEnforce(matcher string, request []interface{}, result bool, explains [][]string) {
if !l.enabled {
return
}
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))
}
}
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) LogPolicy(policy map[string][][]string) {
if !l.enabled {
return
}
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) LogRole(roles []string) {
if !l.enabled {
return
}
log.Println("Roles: ", roles)
}
Error handling
Errors or panics may occur when you use Casbin for reasons like:
- Invalid syntax in the model file (.conf).
- Invalid syntax in the policy file (.csv).
- Custom errors from storage adapters, e.g., MySQL fails to connect.
- Casbin's bug.
There are five main functions you may need to be aware of for errors or panics:
Function | Behavior on error |
---|---|
NewEnforcer() | Returns an error |
LoadModel() | Returns an error |
LoadPolicy() | Returns an error |
SavePolicy() | Returns an error |
Enforce() | Returns an error |
NewEnforcer()
calls LoadModel()
and LoadPolicy()
internally. So you don't have to call the latter two when using NewEnforcer()
.
Enable and disable
The enforcer can be disabled via the Enforcer.EnableEnforce()
function. When it's disabled, Enforcer.Enforce()
will always return true
. Other operations like adding or removing policies are not affected. Here's an example:
e := casbin.NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv")
// Will return false.
// By default, the enforcer is enabled.
e.Enforce("non-authorized-user", "data1", "read")
// Disable the enforcer at runtime.
e.EnableEnforce(false)
// Will return true for any request.
e.Enforce("non-authorized-user", "data1", "read")
// Enable the enforcer again.
e.EnableEnforce(true)
// Will return false.
e.Enforce("non-authorized-user", "data1", "read")