From cb811bf1ebc1fdc2fd333e411fff0aabfe2e6b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BA=84=E8=8B=B1=E6=9D=B0?= <359356743@qq.com> Date: Thu, 28 Sep 2017 11:46:06 +0800 Subject: [PATCH] new start bye haibian. --- .gitignore | 2 + LICENSE | 21 ++++ README.md | 1 + composer.json | 26 ++++ config/logcollector.php | 23 ++++ src/Facades/LogCollector.php | 13 ++ src/LogCollector.php | 189 ++++++++++++++++++++++++++++ src/LogCollectorServiceProvider.php | 33 +++++ src/Middleware/LogAfterRequest.php | 65 ++++++++++ 9 files changed, 373 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 composer.json create mode 100644 config/logcollector.php create mode 100644 src/Facades/LogCollector.php create mode 100644 src/LogCollector.php create mode 100644 src/LogCollectorServiceProvider.php create mode 100644 src/Middleware/LogAfterRequest.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0537c22 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +.idea diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..172cde3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Faris + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6496f11 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# logcollector-service-provider \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..2a0da1a --- /dev/null +++ b/composer.json @@ -0,0 +1,26 @@ +{ + "name": "faris/logcollector-service-provider", + "type": "library", + "description": "通过日志统一收集事件,同时记录每一个请求", + "keywords": ["日志收集", "事件", "记录请求"], + "homepage": "https://github.com/xFaris/logcollector-service-provider", + "license": "MIT", + "authors": [ + { + "name": "faris", + "email": "faris2017@qq.com" + } + ], + "require": { + "php": ">=5.4", + "monolog/monolog": "*", + "illuminate/config": "~5.0", + "illuminate/support": "~5.0", + "webpatser/laravel-uuid": "2.*" + }, + "autoload": { + "psr-4": { + "Faris\\LogCollector\\": "src/" + } + } +} diff --git a/config/logcollector.php b/config/logcollector.php new file mode 100644 index 0000000..f6c7fd5 --- /dev/null +++ b/config/logcollector.php @@ -0,0 +1,23 @@ + 'product_name', + 'service_name' => 'server', + + 'access' => [ + 'log_channel' => 'ACCESS', + 'file_name' => storage_path("logs/access.log"), + ], + + 'event' => [ + 'log_channel' => 'EVENT', + 'file_name' => storage_path("logs/event.log"), + ], + + 'exception' => [ + 'log_channel' => 'EXCEPTION', + 'file_name' => storage_path("logs/exception.log"), + 'dingtalk_token'=> 'dingtalk_token', + ], +]; diff --git a/src/Facades/LogCollector.php b/src/Facades/LogCollector.php new file mode 100644 index 0000000..9c2d27e --- /dev/null +++ b/src/Facades/LogCollector.php @@ -0,0 +1,13 @@ +config = $config; + + //info logger + $this->accessLogger = new Logger($this->config->get('logcollector.access.log_channel')); + $accessRotate = new RotatingFileHandler($this->config->get('logcollector.access.file_name'), Logger::INFO); + $accessRotate->setFormatter(new LineFormatter("[%datetime%] [%level_name%] %channel% - %message% %extra%\n")); + $this->accessLogger->pushHandler($accessRotate); + + //event logger + $this->eventLogger = new Logger($this->config->get('logcollector.event.log_channel')); + $eventRotate = new RotatingFileHandler($this->config->get('logcollector.event.file_name'), Logger::INFO); + $eventRotate->setFormatter(new LineFormatter("[%datetime%] [%level_name%] %channel% - %message% %extra%\n")); + $this->eventLogger->pushHandler($eventRotate); + + + //exception logger + $exception_channel = + $this->config->has('logcollector.exception.log_channel') ? + $this->config->get('logcollector.exception.log_channel') : 'EXCEPTION'; + + $this->exceptionLogger = new Logger($exception_channel); + $exception_file = + $this->config->has('logcollector.exception.file_name') ? + $this->config->get('logcollector.exception.file_name') : + base_path("../logs/".$this->config->get('logcollector.service_name').'.exception.log'); + + $errorRotate = new RotatingFileHandler($exception_file, Logger::INFO); + $errorRotate->setFormatter(new LineFormatter("[%datetime%] [%level_name%] %channel% - %message% %extra%\n")); + $this->exceptionLogger->pushHandler($errorRotate); + + //add info + $extraFields = array( + 'url' => 'REQUEST_URI', + 'http_method' => 'REQUEST_METHOD', + 'server' => 'SERVER_NAME', + 'referrer' => 'HTTP_REFERER', + ); + $webProcessor = new WebProcessor(null, $extraFields); + //$codeProcessor = new IntrospectionProcessor(); + $this->accessLogger->pushProcessor($webProcessor); + //$this->eventLogger->pushProcessor($webProcessor); + + //basic info + if ($this->config->has('logcollector.product')) { + $this->product = $this->config->get('logcollector.product'); + } else { + $this->product = 'haibian'; + } + + if ($this->config->has('logcollector.service_name')) { + $this->serviceName = $this->config->get('logcollector.service_name'); + } else { + $this->serviceName = 'server'; + } + + $this->startTime = defined(LARAVEL_START) ? LARAVEL_START * 1000 : microtime(true); + $this->requestId = (string)Uuid::generate(4); + + $this->logInfo = []; + $this->prefix = $this->product." ".$this->serviceName; + } + + public function addLogInfo($key, $value) + { + if (!isset($key) || !isset($value)) { + return false; + } + + $this->logInfo[$key] = $value; + return true; + } + + public function logAfterRequest() + { + $this->accessLogger->pushProcessor(function($record) { + $record['extra'] = array_merge($this->logInfo, $record['extra']); + $record['extra']['request_id'] = $this->requestId; + $record['extra']['response_time'] = sprintf('%dms', round(microtime(true) * 1000 - $this->startTime * 1000)); + $record['extra']['ip'] = $this->getClientIp(); + return $record; + }); + + $this->accessLogger->addInfo($this->prefix); + } + + public function logEvent($userId, $eventName, $eventInfo) + { + $this->eventName = $eventName; + $this->eventInfo = $eventInfo; + $this->eventUserId = $userId; + + $this->eventLogger->pushProcessor(function($record) { + $record['extra']['request_id'] = $this->requestId; + $record['extra']['event_name'] = $this->eventName; + $record['extra']['event_info'] = $this->eventInfo; + $record['extra']['event_user_id'] = $this->eventUserId; + return $record; + }); + + $this->eventLogger->addInfo($this->prefix); + } + + + public function logException($exceptionName, $msg, $dingtalk_token = '') + { + $this->exceptionName = $exceptionName; + $this->exceptionMsg = $msg; + $this->exceptionToken = '32c2a4305bb3b302551d0a308901b0b81d7f2e64ba0e0deff09665f7e9f58a54'; + if ($this->config->has('logcollector.exception.dingtalk_token')) { + $this->exceptionToken = $this->config->get('logcollector.exception.dingtalk_token'); + } + if (!empty($dingtalk_token)) { + $this->exceptionToken = $dingtalk_token; + } + + $this->exceptionLogger->pushProcessor(function($record) { + $record['extra']['request_id'] = $this->requestId; + $record['extra']['exception_name'] = $this->exceptionName; + $record['extra']['exception_msg'] = $this->exceptionMsg; + $record['extra']['exception_token'] = $this->exceptionToken; + return $record; + }); + + $this->exceptionLogger->addInfo($this->prefix); + } + + public function addUserId($userId) + { + $this->logInfo['user_id'] = $userId; + } + + public function addResponseCode($responseCode, $responseMsg) + { + $this->logInfo['response_code'] = $responseCode; + $this->logInfo['response_msg'] = $responseMsg; + } + + public function getRequestId() + { + return $this->requestId; + } + + public static function getClientIp() + { + $uip = '0.0.0.0'; + if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) { + $uip = getenv('HTTP_CLIENT_IP'); + } elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) { + $uip = getenv('HTTP_X_FORWARDED_FOR'); + strpos(',', $uip) && list($uip) = explode(',', $uip); + } elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) { + $uip = getenv('REMOTE_ADDR'); + } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) { + $uip = $_SERVER['REMOTE_ADDR']; + } + return $uip; + } +} diff --git a/src/LogCollectorServiceProvider.php b/src/LogCollectorServiceProvider.php new file mode 100644 index 0000000..aaf8f89 --- /dev/null +++ b/src/LogCollectorServiceProvider.php @@ -0,0 +1,33 @@ +publishes([ + __DIR__.'/../config/logcollector.php' => config_path('logcollector.php') + ], 'config'); + } + + public function register() + { + // Merge configs + $this->mergeConfigFrom( + __DIR__.'/../config/logcollector.php', 'logcollector' + ); + + // Bind captcha + $this->app->singleton('logcollector', function($app) + { + return new LogCollector( + $app['Illuminate\Config\Repository'] + ); + }); + } +} \ No newline at end of file diff --git a/src/Middleware/LogAfterRequest.php b/src/Middleware/LogAfterRequest.php new file mode 100644 index 0000000..430f2d1 --- /dev/null +++ b/src/Middleware/LogAfterRequest.php @@ -0,0 +1,65 @@ +getRequestId(); + + $response = $next($request); + $response->headers->set('X-Request-Id', $requestId, false); + return $response; + } + + public function terminate($request, $response) { + $this->logRequest($request); + $this->logResponse($response); + app('logcollector')->logAfterRequest(); + } + + public function logRequest($request) { + //添加过滤信息 + $inputSafe = [ + 'password' + ]; + $inputs = $request->input(); + if (!empty($inputs)) { + foreach($inputSafe as $safe) { + if(!empty($inputs[$safe])) { + $inputs[$safe] = '[*** SENSOR ***]'; + } + } + } + + app('logcollector')->addLogInfo('request', $inputs); + } + + public function logResponse($response) { + $status = 0; + if (method_exists($response, 'status')) { + $status = $response->status(); + } elseif (method_exists($response, 'getStatusCode')) { + $status = $response->getStatusCode(); + } + $returns = [ + 'status' => $status, + ]; + + //只打印json格式的返回 + $content = []; + if (method_exists($response, 'content')) { + $content = $response->content(); + } elseif (method_exists($response, 'getContent')) { + $content = $response->getContent(); + } + $content = json_decode($content, true); + if (json_last_error() == JSON_ERROR_NONE) { + $returns['content'] = $content; + } + + app('logcollector')->addLogInfo('response', $returns); + } +} \ No newline at end of file