参考地址:https://learnku.com/docs/laravel/7.x/logging/7469
现有的日志格式不适用于公司,且存储位置不符合公司现有生产环境。
位置调整
原来记录日志位置在storage
下
现在想要调整为通过api.exp.com
则记录日志到/logs/service/log_api.log
下
通过web.exp.com
则记录日志到/logs/service/log.log
下
修改Laravel的日志配置文件 config/logging.php
源文件
<?php
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
return [
/*
|--------------------------------------------------------------------------
| Default Log Channel
|--------------------------------------------------------------------------
|
| This option defines the default log channel that gets used when writing
| messages to the logs. The name specified in this option should match
| one of the channels defined in the "channels" configuration array.
|
*/
'default' => env('LOG_CHANNEL', 'stack'),
/*
|--------------------------------------------------------------------------
| Log Channels
|--------------------------------------------------------------------------
|
| Here you may configure the log channels for your application. Out of
| the box, Laravel uses the Monolog PHP logging library. This gives
| you a variety of powerful log handlers / formatters to utilize.
|
| Available Drivers: "single", "daily", "slack", "syslog",
| "errorlog", "monolog",
| "custom", "stack"
|
*/
'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,
],
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => 'Laravel Log',
'emoji' => ':boom:',
'level' => 'critical',
],
'papertrail' => [
'driver' => 'monolog',
'level' => 'debug',
'handler' => SyslogUdpHandler::class,
'handler_with' => [
'host' => env('PAPERTRAIL_URL'),
'port' => env('PAPERTRAIL_PORT'),
],
],
'stderr' => [
'driver' => 'monolog',
'handler' => StreamHandler::class,
'formatter' => env('LOG_STDERR_FORMATTER'),
'with' => [
'stream' => 'php://stderr',
],
],
'syslog' => [
'driver' => 'syslog',
'level' => 'debug',
],
'errorlog' => [
'driver' => 'errorlog',
'level' => 'debug',
],
'null' => [
'driver' => 'monolog',
'handler' => NullHandler::class,
],
'emergency' => [
'path' => storage_path('logs/laravel.log'),
],
],
];
调整后 - 只需要调整path即可,formatter是调整格式使用
<?php
use App\Enum\System\RouteEnum;
use App\Logging\CustomizeJsonFormatter;
use Monolog\Handler\NullHandler;
/**
* 切换日志文件
*/
$logPath = [
'api' => '/logs/service/log_api.log', 'web' => '/logs/service/log.log'
];
$defaultStack = [
'name' => 'web_log', 'path' => $logPath['web']
];
if (defined('ENTRY_FILE') && ENTRY_FILE === 'API') {
$defaultStack = [
'name' => 'api_log', 'path' => $logPath['api']
];
}
return [
// 默认
'default' => 'stack',
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => [$defaultStack['name']],
'ignore_exceptions' => false,
],
'api_log' => [
'path' => $logPath['api'],
'driver' => 'single',
'level' => 'debug',
'formatter' => CustomizeJsonFormatter::class,
],
'web_log' => [
'path' => $logPath['web'],
'driver' => 'single',
'level' => 'debug',
'formatter' => CustomizeJsonFormatter::class,
],
'errorlog' => [
'path' => $defaultStack['path'],
'driver' => 'single',
'level' => 'debug',
'formatter' => CustomizeJsonFormatter::class,
],
'null' => [
'driver' => 'monolog',
'handler' => NullHandler::class,
],
'emergency' => [
'path' => $defaultStack['path'],
'driver' => 'single',
'level' => 'debug',
'formatter' => CustomizeJsonFormatter::class,
],
],
];
格式自定义
本文使用json
的格式进行记录,laravel
有很多记录格式可以自定义。
添加文件: app/Logging/CustomizeJsonFormatter.php
<?php
declare(strict_types=1);
namespace App\Logging;
use Monolog\Formatter\JsonFormatter;
use Monolog\Processor\UidProcessor;
/**
* Class CustomizeJsonFormatter
*
* 特殊处理:为了适用于公司ELK统一文件采集机制
*
* @package App\Logging
* @author wei
*/
class CustomizeJsonFormatter extends JsonFormatter
{
/**
* 日志唯一ID
*
* @var null|string
*/
private static $_uid = null;
/**
* {@inheritdoc}
*/
public function format(array $record): string
{
$normalized = $this->customizeNormalize($record);
if (isset($normalized['context']) && $normalized['context'] === []) {
if ($this->ignoreEmptyContextAndExtra) {
unset($normalized['context']);
} else {
$normalized['context'] = new \stdClass;
}
}
if (isset($normalized['extra']) && $normalized['extra'] === []) {
if ($this->ignoreEmptyContextAndExtra) {
unset($normalized['extra']);
} else {
$normalized['extra'] = new \stdClass;
}
}
return $this->toJson($normalized, true) . ($this->appendNewline ? PHP_EOL : '');
}
/**
* Normalizes given $data.
*
* 自定义一些自己想要个参数
*
* @param mixed $data
*
* @return mixed
*/
protected function customizeNormalize($data)
{
$normalized = $this->normalize($data);
$normalized['url'] = request()->url();
$normalized['query_str'] = request()->getQueryString();
$normalized['microtime'] = microtime(true);
$normalized['log_id'] = self::getUid();
$normalized['server_ip'] = request()->server('SERVER_ADDR', '');
$normalized['run'] = app()->runningInConsole() ? 'cli' : 'net';
$normalized['client_id'] = request()->ip();
$normalized['method'] = request()->method();
return $normalized;
}
/**
* @return string|null
*/
private static function getUid()
{
if (empty(self::$_uid)) {
$oUid = new UidProcessor(16);
self::$_uid = $oUid->getUid();
}
return self::$_uid;
}
}
使用日志
Log::info("Route Log");
效果如下
{
"message":"Route Log",
"context":{
},
"level":200,
"level_name":"INFO",
"channel":"local",
"datetime":"2020-12-04T23:42:39.013856+08:00",
"extra":{
},
"url":"http://api.exp.com/test1",
"query_str":"app_key=1×tamp=123",
"microtime":1607096559.01408,
"log_id":"9f022aaa3ef30195",
"server_ip":"172.16.0.54",
"run":"net",
"client_id":"172.18.249.45",
"method":"GET"
}