public function log($level, $message, array $context = [], $traceShift = 0)
    {
        $this->checkCorrectLogLevel($level);
        $message = $this->convertMessageToString($message);
        $message = $this->processPlaceHolders($message, $context);
        if (strlen($message) > 0 && mb_substr($message, -1) !== "\n" && !$this->newLine) {
            $message .= self::NEW_LINE;
        }
        if ($this->hideLevel === false) {
            $logColors = isset(static::$LOG_COLORS[$level]) ? static::$LOG_COLORS[$level] : [];
            if ($level !== static::LOG_LEVEL_RAW) {
                $message = str_pad('[' . $level . ']', 10, ' ') . $message;
            }
            if (!empty($logColors)) {
                $message = $this->colorizeText($message, $logColors);
            }
        }
        if ($this->newLine === true) {
            $message .= self::NEW_LINE;
        }
        //Add script and line number
        if ($this->withLineNum) {
            $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
            $lineNum = $this->getCalleeData($trace, $traceShift + 1);
            $unixTime = microtime(true);
            $micro = substr(sprintf("%06d", ($unixTime - floor($unixTime)) * 1000000), 0, 3);
            $time = date('H:i:s') . '.' . $micro;
            $message .= $this->colorizeText('^^^ ' . $time . ' - ' . $lineNum, static::FG_BLACK) . self::NEW_LINE;
        }
        $message = $this->format($message, $context);
        $this->stdio->write($message);
    }