在yii2.0.44中,安全获取当前登录用户名需先判断isguest,再访问identity->username;推荐通过扩展filetarget重写formatmessage自动注入用户信息,或使用日志上下文传递结构化用户数据。

在 Yii2.0.44 中,日志记录中想自动带上当前登录用户名,关键不是“写日志”,而是确保日志消息能安全、稳定地访问到已认证用户的用户名,且避免在未登录(isGuest === true)或身份对象不可用时触发错误。
以下是实用、稳妥的实现方式:
直接在日志语句中安全获取用户名
不建议每次都手动判断 isGuest,推荐封装成一个辅助方法,但若仅临时使用,可这样写:
$username = \Yii::$app->user->isGuest ? 'guest' : \Yii::$app->user->identity->username;
\Yii::info("用户 {$username} 执行了XX操作", 'app');
⚠️ 注意:identity 在 isGuest === true 时为 null,直接访问 ->username 会报 PHP Notice 或 Fatal Error。所以必须先判 guest。
在自定义日志目标中统一注入用户名
更规范的做法是扩展 FileTarget 或 DbTarget,重写 formatMessage() 方法,自动追加用户名:
use yii\log\FileTarget;
class UserAwareFileTarget extends FileTarget
{
public function formatMessage($message)
{
$username = \Yii::$app->user->isGuest ? 'guest' : \Yii::$app->user->identity->username;
$prefix = "[user:{$username}] ";
return $prefix . parent::formatMessage($message);
}
}
然后在 config/web.php 的 log 组件中配置:
'log' => [
'targets' => [
[
'class' => 'app\components\UserAwareFileTarget',
'levels' => ['info', 'warning', 'error'],
'categories' => ['app'],
],
],
],
这样所有 Yii::info() 等调用都会自动带前缀,无需每处重复判断。
使用日志上下文(context)传递用户信息
Yii2 支持以数组形式传入额外上下文,适合结构化日志(如写入数据库或 ELK):
\Yii::info('订单创建成功', 'app', [
'user_id' => \Yii::$app->user->isGuest ? null : \Yii::$app->user->id,
'username' => \Yii::$app->user->isGuest ? 'guest' : \Yii::$app->user->identity->username,
'ip' => \Yii::$app->request->userIP,
]);
配合 DbTarget,这些字段可映射到数据库日志表的对应列,便于后续查询与审计。
补充说明
- 不要使用
User::findOne(Yii::$app->user->id)获取用户名——这是冗余查询,identity已是加载好的模型实例; - 若项目启用了
enableAutoLogin,且用户凭 cookie 登录,identity仍可用,无需额外处理; - 在控制台命令(console app)中
Yii::$app->user默认不可用(无 session),若需兼容,请先检查组件是否存在:isset(\Yii::$app->user)。
不复杂但容易忽略。











