用swoole实现nginx日志解析
1.原技术路线解析
在nging配置中将日志信息交给syslog处理,rsyslog配置中将数据传递给了514端口解析,然后将解析好的数据传入elasticsearch中。
nginx配置
server {
listen 80;
listen [::]:80;
server_name test.86dev.wrddns.com;
# 以下两行将日志写入syslog
access_log syslog:server=unix:/dev/log,facility=local5,tag=web_1,severity=info main;
error_log syslog:server=unix:/dev/log,facility=local5,tag=web_1,severity=error warn;
# ....其他配置
}
/etc/rsyslog.conf
# 配置文件,存放解析规则xxx.conf和ruleBase文件xx.rb
$IncludeConfig /etc/rsyslog.d/*.conf
# 配置将日志放到哪个端口解析
local5.* @10.3.19.86:514
在实际应用过程中有一些问题,不能和php上面的一些配置进行配合记录,解析规则不好配置,有些内容解析不好,所以探索使用新的技术路线。
2.新技术路线
尝试使用新技术路线,通过swoole起一个服务,然后监听9502端口,rsyslog将日志推向该端口,对日志进行解析后推入elasticsearch,此时可以获取到php端的一些配置。以下是大体思路
2.1 选择swoole的server类型。
这里不再赘述swoole的安装,首要考虑的问题是原推向514的协议类型。
先查看端口的协议类型
# root @ WENGINE in ~ [9:48:51]
$ netstat -antup | grep 514
udp 0 0 0.0.0.0:514 0.0.0.0:* 23560/rsyslogd
udp 0 0 :::514 :::* 23560/rsyslogd
可以看到是udp协议,所以选用swoole的 upd服务
结合laravel的commands来编写服务端
<?php
namespace App\Console\Swoole;
use Illuminate\Console\Command;
use swoole_websocket_server;
use swoole_server;
use swoole_process;
use swoole_sock_udp;
use UAParser\Parser;
use GeoIp2\Database\Reader;
use Wrd\Framework\Models\SysConfig;
use Elasticsearch\ClientBuilder;
class SwooleServer extends Command
{
protected $signature = 'swoole-server start
{cmd=start : can use start}
{--daemon : set to run in daemonize mode}
';
protected $description = 'swoole server control';
public $access_buffer = [];
public function __construct()
{
parent::__construct();
}
public function handle()
{
$command = $this->argument('cmd');
$option = $this->option('daemon');
switch ($command) {
case 'start':
$this->initWs($option);
break;
default:
$this->info('请按照下面格式输入命令:php artisan swoole-server {start}');
break;
}
}
public function initWs($daemonize = false)
{
if ($daemonize) {
$this->info('Starting Websocket server in daemon mode...');
} else {
$this->info('Starting Websocket server in interactive mode...');
}
$server = new swoole_server('0.0.0.0', 9502, SWOOLE_PROCESS, SWOOLE_SOCK_UDP);
$server->set([
'daemonize' => $daemonize,
'log_file' => '/var/www/html/storage/logs/websocket.log',
'worker_num' => 1,
'task_worker_num' => 1,
]);
$server->on('Packet', function($serv, $data, $clientInfo)
{
$serv->task($data);
});
$server->on('Task', function ($serv, $task_id, $from_id, $data) {
//通过正则表达式提取出需要的信息,不同的日志格式需要不同的正则,这里只写一种情况
$rule = '/\<\d*\>.*\d{2}\:\d{2}\:\d{2}\s[^\s]*\s[^\s]*\s(\w*\_\d*)\:\s\[Customize-format\]/';
preg_match($rule, $data, $matches);
if (empty($matches)) {
$this->writeLog($data); //记录下无法解析的日志,更正正则
return false;
}
$vhost = $matches[1];
$ip = $matches[2];
//...更多参数
$ua = $matches[12];
//解析UA,这里使用的解析库https://github.com/ua-parser/uap-php
$parser = Parser::create();
$parser_ua = $parser->parse($ua);
$browser = $parser_ua->ua->family;
$os = $parser_ua->os->family;
$device = $parser_ua->device->family;
//解析IP,这里使用的解析库https://github.com/maxmind/GeoIP2-php
$reader = new Reader(public_path().'/geoip2/GeoLite2-City.mmdb');
try{
$record = $reader->city($ip);
$country = $record->country->isoCode;
$continent = $record->continent->names['zh-CN'];
$subdivisions = $record->mostSpecificSubdivision->names['zh-CN'];
$city = $record->city->names['zh-CN'];
$geoip = array(
'location' => array($record->location->longitude, $record->location->latitude)
);
} catch (\Exception $e) {
//如果ip没有被收录(项目有很多内网ip),则拿数据库中的提前配置项,进行解析
}
$res = array(
'vhost' => $vhost,
'ip' => $ip,
// ...其它项
'token' => $token,
'browser' => $browser,
'os' => $os,
'device' => $device,
'continent' => $continent,
'country' => $country,
'subdivisions' => $subdivisions,
'city' => $city,
'geoip' => $geoip,
);
$this->access_buffer[] = $res;
//每隔一段时间,写入到elasticsearch
if (count($this->access_buffer) > 0 && time() - strtotime($this->access_buffer[0]['@timestamp']) > 10) {
$insert_data = $this->access_buffer;
$this->access_buffer = [];
$this->insertElasticsearch('access', $insert_data);
}
//return 数据 给 Finish
return "Task {$task_id}'s result";
});
$server->on('Finish', function ($serv,$task_id, $data) {
echo "Task {$task_id} finish\n";
});
$server->start();
}
public function insertElasticsearch($type='access', $data){
foreach($data as $item){
$params['body'][] = [
'index' => [
'_index' => $type.'-'.date('Y.m.d', time()),
'_type' => 'events',
]
];
$params['body'][] = $item;
}
extract(\Config::get('app.elastic', [
'host' => '127.0.0.1',
'port' => '9200'
]));
//往elasticsearch写数据,这里使用的库https://github.com/elastic/elasticsearch-php
$helper = ClientBuilder::create()
->setHosts([$host.":".$port])
->build();
if (!empty($params['body'])) {
$response = $helper->bulk($params);
//var_dump($response);
}
}
public function writeLog($info){
$alert_message = array(
'error' => '此条信息未能命中日志格式,未写入elasticsearch',
'info' => $info
);
\Log::alert($alert_message);
}
2.2 通过更改nginx的main日志格式简化正则表达式
nginx的配置中的
log_format main [$proxy_add_x_forwarded_for]-[$remote_user]-[$time_local]-[$request]-[$status]-[$bytes_sent]-[$http_host]-[$http_referer]-[$http_user_agent]-[$cookie_wengine_ticket]-[archer-main];
加了特殊符号,并且最后给了一个标识,这样能提高命中准确度
2.3 更改rsyslog的端口
local5.* @10.3.19.86:9502
2.4 其它一些问题
可以通过nc来检测swoole的udp服务是否通
yum install -y nc
# root @ WENGINE in ~ [10:17:07] C:130
$ nc -u 127.0.0.1 9502
ceshi
可以写supervisor的脚本来使swoole服务器一直启动
[program:swooleserver]
directory = /var/www/html
command=php artisan swoole-server
user=apache
autostart=true
startsecs=2
autorestart=true
redirect_stderr=true
stopsignal=INT
stderr_logfile_maxbytes=1MB
stderr_logfile_backups=10
stderr_capture_maxbytes=1MB
stderr_events_enabled=false
用swoole实现nginx日志解析的更多相关文章
- tomcat及nginx相关,格式化输出,配置及日志解析
1.https://www.cnblogs.com/jingmoxukong/p/8258837.html?utm_source=gold_browser_extension Tomcat ...
- Logstash使用grok插件解析Nginx日志
grok表达式的打印复制格式的完整语法是下面这样的: %{PATTERN_NAME:capture_name:data_type}data_type 目前只支持两个值:int 和 float. 在线g ...
- Logstash收集nginx日志之使用grok过滤插件解析日志
grok作为一个logstash的过滤插件,支持根据模式解析文本日志行,拆成字段. nginx日志的配置: log_format main '$remote_addr - $remote_user [ ...
- ELK+Redis 解析Nginx日志
一.ELK简介 Elk是指logstash,elasticsearch,kibana三件套,我们一般使用它们做日志分析. ELK工作原理图: 简单来讲ELK具体的工作流程就是客户端的logstash ...
- 使用Hive的正则解析器RegexSerDe分析nginx日志
1.环境: hadoop-2.6.0 + apache-hive-1.2.0-bin 2.使用Hive分析nginx日志,站点的訪问日志部分内容为: cat /home/hadoop/hivetest ...
- [日志分析]Graylog2进阶 通过正则解析Nginx日志
之前分享的 [日志分析]Graylog2采集Nginx日志 主动方式 这篇文章介绍了Graylog如何通过Graylog Collector Sidecar来采集nginx日志. 由于日志是未经处理的 ...
- Goaccess解析nginx日志备忘
参考 http://nginx.org/en/docs/http/ngx_http_log_module.html?&_ga=1.92028562.949762386.1481787781#l ...
- 烂泥:利用awstats分析nginx日志
本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 昨天把nginx的日志进行了切割,关于如何切割nginx日志,可以查看<烂泥:切割 ...
- nginx日志分析利器GoAccess
面试的时候一定会被面到的问题是:给出web服务器的访问日志,请写一个脚本来统计访问前10的IP有哪些?访问前10的请求有哪些?当你领略过goaccess之后,你就明白,这些问题,除了考验你的脚本背诵记 ...
随机推荐
- eclipse中Tomcat启动了 但看不到tomcat首页
症状: tomcat在eclipse里面能正常启动,而在浏览器中访问http://localhost:8080/不能访问,且报404错误.同时其他项目页面也不能访问. 关闭eclipse里面的tomc ...
- May 05th 2017 Week 18th Friday
No matter what have happened today, the sun will just rise in the morning of tomorrow. 无论今天发生了什么,明天早 ...
- frame、window和dialog区别
属性 Window Frame Dialog 模式化 不是 不是 不是(可设置) 可调大小 不可 可 可 标题栏 无 有 有 边界 无 有 有 标题 无 有 有 菜单栏 无 有 无 焦点管理器 有 有 ...
- jsc
之前发现一个神器,js代码测试脱离浏览器,mac终端也可以做到 调试js的时候,一般都是用浏览器的开发者工具,这里给大家推荐另外一种,抛开浏览器,在终端执行的方式,Mac内置了一个javascript ...
- 【转】批处理命令 For循环命令详解!
批处理for命令详解FOR这条命令基本上都被用来处理文本,但还有其他一些好用的功能!看看他的基本格式(这里我引用的是批处理中的格式,直接在命令行只需要一个%号)FOR 参数 %%变量名 IN (相关文 ...
- 2018.8.5 Bootstrap 使用
Bootstrap的环境搭建 <link rel="stylesheet" type="text/css" href="css/bootstra ...
- JS面向对象、prototype、call()、apply()
一. 起因 那天用到prototype.js于是打开看看,才看几行就满头雾水,原因是对js的面向对象不是很熟悉,于是百度+google了一把,最后终于算小有收获,写此纪念一下^_^. prototyp ...
- Ubuntu 12.04 the system is running in low-graphics mode
1.出现问题如图所示: 2.解决方案: Ctrl + Alt + F1 df -h 输入密码,到了这一步,也是可以使用terminal,那么没有图形界面也是可以的 cd /etc/X11 sudo c ...
- 记录表TABLE的使用详解
定义记录表(或索引表)数据类型与记录类型相似,但它是对记录类型的扩展.它可以处理多行记录,类似于高级中的二维数组,使得可以在PL/SQL中模仿数据库中的表. 定义记录表类型的语法如下: 1 2 TYP ...
- 关于Vue 兄弟组件通信
最近项目中遇到希望在操作路由组件里面内容的时候可以影响共用组件Header组件(这个其实就是他的兄弟组件)的操作. 意思就是 router-view指向的router来影响Header组件的信息 首 ...