Passed
Push — master ( 8dcc68...34e8da )
by
unknown
23:44 queued 20:40
created

Syslog::GetZpushLogLevelToSyslogLogLevel()   B

Complexity

Conditions 9
Paths 9

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 10
nc 9
nop 1
dl 0
loc 12
rs 8.0555
c 0
b 0
f 0
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
12
    protected $program_name = '';
13
14
    protected $host;
15
16
    protected $port;
17
18
    /**
19
     * @access public
20
     * @return string
21
     */
22
    public function GetProgramName() {
23
        return $this->program_name;
24
    }
25
26
    /**
27
     * @param string $value
28
     *
29
     * @access public
30
     */
31
    public function SetProgramName($value) {
32
        $this->program_name = $value;
33
    }
34
35
    /**
36
     * @access public
37
     * @return string
38
     */
39
    public function GetHost() {
40
        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...
41
    }
42
43
    /**
44
     * @param string $value
45
     *
46
     * @access public
47
     */
48
    public function SetHost($value) {
49
        $this->host = $value;
50
    }
51
52
    /**
53
     * @access public
54
     * @return int
55
     */
56
    public function GetPort() {
57
        return $this->port;
58
    }
59
60
    /**
61
     * @param int $value
62
     *
63
     * @access public
64
     */
65
    public function SetPort($value) {
66
        if (is_numeric($value)) {
0 ignored issues
show
introduced by
The condition is_numeric($value) is always true.
Loading history...
67
            $this->port = (int)$value;
68
        }
69
    }
70
71
    /**
72
     * Constructor.
73
     * Sets configured values if no parameters are given.
74
     *
75
     * @param string $program_name
76
     * @param string $host
77
     * @param string $port
78
     */
79
    public function __construct($program_name = null, $host = null, $port = null) {
80
        parent::__construct();
81
82
        if (is_null($program_name)) $program_name = LOG_SYSLOG_PROGRAM;
83
        if (is_null($host)) $host = LOG_SYSLOG_HOST;
84
        if (is_null($port)) $port = LOG_SYSLOG_PORT;
85
86
        $this->SetProgramName($program_name);
87
        $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

87
        $this->SetHost(/** @scrutinizer ignore-type */ $host);
Loading history...
88
        $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

88
        $this->SetPort(/** @scrutinizer ignore-type */ $port);
Loading history...
89
    }
90
91
    /**
92
     * Return the full program name for syslog.
93
     * The name can be grommunio-sync/core or grommunio-sync/{backend} where backend is the backend that initiated the log.
94
     *
95
     * @access protected
96
     * @return string
97
     */
98
    protected function GenerateProgramName() {
99
        // @TODO Use another mechanism than debug_backtrace to determine to origin of the log
100
        $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
101
        // Shift the "syslog.php" entry.
102
        array_shift($backtrace);
103
        foreach ($backtrace as $trace) {
104
            if (!isset($trace['file'])) {
105
                continue;
106
            }
107
            if (strpos($trace['file'], REAL_BASE_PATH . 'backend/') !== false) {
108
                preg_match('/\/backend\/([a-zA-Z]*)/', $trace['file'], $match);
109
                if (isset($match[1])) {
110
                    return $this->GetProgramName() . '/' . $match[1];
111
                }
112
            } elseif (basename($trace['file'], '.php') != 'zlog') {
113
                return $this->GetProgramName() . '/core';
114
            }
115
        }
116
117
        return $this->GetProgramName() . '/core';
118
    }
119
120
    /**
121
     * Maps the grommunio-sync loglevel with those of syslog.
122
     *
123
     * @access protected
124
     * @param int $loglevel
125
     * @return int One of many LOG_* syslog level.
126
     */
127
    protected function GetZpushLogLevelToSyslogLogLevel($loglevel) {
128
        switch ($loglevel) {
129
            case LOGLEVEL_FATAL: return LOG_ALERT; break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
130
            case LOGLEVEL_ERROR: return LOG_ERR; break;
131
            case LOGLEVEL_WARN:    return LOG_WARNING; break;
132
            case LOGLEVEL_INFO:    return LOG_INFO; break;
133
            case LOGLEVEL_DEBUG: return LOG_DEBUG; break;
134
            case LOGLEVEL_WBXML: return LOG_DEBUG; break;
135
            case LOGLEVEL_DEVICEID: return LOG_DEBUG; break;
136
            case LOGLEVEL_WBXMLSTACK: return LOG_DEBUG; break;
137
        }
138
        return null;
139
    }
140
141
    /**
142
     * Build the log string for syslog.
143
     *
144
     * @param int       $loglevel
145
     * @param string    $message
146
     * @param boolean   $includeUserDevice  puts username and device in the string, default: true
147
     *
148
     * @access public
149
     * @return string
150
     */
151
    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

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