/php/Terminus/Loggers/Logger.php

https://gitlab.com/blueprintmrk/cli · PHP · 209 lines · 115 code · 22 blank · 72 comment · 22 complexity · e14d19ea96e76d797eb32116e1c0d0b5 MD5 · raw file

  1. <?php
  2. namespace Terminus\Loggers;
  3. use Katzgrau\KLogger\Logger as KLogger;
  4. use Psr\Log\LogLevel;
  5. class Logger extends KLogger {
  6. /**
  7. * Class constructor. Feeds in output destination from env vars
  8. *
  9. * @param [array] $options Options for operation of logger
  10. * [array] config Configuration options from Runner
  11. * @param [string] $logDirectory File path to the logging directory
  12. * @param [string] $logLevelThreshold The LogLevel Threshold
  13. * @return [Logger] $this
  14. */
  15. public function __construct(
  16. array $options = array(),
  17. $logDirectory = 'php://stderr',
  18. $logLevelThreshold = LogLevel::INFO
  19. ) {
  20. $config = $options['config'];
  21. unset($options['config']);
  22. $options['dateFormat'] = 'Y-m-d H:i:s';
  23. if ($config['debug']) {
  24. $logLevelThreshold = LogLevel::DEBUG;
  25. }
  26. if (!isset($options['logFormat'])) {
  27. $options['logFormat'] = $config['format'];
  28. }
  29. if (isset($_SERVER['TERMINUS_LOG_DIR'])) {
  30. $logDirectory = $_SERVER['TERMINUS_LOG_DIR'];
  31. } elseif ($config['format'] == 'silent') {
  32. $logDirectory = ini_get('error_log');
  33. if ($logDirectory == '') {
  34. die(
  35. 'You must either set error_log in your php.ini, or define '
  36. . ' TERMINUS_LOG_DIR to use silent mode.' . PHP_EOL
  37. );
  38. }
  39. }
  40. parent::__construct($logDirectory, $logLevelThreshold, $options);
  41. }
  42. /**
  43. * Logs with an arbitrary level.
  44. *
  45. * @param [mixed] $level
  46. * @param [string] $message
  47. * @param [array] $context
  48. * @return [void]
  49. */
  50. public function log($level, $message, array $context = array()) {
  51. if (
  52. isset($this->logLevelThreshold)
  53. && ($this->logLevels[$this->logLevelThreshold] < $this->logLevels[$level])
  54. ) {
  55. return;
  56. }
  57. // Replace the context variables into the message per PSR spec:
  58. // https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#12-message
  59. $message = $this->interpolate($message, $context);
  60. if (isset($this->options) && $this->options['logFormat'] == 'json') {
  61. $message = $this->formatJsonMessages($level, $message, $context);
  62. } elseif (isset($this->options) && $this->options['logFormat'] == 'bash') {
  63. $message = $this->formatBashMessages($level, $message, $context);
  64. } else {
  65. $message = $this->formatMessage($level, $message, $context);
  66. }
  67. $this->write($message);
  68. }
  69. /**
  70. * Sets the output handle to php://std___
  71. *
  72. * @return [void]
  73. */
  74. public function setBufferHandle() {
  75. $handle_name = strtoupper(substr($this->getLogFilePath(), 6));
  76. $this->fileHandle = constant($handle_name);
  77. }
  78. /**
  79. * Formats the message for bash-type logging.
  80. *
  81. * @param [string] $level The Log Level of the message
  82. * @param [string] $message The message to log
  83. * @param [array] $context The context
  84. * @return [string] $message
  85. */
  86. private function formatBashMessages($level, $message, $context) {
  87. $parts = $this->getMessageParts($level, $message, $context);
  88. $message = '';
  89. foreach ($parts as $key => $value) {
  90. $message .= "$key\t$value\n";
  91. }
  92. return $message;
  93. }
  94. /**
  95. * Formats the message for JSON-type logging.
  96. *
  97. * @param [string] $level The Log Level of the message
  98. * @param [string] $message The message to log
  99. * @param [array] $context The context
  100. * @return [string] $message
  101. */
  102. private function formatJsonMessages($level, $message, $context) {
  103. $parts = $this->getMessageParts($level, $message, $context);
  104. $message = json_encode($parts) . "\n";
  105. return $message;
  106. }
  107. /**
  108. * Formats the message for logging.
  109. *
  110. * @param [string] $level The Log Level of the message
  111. * @param [string] $message The message to log
  112. * @param [array] $context The context
  113. * @return [string] $message
  114. */
  115. protected function formatMessage($level, $message, $context) {
  116. if (
  117. isset($this->options)
  118. && in_array($this->options['logFormat'], array('bash', 'json'))
  119. ) {
  120. $parts = $this->getMessageParts($level, $message, $context);
  121. $message = $this->options['logFormat'];
  122. foreach ($parts as $part => $value) {
  123. $message = str_replace('{'.$part.'}', $value, $message);
  124. }
  125. } else {
  126. $message = "[{$this->getTimestamp()}] [$level] $message";
  127. }
  128. if (
  129. isset($this->options)
  130. && $this->options['appendContext']
  131. && ! empty($context)
  132. ) {
  133. $message .= PHP_EOL . $this->indent($this->contextToString($context));
  134. }
  135. return $message . PHP_EOL;
  136. }
  137. /**
  138. * Collects and formats the log message parts
  139. *
  140. * @param [string] $level The Log Level of the message
  141. * @param [string] $message The message to log
  142. * @param [array] $context The context
  143. * @return [string] $parts
  144. */
  145. private function getMessageParts($level, $message, $context) {
  146. $parts = array(
  147. 'date' => $this->getTimestamp(),
  148. 'level' => strtoupper($level),
  149. //'priority' => $this->logLevels[$level],
  150. 'message' => $message,
  151. //'context' => json_encode($context),
  152. );
  153. return $parts;
  154. }
  155. /**
  156. * Gets the correctly formatted Date/Time for the log entry.
  157. *
  158. * @return [string] $date
  159. */
  160. private function getTimestamp() {
  161. $date_format = 'Y-m-dTH:i:s';
  162. if (isset($this->options)) {
  163. $date_format = $this->options['dateFormat'];
  164. }
  165. $date = date($date_format);
  166. return $date;
  167. }
  168. /**
  169. * Interpolates context variables per the PSR spec.
  170. *
  171. * @param string $message The message containing replacements in the form {key}
  172. * @param array $context The array containing the values to be substituted.
  173. * @return string
  174. */
  175. private function interpolate($message, $context) {
  176. // build a replacement array with braces around the context keys
  177. $replace = array();
  178. foreach ($context as $key => $val) {
  179. $replace['{' . $key . '}'] = $val;
  180. }
  181. // interpolate replacement values into the message and return
  182. if(!is_string($message)) {
  183. $message = json_encode($message);
  184. }
  185. return strtr($message, $replace);
  186. }
  187. }