Logging & Error Handling
日志记录
Casbin 可以记录请求、模型加载和策略变更的日志。日志默认关闭。 用 Enforcer.EnableLog() 或通过 NewEnforcer() 的日志器参数开启。输出示例:
2017/07/15 19:43:56 [Request: alice, data1, read ---> true]
备注
Go: 可以接入自定义日志器,Casbin 通过它记录模型、请求、角色和策略。
备注
Python: PyCasbin 使用标准 的 logging 模块。照常配置应用的日志即可;PyCasbin 使用 logging.getLogger()。可选的 logging_config 说明见 pycasbin/util/log.py。配置方法见 Python logging 和 Django logging。
为不同的 enforcer 配置单独的日志器
每个 enforcer 可以有自己的日志器,并且可以在运行时更换。
可以通过 NewEnforcer() 的最后一个参数指定日志器。使用这种方式时,日志器的 enabled 字段优先于 enforcer 的 enabled 参数。
// 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)
支持的日志器
Casbin 提供了几种日志器实现:
| 日志记录器 | 作者 | 描述 |
|---|---|---|
| 默认记录器(内置) | Casbin | 使用 Go 标准 log 包的默认日志器。 |
| Zap记录器 | Casbin | 使用 zap 输出 JSON 格式的日志,并可通过 zap-logger 做更多定制。 |
| 日志记录器 | 作者 | 描述 |
|---|---|---|
| psr3-bridge logger | Casbin | 提供一个符合PSR-3的桥接。 |
实现自定义日志器
自定义日志器必须实现 Logger 接口。
| 方法 | 类型 | 描述 |
|---|---|---|
| EnableLog() | 必需 | 控制是否输出消息。 |
| IsEnabled() | 必需 | 返回当前日志器是否启用。 |
| LogModel() | 必需 | 记录与模型相关的信息。 |
| LogEnforce() | 必需 | 记录与判定相关的信息。 |
| LogRole() | 必需 | 记录与角色相关的信息。 |
| LogPolicy() | 必需 | 记录与策略相关的信息。 |
把自定义日志器传给 Enforcer.SetLogger()。
下面是在 Go 中实现自定义日志器的示例:
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)
}
错误处理
Casbin 中可能因以下原因出现错误或 panic:
- 模型文件(.conf)语法错误
- 策略文件(.csv)语法错误
- 存储适配器返回的自定义错误(例如 MySQL 连接失败)
- Casbin 自身的 bug
有五个主要函数可能产生错误或 panic:
| 函数 | 出错时的行为 |
|---|---|
| NewEnforcer() | 返回一个错误 |
| LoadModel() | 返回一个错误 |
| LoadPolicy() | 返回一个错误 |
| SavePolicy() | 返回一个错误 |
| Enforce() | 返回一个错误 |
备注
NewEnforcer() 内部会调用 LoadModel() 和 LoadPolicy(),所以使用 NewEnforcer() 时无需再单独调用它们。
启用和禁用判定
可以用 Enforcer.EnableEnforce() 禁用 enforcer。禁用后,Enforcer.Enforce() 总是返回 true。策略管理等其他操作不受影响。示例:
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")