Issues (1513)

lib/log/syslog.php (5 issues)

1
<?php
2
/*
3
 * SPDX-License-Identifier: AGPL-3.0-only
4
 * SPDX-FileCopyrightText: Copyright 2007-2016 Zarafa Deutschland GmbH
5
 * SPDX-FileCopyrightText: Copyright 2020-2022 grommunio GmbH
6
 *
7
 * Logging functionalities
8
 */
9
10
class Syslog extends Log {
11
	protected $program_name = '';
12
	protected $host;
13
	protected $port;
14
15
	/**
16
	 * @return string
17
	 */
18
	public function GetProgramName() {
19
		return $this->program_name;
20
	}
21
22
	/**
23
	 * @param string $value
24
	 */
25
	public function SetProgramName($value) {
26
		$this->program_name = $value;
27
	}
28
29
	/**
30
	 * @return string
31
	 */
32
	public function GetHost() {
33
		return $this->host;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->host also could return the type boolean which is incompatible with the documented return type string.
Loading history...
34
	}
35
36
	/**
37
	 * @param string $value
38
	 */
39
	public function SetHost($value) {
40
		$this->host = $value;
41
	}
42
43
	/**
44
	 * @return int
45
	 */
46
	public function GetPort() {
47
		return $this->port;
48
	}
49
50
	/**
51
	 * @param int $value
52
	 */
53
	public function SetPort($value) {
54
		if (is_numeric($value)) {
0 ignored issues
show
The condition is_numeric($value) is always true.
Loading history...
55
			$this->port = (int) $value;
56
		}
57
	}
58
59
	/**
60
	 * Constructor.
61
	 * Sets configured values if no parameters are given.
62
	 *
63
	 * @param string $program_name
64
	 * @param string $host
65
	 * @param string $port
66
	 */
67
	public function __construct($program_name = null, $host = null, $port = null) {
68
		parent::__construct();
69
70
		if (is_null($program_name)) {
71
			$program_name = LOG_SYSLOG_PROGRAM;
72
		}
73
		if (is_null($host)) {
74
			$host = LOG_SYSLOG_HOST;
75
		}
76
		if (is_null($port)) {
77
			$port = LOG_SYSLOG_PORT;
78
		}
79
80
		$this->SetProgramName($program_name);
81
		$this->SetHost($host);
0 ignored issues
show
It seems like $host can also be of type false; however, parameter $value of Syslog::SetHost() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

81
		$this->SetHost(/** @scrutinizer ignore-type */ $host);
Loading history...
82
		$this->SetPort($port);
0 ignored issues
show
It seems like $port can also be of type string; however, parameter $value of Syslog::SetPort() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

82
		$this->SetPort(/** @scrutinizer ignore-type */ $port);
Loading history...
83
	}
84
85
	/**
86
	 * Return the full program name for syslog.
87
	 * The name can be grommunio-sync/core or grommunio-sync/{backend} where backend is the backend that initiated the log.
88
	 *
89
	 * @return string
90
	 */
91
	protected function GenerateProgramName() {
92
		// @TODO Use another mechanism than debug_backtrace to determine to origin of the log
93
		$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
94
		// Shift the "syslog.php" entry.
95
		array_shift($backtrace);
96
		foreach ($backtrace as $trace) {
97
			if (!isset($trace['file'])) {
98
				continue;
99
			}
100
			if (strpos($trace['file'], REAL_BASE_PATH . 'backend/') !== false) {
101
				preg_match('/\/backend\/([a-zA-Z]*)/', $trace['file'], $match);
102
				if (isset($match[1])) {
103
					return $this->GetProgramName() . '/' . $match[1];
104
				}
105
			}
106
			elseif (basename($trace['file'], '.php') != 'slog') {
107
				return $this->GetProgramName() . '/core';
108
			}
109
		}
110
111
		return $this->GetProgramName() . '/core';
112
	}
113
114
	/**
115
	 * Maps the grommunio-sync loglevel with those of syslog.
116
	 *
117
	 * @param int $loglevel
118
	 *
119
	 * @return int one of many LOG_* syslog level
120
	 */
121
	protected function GetGsyncLogLevelToSyslogLogLevel($loglevel) {
122
		switch ($loglevel) {
123
			case LOGLEVEL_FATAL:
124
				return LOG_ALERT;
125
126
			case LOGLEVEL_ERROR:
127
				return LOG_ERR;
128
129
			case LOGLEVEL_WARN:
130
				return LOG_WARNING;
131
132
			case LOGLEVEL_INFO:
133
				return LOG_INFO;
134
135
			case LOGLEVEL_DEBUG:
136
				return LOG_DEBUG;
137
138
			case LOGLEVEL_WBXML:
139
				return LOG_DEBUG;
140
141
			case LOGLEVEL_DEVICEID:
142
				return LOG_DEBUG;
143
144
			case LOGLEVEL_WBXMLSTACK:
145
				return LOG_DEBUG;
146
		}
147
148
		return null;
149
	}
150
151
	/**
152
	 * Build the log string for syslog.
153
	 *
154
	 * @param int    $loglevel
155
	 * @param string $message
156
	 * @param bool   $includeUserDevice puts username and device in the string, default: true
157
	 *
158
	 * @return string
159
	 */
160
	public function BuildLogString($loglevel, $message, $includeUserDevice = true) {
0 ignored issues
show
The parameter $includeUserDevice is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

160
	public function BuildLogString($loglevel, $message, /** @scrutinizer ignore-unused */ $includeUserDevice = true) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
161
		$log = $this->GetLogLevelString($loglevel); // Never pad syslog log because syslog log are usually read with a software.
162
		// when the users differ, we need to log both
163
		if (strcasecmp($this->GetAuthUser(), $this->GetUser()) == 0) {
164
			$log .= ' [' . $this->GetUser() . ']';
165
		}
166
		else {
167
			$log .= ' [' . $this->GetAuthUser() . Request::IMPERSONATE_DELIM . $this->GetUser() . ']';
168
		}
169
		if ($loglevel >= LOGLEVEL_DEVICEID) {
170
			$log .= '[' . $this->GetDevid() . ']';
171
		}
172
		$log .= ' ' . $message;
173
174
		return $log;
175
	}
176
177
	//
178
	// Implementation of Log
179
	//
180
181
	/**
182
	 * Writes a log message to the general log.
183
	 *
184
	 * @param int    $loglevel
185
	 * @param string $message
186
	 */
187
	protected function Write($loglevel, $message) {
188
		if ($this->GetHost() && $this->GetPort()) {
189
			$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
190
			$facility = 1; // user level
191
			$pri = ($facility * 8) + $loglevel; // multiplying the Facility number by 8 + adding the level
192
			$data = $this->BuildLogString($loglevel, $message);
193
			if (strlen(trim($data)) > 0) {
194
				$syslog_message = "<{$pri}>" . date('M d H:i:s ') . '[' . $this->GetProgramName() . ']: ' . $data;
195
				socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, $this->GetHost(), $this->GetPort());
196
			}
197
			socket_close($sock);
198
		}
199
		else {
200
			openlog($this->GenerateProgramName(), LOG_PID, LOG_SYSLOG_FACILITY);
201
			syslog(
202
				$this->GetGsyncLogLevelToSyslogLogLevel($loglevel),
203
				$this->BuildLogString($loglevel, $message)
204
			);
205
		}
206
	}
207
208
	/**
209
	 * This function is used as an event for log implementer.
210
	 * It happens when the a call to the Log function is finished.
211
	 *
212
	 * @param mixed $loglevel
213
	 * @param mixed $message
214
	 */
215
	public function WriteForUser($loglevel, $message) {
216
		$this->Write(LOGLEVEL_DEBUG, $message); // Always pass the logleveldebug so it uses syslog level LOG_DEBUG
217
	}
218
}
219