用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之后,你就明白,这些问题,除了考验你的脚本背诵记 ...
随机推荐
- 第五章 存储过程&触发器
1.前言 2.存储过程和触发器->存储过程 ·理解:是一组SQL命令集合,经过预编译存放在系统中:就像java程序里的方法,可以重复的被调用: 在日常的数据库操作中,会有大量的T-SQL批处理. ...
- zabbix3.0问题及解决方法
一.问题:Zabbix agent on T2 is unreachable for 5 minutes 解决:1.进入zabbix service端 vim /etc/zabbix/ ...
- 二维码生成的WEB api方法
/// <summary> /// 获取二维码 /// </summary> /// <param name="size">编码测量度,值越大生 ...
- 两次DFS,POJ(1481)
题目链接:http://poj.org/problem?id=1481 两次DFS,这里的思路是,没找到*,就说明,有一个骰子,因此,每搜索到一个*,深搜4个方向,并且变为'.',要是搜到'X',就是 ...
- [USACO07FEB]银牛派对Silver Cow Party---最短路模板题
银牛排队 对于我这种蒟蒻来说,还是不要跑一次单元最短路.跑两次好写呀(- ̄▽ ̄)- 而题目中是有向图.如果如果按照题意进行最短路的话.就会出现一个单终点最短路和一个单起点最短路 对于单起点自然就是套模 ...
- Yarn下分片和分块源代码分析
public class FileSplit extends InputSplit implements Writable { private Path file; private long star ...
- pycharm中常用设置
当安装时检查版本过低 首先 pip --help 进入帮助,找到 复制,然后 pip install --disable-pip-version-check 要安装的包 这样就会跳过版本检测. 在py ...
- js加减乘除精确计算
Javascript精确计算时的bug JS无法进行精确计算的bug 在做CRM,二代审核需求审核详情页面时.需要按比例(后端传类似0.8的小数)把用户输入的数字显示在不同的地方. 在做dubheIn ...
- 模拟ie9的placeholder
ie9 的input框没有placeholder属性 啧啧啧~~~ 所以就用span标签来模拟一下 先判断浏览器类型 if(navigator.useAgent.indexOf("MSIE ...
- JS - 给数组的原型添加去掉重复元素的distinct方法
/* 调用完该方法,原数组只留下非重复的数据 返回一个数组,里面是依次出现的重复元素 */Array.prototype.distinct = function () { var removeA ...