照猫画虎 实现 min-laravel 框架系列之日志
- laravel
- 2020-08-26
- 141
- 0
路由
laravel 系统的日志是建立在 monolog包上的
加入依赖
在 minlaravelframework/framework 的 composer.json 配置文件中添加依赖包
"require": {...."monolog/monolog": "^2.1",....},
在 minlaravel 目录下更新, composer update
日志文件加载过程
日志写入服务是作为基础服务提供者,在 application 初始化时就注册加载的服务
Illuminate\Foundation\Application 类protected function registerBaseServiceProviders(){...$this->register(new RoutingServiceProvider($this));...}Illuminate\Log\LogServiceProvider 服务提供者类use Illuminate\Support\ServiceProvider;class LogServiceProvider extends ServiceProvider{/*** Register the service provider.** @return void*/public function register(){$this->app->singleton('log', function ($app) {return new LogManager($app);});}}
可以看出,为系统提供日志服务的类是 LogManager
LogManager 类
LogManager 类实现了 Psr\Log\LoggerInterface 接口函数,而 LoggerInterface 是monolog/monolog 提供的契约类,定义了一些日志函数,ex:error、warning、notice、info 等等
driver 方法
获取日志的具体实现,由 getDefaultDriver 方法可以看出,日志配置为 app/logging.php 文件中的 default 指定,系统默认是 stack,一般常用的有 single、daily
public function driver($driver = null){return $this->get($driver ?? $this->getDefaultDriver());}public function getDefaultDriver(){return $this->app['config']['logging.default'];}/*** Attempt to get the log from the local cache.** @param string $name* @return \Psr\Log\LoggerInterface*/protected function get($name){// channels 为内存缓存,一次请求只 new 一次就行了,同时可以清楚的了解,Logger 类是 laravel 系统在 monolog 之上的自定义实现类try {return $this->channels[$name] ?? with($this->resolve($name), function ($logger) use ($name) {return $this->channels[$name] = $this->tap($name, new Logger($logger, $this->app['events']));});} catch (Throwable $e) {return tap($this->createEmergencyLogger(), function ($logger) use ($e) {$logger->emergency('Unable to create configured logger. Using emergency logger.', ['exception' => $e,]);});}}
resolve 方法
通过 name 参数,构造对应的函数进行调用,ex:stack => createStackDriver,daily => createDailyDriver
protected function resolve($name){// 读取配置文件的数据$config = $this->configurationFor($name);// 读取失败,抛出异常if (is_null($config)) {throw new InvalidArgumentException("Log [{$name}] is not defined.");}// 自定义实现if (isset($this->customCreators[$config['driver']])) {return $this->callCustomCreator($config);}// 拼接函数名称$driverMethod = 'create'.ucfirst($config['driver']).'Driver';if (method_exists($this, $driverMethod)) {return $this->{$driverMethod}($config);}throw new InvalidArgumentException("Driver [{$config['driver']}] is not supported.");}
configurationFor 读取配置
配置文件值'channels' => ['stack' => ['driver' => 'stack','channels' => ['single'],'ignore_exceptions' => false,],'single' => ['driver' => 'single','path' => storage_path('logs/laravel.log'),'level' => 'debug',],'daily' => ['driver' => 'daily','path' => storage_path('logs/laravel.log'),'level' => 'debug','days' => 14,],......]protected function configurationFor($name){return $this->app['config']["logging.channels.{$name}"];}
createXxxDriver 初始化 monolog 类
protected function createSingleDriver(array $config){return new Monolog($this->parseChannel($config), [$this->prepareHandler(new StreamHandler($config['path'], $this->level($config),$config['bubble'] ?? true, $config['permission'] ?? null, $config['locking'] ?? false), $config),]);}protected function createDailyDriver(array $config){return new Monolog($this->parseChannel($config), [$this->prepareHandler(new RotatingFileHandler($config['path'], $config['days'] ?? 7, $this->level($config),$config['bubble'] ?? true, $config['permission'] ?? null, $config['locking'] ?? false), $config),]);}
Logger 类
laravel 自定义的日志实现类,此类也实现了 LoggerInterface 接口类,
// 写日志protected function writeLog($level, $message, $context){$this->logger->{$level}($message = $this->formatMessage($message), $context);// 事件相关实现$this->fireLogEvent($level, $message, $context);}// 格式化信息,数组、json、等进行字符串转化protected function formatMessage($message){if (is_array($message)) {return var_export($message, true);} elseif ($message instanceof Jsonable) {return $message->toJson();} elseif ($message instanceof Arrayable) {return var_export($message->toArray(), true);}return $message;}
Facades 实现
config/app.php 文件中的别名
// Facades 用到的别名问题'aliases' => [...'Log' => Illuminate\Support\Facades\Log::class,...],
Facades 类
namespace Illuminate\Support\Facades;class Log extends Facade{/*** Get the registered name of the component.** @return string*/protected static function getFacadeAccessor(){return 'log';}}
测试
public/app.php 文件中,
// 日志$log = $app['log'];$log->log('error',"日志",[]);$log->info("日志");\Log::debug("日志");