]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/SugarLogger/SugarLogger.php
Release 6.5.16
[Github/sugarcrm.git] / include / SugarLogger / SugarLogger.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM Community Edition is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38 /*********************************************************************************
39
40  * Description:  Defines the English language pack for the base application.
41  * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc.
42  * All Rights Reserved.
43  * Contributor(s): ______________________________________..
44  ********************************************************************************/
45 require_once('include/SugarLogger/LoggerManager.php');
46 require_once('include/SugarLogger/LoggerTemplate.php');
47
48 /**
49  * Default SugarCRM Logger
50  * @api
51  */
52 class SugarLogger implements LoggerTemplate
53 {
54     /**
55      * properties for the SugarLogger
56      */
57         protected $logfile = 'sugarcrm';
58         protected $ext = '.log';
59         protected $dateFormat = '%c';
60         protected $logSize = '10MB';
61         protected $maxLogs = 10;
62         protected $filesuffix = "";
63     protected $date_suffix = "";
64         protected $log_dir = '.';
65     protected $full_log_file;
66
67         /**
68          * used for config screen
69          */
70         public static $filename_suffix = array(
71         //bug#50265: Added none option for previous version users
72         "" => "None",
73             "%m_%Y"    => "Month_Year",
74         "%d_%m"    => "Day_Month",
75             "%m_%d_%y" => "Month_Day_Year",
76             );
77
78         /**
79          * Let's us know if we've initialized the logger file
80          */
81     protected $initialized = false;
82
83     /**
84      * Logger file handle
85      */
86     protected $fp = false;
87
88     public function __get(
89         $key
90         )
91     {
92         return $this->$key;
93     }
94
95     /**
96      * Used by the diagnostic tools to get SugarLogger log file information
97      */
98     public function getLogFileNameWithPath()
99     {
100         return $this->full_log_file;
101     }
102
103     /**
104      * Used by the diagnostic tools to get SugarLogger log file information
105      */
106     public function getLogFileName()
107     {
108         return ltrim($this->full_log_file, "./");
109     }
110
111     /**
112      * Constructor
113      *
114      * Reads the config file for logger settings
115      */
116     public function __construct()
117     {
118         $config = SugarConfig::getInstance();
119         $this->ext = $config->get('logger.file.ext', $this->ext);
120         $this->logfile = $config->get('logger.file.name', $this->logfile);
121         $this->dateFormat = $config->get('logger.file.dateFormat', $this->dateFormat);
122         $this->logSize = $config->get('logger.file.maxSize', $this->logSize);
123         $this->maxLogs = $config->get('logger.file.maxLogs', $this->maxLogs);
124         $this->filesuffix = $config->get('logger.file.suffix', $this->filesuffix);
125         $log_dir = $config->get('log_dir' , $this->log_dir);
126         $this->log_dir = $log_dir . (empty($log_dir)?'':'/');
127         unset($config);
128         $this->_doInitialization();
129         LoggerManager::setLogger('default','SugarLogger');
130         }
131
132         /**
133          * Handles the SugarLogger initialization
134          */
135     protected function _doInitialization()
136     {
137
138         if( $this->filesuffix && array_key_exists($this->filesuffix, self::$filename_suffix) )
139         { //if the global config contains date-format suffix, it will create suffix by parsing datetime
140             $this->date_suffix = "_" . date(str_replace("%", "", $this->filesuffix));
141         }
142         $this->full_log_file = $this->log_dir . $this->logfile . $this->date_suffix . $this->ext;
143         $this->initialized = $this->_fileCanBeCreatedAndWrittenTo();
144         $this->rollLog();
145     }
146
147     /**
148          * Checks to see if the SugarLogger file can be created and written to
149          */
150     protected function _fileCanBeCreatedAndWrittenTo()
151     {
152         $this->_attemptToCreateIfNecessary();
153         return file_exists($this->full_log_file) && is_writable($this->full_log_file);
154     }
155
156     /**
157          * Creates the SugarLogger file if it doesn't exist
158          */
159     protected function _attemptToCreateIfNecessary()
160     {
161         if (file_exists($this->full_log_file)) {
162             return;
163         }
164         @touch($this->full_log_file);
165     }
166
167     /**
168      * see LoggerTemplate::log()
169      */
170         public function log(
171             $level,
172             $message
173             )
174         {
175         if (!$this->initialized) {
176             return;
177         }
178                 //lets get the current user id or default to -none- if it is not set yet
179                 $userID = (!empty($GLOBALS['current_user']->id))?$GLOBALS['current_user']->id:'-none-';
180
181                 //if we haven't opened a file pointer yet let's do that
182                 if (! $this->fp)$this->fp = fopen ($this->full_log_file , 'a' );
183
184
185                 // change to a string if there is just one entry
186             if ( is_array($message) && count($message) == 1 )
187                 $message = array_shift($message);
188             // change to a human-readable array output if it's any other array
189             if ( is_array($message) )
190                     $message = print_r($message,true);
191
192                 //write out to the file including the time in the dateFormat the process id , the user id , and the log level as well as the message
193                 fwrite($this->fp,
194                     strftime($this->dateFormat) . ' [' . getmypid () . '][' . $userID . '][' . strtoupper($level) . '] ' . $message . "\n"
195                     );
196         }
197
198         /**
199          * rolls the logger file to start using a new file
200          */
201         protected function rollLog(
202             $force = false
203             )
204         {
205         if (!$this->initialized || empty($this->logSize)) {
206             return;
207         }
208                 // bug#50265: Parse the its unit string and get the size properly
209         $units = array(
210             'b' => 1,                   //Bytes
211             'k' => 1024,                //KBytes
212             'm' => 1024 * 1024,         //MBytes
213             'g' => 1024 * 1024 * 1024,  //GBytes
214         );
215         if( preg_match('/^\s*([0-9]+\.[0-9]+|\.?[0-9]+)\s*(k|m|g|b)(b?ytes)?/i', $this->logSize, $match) ) {
216             $rollAt = ( int ) $match[1] * $units[strtolower($match[2])];
217         }
218                 //check if our log file is greater than that or if we are forcing the log to roll if and only if roll size assigned the value correctly
219                 if ( $force || ($rollAt && filesize ( $this->full_log_file ) >= $rollAt) ) {
220             $temp = tempnam($this->log_dir, 'rot');
221             if ($temp) {
222                 // warning here is expected in case if log file is opened by another process on Windows
223                 // or rotation has been already started by another process
224                 if (@rename($this->full_log_file, $temp)) {
225
226                     // manually remove the obsolete part. Otherwise, rename() may fail on Windows (bug #22548)
227                     $obsolete_part = $this->getLogPartPath($this->maxLogs - 1);
228                     if (file_exists($obsolete_part)) {
229                         unlink($obsolete_part);
230                     }
231
232                     // now lets move the logs starting at the oldest and going to the newest
233                     for ($old = $this->maxLogs - 2; $old > 0; $old--) {
234                         $old_name = $this->getLogPartPath($old);
235                         if (file_exists($old_name)) {
236                             $new_name = $this->getLogPartPath($old + 1);
237                             rename($old_name, $new_name);
238                         }
239                     }
240
241                     $part1 = $this->getLogPartPath(1);
242                     rename($temp, $part1);
243                 } else {
244                     unlink($temp);
245                 }
246             }
247                 }
248         }
249
250     /**
251      * Returns path for the given log part
252      *
253      * @param int $i
254      * @return string
255      */
256     protected function getLogPartPath($i)
257     {
258         return $this->log_dir . $this->logfile . $this->date_suffix . '_' . $i . $this->ext;
259     }
260
261     /**
262          * This is needed to prevent unserialize vulnerability
263      */
264     public function __wakeup()
265     {
266         // clean all properties
267         foreach(get_object_vars($this) as $k => $v) {
268             $this->$k = null;
269         }
270         throw new Exception("Not a serializable object");
271     }
272
273         /**
274          * Destructor
275          *
276          * Closes the SugarLogger file handle
277      */
278         public function __destruct()
279         {
280                 if ($this->fp)
281         {
282                         fclose($this->fp);
283             $this->fp = FALSE;
284         }
285         }
286 }