Skip to content

Instantly share code, notes, and snippets.

@azjezz
Created May 22, 2020 20:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save azjezz/cebf9412e564f17ce8a8edb048eff918 to your computer and use it in GitHub Desktop.
Save azjezz/cebf9412e564f17ce8a8edb048eff918 to your computer and use it in GitHub Desktop.
Nuxed basic console logger implementation
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