我已经深入挖掘了systemd它journal,而且,我偶然发现了这一点,它说:
systemd-journald将所有收到的日志消息转发到AF_UNIX SOCK_DGRAM套接字/run/systemd/journal/syslog(如果存在),Unix syslog守护程序可以使用它来进一步处理数据.
根据联机帮助页,我确实设置了我的环境以下面还有syslog,我相应地调整了我的代码:
define('NL', "\n\r");
$log = function ()
{
if (func_num_args() >= 1)
{
$message = call_user_func_array('sprintf', func_get_args());
echo '[' . date('r') . '] ' . $message . NL;
}
};
$syslog = '/var/run/systemd/journal/syslog';
$sock = socket_create(AF_UNIX, SOCK_DGRAM, 0);
$connection = socket_connect($sock, $syslog);
if (!$connection)
{
$log('Couldn\'t connect to ' . $syslog);
}
else
{
$log('Connected to ' . $syslog);
$readables = array($sock);
socket_set_nonblock($sock);
while (true)
{
$read = $readables;
$write = $readables;
$except = $readables;
$select = socket_select($read, $write, $except, 0);
$log('Changes: %d.', $select);
$log('-------');
$log('Read: %d.', count($read));
$log('Write: %d.', count($write));
$log('Except: %d.', count($except));
if ($select > 0)
{
if ($read)
{
foreach ($read as $readable)
{
$data = socket_read($readable, 4096, PHP_BINARY_READ);
if ($data === false)
{
$log(socket_last_error() . ': ' . socket_strerror(socket_last_error()));
}
else if (!empty($data))
{
$log($data);
}
else
{
$log('Read empty.');
}
}
}
if ($write)
{
foreach ($write as $writable)
{
$data = socket_read($writable, 4096, PHP_BINARY_READ);
if ($data === false)
{
$log(socket_last_error() . ': ' . socket_strerror(socket_last_error()));
}
else if (!empty($data))
{
$log($data);
}
else
{
$log('Write empty.');
}
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这显然只能看到(选择)write套接字上的更改.好吧,可能是这里的东西是错的,所以我试图从他们读,没有运气(也不应该):
[Thu, 12 Sep 2013 14:45:15 +0300] Changes: 1.
[Thu, 12 Sep 2013 14:45:15 +0300] -------
[Thu, 12 Sep 2013 14:45:15 +0300] Read: 0.
[Thu, 12 Sep 2013 14:45:15 +0300] Write: 1.
[Thu, 12 Sep 2013 14:45:15 +0300] Except: 0.
[Thu, 12 Sep 2013 14:45:15 +0300] 11: Resource temporarily unavailable
现在,这让我疯了一点.syslog文档说这应该是可能的.代码有什么问题?
我有一个工作原型,简单地说:
while(true)
{
exec('journalctl -r -n 1 | more', $result, $exit);
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
但是这感觉不对,并且消耗了太多的系统资源,然后我发现了带有套接字的journald.
我试图连接和阅读:
AF_UNIX, SOCK_DGRAM : /var/run/systemd/journal/socket
AF_UNIX, SOCK_STREAM : /var/run/systemd/journal/stdout
Run Code Online (Sandbox Code Playgroud)
给定的套接字.
随着/var/run/systemd/journal/socket,socket_select看到0变化.随着/var/run/systemd/journal/stdout我总是(每个循环)获得1个更改,0字节数据.
这是我的"读者":
<?php
define('NL', "\n\r");
$journal = '/var/run/systemd/journal/socket';
$jSTDOUT = '/var/run/systemd/journal/stdout';
$journal = $jSTDOUT;
$sock = socket_create(AF_UNIX, SOCK_STREAM, 0);
$connection = @socket_connect($sock, $journal);
$log = function ($message)
{
echo '[' . date('r') . '] ' . $message . NL;
};
if (!$connection)
{
$log('Couldn\'t connect to ' . $journal);
}
else
{
$log('Connected to ' . $journal);
$readables = array($sock);
while (true)
{
$read = $readables;
if (socket_select($read, $write = NULL, $except = NULL, 0) < 1)
{
continue;
}
foreach ($read as $read_socket)
{
$data = @socket_read($read_socket, 1024, PHP_BINARY_READ);
if ($data === false)
{
$log('Couldn\'t read.');
socket_shutdown($read_socket, 2);
socket_close($read_socket);
$log('Server terminated.');
break 2;
}
$data = trim($data);
if (!empty($data))
{
$log($data);
}
}
}
$log('Exiting.');
}
Run Code Online (Sandbox Code Playgroud)
在读取套接字中没有数据,我认为我做错了什么.
我的目标是阅读消息,并在其中一些消息上执行回调.
有人能指出我如何以编程方式阅读期刊信息的正确方向吗?
gra*_*ity 10
下面的套接字/run/systemd/journal/不适用于此 - …/socket并且…/stdout实际上是只写的(即用于将数据馈送到日志中),而…/syslog套接字不应该由真正的syslogd之外的任何其他东西使用,更不用说journald不发送任何元数据.(事实上,…/syslog默认情况下套接字甚至不存在 - syslogd实际上必须监听它,并且journald连接到它.)
官方方法是直接从日志文件中读取,并使用inotify监视更改(这是相同的事情journalctl --follow,甚至tail -f /var/log/syslog用于代替轮询).在C程序中,您可以使用libsystemd-journal中的函数,它们将为您进行必要的解析甚至过滤.
在其他语言中,您有三种选择:调用C库; 自己解析日志文件(格式记录); 或者journalctl --follow可以告诉他们输出JSON格式的条目(或更详细的日记导出格式).第三个选项实际上非常有效,因为它只为整个流分配一个进程; 我为它编写了一个PHP包装器(见下文).
最新的systemd版本(v193)也随之而来systemd-journal-gatewayd,它本质上是基于HTTP的版本journalctl; 也就是说,您可以获取JSON或日记 - 导出流http://localhost:19531/entries.(gatewayd和journalctl甚至支持服务器发送的事件,用于从HTML 5网页访问流.)但是,由于明显的安全问题,gatewayd默认是禁用的.
附件:PHP包装器 journalctl --follow
<?php
/* © 2013 Mantas Mikul?nas <grawity@gmail.com>
* Released under the MIT Expat License <https://opensource.org/licenses/MIT>
*/
/* Iterator extends Traversable {
void rewind()
boolean valid()
void next()
mixed current()
scalar key()
}
calls: rewind, valid==true, current, key
next, valid==true, current, key
next, valid==false
*/
class Journal implements Iterator {
private $filter;
private $startpos;
private $proc;
private $stdout;
private $entry;
static function _join_argv($argv) {
return implode(" ",
array_map(function($a) {
return strlen($a) ? escapeshellarg($a) : "''";
}, $argv));
}
function __construct($filter=[], $cursor=null) {
$this->filter = $filter;
$this->startpos = $cursor;
}
function _close_journal() {
if ($this->stdout) {
fclose($this->stdout);
$this->stdout = null;
}
if ($this->proc) {
proc_close($this->proc);
$this->proc = null;
}
$this->entry = null;
}
function _open_journal($filter=[], $cursor=null) {
if ($this->proc)
$this->_close_journal();
$this->filter = $filter;
$this->startpos = $cursor;
$cmd = ["journalctl", "-f", "-o", "json"];
if ($cursor) {
$cmd[] = "-c";
$cmd[] = $cursor;
}
$cmd = array_merge($cmd, $filter);
$cmd = self::_join_argv($cmd);
$fdspec = [
0 => ["file", "/dev/null", "r"],
1 => ["pipe", "w"],
2 => ["file", "/dev/null", "w"],
];
$this->proc = proc_open($cmd, $fdspec, $fds);
if (!$this->proc)
return false;
$this->stdout = $fds[1];
}
function seek($cursor) {
$this->_open_journal($this->filter, $cursor);
}
function rewind() {
$this->seek($this->startpos);
}
function next() {
$line = fgets($this->stdout);
if ($line === false)
$this->entry = false;
else
$this->entry = json_decode($line);
}
function valid() {
return ($this->entry !== false);
/* null is valid, it just means next() hasn't been called yet */
}
function current() {
if (!$this->entry)
$this->next();
return $this->entry;
}
function key() {
if (!$this->entry)
$this->next();
return $this->entry->__CURSOR;
}
}
$a = new Journal();
foreach ($a as $cursor => $item) {
echo "================\n";
var_dump($cursor);
//print_r($item);
if ($item)
var_dump($item->MESSAGE);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3727 次 |
| 最近记录: |