<?php


/**
 * 执行日志记录
 */

namespace Meibuyu\Micro\Handler\LogTrace;

use Meibuyu\Micro\Model\LogTrace;
use Hyperf\Utils\Coroutine;
use Swoole\Server;
use Throwable;

/**
 * Class LogTraceHandler
 * @package App\Service
 */
class LogTraceHandler
{

    /**
     * 1.对执行操作进行的方法入口注解 LogTrace
       2.对程序主动进行输出
          try {
                //流程1
                LogTraceHandler::recordProcess('执行到流程1');

                //流程2
                LogTraceHandler::recordProcess('执行到流程2');

                //记录输出数组
                LogTraceHandler::recordProcess(['test'=>1]);

                //流程3 抛出一个异常
                throw new Exception('test111');

                //流程执行完成标记结束
                LogTraceHandler::markComplete();

            }catch (\Throwable $exception){
                //记录异常日志
                LogTraceHandler::recordProcess($exception);
        }
     * @param $params
     * @param $source
     * @return mixed
     * @throws \Exception
     */
    public static function createLogTrace($source, $params)
    {
        if(!Coroutine::inCoroutine()) return;

        LogTrace::insertOrIgnore([
            'request_id'            => self::getRequestId(),
            'origin_params' => json_encode($params),
            'source'        => $source,
            'created_at'    => now(),
            'process_info'  => ''
        ]);
    }


    /**
     * @param bool $isInAsyncCoroutine
     * @return string
     * @throws \Exception
     */
    private static function getRequestId($isInAsyncCoroutine=false)
    {
        $workId = posix_getpid();
        $cid = $isInAsyncCoroutine?Coroutine::parentId(Coroutine::id()):Coroutine::id();
        if(!$cid) throw new \Exception('无法使用协程标记录日志');
        return container(Server::class)->stats()['start_time'] .$workId. $cid;
    }

    /**
     * 程序执行完成标记结束
     * @throws \Exception
     */
    public static function markComplete()
    {
        if(!Coroutine::inCoroutine()) return;
        container(LogTraceQueue::class)->addToQueue([
            'request_id'=>self::getRequestId(),
            'is_completed'=>YES
        ]);
        //LogTrace::where('request_id', self::getRequestId())->update(['is_completed' => YES]);
    }

    /*
     * 事务回滚导致部分流程日志无法记录 暂写到文件里
     * 待写到Es后可以避免
     * 记录当前日志(包括异常捕获)
     */
    public static function recordProcess($track,$isInAsyncCoroutine=false)
    {
        if (empty($track)) return;
        if(!Coroutine::inCoroutine()) return;

        $logInfo = '';
        if ($track instanceof Throwable) {
            $logInfo = $track->getMessage() . "\n" .
                $track->getFile() . " line:" .
                $track->getLine() . "\n" .
                $track->getTraceAsString();
        }

        if (is_array($track)) {
            $logInfo = var_export($track, true);
        }
        if (is_string($track)||is_numeric($track)) {
            $logInfo = $track;
        }
        $logInfo .=  "\n\n";

        container(LogTraceQueue::class)->addToQueue([
            'request_id'=>self::getRequestId($isInAsyncCoroutine),
            'process_info'=>$logInfo
        ]);
//        $log = LogTrace::where('request_id', self::getRequestId())->first();
//        if(empty($log)) return ;
//
//        $log->update([
//            'process_info' => Db::raw("CONCAT(process_info,\"{$logInfo}\")")
//        ]);
//        //写入文件
//        put_log(
//            self::getRequestId()."\n".
//            $logInfo,
//            str_replace('\\','_',$log->source).'/'.today()
//        );


    }


//    /**
//     * 记录流程日志
//     * @param $funName
//     * @param $arguments
//     * @throws \Exception
//     */
//    public static function __callStatic($funName, $arguments)
//    {
//        if(self::$instance){
//            throw new \Exception('请用LogTraceService::createLogTrace 先实例化对象');
//        }
//        self::$instance->$funName($arguments);
//    }

}