Created
May 22, 2020 20:13
-
-
Save azjezz/cebf9412e564f17ce8a8edb048eff918 to your computer and use it in GitHub Desktop.
Nuxed basic console logger implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Nuxed\Console\Log; | |
use namespace HH\Lib\Str; | |
use namespace Nuxed\Console; | |
use namespace Nuxed\Console\Output; | |
use namespace Nuxed\Contract\Log; | |
final class Logger implements Log\ILogger { | |
public function __construct(private Output\IOutput $output) {} | |
/** | |
* System is unusable. | |
*/ | |
public async function emergency( | |
string $message, | |
KeyedContainer<string, mixed> $context = dict[], | |
): Awaitable<void> { | |
return await $this->block( | |
'[EMERGENCY]', | |
$message, | |
'red', | |
'black', | |
$context, | |
); | |
} | |
/** | |
* Action must be taken immediately. | |
* | |
* Example: Entire website down, database unavailable, etc. This should | |
* trigger the SMS alerts and wake you up. | |
*/ | |
public async function alert( | |
string $message, | |
KeyedContainer<string, mixed> $context = dict[], | |
): Awaitable<void> { | |
return await $this->block('[ALERT]', $message, 'black', 'red', $context); | |
} | |
/** | |
* Critical conditions. | |
* | |
* Example: Application component unavailable, unexpected exception. | |
*/ | |
public async function critical( | |
string $message, | |
KeyedContainer<string, mixed> $context = dict[], | |
): Awaitable<void> { | |
return await $this->block('[CRITICAL]', $message, 'white', 'red', $context); | |
} | |
/** | |
* Runtime errors that do not require immediate action but should typically | |
* be logged and monitored. | |
*/ | |
public async function error( | |
string $message, | |
KeyedContainer<string, mixed> $context = dict[], | |
): Awaitable<void> { | |
$message = Str\format( | |
'<fg=red; bold>[error]</> <fg=red>%s</>', | |
$this->process($message, $context), | |
); | |
await $this->output->writeln($message, Output\Verbosity::Normal); | |
} | |
/** | |
* Exceptional occurrences that are not errors. | |
* | |
* Example: Use of deprecated APIs, poor use of an API, undesirable things | |
* that are not necessarily wrong. | |
*/ | |
public async function warning( | |
string $message, | |
KeyedContainer<string, mixed> $context = dict[], | |
): Awaitable<void> { | |
$message = Str\format( | |
'<fg=yellow; bold>[warning]</> <fg=yellow>%s</>', | |
$this->process($message, $context), | |
); | |
await $this->output->writeln($message, Output\Verbosity::Normal); | |
} | |
/** | |
* Normal but significant events. | |
*/ | |
public async function notice( | |
string $message, | |
KeyedContainer<string, mixed> $context = dict[], | |
): Awaitable<void> { | |
$message = Str\format( | |
'<fg=magenta; bold>[notice]</> <fg=magenta>%s</>', | |
$this->process($message, $context), | |
); | |
await $this->output->writeln($message, Output\Verbosity::Verbose); | |
} | |
/** | |
* Interesting events. | |
* | |
* Example: User logs in, SQL logs. | |
*/ | |
public async function info( | |
string $message, | |
KeyedContainer<string, mixed> $context = dict[], | |
): Awaitable<void> { | |
$message = Str\format( | |
'<fg=blue; bold>[info]</> <fg=blue>%s</>', | |
$this->process($message, $context), | |
); | |
await $this->output->writeln($message, Output\Verbosity::VeryVerbos); | |
} | |
/** | |
* Detailed debug information. | |
*/ | |
public async function debug( | |
string $message, | |
KeyedContainer<string, mixed> $context = dict[], | |
): Awaitable<void> { | |
$message = Str\format( | |
'<fg=cyan; bold>[debug]</> <fg=cyan>%s</>', | |
$this->process($message, $context), | |
); | |
await $this->output->writeln($message, Output\Verbosity::Debug); | |
} | |
/** | |
* Logs with an arbitrary level. | |
*/ | |
public async function log( | |
Log\LogLevel $level, | |
string $message, | |
KeyedContainer<string, mixed> $context = dict[], | |
): Awaitable<void> { | |
switch ($level) { | |
case Log\LogLevel::Debug: | |
return await $this->debug($message, $context); | |
case Log\LogLevel::Info: | |
return await $this->info($message, $context); | |
case Log\LogLevel::Notice: | |
return await $this->notice($message, $context); | |
case Log\LogLevel::Warning: | |
return await $this->warning($message, $context); | |
case Log\LogLevel::Error: | |
return await $this->error($message, $context); | |
case Log\LogLevel::Critical: | |
return await $this->critical($message, $context); | |
case Log\LogLevel::Alert: | |
return await $this->alert($message, $context); | |
case Log\LogLevel::Emergency: | |
return await $this->emergency($message, $context); | |
} | |
} | |
public async function reset(): Awaitable<void> { | |
// Do nothing. | |
} | |
private function process( | |
string $message, | |
KeyedContainer<string, mixed> $context = dict[], | |
): string { | |
foreach ($context as $key => $value) { | |
if (!$value is string && !$value is num) { | |
continue; | |
} | |
if ($value is string) { | |
$message = Str\replace($message, Str\format('{%s}', $key), $value); | |
} else if ($value is float) { | |
$message = Str\replace( | |
$message, | |
Str\format('{%s}', $key), | |
Str\format('%g', $value), | |
); | |
} else if ($value is int) { | |
$message = Str\replace( | |
$message, | |
Str\format('{%s}', $key), | |
Str\format('%d', $value), | |
); | |
} | |
} | |
return $message; | |
} | |
/** | |
* System is unusable. | |
*/ | |
public async function block( | |
string $title, | |
string $message, | |
string $foreground, | |
string $background, | |
KeyedContainer<string, mixed> $context = dict[], | |
Output\Verbosity $verbosity = Output\Verbosity::Quiet, | |
): Awaitable<void> { | |
$title .= ' '; | |
$length = await Console\get_width() - 4; | |
$message = $this->process($message, $context); | |
$message = Str\split( | |
\wordwrap( | |
Str\replace($message, Output\IOutput::EndOfLine, "{{BREAK}}"), | |
$length - \mb_strwidth($title), | |
"{{BREAK}}", | |
true, | |
), | |
'{{BREAK}}', | |
); | |
$lastOperation = async { | |
await $this->output | |
->writeln( | |
Str\format( | |
'%s<fg=%s; bg=%s> %s </>', | |
Output\IOutput::EndOfLine, | |
$foreground, | |
$background, | |
Str\pad_right('', $length), | |
), | |
$verbosity, | |
); | |
}; | |
foreach ($message as $i => $line) { | |
$lastOperation = async { | |
$line = 0 === $i | |
? $title.$line | |
: Str\format('%s%s', Str\repeat(' ', \mb_strwidth($title)), $line); | |
await $lastOperation; | |
await $this->output | |
->writeln( | |
Str\format( | |
'<fg=%s; bg=%s> %s </>', | |
$foreground, | |
$background, | |
Str\pad_right($line, $length), | |
), | |
$verbosity, | |
); | |
}; | |
} | |
$lastOperation = async { | |
await $lastOperation; | |
await $this->output | |
->writeln( | |
Str\format( | |
'<fg=%s; bg=%s> %s </>%s', | |
$foreground, | |
$background, | |
Str\pad_right('', $length), | |
Output\IOutput::EndOfLine, | |
), | |
$verbosity, | |
); | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment