<?php
/**
 * Description of MonUtil.php
 *
 * @author caoyunmeng
 * Date: 2021/2/2
 * Time: 2:27 PM
 */
namespace Api\PhpUtils\Mon;

class MonUtil{
    /**
     * 向安装有ydbot服务的机器发送信息，进行监控打点
     *
     * @param string $send_msg  打点信息
     * @param string $ip  服务器ip，默认为宿主机ip(172.17.0.1)
     * @param string $port 端口，默认为15688
     * @return string
     */
    public static function base($send_msg, $ip = '172.17.0.1', $port = '15688'){
        if(isset($_SERVER['YIDIAN_LOCAL_IP']) && !empty($_SERVER['YIDIAN_LOCAL_IP'])){
            $ip = $_SERVER['YIDIAN_LOCAL_IP'];
        }
        $handle = stream_socket_client("udp://{$ip}:{$port}", $errno,$errstr, 1);

        if($handle){
            //在一个stream上设置超时
            stream_set_timeout($handle,0,15000);
            fwrite($handle, $send_msg."\n");
            //从封装协议文件指针中取得报头／元数据，返回数组，索引timed_out为超时信息，超时则为true，未超时则为false
            $info = stream_get_meta_data($handle);
            fclose($handle);

            if ($info['timed_out']) {
                return 'fwrite timeout!';
            } else {
                return $send_msg;
            }
        }else{
            return "stream_socket_client timeout ($errno):$errstr";
        }
    }

    /**
     * 针对第三方服务接入，返回状态码与请求响应总时间进行监控打点
     *
     * @param string $module 请求模块
     * @param string $url 请求第三方服务url
     * @param int $code 请求返回状态码
     * @param int $request_time 请求总时长
     * @return string 打点信息或""
     */
    public static function proxyMon($module, $url, $code, $request_time = -899){
        $result = "";

        if(is_string($url) && !empty($url)){
            //截取请求第三方服务的uri
            $index = strpos($url,'?');
            if($index != 0){
                $preg_uri = substr($url,0, $index);
            }else{
                $preg_uri = $url;
            }

            //替换$uri中的"."为"_", ":"为"_", "/"为"-"
            $request_uri = str_replace(array(".", ":", "/"),array("_", "_", "-"), $preg_uri);

            //接口返回状态码打点
            if(!empty($code) && is_numeric($code)){
                $result = MonUtil::counting($module . "." . strval($request_uri), strval($code),1) . "\n";
            }else{
                $result = MonUtil::counting($module . "." . strval($request_uri), strval(-999),1) . "\n";
            }

            //接口请求响应总时间打点
            if(!empty($request_time) && is_numeric($request_time) && $request_time != -899){
                $result = $result . MonUtil::timing(strval($request_uri),"TotalTime", $request_time);
            }
        }
        return $result;
    }

    /**
     * @param string $module
     * @param string $index
     * @param int $value
     * @param string $type  监控打点类型
     * @return string  返回监控打点信息
     */
    public static function getMsg($module, $index, $value, $type){
        if(is_string($module) && !empty($module) && is_string($index) && !empty($index)){
            return "Ydbot.statsd.superfe.api." . $module . "." . $index . ".1sec:" . $value . "|" . $type;
        }

        return "";
    }

    /**
     * 对值进行计数。在一个flush区间，把上报的值累加；flush输出的时候，将上报的值重新清零
     *
     * @param string $module 子模块名字
     * @param string $index  指标
     * @param int $value
     * @return mixed
     */
    public static function counting($module = 'api', $index = '', $value = 0){
        $result = "";

        $send_msg = self::getMsg($module, $index, $value, "c");
        if($send_msg){
            $result = self::base($send_msg);
        }

        return $result;
    }

    /**
     * 标量是任何可以测量的一维变量，可以通过显示的加入符号让系统进行值的累加，不加符号时添加的新值会覆盖旧值
     *
     * @param string $module 子模块名字
     * @param string $index  指标
     * @param int $value
     * @return mixed
     */
    public static function gauges($module = 'api', $index = '', $value = 0){
        $result = "";

        $send_msg = self::getMsg($module, $index, $value, "g");
        if($send_msg){
            $result = self::base($send_msg);
        }

        return $result;
    }

    /**
     * 记录flush期间，不重复的值。譬如对于一个接口，记录有多少个user访问
     *
     * @param string $module 子模块名字
     * @param string $index  指标
     * @param int $value
     * @return mixed
     */
    public static function sets($module = 'api', $index = '', $value = 0){
        $result = "";

        $send_msg = self::getMsg($module, $index, $value, "s");
        if($send_msg){
            $result = self::base($send_msg);
        }

        return $result;
    }

    /**
     * 记录某个操作的耗时，单位ms。在一个flush期间，会自动记录平均值（mean）、最大值（upper）、最小值（lower）、
     *  个数（count）以及部分百分值（P95/P99/P999）
     *
     * @param string $module 子模块名字
     * @param string $index  指标
     * @param int $value
     * @return mixed
     */
    public static function timing($module = 'api', $index = '', $value = 0){
        $result = "";

        $send_msg = self::getMsg($module, $index, $value, "ms");
        if($send_msg){
            $result = self::base($send_msg);
        }

        return $result;
    }

    /**
     * 记录指标概率，Value为“100”和“0”。在一个flush期间，成功的概率
     *
     * @param string $module 子模块名字
     * @param string $index  指标
     * @param int $value
     * @return mixed
     */
    public static function rate($module = 'api', $index = '', $value = 0){
        $result = "";

        $send_msg = self::getMsg($module, $index, $value, "rate");
        if($send_msg){
            $result = self::base($send_msg);
        }

        return $result;
    }
}
