/google_api/Logger/Abstract.php

  1. <?php 
  2. /** 
  3. * Copyright 2014 Google Inc. 
  4. * 
  5. * Licensed under the Apache License, Version 2.0 (the "License"); 
  6. * you may not use this file except in compliance with the License. 
  7. * You may obtain a copy of the License at 
  8. * 
  9. * http://www.apache.org/licenses/LICENSE-2.0 
  10. * 
  11. * Unless required by applicable law or agreed to in writing, software 
  12. * distributed under the License is distributed on an "AS IS" BASIS,  
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  14. * See the License for the specific language governing permissions and 
  15. * limitations under the License. 
  16. */ 
  17.  
  18. if (!class_exists('Google_Client')) { 
  19. require_once dirname(__FILE__) . '/../autoload.php'; 
  20.  
  21. /** 
  22. * Abstract logging class based on the PSR-3 standard. 
  23. * 
  24. * NOTE: We don't implement `Psr\Log\LoggerInterface` because we need to 
  25. * maintain PHP 5.2 support. 
  26. * 
  27. * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md 
  28. */ 
  29. abstract class Google_Logger_Abstract 
  30. /** 
  31. * Default log format 
  32. */ 
  33. const DEFAULT_LOG_FORMAT = "[%datetime%] %level%: %message% %context%\n"; 
  34. /** 
  35. * Default date format 
  36. * 
  37. * Example: 16/Nov/2014:03:26:16 -0500 
  38. */ 
  39. const DEFAULT_DATE_FORMAT = 'd/M/Y:H:i:s O'; 
  40.  
  41. /** 
  42. * System is unusable 
  43. */ 
  44. const EMERGENCY = 'emergency'; 
  45. /** 
  46. * Action must be taken immediately 
  47. * 
  48. * Example: Entire website down, database unavailable, etc. This should 
  49. * trigger the SMS alerts and wake you up. 
  50. */ 
  51. const ALERT = 'alert'; 
  52. /** 
  53. * Critical conditions 
  54. * 
  55. * Example: Application component unavailable, unexpected exception. 
  56. */ 
  57. const CRITICAL = 'critical'; 
  58. /** 
  59. * Runtime errors that do not require immediate action but should typically 
  60. * be logged and monitored. 
  61. */ 
  62. const ERROR = 'error'; 
  63. /** 
  64. * Exceptional occurrences that are not errors. 
  65. * 
  66. * Example: Use of deprecated APIs, poor use of an API, undesirable things 
  67. * that are not necessarily wrong. 
  68. */ 
  69. const WARNING = 'warning'; 
  70. /** 
  71. * Normal but significant events. 
  72. */ 
  73. const NOTICE = 'notice'; 
  74. /** 
  75. * Interesting events. 
  76. * 
  77. * Example: User logs in, SQL logs. 
  78. */ 
  79. const INFO = 'info'; 
  80. /** 
  81. * Detailed debug information. 
  82. */ 
  83. const DEBUG = 'debug'; 
  84.  
  85. /** 
  86. * @var array $levels Logging levels 
  87. */ 
  88. protected static $levels = array( 
  89. self::EMERGENCY => 600,  
  90. self::ALERT => 550,  
  91. self::CRITICAL => 500,  
  92. self::ERROR => 400,  
  93. self::WARNING => 300,  
  94. self::NOTICE => 250,  
  95. self::INFO => 200,  
  96. self::DEBUG => 100,  
  97. ); 
  98.  
  99. /** 
  100. * @var integer $level The minimum logging level 
  101. */ 
  102. protected $level = self::DEBUG; 
  103.  
  104. /** 
  105. * @var string $logFormat The current log format 
  106. */ 
  107. protected $logFormat = self::DEFAULT_LOG_FORMAT; 
  108. /** 
  109. * @var string $dateFormat The current date format 
  110. */ 
  111. protected $dateFormat = self::DEFAULT_DATE_FORMAT; 
  112.  
  113. /** 
  114. * @var boolean $allowNewLines If newlines are allowed 
  115. */ 
  116. protected $allowNewLines = false; 
  117.  
  118. /** 
  119. * @param Google_Client $client The current Google client 
  120. */ 
  121. public function __construct(Google_Client $client) 
  122. $this->setLevel( 
  123. $client->getClassConfig('Google_Logger_Abstract', 'level') 
  124. ); 
  125.  
  126. $format = $client->getClassConfig('Google_Logger_Abstract', 'log_format'); 
  127. $this->logFormat = $format ? $format : self::DEFAULT_LOG_FORMAT; 
  128.  
  129. $format = $client->getClassConfig('Google_Logger_Abstract', 'date_format'); 
  130. $this->dateFormat = $format ? $format : self::DEFAULT_DATE_FORMAT; 
  131.  
  132. $this->allowNewLines = (bool) $client->getClassConfig( 
  133. 'Google_Logger_Abstract',  
  134. 'allow_newlines' 
  135. ); 
  136.  
  137. /** 
  138. * Sets the minimum logging level that this logger handles. 
  139. * 
  140. * @param integer $level 
  141. */ 
  142. public function setLevel($level) 
  143. $this->level = $this->normalizeLevel($level); 
  144.  
  145. /** 
  146. * Checks if the logger should handle messages at the provided level. 
  147. * 
  148. * @param integer $level 
  149. * @return boolean 
  150. */ 
  151. public function shouldHandle($level) 
  152. return $this->normalizeLevel($level) >= $this->level; 
  153.  
  154. /** 
  155. * System is unusable. 
  156. * 
  157. * @param string $message The log message 
  158. * @param array $context The log context 
  159. */ 
  160. public function emergency($message, array $context = array()) 
  161. $this->log(self::EMERGENCY, $message, $context); 
  162.  
  163. /** 
  164. * Action must be taken immediately. 
  165. * 
  166. * Example: Entire website down, database unavailable, etc. This should 
  167. * trigger the SMS alerts and wake you up. 
  168. * 
  169. * @param string $message The log message 
  170. * @param array $context The log context 
  171. */ 
  172. public function alert($message, array $context = array()) 
  173. $this->log(self::ALERT, $message, $context); 
  174.  
  175. /** 
  176. * Critical conditions. 
  177. * 
  178. * Example: Application component unavailable, unexpected exception. 
  179. * 
  180. * @param string $message The log message 
  181. * @param array $context The log context 
  182. */ 
  183. public function critical($message, array $context = array()) 
  184. $this->log(self::CRITICAL, $message, $context); 
  185.  
  186. /** 
  187. * Runtime errors that do not require immediate action but should typically 
  188. * be logged and monitored. 
  189. * 
  190. * @param string $message The log message 
  191. * @param array $context The log context 
  192. */ 
  193. public function error($message, array $context = array()) 
  194. $this->log(self::ERROR, $message, $context); 
  195.  
  196. /** 
  197. * Exceptional occurrences that are not errors. 
  198. * 
  199. * Example: Use of deprecated APIs, poor use of an API, undesirable things 
  200. * that are not necessarily wrong. 
  201. * 
  202. * @param string $message The log message 
  203. * @param array $context The log context 
  204. */ 
  205. public function warning($message, array $context = array()) 
  206. $this->log(self::WARNING, $message, $context); 
  207.  
  208. /** 
  209. * Normal but significant events. 
  210. * 
  211. * @param string $message The log message 
  212. * @param array $context The log context 
  213. */ 
  214. public function notice($message, array $context = array()) 
  215. $this->log(self::NOTICE, $message, $context); 
  216.  
  217. /** 
  218. * Interesting events. 
  219. * 
  220. * Example: User logs in, SQL logs. 
  221. * 
  222. * @param string $message The log message 
  223. * @param array $context The log context 
  224. */ 
  225. public function info($message, array $context = array()) 
  226. $this->log(self::INFO, $message, $context); 
  227.  
  228. /** 
  229. * Detailed debug information. 
  230. * 
  231. * @param string $message The log message 
  232. * @param array $context The log context 
  233. */ 
  234. public function debug($message, array $context = array()) 
  235. $this->log(self::DEBUG, $message, $context); 
  236.  
  237. /** 
  238. * Logs with an arbitrary level. 
  239. * 
  240. * @param mixed $level The log level 
  241. * @param string $message The log message 
  242. * @param array $context The log context 
  243. */ 
  244. public function log($level, $message, array $context = array()) 
  245. if (!$this->shouldHandle($level)) { 
  246. return false; 
  247.  
  248. $levelName = is_int($level) ? array_search($level, self::$levels) : $level; 
  249. $message = $this->interpolate( 
  250. array( 
  251. 'message' => $message,  
  252. 'context' => $context,  
  253. 'level' => strtoupper($levelName),  
  254. 'datetime' => new DateTime(),  
  255. ); 
  256.  
  257. $this->write($message); 
  258.  
  259. /** 
  260. * Interpolates log variables into the defined log format. 
  261. * 
  262. * @param array $variables The log variables. 
  263. * @return string 
  264. */ 
  265. protected function interpolate(array $variables = array()) 
  266. $template = $this->logFormat; 
  267.  
  268. if (!$variables['context']) { 
  269. $template = str_replace('%context%', '', $template); 
  270. unset($variables['context']); 
  271. } else { 
  272. $this->reverseJsonInContext($variables['context']); 
  273.  
  274. foreach ($variables as $key => $value) { 
  275. if (strpos($template, '%'. $key .'%') !== false) { 
  276. $template = str_replace( 
  277. '%' . $key . '%',  
  278. $this->export($value),  
  279. $template 
  280. ); 
  281.  
  282. return $template; 
  283.  
  284. /** 
  285. * Reverses JSON encoded PHP arrays and objects so that they log better. 
  286. * 
  287. * @param array $context The log context 
  288. */ 
  289. protected function reverseJsonInContext(array &$context) 
  290. if (!$context) { 
  291. return; 
  292.  
  293. foreach ($context as $key => $val) { 
  294. if (!$val || !is_string($val) || !($val[0] == '{' || $val[0] == '[')) { 
  295. continue; 
  296.  
  297. $json = @json_decode($val); 
  298. if (is_object($json) || is_array($json)) { 
  299. $context[$key] = $json; 
  300.  
  301. /** 
  302. * Exports a PHP value for logging to a string. 
  303. * 
  304. * @param mixed $value The value to 
  305. */ 
  306. protected function export($value) 
  307. if (is_string($value)) { 
  308. if ($this->allowNewLines) { 
  309. return $value; 
  310.  
  311. return preg_replace('/[\r\n]+/', ' ', $value); 
  312.  
  313. if (is_resource($value)) { 
  314. return sprintf( 
  315. 'resource(%d) of type (%s)',  
  316. $value,  
  317. get_resource_type($value) 
  318. ); 
  319.  
  320. if ($value instanceof DateTime) { 
  321. return $value->format($this->dateFormat); 
  322.  
  323. if (version_compare(PHP_VERSION, '5.4.0', '>=')) { 
  324. $options = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; 
  325.  
  326. if ($this->allowNewLines) { 
  327. $options |= JSON_PRETTY_PRINT; 
  328.  
  329. return @json_encode($value, $options); 
  330.  
  331. return str_replace('\\/', '/', @json_encode($value)); 
  332.  
  333. /** 
  334. * Converts a given log level to the integer form. 
  335. * 
  336. * @param mixed $level The logging level 
  337. * @return integer $level The normalized level 
  338. * @throws Google_Logger_Exception If $level is invalid 
  339. */ 
  340. protected function normalizeLevel($level) 
  341. if (is_int($level) && array_search($level, self::$levels) !== false) { 
  342. return $level; 
  343.  
  344. if (is_string($level) && isset(self::$levels[$level])) { 
  345. return self::$levels[$level]; 
  346.  
  347. throw new Google_Logger_Exception( 
  348. sprintf("Unknown LogLevel: '%s'", $level) 
  349. ); 
  350.  
  351. /** 
  352. * Writes a message to the current log implementation. 
  353. * 
  354. * @param string $message The message 
  355. */ 
  356. abstract protected function write($message); 
.