1<?php 2/*********************************************** 3 * File : syslog.php 4 * Project : Z-Push 5 * Descr : Logging functionalities 6 * 7 * Created : 13.11.2015 8 * 9 * Copyright 2007 - 2016 Zarafa Deutschland GmbH 10 * 11 * This program is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Affero General Public License, version 3, 13 * as published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Affero General Public License for more details. 19 * 20 * You should have received a copy of the GNU Affero General Public License 21 * along with this program. If not, see <http://www.gnu.org/licenses/>. 22 * 23 * Consult LICENSE file for details 24 ************************************************/ 25 26class Syslog extends Log { 27 28 protected $program_name = ''; 29 30 protected $host; 31 32 protected $port; 33 34 /** 35 * @access public 36 * @return string 37 */ 38 public function GetProgramName() { 39 return $this->program_name; 40 } 41 42 /** 43 * @param string $value 44 * 45 * @access public 46 */ 47 public function SetProgramName($value) { 48 $this->program_name = $value; 49 } 50 51 /** 52 * @access public 53 * @return string 54 */ 55 public function GetHost() { 56 return $this->host; 57 } 58 59 /** 60 * @param string $value 61 * 62 * @access public 63 */ 64 public function SetHost($value) { 65 $this->host = $value; 66 } 67 68 /** 69 * @access public 70 * @return int 71 */ 72 public function GetPort() { 73 return $this->port; 74 } 75 76 /** 77 * @param int $value 78 * 79 * @access public 80 */ 81 public function SetPort($value) { 82 if (is_numeric($value)) { 83 $this->port = (int)$value; 84 } 85 } 86 87 /** 88 * Constructor. 89 * Sets configured values if no parameters are given. 90 * 91 * @param string $program_name 92 * @param string $host 93 * @param string $port 94 */ 95 public function __construct($program_name = null, $host = null, $port = null) { 96 parent::__construct(); 97 98 if (is_null($program_name)) $program_name = LOG_SYSLOG_PROGRAM; 99 if (is_null($host)) $host = LOG_SYSLOG_HOST; 100 if (is_null($port)) $port = LOG_SYSLOG_PORT; 101 102 $this->SetProgramName($program_name); 103 $this->SetHost($host); 104 $this->SetPort($port); 105 } 106 107 /** 108 * Return the full program name for syslog. 109 * The name can be z-push/core or z-push/{backend} where backend is the backend that initiated the log. 110 * 111 * @access protected 112 * @return string 113 */ 114 protected function GenerateProgramName() { 115 // @TODO Use another mechanism than debug_backtrace to determine to origin of the log 116 $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); 117 // Shift the "syslog.php" entry. 118 array_shift($backtrace); 119 foreach ($backtrace as $trace) { 120 if (!isset($trace['file'])) { 121 continue; 122 } 123 if (strpos($trace['file'], REAL_BASE_PATH . 'backend/') !== false) { 124 preg_match('/\/backend\/([a-zA-Z]*)/', $trace['file'], $match); 125 if (isset($match[1])) { 126 return $this->GetProgramName() . '/' . $match[1]; 127 } 128 } elseif (basename($trace['file'], '.php') != 'zlog') { 129 return $this->GetProgramName() . '/core'; 130 } 131 } 132 133 return $this->GetProgramName() . '/core'; 134 } 135 136 /** 137 * Maps the z-push loglevel with those of syslog. 138 * 139 * @access protected 140 * @param int $loglevel 141 * @return int One of many LOG_* syslog level. 142 */ 143 protected function GetZpushLogLevelToSyslogLogLevel($loglevel) { 144 switch ($loglevel) { 145 case LOGLEVEL_FATAL: return LOG_ALERT; break; 146 case LOGLEVEL_ERROR: return LOG_ERR; break; 147 case LOGLEVEL_WARN: return LOG_WARNING; break; 148 case LOGLEVEL_INFO: return LOG_INFO; break; 149 case LOGLEVEL_DEBUG: return LOG_DEBUG; break; 150 case LOGLEVEL_WBXML: return LOG_DEBUG; break; 151 case LOGLEVEL_DEVICEID: return LOG_DEBUG; break; 152 case LOGLEVEL_WBXMLSTACK: return LOG_DEBUG; break; 153 } 154 return null; 155 } 156 157 /** 158 * Build the log string for syslog. 159 * 160 * @param int $loglevel 161 * @param string $message 162 * @param boolean $includeUserDevice puts username and device in the string, default: true 163 * 164 * @access public 165 * @return string 166 */ 167 public function BuildLogString($loglevel, $message, $includeUserDevice = true) { 168 $log = $this->GetLogLevelString($loglevel); // Never pad syslog log because syslog log are usually read with a software. 169 // when the users differ, we need to log both 170 if (strcasecmp($this->GetAuthUser(), $this->GetUser()) == 0) { 171 $log .= ' ['. $this->GetUser() .']'; 172 } 173 else { 174 $log .= ' ['. $this->GetAuthUser() . Request::IMPERSONATE_DELIM . $this->GetUser() .']'; 175 } 176 if ($loglevel >= LOGLEVEL_DEVICEID) { 177 $log .= '['. $this->GetDevid() .']'; 178 } 179 $log .= ' ' . $message; 180 return $log; 181 } 182 183 // 184 // Implementation of Log 185 // 186 187 /** 188 * Writes a log message to the general log. 189 * 190 * @param int $loglevel 191 * @param string $message 192 * 193 * @access protected 194 * @return void 195 */ 196 protected function Write($loglevel, $message) { 197 if ($this->GetHost() && $this->GetPort()) { 198 $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); 199 $facility = 1; // user level 200 $pri = ($facility * 8) + $loglevel; // multiplying the Facility number by 8 + adding the level 201 $data = $this->BuildLogString($loglevel, $message); 202 if (strlen(trim($data)) > 0) { 203 $syslog_message = "<{$pri}>" . date('M d H:i:s ') . '[' . $this->GetProgramName() . ']: ' . $data; 204 socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, $this->GetHost(), $this->GetPort()); 205 } 206 socket_close($sock); 207 } else { 208 openlog($this->GenerateProgramName(), LOG_PID, LOG_SYSLOG_FACILITY); 209 syslog( 210 $this->GetZpushLogLevelToSyslogLogLevel($loglevel), 211 $this->BuildLogString($loglevel, $message) 212 ); 213 } 214 } 215 216 /** 217 * This function is used as an event for log implementer. 218 * It happens when the a call to the Log function is finished. 219 * 220 * @access public 221 * @return void 222 */ 223 public function WriteForUser($loglevel, $message) { 224 $this->Write(LOGLEVEL_DEBUG, $message); // Always pass the logleveldebug so it uses syslog level LOG_DEBUG 225 } 226}