Passed
Push — master ( e4dbf7...cd116d )
by
unknown
17:17 queued 13:52
created

Syslog::GetGsyncLogLevelToSyslogLogLevel()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 11
rs 9.9332
1
<?php
2
3
/*
4
 * SPDX-License-Identifier: AGPL-3.0-only
5
 * SPDX-FileCopyrightText: Copyright 2007-2016 Zarafa Deutschland GmbH
6
 * SPDX-FileCopyrightText: Copyright 2020-2022 grommunio GmbH
7
 *
8
 * Logging functionalities
9
 */
10
11
class Syslog extends Log {
12
	protected $program_name = '';
13
	protected $host;
14
	protected $port;
15
16
	/**
17
	 * @return string
18
	 */
19
	public function GetProgramName() {
20
		return $this->program_name;
21
	}
22
23
	/**
24
	 * @param string $value
25
	 */
26
	public function SetProgramName($value) {
27
		$this->program_name = $value;
28
	}
29
30
	/**
31
	 * @return string
32
	 */
33
	public function GetHost() {
34
		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...
35
	}
36
37
	/**
38
	 * @param string $value
39
	 */
40
	public function SetHost($value) {
41
		$this->host = $value;
42
	}
43
44
	/**
45
	 * @return int
46
	 */
47
	public function GetPort() {
48
		return $this->port;
49
	}
50
51
	/**
52
	 * @param int $value
53
	 */
54
	public function SetPort($value) {
55
		if (is_numeric($value)) {
0 ignored issues
show
introduced by
The condition is_numeric($value) is always true.
Loading history...
56
			$this->port = (int) $value;
57
		}
58
	}
59
60
	/**
61
	 * Constructor.
62
	 * Sets configured values if no parameters are given.
63
	 *
64
	 * @param string $program_name
65
	 * @param string $host
66
	 * @param string $port
67
	 */
68
	public function __construct($program_name = null, $host = null, $port = null) {
69
		parent::__construct();
70
71
		if (is_null($program_name)) {
72
			$program_name = LOG_SYSLOG_PROGRAM;
73
		}
74
		if (is_null($host)) {
75
			$host = LOG_SYSLOG_HOST;
76
		}
77
		if (is_null($port)) {
78
			$port = LOG_SYSLOG_PORT;
79
		}
80
81
		$this->SetProgramName($program_name);
82
		$this->SetHost($host);
0 ignored issues
show
Bug introduced by
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

82
		$this->SetHost(/** @scrutinizer ignore-type */ $host);
Loading history...
83
		$this->SetPort($port);
0 ignored issues
show
Bug introduced by
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

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

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