Move log detail aggregation to separate class and reuse it in syslog/systemd logger
Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
parent
c048c56411
commit
07bbec3355
|
@ -974,6 +974,7 @@ return array(
|
|||
'OC\\Log\\Errorlog' => $baseDir . '/lib/private/Log/Errorlog.php',
|
||||
'OC\\Log\\ExceptionSerializer' => $baseDir . '/lib/private/Log/ExceptionSerializer.php',
|
||||
'OC\\Log\\File' => $baseDir . '/lib/private/Log/File.php',
|
||||
'OC\\Log\\LogDetails' => $baseDir . '/lib/private/Log/LogDetails.php',
|
||||
'OC\\Log\\LogFactory' => $baseDir . '/lib/private/Log/LogFactory.php',
|
||||
'OC\\Log\\Rotate' => $baseDir . '/lib/private/Log/Rotate.php',
|
||||
'OC\\Log\\Syslog' => $baseDir . '/lib/private/Log/Syslog.php',
|
||||
|
|
|
@ -1008,6 +1008,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
|||
'OC\\Log\\Errorlog' => __DIR__ . '/../../..' . '/lib/private/Log/Errorlog.php',
|
||||
'OC\\Log\\ExceptionSerializer' => __DIR__ . '/../../..' . '/lib/private/Log/ExceptionSerializer.php',
|
||||
'OC\\Log\\File' => __DIR__ . '/../../..' . '/lib/private/Log/File.php',
|
||||
'OC\\Log\\LogDetails' => __DIR__ . '/../../..' . '/lib/private/Log/LogDetails.php',
|
||||
'OC\\Log\\LogFactory' => __DIR__ . '/../../..' . '/lib/private/Log/LogFactory.php',
|
||||
'OC\\Log\\Rotate' => __DIR__ . '/../../..' . '/lib/private/Log/Rotate.php',
|
||||
'OC\\Log\\Syslog' => __DIR__ . '/../../..' . '/lib/private/Log/Syslog.php',
|
||||
|
|
|
@ -47,7 +47,7 @@ use OCP\ILogger;
|
|||
* Log is saved at data/nextcloud.log (on default)
|
||||
*/
|
||||
|
||||
class File implements IWriter, IFileBased {
|
||||
class File extends LogDetails implements IWriter, IFileBased {
|
||||
/** @var string */
|
||||
protected $logFile;
|
||||
/** @var int */
|
||||
|
@ -56,6 +56,7 @@ class File implements IWriter, IFileBased {
|
|||
private $config;
|
||||
|
||||
public function __construct(string $path, string $fallbackPath = '', SystemConfig $config) {
|
||||
parent::__construct($config);
|
||||
$this->logFile = $path;
|
||||
if (!file_exists($this->logFile)) {
|
||||
if(
|
||||
|
@ -79,63 +80,7 @@ class File implements IWriter, IFileBased {
|
|||
* @param int $level
|
||||
*/
|
||||
public function write(string $app, $message, int $level) {
|
||||
// default to ISO8601
|
||||
$format = $this->config->getValue('logdateformat', \DateTime::ATOM);
|
||||
$logTimeZone = $this->config->getValue('logtimezone', 'UTC');
|
||||
try {
|
||||
$timezone = new \DateTimeZone($logTimeZone);
|
||||
} catch (\Exception $e) {
|
||||
$timezone = new \DateTimeZone('UTC');
|
||||
}
|
||||
$time = \DateTime::createFromFormat("U.u", number_format(microtime(true), 4, ".", ""));
|
||||
if ($time === false) {
|
||||
$time = new \DateTime(null, $timezone);
|
||||
} else {
|
||||
// apply timezone if $time is created from UNIX timestamp
|
||||
$time->setTimezone($timezone);
|
||||
}
|
||||
$request = \OC::$server->getRequest();
|
||||
$reqId = $request->getId();
|
||||
$remoteAddr = $request->getRemoteAddress();
|
||||
// remove username/passwords from URLs before writing the to the log file
|
||||
$time = $time->format($format);
|
||||
$url = ($request->getRequestUri() !== '') ? $request->getRequestUri() : '--';
|
||||
$method = is_string($request->getMethod()) ? $request->getMethod() : '--';
|
||||
if($this->config->getValue('installed', false)) {
|
||||
$user = \OC_User::getUser() ? \OC_User::getUser() : '--';
|
||||
} else {
|
||||
$user = '--';
|
||||
}
|
||||
$userAgent = $request->getHeader('User-Agent');
|
||||
if ($userAgent === '') {
|
||||
$userAgent = '--';
|
||||
}
|
||||
$version = $this->config->getValue('version', '');
|
||||
$entry = compact(
|
||||
'reqId',
|
||||
'level',
|
||||
'time',
|
||||
'remoteAddr',
|
||||
'user',
|
||||
'app',
|
||||
'method',
|
||||
'url',
|
||||
'message',
|
||||
'userAgent',
|
||||
'version'
|
||||
);
|
||||
// PHP's json_encode only accept proper UTF-8 strings, loop over all
|
||||
// elements to ensure that they are properly UTF-8 compliant or convert
|
||||
// them manually.
|
||||
foreach($entry as $key => $value) {
|
||||
if(is_string($value)) {
|
||||
$testEncode = json_encode($value);
|
||||
if($testEncode === false) {
|
||||
$entry[$key] = utf8_encode($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
$entry = json_encode($entry, JSON_PARTIAL_OUTPUT_ON_ERROR);
|
||||
$entry = $this->logDetailsAsJSON($app, $message, $level);
|
||||
$handle = @fopen($this->logFile, 'a');
|
||||
if ($this->logFileMode > 0 && (fileperms($this->logFile) & 0777) != $this->logFileMode) {
|
||||
@chmod($this->logFile, $this->logFileMode);
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2019 Julius Härtl <jus@bitgrid.net>
|
||||
*
|
||||
* @author Julius Härtl <jus@bitgrid.net>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OC\Log;
|
||||
|
||||
use OC\SystemConfig;
|
||||
|
||||
abstract class LogDetails {
|
||||
|
||||
/** @var SystemConfig */
|
||||
private $config;
|
||||
|
||||
public function __construct(SystemConfig $config) {
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
public function logDetails(string $app, $message, int $level): array {
|
||||
// default to ISO8601
|
||||
$format = $this->config->getValue('logdateformat', \DateTime::ATOM);
|
||||
$logTimeZone = $this->config->getValue('logtimezone', 'UTC');
|
||||
try {
|
||||
$timezone = new \DateTimeZone($logTimeZone);
|
||||
} catch (\Exception $e) {
|
||||
$timezone = new \DateTimeZone('UTC');
|
||||
}
|
||||
$time = \DateTime::createFromFormat("U.u", number_format(microtime(true), 4, ".", ""));
|
||||
if ($time === false) {
|
||||
$time = new \DateTime(null, $timezone);
|
||||
} else {
|
||||
// apply timezone if $time is created from UNIX timestamp
|
||||
$time->setTimezone($timezone);
|
||||
}
|
||||
$request = \OC::$server->getRequest();
|
||||
$reqId = $request->getId();
|
||||
$remoteAddr = $request->getRemoteAddress();
|
||||
// remove username/passwords from URLs before writing the to the log file
|
||||
$time = $time->format($format);
|
||||
$url = ($request->getRequestUri() !== '') ? $request->getRequestUri() : '--';
|
||||
$method = is_string($request->getMethod()) ? $request->getMethod() : '--';
|
||||
if($this->config->getValue('installed', false)) {
|
||||
$user = \OC_User::getUser() ? \OC_User::getUser() : '--';
|
||||
} else {
|
||||
$user = '--';
|
||||
}
|
||||
$userAgent = $request->getHeader('User-Agent');
|
||||
if ($userAgent === '') {
|
||||
$userAgent = '--';
|
||||
}
|
||||
$version = $this->config->getValue('version', '');
|
||||
$entry = compact(
|
||||
'reqId',
|
||||
'level',
|
||||
'time',
|
||||
'remoteAddr',
|
||||
'user',
|
||||
'app',
|
||||
'method',
|
||||
'url',
|
||||
'message',
|
||||
'userAgent',
|
||||
'version'
|
||||
);
|
||||
return $entry;
|
||||
}
|
||||
|
||||
public function logDetailsAsJSON(string $app, $message, int $level): string {
|
||||
$entry = $this->logDetails($app, $message, $level);
|
||||
// PHP's json_encode only accept proper UTF-8 strings, loop over all
|
||||
// elements to ensure that they are properly UTF-8 compliant or convert
|
||||
// them manually.
|
||||
foreach($entry as $key => $value) {
|
||||
if(is_string($value)) {
|
||||
$testEncode = json_encode($value);
|
||||
if($testEncode === false) {
|
||||
$entry[$key] = utf8_encode($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return json_encode($entry, JSON_PARTIAL_OUTPUT_ON_ERROR);
|
||||
}
|
||||
}
|
|
@ -25,11 +25,11 @@
|
|||
|
||||
namespace OC\Log;
|
||||
|
||||
use OC\SystemConfig;
|
||||
use OCP\ILogger;
|
||||
use OCP\IConfig;
|
||||
use OCP\Log\IWriter;
|
||||
|
||||
class Syslog implements IWriter {
|
||||
class Syslog extends LogDetails implements IWriter {
|
||||
protected $levels = [
|
||||
ILogger::DEBUG => LOG_DEBUG,
|
||||
ILogger::INFO => LOG_INFO,
|
||||
|
@ -38,7 +38,8 @@ class Syslog implements IWriter {
|
|||
ILogger::FATAL => LOG_CRIT,
|
||||
];
|
||||
|
||||
public function __construct(IConfig $config) {
|
||||
public function __construct(SystemConfig $config) {
|
||||
parent::__construct($config);
|
||||
openlog($config->getSystemValue('syslog_tag', 'Nextcloud'), LOG_PID | LOG_CONS, LOG_USER);
|
||||
}
|
||||
|
||||
|
@ -54,6 +55,6 @@ class Syslog implements IWriter {
|
|||
*/
|
||||
public function write(string $app, $message, int $level) {
|
||||
$syslog_level = $this->levels[$level];
|
||||
syslog($syslog_level, '{'.$app.'} '.$message);
|
||||
syslog($syslog_level, $this->logDetailsAsJSON($app, $message, $level));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
namespace OC\Log;
|
||||
|
||||
use OC\HintException;
|
||||
use OC\SystemConfig;
|
||||
use OCP\ILogger;
|
||||
use OCP\IConfig;
|
||||
use OCP\Log\IWriter;
|
||||
|
@ -42,7 +43,7 @@ use OCP\Log\IWriter;
|
|||
// SYSLOG_FACILITY=, SYSLOG_IDENTIFIER=, SYSLOG_PID=
|
||||
// Syslog compatibility fields
|
||||
|
||||
class Systemdlog implements IWriter {
|
||||
class Systemdlog extends LogDetails implements IWriter {
|
||||
protected $levels = [
|
||||
ILogger::DEBUG => 7,
|
||||
ILogger::INFO => 6,
|
||||
|
@ -53,14 +54,15 @@ class Systemdlog implements IWriter {
|
|||
|
||||
protected $syslogId;
|
||||
|
||||
public function __construct(IConfig $config) {
|
||||
public function __construct(SystemConfig $config) {
|
||||
parent::__construct($config);
|
||||
if(!function_exists('sd_journal_send')) {
|
||||
throw new HintException(
|
||||
'PHP extension php-systemd is not available.',
|
||||
'Please install and enable PHP extension systemd if you wish to log to the Systemd journal.');
|
||||
|
||||
}
|
||||
$this->syslogId = $config->getSystemValue('syslog_tag', 'Nextcloud');
|
||||
$this->syslogId = $config->getValue('syslog_tag', 'Nextcloud');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,6 +75,6 @@ class Systemdlog implements IWriter {
|
|||
$journal_level = $this->levels[$level];
|
||||
sd_journal_send('PRIORITY='.$journal_level,
|
||||
'SYSLOG_IDENTIFIER='.$this->syslogId,
|
||||
'MESSAGE={'.$app.'} '.$message);
|
||||
'MESSAGE=' . $this->logDetailsAsJSON($app, $message, $level));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue