<commit_before><?php

namespace Stackify\Log\MessageBuilder;

use Stackify\Log\Entities\ErrorItem;
use Stackify\Log\Entities\TraceFrame;
use Stackify\Log\Entities\StackifyError;
use Stackify\Exceptions\InitializationException;

abstract class AbstractBuilder implements BuilderInterface
{

    /**
     * Structured data is a part of RFC5424
     * Placeholders mean logger name + logger version
     * @link https://tools.ietf.org/html/rfc5424#page-15
     */
    const TEMPLATE_SD_DATA = '[STACKIFY_LOG][SENDER_INFO LOGGER_NAME="%s v.%s"]';

    public function __construct()
    {
        if (!function_exists('json_encode')) {
            throw new InitializationException('JSON extension is required for Stackify logger');
        }
        // @TODO for all children gather stacktrace even if exception is not available
    }

    public function getSyslogMessage($logEvent)
    {
        $logMsg = $this->createLogMsg($logEvent);
        return $this->getStructuredData() . ' ' . $this->encodeJSON($logMsg);
    }

    /**
     * @return \Stackify\Log\Entities\LogMsg
     */
    protected abstract function createLogMsg($logEvent);

    /**
     * Returns logger name (will be visible in OpsManager)
     * @return string
     */
    protected abstract function getLoggerName();

    /**
     * Returns logger version (string) (will be visible in OpsManager)
     * @return string
     */
    protected abstract function getLoggerVersion();

    /**
     * @return \Stackify\Log\Entities\ErrorItem
     */
    protected function getErrorItem(\Exception $exception)
    {
        $errorItem = new ErrorItem();
        $errorItem->Message = $exception->getMessage();
        $errorItem->ErrorTypeCode = $exception->getCode();
        foreach ($exception->getTrace() as $index => $trace) {
            $errorItem->StackTrace[] = new TraceFrame(
                $trace['file'],
                $trace['line'],
                $trace['function']
            );
            if (0 === $index) {
                // first record in stack trace has method
                $errorItem->SourceMethod = $trace['function'];
            }
        }
        $previous = $exception->getPrevious();
        if ($previous) {
            $errorItem->InnerError = $this->getErrorItem($previous);
        }
        return $errorItem;
    }

    /**
     * @return \Exception
     */
    protected function popException(array &$context)
    {
        $exception = null;
        $keyToUnset = null;
        foreach ($context as $key => $value) {
            if ($value instanceof \Exception) {
                $exception = $value;
                $keyToUnset = $key;
                break;
            }
        }
        if (null !== $keyToUnset) {
            unset($context[$keyToUnset]);
        }
        return $exception;
    }

    /**<commit_msg>Add one more TODO for future implementation (recurrent exceptions)<commit_after><?php

namespace Stackify\Log\MessageBuilder;

use Stackify\Log\Entities\ErrorItem;
use Stackify\Log\Entities\TraceFrame;
use Stackify\Log\Entities\StackifyError;
use Stackify\Exceptions\InitializationException;

abstract class AbstractBuilder implements BuilderInterface
{

    /**
     * Structured data is a part of RFC5424
     * Placeholders mean logger name + logger version
     * @link https://tools.ietf.org/html/rfc5424#page-15
     */
    const TEMPLATE_SD_DATA = '[STACKIFY_LOG][SENDER_INFO LOGGER_NAME="%s v.%s"]';

    public function __construct()
    {
        if (!function_exists('json_encode')) {
            throw new InitializationException('JSON extension is required for Stackify logger');
        }
        // @TODO for all children gather stacktrace even if exception is not available
    }

    public function getSyslogMessage($logEvent)
    {
        $logMsg = $this->createLogMsg($logEvent);
        return $this->getStructuredData() . ' ' . $this->encodeJSON($logMsg);
    }

    /**
     * @return \Stackify\Log\Entities\LogMsg
     */
    protected abstract function createLogMsg($logEvent);

    /**
     * Returns logger name (will be visible in OpsManager)
     * @return string
     */
    protected abstract function getLoggerName();

    /**
     * Returns logger version (string) (will be visible in OpsManager)
     * @return string
     */
    protected abstract function getLoggerVersion();

    /**
     * @return \Stackify\Log\Entities\ErrorItem
     */
    protected function getErrorItem(\Exception $exception)
    {
        $errorItem = new ErrorItem();
        $errorItem->Message = $exception->getMessage();
        $errorItem->ErrorTypeCode = $exception->getCode();
        foreach ($exception->getTrace() as $index => $trace) {
            $errorItem->StackTrace[] = new TraceFrame(
                $trace['file'],
                $trace['line'],
                $trace['function']
            );
            if (0 === $index) {
                // first record in stack trace has method
                $errorItem->SourceMethod = $trace['function'];
            }
        }
        $previous = $exception->getPrevious();
        if ($previous) {
            // @TODO limit recurrence?
            $errorItem->InnerError = $this->getErrorItem($previous);
        }
        return $errorItem;
    }

    /**
     * @return \Exception
     */
    protected function popException(array &$context)
    {
        $exception = null;
        $keyToUnset = null;
        foreach ($context as $key => $value) {
            if ($value instanceof \Exception) {
                $exception = $value;
                $keyToUnset = $key;
                break;
            }
        }
        if (null !== $keyToUnset) {
            unset($context[$keyToUnset]);
        }
        return $exception;
    }

    /**
{'fraction_non_alphanumeric': 0.11966701352757544, 'fraction_numerical': 0.003815469996531391, 'mean_word_length': 2.1530891197375617, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 33, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5825782', 'n_tokens_mistral': 1580, 'n_tokens_neox': 1543, 'n_words': 369}