Passed
Push — master ( d979ac...b22592 )
by Fabio
05:10
created

TSysLogRoute::translateLogLevel()   B

Complexity

Conditions 11
Paths 11

Size

Total Lines 22
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 20
nc 11
nop 1
dl 0
loc 22
rs 7.3166
c 1
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * TSysLogRoute class file
4
 *
5
 * @author Brad Anderson <[email protected]>
6
 * @link https://github.com/pradosoft/prado
7
 * @license https://github.com/pradosoft/prado/blob/master/LICENSE
8
 */
9
10
namespace Prado\Util;
11
12
use Prado\Exceptions\TConfigurationException;
13
use Prado\Exceptions\TLogException;
14
use Prado\Prado;
15
use Prado\TPropertyValue;
16
17
/**
18
 * TSysLogRoute class.
19
 *
20
 * Sends the log to the syslog.
21
 *
22
 * @author Brad Anderson <[email protected]>
23
 * @since 4.2.3
24
 * @link https://www.php.net/manual/en/function.openlog.php
25
 * @link https://www.php.net/manual/en/function.syslog.php
26
 */
27
class TSysLogRoute extends TLogRoute
28
{
29
	/**
30
	 * @var false|string The Prefix for openlog()
31
	 */
32
	private string|false $_sysLogPrefix = false;
33
34
	/**
35
	 * @var ?int The flags for openlog(), default null for `LOG_ODELAY | LOG_PID`
36
	 */
37
	private ?int $_sysLogFlags = null;
38
39
	/**
40
	 * @var int The facility for openlog().
41
	 */
42
	private int $_facility = LOG_USER;
43
44
	/**
45
	 * @param array $logs list of log messages
46
	 * @param bool $final is the final flush
47
	 * @param array $meta the meta data for the logs.
48
	 * @throws TLogException When failing to write to syslog.
49
	 */
50
	protected function processLogs(array $logs, bool $final, array $meta)
51
	{
52
		openlog($this->getSysLogPrefix(), $this->getSysLogFlags(), $this->getFacility());
0 ignored issues
show
Bug introduced by
It seems like $this->getSysLogPrefix() can also be of type false; however, parameter $prefix of openlog() 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

52
		openlog(/** @scrutinizer ignore-type */ $this->getSysLogPrefix(), $this->getSysLogFlags(), $this->getFacility());
Loading history...
53
		foreach ($logs as $log) {
54
			if (syslog($this->translateLogLevel($log[TLogger::LOG_LEVEL]), $this->formatLogMessage($log)) === false) {
55
				throw new TLogException('syslogroute_log_failed');
56
			}
57
		}
58
		closelog();
59
	}
60
61
	/**
62
	 * Translates a PRADO log level attribute into one understood by syslog
63
	 * @param int $level prado log level
64
	 * @return int syslog priority
65
	 */
66
	protected static function translateLogLevel($level)
67
	{
68
		switch ($level) {
69
			case TLogger::PROFILE:
70
			case TLogger::PROFILE_BEGIN:
71
			case TLogger::PROFILE_END:
72
			case TLogger::DEBUG:
73
				return LOG_DEBUG;
74
			case TLogger::INFO:
75
				return LOG_INFO;
76
			case TLogger::NOTICE:
77
				return LOG_NOTICE;
78
			case TLogger::WARNING:
79
				return LOG_WARNING;
80
			case TLogger::ERROR:
81
				return LOG_ERR;
82
			case TLogger::ALERT:
83
				return LOG_ALERT;
84
			case TLogger::FATAL:
85
				return LOG_CRIT;
86
			default:
87
				return LOG_INFO;
88
		}
89
	}
90
91
	/**
92
	 * @return string The prefix for syslog. Defaults to false
93
	 */
94
	public function getSysLogPrefix(): string|false
95
	{
96
		return $this->_sysLogPrefix;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->_sysLogPrefix could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
97
	}
98
99
	/**
100
	 * @param string $value the prefix for the syslog, via openlog
101
	 */
102
	public function setSysLogPrefix($value)
103
	{
104
		$value = TPropertyValue::ensureString($value);
105
		if ($value === '') {
106
			$value = false;
107
		}
108
		$this->_sysLogPrefix = $value;
109
	}
110
111
	/**
112
	 * @return int The options for syslog. Defaults to LOG_ODELAY | LOG_PID
113
	 */
114
	public function getSysLogFlags()
115
	{
116
		return ($this->_sysLogFlags !== null) ? $this->_sysLogFlags : LOG_ODELAY | LOG_PID;
117
	}
118
119
	/**
120
	 * This sets the `openlog` flags.  It can be an integer, a string or an array of strings.
121
	 * As a string, the delimiters are ',' and '|' acting identically.
122
	 *
123
	 * By setting to null, this will default to `LOG_ODELAY | LOG_PID`.
124
	 * @param null|int|string|string[] $value the options for syslog
125
	 * @return static The current object.
126
	 * @throw TConfigurationException When the Flags are not valid.
127
	 */
128
	public function setSysLogFlags($value): static
129
	{
130
		static $_flagsMap = [
131
			'LOG_CONS' => LOG_CONS, // Errors to console
132
			'LOG_NDELAY' => LOG_NDELAY, // open immediately
133
			'LOG_ODELAY' => LOG_ODELAY, // delay opening until a log
134
			'LOG_PERROR' => LOG_PERROR, // Print to STDERR as well.
135
			'LOG_PID' => LOG_PID, // include ProcessID
136
		];
137
138
		if ($value === null || is_int($value)) {
139
			$invalidFlags = ~array_reduce($_flagsMap, function ($flags, $flag) {
140
				return $flags | $flag;
141
			}, 0);
142
			if ($invalidFlags & ((int) $value)) {
143
				throw new TConfigurationException('syslogroute_bad_flags', '0x' . dechex($value));
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type null; however, parameter $num of dechex() 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

143
				throw new TConfigurationException('syslogroute_bad_flags', '0x' . dechex(/** @scrutinizer ignore-type */ $value));
Loading history...
144
			}
145
			$this->_sysLogFlags = $value;
146
		} else {
147
			if (!is_array($value)) {
148
				$value = preg_split('/[|,]/', strtoupper($value));
149
			} else {
150
				$value = array_map('strtoupper', $value);
151
			}
152
			$options = array_map('trim', $value);
153
			$this->_sysLogFlags = 0;
154
			while(count($options)) {
155
				$option = array_pop($options);
156
				if (isset($_flagsMap[$option])) {
157
					$this->_sysLogFlags |= $_flagsMap[$option];
158
				}
159
			}
160
		}
161
		return $this;
162
	}
163
164
	/**
165
	 * @return int The facility for syslog.
166
	 */
167
	public function getFacility(): int
168
	{
169
		return $this->_facility;
170
	}
171
172
	/**
173
	 * @param int|string $value the options for syslog
174
	 * @return static The current object.
175
	 */
176
	public function setFacility($value): static
177
	{
178
		static $_facilitiesMap = [
179
			'LOG_AUTH' => LOG_AUTH,		// 0x20
180
			'LOG_CRON' => LOG_CRON,		// 0x48
181
			'LOG_DAEMON' => LOG_DAEMON,	// 0x18
182
			'LOG_KERN' => LOG_KERN,		// 0x00
183
			'LOG_LOCAL0' => LOG_LOCAL0,	// 0x80
184
			'LOG_LOCAL1' => LOG_LOCAL1,	// 0x88
185
			'LOG_LOCAL2' => LOG_LOCAL2,	// 0x90
186
			'LOG_LOCAL3' => LOG_LOCAL3,	// 0x98
187
			'LOG_LOCAL4' => LOG_LOCAL4,	// 0xa0
188
			'LOG_LOCAL5' => LOG_LOCAL5,	// 0xa8
189
			'LOG_LOCAL6' => LOG_LOCAL6,	// 0xb0
190
			'LOG_LOCAL7' => LOG_LOCAL7,	// 0xb8
191
			'LOG_LPR' => LOG_LPR,		// 0x30
192
			'LOG_MAIL' => LOG_MAIL,		// 0x10
193
			'LOG_NEWS' => LOG_NEWS, 	// 0x38
194
			'LOG_SYSLOG' => LOG_SYSLOG, // 0x28
195
			'LOG_USER' => LOG_USER, 	// 0x08
196
			'LOG_UUCP' => LOG_UUCP, 	// 0x40
197
		];
198
		if (defined('LOG_AUTHPRIV')) {
199
			$_facilitiesMap['LOG_AUTH'] = LOG_AUTHPRIV;
200
		}
201
202
		if (is_int($value)) {
203
			if (defined('LOG_AUTHPRIV') && $value === LOG_AUTH) {
204
				$value = LOG_AUTHPRIV;
205
			}
206
207
			if (array_search($value, $_facilitiesMap) === false) {
208
				throw new TConfigurationException('syslogroute_bad_facility', '0x' . dechex($value));
209
			}
210
		} else {
211
			$value = trim(strtoupper($value));
212
			if (isset($_facilitiesMap[$value])) {
213
				$value = $_facilitiesMap[$value];
214
			} else {
215
				throw new TConfigurationException('syslogroute_bad_facility', '0x' . dechex($value));
0 ignored issues
show
Bug introduced by
$value of type string is incompatible with the type integer expected by parameter $num of dechex(). ( Ignorable by Annotation )

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

215
				throw new TConfigurationException('syslogroute_bad_facility', '0x' . dechex(/** @scrutinizer ignore-type */ $value));
Loading history...
216
			}
217
		}
218
		$this->_facility = $value;
219
220
		return $this;
221
	}
222
223
	/**
224
	 * {@inheritdoc}
225
	 */
226
	public function formatLogMessage(array $log): string
227
	{
228
		if (!is_string($log[TLogger::LOG_MESSAGE])) {
229
			if ($log[TLogger::LOG_MESSAGE] instanceof \Exception || $log[TLogger::LOG_MESSAGE] instanceof \Throwable) {
230
				$log[TLogger::LOG_MESSAGE] = (string) $log[TLogger::LOG_MESSAGE];
231
			} else {
232
				$log[TLogger::LOG_MESSAGE] = \Prado\Util\TVarDumper::dump($log[TLogger::LOG_MESSAGE]);
233
			}
234
		}
235
236
		$prefix = $this->getLogPrefix($log);
237
238
		return $prefix . '[' . static::getLevelName($log[TLogger::LOG_LEVEL]) . '][' . $log[TLogger::LOG_CATEGORY] . '] ' . $log[TLogger::LOG_MESSAGE];
0 ignored issues
show
Bug Best Practice introduced by
The method Prado\Util\TLogRoute::getLevelName() is not static, but was called statically. ( Ignorable by Annotation )

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

238
		return $prefix . '[' . static::/** @scrutinizer ignore-call */ getLevelName($log[TLogger::LOG_LEVEL]) . '][' . $log[TLogger::LOG_CATEGORY] . '] ' . $log[TLogger::LOG_MESSAGE];
Loading history...
239
	}
240
}
241