php - 找出执行辅助函数的控制器和方法(从辅助函数本身)
问题描述
假设我们有一个辅助函数 logDatabaseError($exception),它将 QueryExceptions 记录到一个特殊的日志中。
助手.php
function logDatabaseError ($exception) {
$controller = ????;
$function = ????;
$log_string = "TIME: ".now().PHP_EOL;
$log_string.= "User ID: ".Auth::user()->id.PHP_EOL;
$log_string.= "Controller->Action:".$controller."->".$function.PHP_EOL;
$log_string.= $exception.PHP_EOL;
Storage::disk('logs')->append('database.log', $log_string);
}
从多个控制器和这些控制器中的多个函数调用此函数。
每当需要将某些内容写入数据库时,在 catch 部分,我们调用此 logDatabaseError 函数并将 \Illuminate\Database\QueryException 作为 $exception 传递给它。
BestControllerEverController.php
class BestControllerEver extends Controller
{
function writeStuffToDatabase (Request $request) {
try {
DB::does-its-thing
}
catch(\Illuminate\Database\QueryException $exception) {
logDatabaseError($exception)
}
}
}
logDatabaseError 函数是否可以在不将它们作为函数参数传递的情况下同时获取控制器名称和函数名称?
在这个特定的示例中,logDatabaseError 函数中的 $controller 和 $function 变量将分别设置为 BestControllerEver 和 writeStuffToDatabase。
我知道这已记录在堆栈跟踪中,但它们在 $exception 对象中的位置并不总是相同的,并且从那里提取它并不可靠,至少从我有限的经验来看。
解决方案
您可以使用 php debug_backtrace函数来跟踪错误帧。由于spatie/backtrace在幕后使用 debug_backtrace 您可以使用该包
通过运行将包安装到应用程序中
composer require spatie/backtrace
把它放在你的控制器中:
try {
\Illuminate\Support\Facades\DB::table('myunavialbetable')->get();
}
catch(\Illuminate\Database\QueryException $exception) {
logDatabaseError($exception);
}
在您的帮助文件中
function logDatabaseError ($exception) {
$backtrace = Spatie\Backtrace\Backtrace::create();
$controllerResponsible = collect($backtrace->frames())
->filter(function(Spatie\Backtrace\Frame $frame){
return ($frame->class);
})
->filter(function(Spatie\Backtrace\Frame $frame){
return is_subclass_of($frame->class, App\Http\Controllers\Controller::class);
})
->first();
$log_string = "TIME: " . now() . PHP_EOL;
$log_string .= "User ID: " . auth()->id() . PHP_EOL;
if ($controllerResponsible){
$log_string .= "Controller->Action:" . $controllerResponsible->class . "->" . $controllerResponsible->method . PHP_EOL;
}
$log_string .= $exception . PHP_EOL;
\Illuminate\Support\Facades\Storage::disk('logs')->append('database.log', $log_string);
// if you want to use on-demand log feature you can uncomment this
//此功能从 Laravel v8.66.0 可用
// Illuminate\Support\Facades\Log::build([
// 'driver' => 'single',
// 'path' => storage_path('logs/database.log'),
// ])->info($log_string);
}
注意:控制器必须扩展
App\Http\Controllers\Controller
高级解决方案
应遵循的步骤:
- 安装spatie/backtrace
- 从控制器中删除 try/catch 块。
- 修改
app/Exceptions/Handler.php
为以下内容
class Handler extends ExceptionHandler
{
public $controllerResponsible = null;
/**
* A list of the exception types that are not reported.
*
* @var array
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var array
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*
* @return void
*/
public function register()
{
$this->reportable(function (Throwable $e) {
$backtraceInstance = SpatieBacktrace::createForThrowable($e);
$controllerResponsible = collect($backtraceInstance->frames())
->filter(function (SpatieBacktraceFrame $frame) {
return ($frame->class);
})
->filter(function (SpatieBacktraceFrame $frame) {
return is_subclass_of($frame->class, \App\Http\Controllers\Controller::class);
})
->first();
$this->controllerResponsible = $controllerResponsible;
});
}
/**
* Get the default context variables for logging.
*
* @return array
*/
protected function context()
{
$extraContext = [];
if ($this->controllerResponsible instanceof SpatieBacktraceFrame) {
$extraContext['controller'] = $this->controllerResponsible->class;
$extraContext['method'] = $this->controllerResponsible->method;
$extraContext['controller@method'] = $this->controllerResponsible->class . '@' . $this->controllerResponsible->method;
}
return array_merge(parent::context(), $extraContext);
}
}```
So here is what happens.
By default you can add exta [content][3] by overriding context method inside `Handler.php`. And you dont need any other custom log. It will be logged by default logging.
推荐阅读
- mongodb - 如何在json中响应时间毫秒为零
- android-studio - 忽略大小写android studio 3代码补全
- android - Android 模拟器的替代解决方案
- javascript - 如何在 Firebase 云功能中传递某个日期后删除子节点?
- dart - 在 Dart 中使用 Mailer/Mailer2 发送 SMTP 电子邮件
- python - 使用一个字典的值作为另一个字典中的键,键的频率作为值,Python 3.6
- php - Woocommerce 可变产品页面上的定位循环输出
- python - 使用 Python 从现在开始计算 ISO 8601 时间格式到小时/分钟
- python-3.x - 执行数学运算时引发 NoneType 错误
- python - 为什么我收到 SyntaxError:编译单个语句时发现多个语句?