首页 > 解决方案 > 找出执行辅助函数的控制器和方法(从辅助函数本身)

问题描述

假设我们有一个辅助函数 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 对象中的位置并不总是相同的,并且从那里提取它并不可靠,至少从我有限的经验来看。

标签: phplaravelbackend

解决方案


您可以使用 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

高级解决方案

应遵循的步骤:

  1. 安装spatie/backtrace
  2. 从控制器中删除 try/catch 块。
  3. 修改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.


  

推荐阅读