StatisticClient.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <?php
  2. namespace Lib;
  3. /**
  4. * 统计客户端
  5. * @author workerman.net
  6. */
  7. class StatisticClient
  8. {
  9. /**
  10. * [module=>[interface=>time_start, interface=>time_start ...], module=>[interface=>time_start ..], ... ]
  11. * @var array
  12. */
  13. protected static $timeMap = array();
  14. /**
  15. * 模块接口上报消耗时间记时
  16. * @param string $module
  17. * @param string $interface
  18. * @return void
  19. */
  20. public static function tick($module = '', $interface = '')
  21. {
  22. return self::$timeMap[$module][$interface] = microtime(true);
  23. }
  24. /**
  25. * 上报统计数据
  26. * @param string $module
  27. * @param string $interface
  28. * @param bool $success
  29. * @param int $code
  30. * @param string $msg
  31. * @param string $report_address
  32. * @return boolean
  33. */
  34. public static function report($module, $interface, $success, $code, $msg, $report_address = '')
  35. {
  36. $report_address = $report_address ? $report_address : 'udp://127.0.0.1:55656';
  37. if(isset(self::$timeMap[$module][$interface]) && self::$timeMap[$module][$interface] > 0)
  38. {
  39. $time_start = self::$timeMap[$module][$interface];
  40. self::$timeMap[$module][$interface] = 0;
  41. }
  42. else if(isset(self::$timeMap['']['']) && self::$timeMap[''][''] > 0)
  43. {
  44. $time_start = self::$timeMap[''][''];
  45. self::$timeMap[''][''] = 0;
  46. }
  47. else
  48. {
  49. $time_start = microtime(true);
  50. }
  51. $cost_time = microtime(true) - $time_start;
  52. $bin_data = StatisticProtocol::encode($module, $interface, $cost_time, $success, $code, $msg);
  53. if(!$success)
  54. {
  55. echo $msg;
  56. }
  57. return self::sendData($report_address, $bin_data);
  58. }
  59. /**
  60. * 发送数据给统计系统
  61. * @param string $address
  62. * @param string $buffer
  63. * @return boolean
  64. */
  65. public static function sendData($address, $buffer)
  66. {
  67. $socket = stream_socket_client($address);
  68. if(!$socket)
  69. {
  70. return false;
  71. }
  72. return stream_socket_sendto($socket, $buffer) == strlen($buffer);
  73. }
  74. }
  75. /**
  76. *
  77. * struct statisticPortocol
  78. * {
  79. * unsigned char module_name_len;
  80. * unsigned char interface_name_len;
  81. * float cost_time;
  82. * unsigned char success;
  83. * int code;
  84. * unsigned short msg_len;
  85. * unsigned int time;
  86. * char[module_name_len] module_name;
  87. * char[interface_name_len] interface_name;
  88. * char[msg_len] msg;
  89. * }
  90. *
  91. * @author workerman.net
  92. */
  93. class StatisticProtocol
  94. {
  95. /**
  96. * 包头长度
  97. * @var integer
  98. */
  99. const PACKAGE_FIXED_LENGTH = 17;
  100. /**
  101. * udp 包最大长度
  102. * @var integer
  103. */
  104. const MAX_UDP_PACKGE_SIZE = 65507;
  105. /**
  106. * char类型能保存的最大数值
  107. * @var integer
  108. */
  109. const MAX_CHAR_VALUE = 255;
  110. /**
  111. * usigned short 能保存的最大数值
  112. * @var integer
  113. */
  114. const MAX_UNSIGNED_SHORT_VALUE = 65535;
  115. /**
  116. * 编码
  117. * @param string $module
  118. * @param string $interface
  119. * @param float $cost_time
  120. * @param int $success
  121. * @param int $code
  122. * @param string $msg
  123. * @return string
  124. */
  125. public static function encode($module, $interface , $cost_time, $success, $code = 0,$msg = '')
  126. {
  127. // 防止模块名过长
  128. if(strlen($module) > self::MAX_CHAR_VALUE)
  129. {
  130. $module = substr($module, 0, self::MAX_CHAR_VALUE);
  131. }
  132. // 防止接口名过长
  133. if(strlen($interface) > self::MAX_CHAR_VALUE)
  134. {
  135. $interface = substr($interface, 0, self::MAX_CHAR_VALUE);
  136. }
  137. // 防止msg过长
  138. $module_name_length = strlen($module);
  139. $interface_name_length = strlen($interface);
  140. $avalible_size = self::MAX_UDP_PACKGE_SIZE - self::PACKAGE_FIXED_LENGTH - $module_name_length - $interface_name_length;
  141. if(strlen($msg) > $avalible_size)
  142. {
  143. $msg = substr($msg, 0, $avalible_size);
  144. }
  145. // 打包
  146. return pack('CCfCNnN', $module_name_length, $interface_name_length, $cost_time, $success ? 1 : 0, $code, strlen($msg), time()).$module.$interface.$msg;
  147. }
  148. /**
  149. * 解包
  150. * @param string $bin_data
  151. * @return array
  152. */
  153. public static function decode($bin_data)
  154. {
  155. // 解包
  156. $data = unpack("Cmodule_name_len/Cinterface_name_len/fcost_time/Csuccess/Ncode/nmsg_len/Ntime", $bin_data);
  157. $module = substr($bin_data, self::PACKAGE_FIXED_LENGTH, $data['module_name_len']);
  158. $interface = substr($bin_data, self::PACKAGE_FIXED_LENGTH + $data['module_name_len'], $data['interface_name_len']);
  159. $msg = substr($bin_data, self::PACKAGE_FIXED_LENGTH + $data['module_name_len'] + $data['interface_name_len']);
  160. return array(
  161. 'module' => $module,
  162. 'interface' => $interface,
  163. 'cost_time' => $data['cost_time'],
  164. 'success' => $data['success'],
  165. 'time' => $data['time'],
  166. 'code' => $data['code'],
  167. 'msg' => $msg,
  168. );
  169. }
  170. }
  171. if(PHP_SAPI == 'cli' && isset($argv[0]) && $argv[0] == basename(__FILE__))
  172. {
  173. StatisticClient::tick("TestModule", 'TestInterface');
  174. usleep(rand(10000, 600000));
  175. $success = rand(0,1);
  176. $code = rand(300, 400);
  177. $msg = '这个是测试消息';
  178. var_export(StatisticClient::report('TestModule', 'TestInterface', $success, $code, $msg));;
  179. }