<?php

namespace Api\PhpUtils\Log;

class Tracer {

    const DEBUG = 1;
    const INFO = 2;
    const WARNING = 3;
    const ERROR = 4;

    protected static $traceId = '';
    protected static $spanId = '';

    /**
     * http 请求日志
     */
    public static function request() {
        $tag = 'request';
        $message = 'request log';
        $content = [
            'uri'=>'',
            'get'=>[],
            'post'=>[],
        ];

        //__METHOD__

        self::info($message, $content, $tag);
    }

    /**
     * @param $ret
     */
    public static function response($ret) {
        $tag = 'response';
        $message = 'response log';
        $content = [
            'ret'=>$ret,
            'requestId'=>self::getTraceId(),
        ];

        self::info($message, $content, $tag);
    }

    public static function daemon() {
        $tag = 'daemon';
        $message = 'daemon log';
        $content = [
            'pid'=>posix_getpid(),
        ];

        self::info($message, $content, $tag);
    }

    /**
     * @param $message
     * @param array $content
     * @param string $tag
     */
    public static function debug($message, $content = [], $tag = ''){
        self::log(self::DEBUG, $message, $content, $tag);
    }

    public static function info($message, $content = [], $tag = ''){
        self::log(self::INFO, $message, $content, $tag);
    }

    public static function warning($message, $content = [], $tag = '') {
        self::log(self::WARNING, $message, $content, $tag);
    }

    public static function error($message, $content = [], $tag = '') {
        self::log(self::ERROR, $message, $content, $tag);
    }

    public static function log($level, $message, $content, $tag) {

        if (!defined('LOG_PATH')) {
            define('LOG_PATH', ROOT_PATH.'/logs/');
        }

        switch ($level) {
            case self::DEBUG:
            case self::INFO:
            case self::WARNING:
            case self::ERROR:
                $file = LOG_PATH . 'log_' . date('Y-m-d') . '.log';
                break;
        }


        $dateTime = new \DateTime();
        $log = [
            'timestamp'=>$dateTime->format(\DateTime::RFC3339_EXTENDED),
            'traceId'=>self::getTraceId(),
            'spanId'=>self::getSpanId(),
            'tag'=>$tag,
            'content'=>$content,
            'message'=>$message
        ];
        //$_SERVER['HTTP_X_FORWARDED_FOR']

        $string = json_encode($log, JSON_UNESCAPED_UNICODE) . "\n";
        if($fd = @fopen($file, 'a')) {
            fputs($fd, $string);
            fclose($fd);
        }
    }

    /**
     * @return false|mixed|string
     * 获取traceId
     */
    public static function getTraceId() {
        if(empty(self::$traceId)) {
            if(!empty($_SERVER['HTTP_X_TRACE_ID'])) {
                self::$traceId = $_SERVER['HTTP_X_TRACE_ID'];

            } elseif(!empty($_SERVER['HTTP_X_REQUEST_ID'])) {
                self::$traceId = $_SERVER['HTTP_X_REQUEST_ID'];

            } else {
                self::$traceId = self::genUniqId();
            }
        }
        return self::$traceId;
    }

    /**
     * @return false|string
     * 获取spanId
     */
    public static function getSpanId() {

        if(empty(self::$spanId)) {
            self::$spanId = self::genUniqId();
        }

        return self::$spanId;
    }

    /**
     * @return false|string
     * @throws \Exception
     * 获取随机串用于记录traceId
     */
    public static function genUniqId() {

        if (function_exists("random_bytes")) {
            $bytes = random_bytes(ceil(8));
            return substr(bin2hex($bytes), 0, 16);

        } elseif (function_exists("openssl_random_pseudo_bytes")) {
            $bytes = openssl_random_pseudo_bytes(ceil(8));
            return substr(bin2hex($bytes), 0, 16);

        } else {
            $pre = rand(1, 4095);
            return uniqid(sprintf("%03x", $pre));
        }
    }
}

