<?php
namespace App\Providers;
use App\Exceptions\ApiException;
use App\Exceptions\Handler;
use Carbon\Carbon;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\QueryException;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
/**
* Class AppServiceProvider.
*/
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot(Request $request)
{
//生成log鏈條
$requestId = (string) Str::uuid();
$context = ['request_id' => $requestId];
collect(config('logging.channels'))->keys()->map(function ($channel) use ($context) {
if (! in_array($channel, ['slack', 'papertrail', 'emergency', 'sql'])) {
Log::channel($channel)->withContext($context);
}
});
$path = request()->path();
$arr_ignore = ['/'];
if (! in_array($path, $arr_ignore)) {
logger($path.' '.json_encode($request->input(), 256));
}
//儲存request_id到app
$this->app->singleton('request_id', function () use ($requestId) {
return $requestId;
});
//本地化 Carbon
Carbon::setLocale('zh');
//開啟db log
DB::listen(function ($query) use ($requestId) {
$sql = $query->sql;
foreach ($query->bindings as $key => $value) {
if (is_numeric($key)) {
if (is_numeric($value)) {
$sql = preg_replace('/\?/', $value, $sql, 1);
} else {
$sql = preg_replace('/\?/', sprintf('\'%s\'', $value), $sql, 1);
}
} else {
if (is_numeric($value)) {
$sql = str_replace(':'.$key, $value, $sql);
} else {
$sql = str_replace(':'.$key, sprintf('\'%s\'', $value), $sql);
}
}
}
$sql = str_replace('\\', '', $sql);
Log::channel('sql')->debug('request_id: '.$requestId.' run-time: '.$query->time.'ms; '.$sql."\n\n\t");
});
//捕獲自定義異常輸出格式
$handle = app(\Dingo\Api\Exception\Handler::class);
$handle->register(function (ApiException $exception) {
return response()::make(formats($exception->getMessage(), [], $exception->getCode()));
});
//捕獲500錯誤
$handle->register(function (\ErrorException $exception) use ($request) {
Log::channel('error_log')->error($exception);
ding()->text( "任務id: " . app('request_id') . " 內容:" . $exception->getMessage() . " " . $exception->getFile() . " " . $exception->getLine() . '行');
return response()::make(formats($exception->getMessage(), [], 422));
});
$handle->register(function (\Error $exception) use ($request) {
Log::channel('error_log')->error($exception);
ding()->text( "任務id: " . app('request_id') . " 內容:" . $exception->getMessage() . " " . $exception->getFile() . " " . $exception->getLine() . '行');
return response()::make(formats($exception->getMessage(), [], 422));
});
$handle->register(function (ApiException $exception) use ($request) {
logger($exception);
return response()::make(formats($exception->getMessage(), [], 500));
});
//sql error
$handle->register(function (QueryException $exception) {
Log::channel('error_log')->error($exception);
ding()->text( "任務id: " . app('request_id') . " 內容:" . $exception->getMessage() . " " . $exception->getFile() . " " . $exception->getLine() . '行');
return response()::make(formats($exception->getMessage(), [], $exception->getCode()));
});
//擴充builder
EloquentBuilder::macro('whereLike', function ($column, $val) {
return $this->where($column, 'like', '%'.$val.'%');
});
//重寫findOrFail
EloquentBuilder::macro('findOrThrow', function ($id, $message = '', $columns = ['*']) {
$flag = true;
//支援逗號拼接傳過來 exp: ["1,2"]
if (is_array($id)) {
$id = explode(',', array_pop($id));
} else {
if (! is_numeric($id)) {
$raw_id = $id;
$id = get_id($id);
if ($id == 'id錯誤') {
$flag = false;
$id = $raw_id;
}
}
}
if ($flag == true) {
$result = $this->find($id, $columns);
$id = $id instanceof Arrayable ? $id->toArray() : $id;
if (is_array($id)) {
if (count($result) === count(array_unique($id))) {
return $result;
}
} elseif (! is_null($result)) {
return $result;
}
}
$message = $message ?: '表資料不存在 '.implode(', ', Arr::wrap($id));
throw_api_exception($message);
});
Validator::extend('allow_dash_new', function ($attribute, $value, $parameters, $validator) {
return is_string($value) && preg_match('/^[.0-9a-zA-Z_-]+$/u', $value);
});
Validator::extend('all_chinese', function ($attribute, $value, $parameters, $validator) {
if (preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', $value)>0) {
return true;
}
return false;
});
}
}
安裝 “owen-it/laravel-auditing”: “^13.5”,
//額外增加欄位 request_id
'resolvers' => [
'ip_address' => OwenIt\Auditing\Resolvers\IpAddressResolver::class,
'user_agent' => OwenIt\Auditing\Resolvers\UserAgentResolver::class,
'url' => OwenIt\Auditing\Resolvers\UrlResolver::class,
'request_id' => \App\Resolvers\RequestIdResolver::class,
],
資料庫遷移檔案
$table->string('request_id')->nullable();
效果:
LINUX 根據request_id追蹤日誌:
tail -100f laravel.log | grep -C 10 "3245dc5d-5f21-43ca-be17-2b53ffe291e0"
tail -100f sql.log | grep -C 10 "3245dc5d-5f21-43ca-be17-2b53ffe291e0"
釘釘機器人報警
"wangju/ding-notice": "^1.0",
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Support\Facades\Log;
use Throwable;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that are not reported.
*
* @var string[]
*/
protected $dontReport = [
ApiException::class,
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var string[]
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*
* @return void
*/
public function register()
{
$this->reportable(function (Throwable $exception) {
if ( ($exception instanceof \ErrorException) || ($exception instanceof \Error) ) {
if (app()->runningInConsole()) {
Log::channel('error_log')->error($exception);
ding()->text( "任務id: " . app('request_id') . " 內容:" . $exception->getMessage() . " " . $exception->getFile() . " " . $exception->getLine() . '行');
}
}
});
}
}
釘釘機器人效果
任務id: ad312b82-e869-436e-ab31-0d63bdd19b41 內容:Invalid argument supplied for foreach() /var/www/WITMED/app/Actions/Offline/ListDepartmentExperts.php 47行
本作品採用《CC 協議》,轉載必須註明作者和本文連結