资讯专栏INFORMATION COLUMN

通过唯一ID实现简单的日志跟踪实现

BakerJ / 3066人阅读

摘要:在实际项目中,通知我们需要记录一些日志,方便问题核查。但是日志多了就很容易混乱,请求,响应,执行中的日志无法对应,这时就需要为请求进行标记唯一来进行跟踪。

在实际项目中,通知我们需要记录一些日志,方便问题核查。但是日志多了就很容易混乱,请求,响应,执行中的日志无法对应,这时就需要为请求进行标记唯一ID来进行跟踪。

/**
 * 记录请求日志
 *
 * Class ApiLog
 * @package AppLibraryComponentsElog
 */
class ApiLog
{
    static $logPath;

    private static $singleton;

    
    /**
     * 单例
     * @return ApiLog
     */
    public static function singleton()
    {

        if (false == self::$singleton instanceof ApiLog) {
            self::$singleton = new static();
        }

        return self::$singleton;
    }

    protected function __construct($logPath = "")
    {
        if (empty($logPath)) {
            self::$logPath = ROOT_PATH . "logs/request/";
        } else {
            self::$logPath = ROOT_PATH . $logPath;
        }

        if (!is_dir(self::$logPath)) {
            mkdir(self::$logPath, 0777, true);
        }
    }

    public function record($action, $request = [], $type = "requestLog")
    {
        $headers = [];
        if (!function_exists("getallheaders")) {
            foreach ($_SERVER as $name => $value) {
                if (substr($name, 0, 5) == "HTTP_") {
                    $headers[str_replace(" ", "-", strtolower(str_replace("_", " ", substr($name, 5))))] = $value;
                }
            }
        } else {
            $headers = getallheaders();
        }

        //==============  加密用户登录密码
        if (isset($request["password"])) {
            $request["password"] = md5(md5($request["password"]));
        }

        //==============  加密邮箱
        if (isset($request["email"])) {
            $request["email"] = encrypt_email($request["email"]);
        }
        // ...... 日志中对关键信息进行加密
        
        // 请求日志记录详细一点
        if ("requestLog" == $type) {
            $data = [
                "action" => $action,
                "platform" => PHONE_SYSTEM,
                "ip" => real_ip(),
                "request" => $request,
                "REQUEST_URI" => isset($_SERVER["REQUEST_URI"]) ? $_SERVER["REQUEST_URI"] : "",
                "headers" => $headers,
            ];
        } else {
            $data = [
                "action" => $action,
                "response" => $request
            ];
        }

        $this->write($data, $type);
    }

    protected function write($logData, $type)
    {
    
        $minutes = date("i");

        $file = date("Y-m-d-H") . "-v" . (intval($minutes / 10)) . ".log";

        $logData = ["request_id" => static::getRequestId(), "add_time" => time(), "type" => $type, "content" => $logData];

        file_put_contents(self::$logPath . $file, json_encode($logData) . PHP_EOL, FILE_APPEND);
    }

    protected static function getRequestId()
    {
        static $requestId = "";

        if (!empty($requestId)) {
            return $requestId;
        }

        if (function_exists("session_create_id")) {
            $hash = session_create_id();
        } else {
            $uid = uniqid("", true);
            $data = "";
            $data .= isset($_SERVER["REQUEST_TIME"]) ? $_SERVER["REQUEST_TIME"] : "";
            $data .= isset($_SERVER["HTTP_USER_AGENT"]) ? $_SERVER["HTTP_USER_AGENT"] : "";
            $data .= isset($_SERVER["LOCAL_ADDR"]) ? $_SERVER["LOCAL_ADDR"] : "";
            $data .= isset($_SERVER["LOCAL_PORT"]) ? $_SERVER["LOCAL_PORT"] : "";
            $data .= isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : "";
            $data .= isset($_SERVER["REMOTE_PORT"]) ? $_SERVER["REMOTE_PORT"] : "";
            $hash = hash("ripemd128", $uid . md5($data));
        }

        $hash = strtoupper($hash);

        return $requestId = substr($hash, 0, 8) . "-" . substr($hash, 8, 4) . "-" . substr($hash, 12, 4) . "-" . substr($hash, 16, 4) . "-" . substr($hash, 20, 12);
    }
}

使用单例,保证一次请求的ID一致

ApiLog::singleton()->record($action,$request);

ApiLog::singleton()->record($action,$actionData,"createOrder");

ApiLog::singleton()->record($action,$errorMessage,"errorHandler");
       
ApiLog::singleton()->record($action,$response,"ResponseLog");

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/29526.html

相关文章

  • 分布式调用跟踪实战

    摘要:为了追踪一个请求完整的流转过程,我可以给请求分配一个唯一的,当请求调用其他服务时,我们传递这个。这是一个简单的实现分布式调用追踪的实践,以上。 背景 分布式环境下,跨服务之间的调用错综复杂,如果突然爆出一个错误,虽然有日志记录,但到底是哪个服务出了问题呢?是移动端传的参数有错误,还是系统X或者系统Y提供的接口导致?在这种情况下,错误排查起来就非常费劲。 为了追踪一个请求完整的流转过程,...

    jlanglang 评论0 收藏0
  • 日志排查问题困难?分布式日志链路跟踪来帮你

    摘要:当前线程的子线程会继承其父线程中的的内容。若希望在线程池与主线程间传递,需配合和使用。 一、背景 开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用ELK来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,由于大量的其他用户/其他线程的日志也一起输出穿行其中导致很难筛选出指定请求的全部相关日志,以及下游线程/服务对应的日志。   二、解决思路 每个请求都使...

    EasonTyler 评论0 收藏0
  • Redux 莞式教程 之 简明篇

    摘要:只要一个有,那无论用什么设备访问,都会得到这个还原也是相当简单把数据库备份导入到另一台机器,部署同样的运行环境与代码。纯粹只是一个状态管理库,几乎可以搭配任何框架使用上述例子连都没用哦亲下一章进阶教程 Redux 简明教程 原文链接(保持更新):https://github.com/kenberkele... 写在前面 本教程深入浅出,配套 简明教程、进阶教程(源码精读)以及文档注释...

    notebin 评论0 收藏0
  • 手把手教你学Dapr

    摘要:配置配置使用概率抽样。采样率定义了对跟踪跨度进行采样的概率,其值可以介于和含之间。例如,以下配置对象将采样率更改为即每个跨度都被采样,并使用协议将跟踪发送到位于的服务器文件路径注将采样率更改为会完全禁用跟踪。目录手把手教你学Dapr - 1. .Net开发者的大时代手把手教你学Dapr - 2. 必须知道的概念手把手教你学Dapr - 3. 使用Dapr运行第一个.Net程序手把手教你学Da...

    qqlcbb 评论0 收藏0

发表评论

0条评论

BakerJ

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<