在使用 laravel
的日志组件(Facade
门面模式)时,我们可以通过 withContext
方法为请求周期注册全局的上下文信息,用来做 RequestID/TraceId
类的请求链路追踪,非常的方便。但在 10- 以下的版本中,withContext
只能为默认日志通道注入全局上下文,在非默认通道的场景,比如 cli
下, 就无法优雅的实现了。
但如果你了解 Service
,ServiceProvider
,Facade
三者之间的关系,那可以参考如下两类方法来优雅的实现非默认日志通道下注册全局 context
的方法:
门面 \Illuminate\Support\Facades\Log
代理的日志服务
实为 \Illuminate\Log\LogServiceProvider
向 app
容器中注册的
标识名为 log
的 \Illuminate\Log\LogManager
日志服务的实例。
只要理解这三者的关系,我们就可以为Log门面重新注册。
方法一、非默认通道的日志Facade
\App\Supports\Facades\LogCli
代理一个非默认通道日志服务的实例即可,比如 log-cli
。
<?php
namespace App\Supports\Facades;
use Illuminate\Support\Facades\Facade;
/**
* @method static \Psr\Log\LoggerInterface channel(string $channel = null)
* @method static \Psr\Log\LoggerInterface stack(array $channels, string $channel = null)
* @method static \Psr\Log\LoggerInterface build(array $config)
* @method static \Illuminate\Log\Logger withContext(array $context = [])
* @method static \Illuminate\Log\Logger withoutContext()
* @method static void alert(string $message, array $context = [])
* @method static void critical(string $message, array $context = [])
* @method static void debug(string $message, array $context = [])
* @method static void emergency(string $message, array $context = [])
* @method static void error(string $message, array $context = [])
* @method static void info(string $message, array $context = [])
* @method static void log($level, string $message, array $context = [])
* @method static void notice(string $message, array $context = [])
* @method static void warning(string $message, array $context = [])
* @method static void write(string $level, string $message, array $context = [])
* @method static void listen(\Closure $callback)
*
* @see \Illuminate\Log\Logger
*/
class LogCli extends Facade
{
public static function getFacadeAccessor(): string
{
return 'log-cli';
}
}
在 \App\Providers\AppServiceProvider
中注册 log-cli
的实例到 app
容器中
<?php
namespace App\Providers;
use Illuminate\Log\LogManager;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
/**
* @see \App\Supports\Facades\LogCli
*/
$this->app->singleton('log-cli', function () {
return (new LogManager($this->app))->channel('cli');
});
}
}
如此后,我们就可以在使用 LogCli::withContext
注册运行周期内的全局上下文参数了。
LogCli::withContext(['traceId' => "traceId will record in all log"]);
// 以下日志都会携带上 traceId 参数
LogCli::info("this is info");
LogCli::warning("this is warning");
LogCli::error("this is error");
方法二、自适应日志Facade
听起来是不是很高大上很优雅?其实就是仍使用 laravel
的 Log Facade
,Facade
只是个代理,将 实例
的诸多 方法
以 静态
的风格 暴露
出来 方便调用
。何谓自适应呢?让 Log Facade
在 http
下使用 default
通道,在 cli
下使用 cli
通道,使用者无需刻意的去指定。
实现起来也很简单,根据运行时环境
来判断,决定 log
代理哪个通道的日志服务。
<?php
namespace App\Providers;
use Illuminate\Log\LogManager;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
/**
* @see \Illuminate\Log\LogManager
* @see \Illuminate\Log\LogServiceProvider
* @see \Illuminate\Support\Facades\Log
* @see \Illuminate\Support\Facades\Log::withContext()
* cli 环境下,将 log 服务重新注册为 cli 通道的日志对象
* 主要为了解决 10- 版本下无法为非默认通道注入全局context的问题
*/
if ('cli' == \PHP_SAPI) {
$this->app->singleton('log', function () {
return (new LogManager($this->app))->channel('cli');
});
}
}
}
这样在 http
模式下自动使用 default
通道,console
模式下自动使用 cli
通道。
Log::withContext(['traceId' => "traceId will record in all log"]);
// 以下日志都会携带上 traceId 参数
Log::info("this is info");
Log::warning("this is warning");
Log::error("this is error");
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。