5 * Contains \Drush\Log\Logger.
7 * This is the actual Logger for Drush that is responsible
8 * for logging messages.
10 * This logger is designed such that it can be provided to
11 * other libraries that log to a Psr\Log\LoggerInterface.
12 * As such, it takes responsibility for passing log messages
13 * to backend invoke, as necessary (c.f. drush_backend_packet()).
15 * Drush supports all of the required log levels from Psr\Log\LogLevel,
16 * and also defines its own. See Drush\Log\LogLevel.
18 * Those who may wish to change the way logging works in Drush
19 * should therefore NOT attempt to replace this logger with their
20 * own LoggerInterface, as it will not work. It would be okay
21 * to extend Drush\Log\Logger, or perhaps we could provide a way
22 * to set an output I/O object here, in case output redirection
23 * was the only thing that needed to be swapped out.
28 use Drush\Log\LogLevel;
29 use Psr\Log\AbstractLogger;
30 use Robo\Log\RoboLogger;
31 use Symfony\Component\Console\Output\OutputInterface;
32 use Drush\Utils\StringUtils;
34 class Logger extends RoboLogger
37 public function __construct(OutputInterface $output)
39 parent::__construct($output);
42 public function log($level, $message, array $context = [])
44 // Convert to old $entry array for b/c calls
47 'message' => StringUtils::interpolate($message, $context),
48 'timestamp' => microtime(true),
49 'memory' => memory_get_usage(),
52 // Drush\Log\Logger should take over all of the responsibilities
53 // of drush_log, including caching the log messages and sending
54 // log messages along to backend invoke.
55 // TODO: move these implementations inside this class.
56 $log =& drush_get_context('DRUSH_LOG', []);
58 if ($level != LogLevel::DEBUG_NOTIFY) {
59 drush_backend_packet('log', $entry);
62 if ($this->output->isDecorated()) {
63 $red = "\033[31;40m\033[1m[%s]\033[0m";
64 $yellow = "\033[1;33;40m\033[1m[%s]\033[0m";
65 $green = "\033[1;32;40m\033[1m[%s]\033[0m";
72 $verbose = \Drush\Drush::verbose();
73 $debug = drush_get_context('DRUSH_DEBUG');
74 $debugnotify = drush_get_context('DRUSH_DEBUG_NOTIFY');
76 $oldStyleEarlyExit = drush_get_context('DRUSH_LEGACY_CONTEXT');
78 // Save the original level in the context name, then
79 // map it to a standard log level.
80 $context['name'] = $level;
82 case LogLevel::WARNING:
83 case LogLevel::CANCEL:
84 $type_msg = sprintf($yellow, $level);
85 $level = LogLevel::WARNING;
87 case 'failed': // Obsolete; only here in case contrib is using it.
88 case LogLevel::EMERGENCY: // Not used by Drush
89 case LogLevel::ALERT: // Not used by Drush
91 $type_msg = sprintf($red, $level);
94 case 'completed': // Obsolete; only here in case contrib is using it.
95 case LogLevel::SUCCESS:
96 case 'status': // Obsolete; only here in case contrib is using it.
97 // In quiet mode, suppress progress messages
98 if ($oldStyleEarlyExit && drush_get_context('DRUSH_QUIET')) {
101 $type_msg = sprintf($green, $level);
102 $level = LogLevel::NOTICE;
104 case LogLevel::NOTICE:
105 $type_msg = sprintf("[%s]", $level);
107 case 'message': // Obsolete; only here in case contrib is using it.
109 if ($oldStyleEarlyExit && !$verbose) {
110 // print nothing. exit cleanly.
113 $type_msg = sprintf("[%s]", $level);
114 $level = LogLevel::INFO;
116 case LogLevel::DEBUG_NOTIFY:
117 $level = LogLevel::DEBUG; // Report 'debug', handle like 'preflight'
118 case LogLevel::PREFLIGHT:
119 if ($oldStyleEarlyExit && !$debugnotify) {
120 // print nothing unless --debug AND --verbose. exit cleanly.
123 $type_msg = sprintf("[%s]", $level);
124 $level = LogLevel::DEBUG;
126 case LogLevel::BOOTSTRAP:
127 case LogLevel::DEBUG:
129 if ($oldStyleEarlyExit && !$debug) {
130 // print nothing. exit cleanly.
133 $type_msg = sprintf("[%s]", $level);
134 $level = LogLevel::DEBUG;
138 // When running in backend mode, log messages are not displayed, as they will
139 // be returned in the JSON encoded associative array.
140 if (\Drush\Drush::backend()) {
144 $columns = drush_get_context('DRUSH_COLUMNS', 80);
147 // Append timer and memory values.
149 $timer = sprintf('[%s sec, %s]', round($entry['timestamp']-DRUSH_REQUEST_TIME, 2), drush_format_size($entry['memory']));
150 $entry['message'] = $entry['message'] . ' ' . $timer;
151 $message = $message . ' ' . $timer;
155 // Drush-styled output
157 $message = $this->interpolate(
159 $this->getLogOutputStyler()->style($context)
162 $width[0] = ($columns - 11);
164 $format = sprintf("%%-%ds%%%ds", $width[0], $width[1]);
166 // Place the status message right aligned with the top line of the error message.
167 $message = wordwrap($message, $width[0]);
168 $lines = explode("\n", $message);
169 $lines[0] = sprintf($format, $lines[0], $type_msg);
170 $message = implode("\n", $lines);
171 $this->getErrorStreamWrapper()->writeln($message);
173 // Robo-styled output
174 parent::log($level, $message, $context);
177 public function error($message, array $context = [])
179 $error_log =& drush_get_context('DRUSH_ERROR_LOG', []);
180 $error_log[$message][] = $message;
181 parent::error($message, $context);