aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private/Log/File.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private/Log/File.php')
-rw-r--r--lib/private/Log/File.php120
1 files changed, 120 insertions, 0 deletions
diff --git a/lib/private/Log/File.php b/lib/private/Log/File.php
new file mode 100644
index 00000000000..ba428ba185b
--- /dev/null
+++ b/lib/private/Log/File.php
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+namespace OC\Log;
+
+use OC\SystemConfig;
+use OCP\ILogger;
+use OCP\Log\IFileBased;
+use OCP\Log\IWriter;
+
+/**
+ * logging utilities
+ *
+ * Log is saved at data/nextcloud.log (on default)
+ */
+
+class File extends LogDetails implements IWriter, IFileBased {
+ protected string $logFile;
+
+ protected int $logFileMode;
+
+ public function __construct(
+ string $path,
+ string $fallbackPath,
+ private SystemConfig $config,
+ ) {
+ parent::__construct($config);
+ $this->logFile = $path;
+ if (!file_exists($this->logFile)) {
+ if (
+ (
+ !is_writable(dirname($this->logFile))
+ || !touch($this->logFile)
+ )
+ && $fallbackPath !== ''
+ ) {
+ $this->logFile = $fallbackPath;
+ }
+ }
+ $this->logFileMode = $config->getValue('logfilemode', 0640);
+ }
+
+ /**
+ * write a message in the log
+ * @param string|array $message
+ */
+ public function write(string $app, $message, int $level): void {
+ $entry = $this->logDetailsAsJSON($app, $message, $level);
+ $handle = @fopen($this->logFile, 'a');
+ if ($this->logFileMode > 0 && is_file($this->logFile) && (fileperms($this->logFile) & 0777) != $this->logFileMode) {
+ @chmod($this->logFile, $this->logFileMode);
+ }
+ if ($handle) {
+ fwrite($handle, $entry . "\n");
+ fclose($handle);
+ } else {
+ // Fall back to error_log
+ error_log($entry);
+ }
+ if (php_sapi_name() === 'cli-server') {
+ if (!\is_string($message)) {
+ $message = json_encode($message);
+ }
+ error_log($message, 4);
+ }
+ }
+
+ /**
+ * get entries from the log in reverse chronological order
+ */
+ public function getEntries(int $limit = 50, int $offset = 0): array {
+ $minLevel = $this->config->getValue('loglevel', ILogger::WARN);
+ $entries = [];
+ $handle = @fopen($this->logFile, 'rb');
+ if ($handle) {
+ fseek($handle, 0, SEEK_END);
+ $pos = ftell($handle);
+ $line = '';
+ $entriesCount = 0;
+ $lines = 0;
+ // Loop through each character of the file looking for new lines
+ while ($pos >= 0 && ($limit === null || $entriesCount < $limit)) {
+ fseek($handle, $pos);
+ $ch = fgetc($handle);
+ if ($ch == "\n" || $pos == 0) {
+ if ($line != '') {
+ // Add the first character if at the start of the file,
+ // because it doesn't hit the else in the loop
+ if ($pos == 0) {
+ $line = $ch . $line;
+ }
+ $entry = json_decode($line);
+ // Add the line as an entry if it is passed the offset and is equal or above the log level
+ if ($entry->level >= $minLevel) {
+ $lines++;
+ if ($lines > $offset) {
+ $entries[] = $entry;
+ $entriesCount++;
+ }
+ }
+ $line = '';
+ }
+ } else {
+ $line = $ch . $line;
+ }
+ $pos--;
+ }
+ fclose($handle);
+ }
+ return $entries;
+ }
+
+ public function getLogFilePath():string {
+ return $this->logFile;
+ }
+}