CodeIgniter框架中抽取部分類庫做問題追蹤的思路
背景
由於各種原因,沒有接入完整的呼叫鏈追蹤,(┬_┬)。但是我們自身再通過php的curl呼叫各端介面時,會請求多次。那麼有沒有一種方法可以在不植入業務程式碼的前提下,捕捉到這些curl的請求呢。顯然,ci有基本的hook操作。我們可以在相關節點時,可選擇的把這些收集到到的通過非同步的方式傳送給指定的監聽者。
curl類庫(部分程式碼)
class Ycurl { public $resource_arr; public static $resource_id = 0; //資源(resource handle id public $save_requests = true;//是否儲存,預設全部儲存 public $requests = array();//n次請求引數、返回引數,錯誤(如果有) public $request_counts = 0;//總的請求次數,可能一個頁面呼叫多次 public $send_redis_email = false;//是否需要以異常方式傳送郵件 ... $ret = curl_exec($ch); $curl_info_arr = curl_getinfo($ch); $this->request_counts += 1; if ($this->save_requests === true) { $arg_list = func_get_args(); $this->requests[$resource_id]['url'] = $curl_info_arr['url']; $this->requests[$resource_id]['req_params'] = json_encode([$arg_list], 320); $this->requests[$resource_id]['response'] = $ret; $this->requests[$resource_id]['http_code'] = $curl_info_arr['http_code']; $this->requests[$resource_id]['is_error'] = curl_error($ch); $this->requests[$resource_id]['total_time'] = $curl_info_arr['total_time']; $this->requests[$resource_id]['primary_ip'] = $curl_info_arr['primary_ip']; if($this->send_redis_email){ redis_list_add(json_encode($this->requests,320)); } }
hooks config
從ci物件中抽取curl物件,其他自定義的物件也可以同樣思路。
$hook['post_system'][] = array( 'class'=> 'Curl_trace', 'function' => '_split_ci_of_curl', 'filename' => 'curl_trace.php', 'filepath' => 'hooks'
curl_trace.php
<?php /** * Created by PhpStorm. * User: TongBo * Date: 2019/2/26 * Time: 16:19 */ defined('BASEPATH') OR exit('No direct script access allowed'); Class Curl_trace { public $ci; public function __construct() { $this->ci =& get_instance(); } /** *抽取整個ci物件的所有curl物件例項 * @time 2019/3/1 11:12 * @author tongbo */ public function _split_ci_of_curl() { $class = $this->ci->router->fetch_class(); $need_trace_controller = [ 'home', 'admin', ]; $func = $this->ci->router->fetch_method(); if (in_array($class, $need_trace_controller) or 1) { foreach (get_object_vars($this->ci) as $name => $ci_object) { if (is_object($ci_object)) { if ($ci_object instanceof Ycurl) { $curls[get_class($this->ci) . "/{$func}:$" . $name] = $ci_object; } } } if (!empty($curls)) { foreach ($curls as $ctl_func => $curl) { foreach ($curl->requests as $index => $single_curl_obj) { $tmp[$ctl_func][$index] = $single_curl_obj; $tmp[$ctl_func][$index]['record_time'] = date('Ymd H:i:s' . substr((string)microtime(), 1, 8) . ' e'); redis_list_add(json_encode([$ctl_func . "_" . $index, $tmp[$ctl_func][$index]], 320)); } } } } } }
佇列中的結果
不足
ci框架中不可避免的使用了exit操作,或者其他業務程式碼中也使用。這樣導致鉤子函式無法正常完成他的使用。除了必要規範不必要的exit之外,我們也可以用register_shut_down這個函式來實現每次都必須記錄。(考慮價效比吧)