StatisticClient.php 5.5 KB

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