From a497824eb4edde59e534c427707c0c08109ffeca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=95=E5=BB=B6=E9=BE=99?= Date: Wed, 13 May 2020 09:52:42 +0800 Subject: [PATCH] Added memcache collection and skywalking 8.0 support Added memcache collection and skywalking 8.0 support --- README.md | 4 +- bak/.gitignore | 1 - bak/README.md | 51 -- bak/README_ZH.md | 51 -- bak/SkyWalking.php | 1019 ---------------------------------- bak/demo.php | 136 ----- cmd/main.go | 2 +- docs/README.md | 2 +- docs/README_ZH.md | 6 - docs/install-agent.md | 165 ------ docs/install.md | 77 +++ docs/quick-start.md | 5 +- docs/zh/change-log.md | 19 - docs/zh/install-sdk.md | 73 --- docs/zh/qa.md | 74 --- docs/zh/start-agent.md | 35 -- package-template.xml | 17 +- package.xml | 142 ++--- pecl-package.php | 9 +- php.ini | 4 +- php_skywalking.h | 2 +- reporter/service/agent.go | 6 +- sw-php-agent.service.example | 13 - who-uses.jpg | Bin 21562 -> 0 bytes 24 files changed, 193 insertions(+), 1720 deletions(-) delete mode 100644 bak/.gitignore delete mode 100644 bak/README.md delete mode 100644 bak/README_ZH.md delete mode 100644 bak/SkyWalking.php delete mode 100644 bak/demo.php delete mode 100644 docs/README_ZH.md delete mode 100644 docs/install-agent.md create mode 100644 docs/install.md delete mode 100644 docs/zh/change-log.md delete mode 100644 docs/zh/install-sdk.md delete mode 100644 docs/zh/qa.md delete mode 100644 docs/zh/start-agent.md delete mode 100644 sw-php-agent.service.example delete mode 100644 who-uses.jpg diff --git a/README.md b/README.md index 30cd3ab..774deda 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,9 @@ SkyAPM PHP ## Documents * [Documents in English](docs/README.md) -* [涓枃鏂囨。](docs/README_ZH.md) ## Docker image -Go to Docker hub -> [SkyAPM PHP](https://hub.docker.com/r/skyapm/skywalking-php) +Go to Docker hub -> [https://hub.docker.com/r/skyapm/skywalking-php](https://hub.docker.com/r/skyapm/skywalking-php) ```shell script docker run -d -e SW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 skywalking-php ``` @@ -34,6 +33,7 @@ Host in Beijing. Go to [demo](http://106.75.237.45:8080/). 1. GRPC Client ([GRPC](https://github.com/grpc/grpc-php)) 1. Predis Client ([Predis](https://packagist.org/packages/predis/predis)) 1. Redis Extension ([Redis Extension](https://github.com/phpredis/phpredis)) +1. Memcache Extension ## Contact Us * Submit an [issue](https://github.com/SkyAPM/SkyAPM-php-sdk/issues) diff --git a/bak/.gitignore b/bak/.gitignore deleted file mode 100644 index 723ef36..0000000 --- a/bak/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.idea \ No newline at end of file diff --git a/bak/README.md b/bak/README.md deleted file mode 100644 index ec89578..0000000 --- a/bak/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# PHP SkyWalking Class: SkyWalking PHP client - - ---- - -- [Installation](#installation) -- [Requirements](#requirements) -- [Quick Start and Examples](#quick-start-and-examples) - ---- - -### Installation - -To install PHP SkyWalking Class, simply: - - -### Requirements - -PHP Curl Class works with PHP 5.2 - 7.9.99 , and HHVM. - -### Quick Start and Examples - - // must put these code at the beginning !!! - // that would auto register shutdown function !!! - - include_once ("./sdk-php/SkyWalking.php");// or use composer - - //LOG_PATH is skywalking's logfile path - SkyWalking::getInstance("api")->setLogPath(LOG_PATH)->setSamplingRate(5); - - .... - .... - - $ch = curl_init(); - curl_setopt($ch); - - .... - .... - - SkyWalking::getInstance()->startSpanOfCurl("www.api.com", $headers); - - .... - .... - - curl_setopt($ch); - $rs = curl_exec($ch); - - SkyWalking::getInstance()->endSpanOfcurl($ch); - - .... - .... \ No newline at end of file diff --git a/bak/README_ZH.md b/bak/README_ZH.md deleted file mode 100644 index bf772d4..0000000 --- a/bak/README_ZH.md +++ /dev/null @@ -1,51 +0,0 @@ -# PHP SkyWalking 类: SkyWalking PHP 客户端 - - ---- - -- [安装](#installation) -- [要求](#requirements) -- [快速开始实例](#quick-start-and-examples) - ---- - -### Installation - -使用安装 SkyWalking 类, 操作: - - -### Requirements - -PHP Curl Class works with PHP 5.2 - 7.9.99 , and HHVM. - -### Quick Start and Examples - - // must put these code at the beginning !!! - // that would auto register shutdown function !!! - - include_once ("./sdk-php/SkyWalking.php");// or use composer - - //LOG_PATH is skywalking's logfile path - SkyWalking::getInstance("api")->setLogPath(LOG_PATH)->setSamplingRate(5); - - .... - .... - - $ch = curl_init(); - curl_setopt($ch); - - .... - .... - - SkyWalking::getInstance()->startSpanOfCurl("www.api.com", $headers); - - .... - .... - - curl_setopt($ch); - $rs = curl_exec($ch); - - SkyWalking::getInstance()->endSpanOfcurl($ch); - - .... - .... \ No newline at end of file diff --git a/bak/SkyWalking.php b/bak/SkyWalking.php deleted file mode 100644 index 7629f96..0000000 --- a/bak/SkyWalking.php +++ /dev/null @@ -1,1019 +0,0 @@ - null, - self::SEGMENT => null, - ); - - /** - * 鍏ㄩ儴娈佃妭鐐圭粨鏋 - * - * @var array - */ - private static $_allSegmentStruct = array - ( - self::TRACE_SEGMENT_ID => array(),//璇锋眰鐨 id - self::APPLICATION_ID => null,//appid - self::APPLICATION_INSTANCE_ID => null,//瀹炰緥id - self::FATHER_NODE_DATA => array(),//鐖惰妭鐐规暟鎹 - self::SPANS_NODE_DATA => array(),//span鑺傜偣鏁版嵁闆嗗悎 - ); - /** - * 鐖惰妭鐐规暟鎹粨鏋 - * 鏁版嵁鏍煎紡 - * @var array - */ - private static $_fatherNodesStruct = array( - self::PARENT_TRACE_SEGMENT_ID => array(),//鐖惰妭鐐癸紝浼犵粰鏈瓙鑺傜偣鐨凾raceId - self::PARENT_APPLICATION_ID => null, - self::PARENT_SPAN_ID => null, - self::PARENT_SERVICE_ID => null, - self::PARENT_SERVICE_NAME => null, - self::NETWORK_ADDRESS_ID => null, - self::NETWORK_ADDRESS => null, - self::ENTRY_APPLICATION_INSTANCE_ID => null, - self::ENTRY_SERVICE_ID => null, - self::ENTRY_SERVICE_NAME => null, - self::REF_TYPE_VALUE => null, - ); - - /** - * span鑺傜偣缁撴瀯 - * 鏁版嵁鏍煎紡 - * @var array - */ - private static $_spanNodeDataStruct = array( - - self::SPAN_ID => '',//SpanId - self::SPAN_TYPE_VALUE => 0, - self::SPAN_LAYER_VALUE => 0, - self::FATHER_SPAN_ID => -1, - self::STARTTIME => '', - self::ENDTIME => '', - //self::COMPONENT_ID => '', - self::COMPONENT_NAME => '', - //self::OPERATION_NAME_ID => '', - //self::PEER_ID => '', - self::PEER => '', - self::IS_ERROR => false, - - self::TAGS => array(),//Span 鐨勬暣鍨嬪弬鏁 - self::LOGS => array(),//Span 鐨勬棩蹇 - ); - - /** - * 杩涜鍗曚緥澶勭悊 - * @param $appCode - * @return SkyWalking - */ - public static function getInstance($appCode = '') - { - if (!(self::$_instance instanceof self)) { - self::$_instance = new self($appCode); - } - return self::$_instance; - } - - private function __construct($appCode) - { - self::$_appCode = $appCode; - $this->_init(); - } - - /** - * 鍒濆鍖栬妭鐐逛俊鎭 - * TRACEID TraceId - * STARTTIME 鎬诲紑濮嬫椂闂 - * FATHER_NODE_DATA 鐖惰妭鐐规暟鎹 - * APP_CODE App Code - * DISTRIBUTED_TRACEIDS DistributedTraceIds - */ - private function _init() - { - if (empty(self::$_appCode)) { - throw new Exception("Error 锛 Must set appCode"); - } - if(!$this->appInitRegister()){ - return ; - } - //娉ㄥ唽涓涓粨鏉熷嚱鏁 - register_shutdown_function(array($this, "__finishAll")); - - //瀵硅妭鐐规暟鎹繘琛岀粨鏋勫垵濮嬪寲 - $this->_allNodeData = self::$_allNodesStruct; - //瀵规鑺傜偣杩涜鍒濆鍖 - $this->_allSegment = self::$_allSegmentStruct; - - /* - * 鎺ユ敹澶翠俊鎭 骞跺 _swHeaderInfo 杩涜璧嬪 - * _swHeaderInfo 淇濆瓨鐖惰妭鐐 - */ - $this->receiveSWHeaderFromCaller(); - - //鎬荤粨闃舵鐨勯摼璺叏灞id - $this->_allNodeData[self::DISTRIBUTED_TRACEIDS] = array($this->_generateTraceId(self::IS_ARRAY)); - - //璁剧疆鑺傜偣id - $this->_allSegment[self::TRACE_SEGMENT_ID] = $this->_generateTraceId(self::IS_ARRAY); - $this->_allSegment[self::APPLICATION_ID] = $this->_getAppId(); - $this->_allSegment[self::APPLICATION_INSTANCE_ID] = $this->_getAppInstanceId(); - $this->_allSegment[self::FATHER_NODE_DATA] = $this->getFatherNodeData(); - - - /** - * 绗竴涓猻pan鑺傜偣鍒濆鎿嶄綔 - * 褰撳墠椤 - */ - $pageUrlAndPeer = $this->getPageUrlAndPeer(); - $this->_spanFirstNodeData = self::$_spanNodeDataStruct; - $this->_spanFirstNodeData[self::SPAN_ID] = $this->_generateSpanId(); - $this->_spanFirstNodeData[self::SPAN_TYPE_VALUE] = 0; - $this->_spanFirstNodeData[self::SPAN_LAYER_VALUE] = 3; - $this->_spanFirstNodeData[self::STARTTIME] = $this->getMillisecond(); - //$this->_spanFirstNodeData[self::COMPONENT_ID] = 'php-server'; - $this->_spanFirstNodeData[self::COMPONENT_NAME] = 'php-server'; - //$this->_spanFirstNodeData[self::PEER_ID] = 'server'; - $this->_spanFirstNodeData[self::PEER] = '127.0.0.1'; - - // $this->_spanFirstNodeData[self::OPERATION_NAME_ID] = $pageUrlAndPeer[0]; - $parseUrl = parse_url($pageUrlAndPeer[0]); - $host = $parseUrl['host']; - if( !empty( $parseUrl['port'] ) ){ - $host .= ':' . $parseUrl['port']; - } - $this->_spanFirstNodeData[self::OPERATION_NAME] = $host . $parseUrl['path']; - $this->_spanFirstNodeData[self::IS_ERROR] = false; - $this->_spanFirstNodeData[self::TAGS][] = array('k'=>'url','v'=>$pageUrlAndPeer[0]); - - } - - - /** - * 寮濮媠pan鐨刢url淇℃伅鐨勭敓浜у紑濮嬫祦绋 - * 璇锋眰curl鍓嶇殑span鐨勭敓浜 - * - * @param string $peerHost 鐩爣鍦板潃 鐢熸垚SWTraceContext header浣跨敤 - * @param array $headers CURL headers 鏁扮粍鍐呭 - * @throws Exception - */ - public function startSpanOfCurl($peerHost, &$headers) - { - - //鍒濆鍖杝anp鑺傜偣淇℃伅 - $this->_spanNodeData = self::$_spanNodeDataStruct; - $this->_spanNodeData[self::SPAN_ID] = $this->_generateSpanId(); - $this->_spanNodeData[self::SPAN_TYPE_VALUE] = 1; - - //浣跨敤绗竴span鑺傜偣id褰撳満鐖惰妭鐐筰d - $this->_spanNodeData[self::FATHER_SPAN_ID] = $this->_spanFirstNodeData[self::SPAN_ID]; - $this->_spanNodeData[self::STARTTIME] = $this->getMillisecond(); - //$this->_spanNodeData[self::COMPONENT_ID] = 'php-curl'; - $this->_spanNodeData[self::COMPONENT_NAME] = 'php-curl'; - - $this->_spanNodeData[self::SPAN_LAYER_VALUE] = 3; - - //$this->_spanNodeData[self::PEER_ID] = 'client'; - - - $_SWTraceHeader = $this->_buildSWHeaderValue($peerHost); - array_push($headers, "sw3: " . $_SWTraceHeader['SWTraceContext']); - } - - - /** - * @param resource $curl - * @throws Exception - */ - public function endSpanOfCurl($curl) - { - //姝ゆ鏄惁閲囨牱 - if (!$this->isSampling() || $this->_isClose) { - return; - } - - if (empty($this->_spanNodeData[self::STARTTIME])) { - throw new Exception("Need setting start time"); - } - if (!is_resource($curl) || strtolower(get_resource_type($curl)) != 'curl') { - throw new Exception("Need setting curl Object"); - } - $curlInfo = curl_getinfo($curl); - - $this->_spanNodeData[self::ENDTIME] = $this->getMillisecond(); - //$this->_spanNodeData[self::OPERATION_NAME_ID] = $curlInfo['url']; - $parseUrl = parse_url($curlInfo['url']); - $host = $parseUrl['host']; - if( !empty( $parseUrl['port'] ) ){ - $host .= ':' . $parseUrl['port']; - } - $this->_spanNodeData[self::OPERATION_NAME] = $host . $parseUrl['path']; - $this->_spanNodeData[self::PEER] = $host; - - //鑾峰彇褰撳墠鏈嶅姟绔彛鍙 - if ($curlInfo['http_code'] != 200) { - $this->_spanNodeData[self::IS_ERROR] = true; - } - - $this->_spanNodeData[self::TAGS][] = array('k'=>'url','v'=>$curlInfo['url']); - - $this->setSpanNodeSData($this->_spanNodeData); - } - - /** - * 鐢熶骇鏈缁堢粨鏋 濡傛灉鏈 瀹屾垚鐨勫洖璋冨鐞嗗苟璋冪敤鍥炶皟澶勭悊鍑芥暟 - * 宸茬粡琚敞鍐屾垚缁撴潫鍑芥暟鑷姩璋冪敤 - * @return string json - */ - public function __finishAll() - { - //姝ゆ鏄惁閲囨牱 - if (!$this->isSampling() || $this->_isClose) { - return; - } - //鍒犻櫎rs - if (empty($this->_allNodeData[self::FATHER_NODE_DATA])) { - unset($this->_allNodeData[self::FATHER_NODE_DATA]); - } - - /** - * 棣栬妭鐐规彃鍏ュ埌span鑺傜偣闆嗕腑 - */ - $this->_spanFirstNodeData[self::ENDTIME] = $this->getMillisecond(); - - array_unshift($this->_spansNodeData, $this->_spanFirstNodeData); - $this->_allSegment[self::SPANS_NODE_DATA] = $this->_spansNodeData; - - // $this->_allNodeData[self::ENDTIME] = $this->getMillisecond(); - $this->_allNodeData[self::SEGMENT] = $this->_allSegment; - $results = json_encode(array($this->_allNodeData)); - //榛樿浣跨敤鍐欐棩蹇楃殑鏂瑰紡 - $this->writeLog($results); - - return $results; - } - - /** - * 璁剧疆鐖惰妭鐐规暟鎹 - * 鏁版嵁鏍煎紡 - * "rs": [鐖惰妭鐐 - * ["ts": "parent_trace_0"], --鐖惰妭鐐癸紝浼犵粰鏈瓙鑺傜偣鐨凾raceId - * ["si": 1], --鐖惰妭鐐癸紝浼犵粰鏈瓙鑺傜偣鐨凷panId - * ["ac": "REMOTE_APP"], --鐖惰妭鐐癸紝浼犵粰鏈瓙鑺傜偣鐨凙pp Code - * ["ph": "10.2.3.16:8080"] --鐖惰妭鐐癸紝浼犵粰鏈瓙鑺傜偣鐨凱eerHost - * ] - * @return array - */ - public function getFatherNodeData() - { - if (empty($this->_swHeaderInfo)) { - return array(); - } - //瀵圭埗鑺傜偣杩涜鍒濆鍖 - $this->_fatherNodeData = self::$_fatherNodesStruct; - - $this->_fatherNodeData[self::PARENT_TRACE_SEGMENT_ID] = explode('.', $this->_swHeaderInfo['TraceId']); - $this->_fatherNodeData[self::PARENT_APPLICATION_ID] = $this->_swHeaderInfo['ParentAppInstanceid']; - $this->_fatherNodeData[self::PARENT_SPAN_ID] = $this->_swHeaderInfo['SpanId']; - $this->_fatherNodeData[self::PARENT_SERVICE_ID] = $this->_swHeaderInfo['ParentAppname']; - $this->_fatherNodeData[self::PARENT_SERVICE_NAME] = $this->_swHeaderInfo['ParentAppname']; - $this->_fatherNodeData[self::NETWORK_ADDRESS_ID] = $this->_swHeaderInfo['PeerHost']; - $this->_fatherNodeData[self::NETWORK_ADDRESS] = $this->_swHeaderInfo['PeerHost']; - $this->_fatherNodeData[self::ENTRY_APPLICATION_INSTANCE_ID] = $this->_swHeaderInfo['EntryAppInstanceid']; - $this->_fatherNodeData[self::ENTRY_SERVICE_ID] = $this->_swHeaderInfo['EntryAppname']; - $this->_fatherNodeData[self::ENTRY_SERVICE_NAME] = $this->_swHeaderInfo['EntryAppname']; - $this->_fatherNodeData[self::REF_TYPE_VALUE] = 0; - - - return $this->_fatherNodeData; - } - - /** - * 璁剧疆span鑺傜偣鏁版嵁 - * @param $nodeData - * 鏁版嵁鏍煎紡 - * [ - * ["si": 1], --Span A鐨凷panId - * ["ps": -1], --鐖惰妭鐐逛紶杩囨潵鐨凷panId - * ["st": 1490097253228], --Span A鐨勫紑濮嬫椂闂达紝鍒涘缓Span A鏃惰缃 - * ["et": 1494965637898], --Span A鐨勭粨鏉熸椂闂达紝Span A澶勭悊瀹屾椂璁剧疆 - * ["on": "/serviceA"], --Span A鐨勬湇鍔RI - * ["ts": --Span A鐨勫瓧绗︿覆鍨嬪弬鏁 - * ["span.layer": "http"] --Span A鐨勫崗璁紝鍒嗕负http銆乺pc銆乨b - * ["component": "Tomcat" ] --Span A鐨勮妭鐐圭粍浠讹紝濡俆omcat銆丯ginx銆丠ttpClient銆丏bClient - * ["peer.host": "127.0.0.1"] --Span A鐨勮姹傛簮IP - * ["span.kind": "server"] --Span A鐨勮妭鐐圭粍浠剁被鍨嬶紝鍒嗕负server銆乧lient - * ["url": "10.2.3.16:8080/serviceA"] --Span A鐨勮闂湴鍧URL - * ], - * ["tb": []], --Span A鐨勫竷灏斿煎瀷鍙傛暟 - * ["ti": [ --Span A鐨勬暣鏁板煎瀷鍙傛暟 - * "peer.port": 80 --Span A鐨勮姹傛簮Port - * ]], - * ["lo": []] --Span A鐨勬棩蹇 - * ] - * @return $this - */ - public function setSpanNodeSData($nodeData) - { - array_push($this->_spansNodeData, $nodeData); - return $this; - } - - public function close(){ - $this->_isClose = 1; - } - - /** - * 璁剧疆 瑕佸啓鏃ュ織鐨勮矾寰 - * @param $logPath - * @return $this - */ - public function setLogPath($logPath) - { - $this->_logPath = $logPath; - return $this; - } - /** - * 鑾峰彇鍐欐棩蹇楄矾寰 - * - * @since 2017骞11鏈28鏃 - * @copyright - * @return return_type - */ - public function getLogPath(){ - if (!empty($this->_logPath)) { - $logPath = rtrim($this->_logPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; - } else { - $logPath = DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR; - } - return $logPath; - } - /** - * 璁剧疆娉ㄥ唽apm鍦板潃 - * @param $registerUrl - * @since 2017骞11鏈28鏃 - * @copyright - * @return return_type - */ - public function setRegisterUrl($registerUrl){ - $this->_registerUrl = $registerUrl; - return $this; - } - /** - * 鑾峰彇娉ㄥ唽apm鍦板潃 - * @return string - * @since 2017骞11鏈28鏃 - * @copyright - * @return string - */ - public function getRegisterUrl(){ - if(!empty($this->_registerUrl)) return $this->_registerUrl; - - return self::DEFAULT_REGISTER_URL; - } - - /** - * 璁剧疆閲囨牱鐜 鏈澶у 100 - * @param int $percent - * @return $this - */ - public function setSamplingRate($percent) - { - if ($percent >= 100) { - $percent = 100; - } - $this->_samplingRate = $percent; - - return $this; - } - - public function closeSampling(){ - $this->_isSampling = false; - return $this; - } - - /** - * 鏈杩涚▼鏄惁閲囨牱 - * 鑻ユ帴鏀跺埌header淇℃伅锛屽垯浠巋eader淇℃伅涓户鎵块噰鏍风巼璁剧疆 - * 鑻ユ病鏈夋帴鏀跺埌header淇℃伅锛屽苟涓斾篃娌℃湁璁剧疆閲囨牱鐜囷紝鍒欎负榛樿涓 100% - * @return bool - */ - private function isSampling() - { - //鍒ゆ柇娌℃湁璁$畻杩囬噰鏍风巼 - if (!isset($this->_isSampling)) { - - $this->_isSampling = true; - if ($this->_samplingRate === null) { - $this->_samplingRate = 100; - } - //鏍规嵁璁剧疆鐨勫艰绠楅噰鏍风巼 - if ($this->_samplingRate < 100) { - $r = rand(1, 100); - $this->_isSampling = ($r <= $this->_samplingRate); - } - } - return $this->_isSampling; - } - - /** - * 鍐欐棩蹇 - * @param $text - * @throws Exception - */ - private function writeLog($text) - { - if (!empty($this->_logPath)) { - $logPath = rtrim($this->_logPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; - } else { - $logPath = DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR; - } - $logFilename = $logPath . 'skywalking.' . date("Ymd") . '.log'; - error_log($text . "\n", 3, $logFilename); - } - - /** - * 鑾峰彇 id parts - * - * @since 2017骞11鏈23鏃 - * @copyright - * @return return_type - */ - private function _getIdParts(){ - - $serverIp = $this->_getCurrentMachineIp(); - $intUuid = base_convert(uniqid(), 16, 10); - return array( - (int)ip2long($serverIp), - (int)getmypid(), - $intUuid, - ); - } - - /** - * 鐢熸垚TraceID锛岀敤浜庢娆¤姹傜殑ID - * @param boolean $isArray - * @return mixed|string - * @since 2017骞11鏈27鏃 - * @copyright - * @return mixed|string - */ - private function _generateTraceId($isArray = false) - { - //娌跨敤鐖惰妭鐐圭殑TraceId ; 鏈妭鐐圭敓鎴愮殑鍏ㄩ摼璺郴缁熷敮涓鐨勪簨鍔$紪鍙枫 - if (!empty($this->_swHeaderInfo)) { - $this->_traceId = $this->_swHeaderInfo['TraceId']; - } - if (empty($this->_traceId)) { - $this->_traceId = $this->makeTraceId(); - } - - if($isArray){ - $traceIdArray = explode('.', $this->_traceId); - foreach ( $traceIdArray as $key => $val ){ - $traceIdArray[$key] = (int)$val; - } - return $traceIdArray; - } - return $this->_traceId; - } - /** - * 鑾峰彇鐖惰妭鐐规敞鍐宨d - * - * @since 2017骞11鏈28鏃 - * @copyright - * @return return_type - */ - private function _parentAppInstanceid(){ - - //娌跨敤鐖惰妭鐐圭殑ParentAppInstanceid ; 鏈妭鐐圭敓鎴愮殑鍏ㄩ摼璺郴缁熷敮涓鐨勪簨鍔$紪鍙枫 - return $this->_getAppInstanceId(); - } - /** - * 鑾峰彇鍏ュ彛鑺傜偣鏁版嵁 - * - * @since 2017骞11鏈28鏃 - * @copyright - * @return return_type - */ - private function _entryAppnameOperationId(){ - if(!empty( $this->_swHeaderInfo['EntryAppnameOperationId'] )){ - return $this->_swHeaderInfo['EntryAppnameOperationId']; - } - return $this->_spanFirstNodeData[self::SPAN_ID]; - } - private function _parentAppnameOperationId(){ - return $this->_spanFirstNodeData[self::SPAN_ID]; - } - /** - * 鑾峰彇鍏ュ彛鑺傜偣鏁版嵁 - * - * @since 2017骞11鏈28鏃 - * @copyright - * @return return_type - */ - private function _entryAppName(){ - if(!empty( $this->_swHeaderInfo['EntryAppname'] )){ - return $this->_swHeaderInfo['EntryAppname']; - } - return self::$_appCode; - } - private function _parentAppName(){ - return self::$_appCode; - } - /** - * 鑾峰彇鍏ュ彛鑺傜偣娉ㄥ唽id - * - * @since 2017骞11鏈28鏃 - * @copyright - * @return return_type - */ - private function _entryAppInstanceid(){ - if(!empty( $this->_swHeaderInfo['EntryAppInstanceid'] )){ - return $this->_swHeaderInfo['EntryAppInstanceid']; - } - return $this->_getAppInstanceId(); - } - - - /** - * 娌跨敤鐖惰妭鐐圭殑DistributedTraceIds锛屽鏋滄病鏈夌埗鑺傜偣鍒欏啀鍒涘缓涓涓猅raceId褰撳仛DistributedTraceIds锛孴race.姣鏃堕棿鎴.UUID鍚7浣嶇殑鍝堝笇鐮.褰撳墠杩涚▼鍙稰ID.褰撳墠绾跨▼ID.褰撳墠绾跨▼ - * @return mixed|string - */ - private function _generateDistributedTraceIds() - { - if (!empty($this->_swHeaderInfo)) { - return $this->_swHeaderInfo['DistributedTraceIds']; - } - if (empty($this->_distributedTraceIds)) { - $this->_distributedTraceIds = $this->makeTraceId(); - } - return $this->_distributedTraceIds; - } - - /** - * 褰撳墠鏈哄櫒ip - * - * @since 2017骞11鏈23鏃 - * @copyright - * @return return_type - */ - private function _getCurrentMachineIp(){ - - if (defined('PHP_SAPI') && PHP_SAPI == 'cli') { - $ip = '127.0.0.1'; - } elseif (isset($_SERVER)) { - if (isset($_SERVER['SERVER_ADDR'])) { - $ip = $_SERVER['SERVER_ADDR']; - } else { - $ip = $_SERVER['LOCAL_ADDR']; - } - } else { - $ip = getenv('SERVER_ADDR'); - } - return $ip; - } - - private function makeTraceId() - { - //鐢熶骇鍞竴鐮佹绉掓椂闂存埑.uuid.褰撳墠杩涚▼鍙稰ID.褰撳墠绾跨▼ID.褰撳墠绾跨▼鐢熸垚鐨勬祦姘村彿.ip - - $makeTraceIdArray = $this->_getIdParts(); - - return implode('.', $makeTraceIdArray); - } - - private function getIp() - { - if (!empty($_SERVER['HTTP_DD_REAL_IP'])) { - $ip = $_SERVER['HTTP_DD_REAL_IP']; - } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { - $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; - } elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) { - $ip = $_SERVER['HTTP_CLIENT_IP']; - } else { - $ip = $_SERVER['REMOTE_ADDR']; - } - if (strpos($ip, ',') > 0) { - $ips = explode(',', $ip); - $ip = $ips[0]; - } - - return $ip; - } - - /** - * 鑾峰彇褰撳墠鐨剈rl - * @return string - */ - private function getPageUrlAndPeer(){ - $pageURL = 'http'; - if (isset($_SERVER["HTTPS"]) && ($_SERVER["HTTPS"] == "on")) { - $pageURL .= "s"; - } - $pageURL .= "://"; - $peer = $_SERVER["HTTP_HOST"]; - $pageURL .= $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]; - return array($pageURL, $peer); - } - - /** - * 鐢熸垚 SpanId - * 鐢ㄤ簬姝ゆ璋冪敤鐨勫尯鍧楁爣绀 - */ - private function _generateSpanId() - { - return $this->_spanID++; - } - - private function getMillisecond() - { - list($t1, $t2) = explode(' ', microtime()); - $millisecond = (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000); - return $millisecond; - } - - /** - * 鑾峰彇鎺ユ敹鍒 SWTraceContext 鐨 header - */ - private function receiveSWHeaderFromCaller() - { - if (!empty($_SERVER['HTTP_SWTRACECONTEXT'])) { - $this->_swHeaderText = $_SERVER['HTTP_SWTRACECONTEXT']; - list( - $this->_swHeaderInfo['traceId'], - $this->_swHeaderInfo['SpanId'], - $this->_swHeaderInfo['ParentAppInstanceid'], - $this->_swHeaderInfo['EntryAppInstanceid'], - $this->_swHeaderInfo['PeerHost'], - $this->_swHeaderInfo['EntryAppnameOperationId'], - $this->_swHeaderInfo['ParentAppnameOperationId'], - $this->_swHeaderInfo['DistributedTraceIds'] - ) = explode('|', $this->_swHeaderText); - } - return $this->_swHeaderInfo; - } - - /** - * 鐢熸垚璋冪敤鎺ュ彛鐨 header - * @param string $peerHost - * @return array - * @throws \Exception - */ - private function _buildSWHeaderValue($peerHost) - { - $_SWHeader = array(); - - $_SWHeader['traceId'] = $this->_generateTraceId(); - $_SWHeader['SpanId'] = $this->_generateSpanId(); - $_SWHeader['ParentAppInstanceid'] = $this->_parentAppInstanceid(); - $_SWHeader['EntryAppInstanceid'] = $this->_entryAppInstanceid(); - $_SWHeader['PeerHost'] = '#' . $peerHost; - $_SWHeader['EntryAppnameOperationId'] = $this->_entryAppnameOperationId(); - $_SWHeader['ParentAppnameOperationId'] = $this->_parentAppnameOperationId(); - $_SWHeader['DistributedTraceIds'] = $this->_generateDistributedTraceIds(); - - return array('SWTraceContext' => implode('|', $_SWHeader)); - } - - /** - * 璁剧疆搴旂敤娉ㄥ唽 - * - * @since 2017骞11鏈23鏃 - * @copyright - * @return return_type - */ - private function appInitRegister(){ - - if($this->_isClose){ - return false; - } - $appId = $this->AppId(); - if(empty($appId)){ - return false; - } - $appInstanceId = $this->AppInstanceId($appId); - if($appInstanceId !== 0 && empty($appInstanceId)){ - return false; - } - $this->_appIds = array($appId, $appInstanceId); - - - return true; - } - - /** - * 鑾峰彇 app_id - * @return mixed - * @since 2017骞11鏈27鏃 - * @copyright - * @return mixed - */ - private function _getAppId(){ - return $this->_appIds[0]; - } - - /** - * 鑾峰彇 app_id - * @return mixed - * @since 2017骞11鏈27鏃 - * @copyright - * @return mixed - */ - private function _getAppInstanceId(){ - return $this->_appIds[1]; - } - - - /** - * 鑾峰彇appid - * - * @since 2017骞11鏈23鏃 - * @copyright - * @return return_type - */ - private function AppId(){ - - $processNo = getmypid(); - $fileName = $this->getLogPath() . $processNo . '.appid.pid'; - $appId = $this->getfilesText($fileName); - if(empty($appId)){ - - $param ='["'. self::$_appCode .'"]'; - $appIds = $this->doRequest($param, $this->getRegisterUrl() . '/application/register'); - $appIds = json_decode($appIds, true); - $appId = $appIds[0]['i']; - if(!empty($appId)){ - $this->fwriteFilesText($fileName, $appId); - } - } - if(empty($appId)){ - return false; - } - - return (int)$appId; - } - - /** - * 鑾峰彇appid鐨勫疄渚媔d - * @param unknown $applicationId - * @since 2017骞11鏈23鏃 - * @copyright - * @return return_type - */ - private function AppInstanceId($appId){ - - $processNo = getmypid(); - $fileName = $this->getLogPath() . $processNo . '.instance.appid.pid'; - $appInstanceId = $this->getfilesText($fileName); - if($appInstanceId !== '0' && empty($appInstanceId)){ - - - $rt = date('YmdHis'); - $ip = $this->_getCurrentMachineIp(); - $agentUuid = self::$_appCode . '.' . $ip; - $hostname = ''; - if(!empty( $_SERVER['HOSTNAME']) ){ - $hostname = $_SERVER['HOSTNAME']; - } - - $param = array( - 'ai' => (int)$appId, - 'au' => $agentUuid, - 'rt' => $rt, - 'oi' => array( - 'osName' => PHP_OS, - 'hostname' => $hostname, - 'processNo' => $processNo, - 'ipv4s' => array($ip), - ), - ); - $appInstanceIds = $this->doRequest(json_encode($param), $this->getRegisterUrl() . '/instance/register'); - $appInstanceIds = json_decode($appInstanceIds, true); - if(isset($appInstanceIds['ii'])){ - $appInstanceId = (string)$appInstanceIds['ii']; - } - if(!empty($appInstanceId) || $appInstanceId === '0'){ - $this->fwriteFilesText($fileName, $appInstanceId); - } - } - if($appInstanceId !== '0' && empty($appInstanceId)){ - return false; - } - - return (int)$appInstanceId; - - } - - /** - * http璇锋眰 - * @param unknown $params - * @since 2017骞11鏈28鏃 - * @copyright - * @return return_type - */ - private function doRequest($params, $registerUrl) { - - if($this->_isClose || !$this->isSampling()){ - return ; - } - //涓嶆敮鎸乧url 鍏抽棴鏀瑰姛鑳 - if( !function_exists('curl_init') ){ - $this->_isClose = false; - } - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $registerUrl); - curl_setopt($ch, CURLOPT_AUTOREFERER, true); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_TIMEOUT,1); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, $params); - $result = curl_exec($ch);//杩愯curl - $info = curl_getinfo($ch); - curl_close($ch); - - if( 0 == strlen($result) || ($info['http_code'] != 200) ){ - return false; - } - return $result; - } - - /** - * 鑾峰彇鏂囦欢褰撳墠琛屽唴瀹 - * @param unknown $filename - * @since 2017骞11鏈28鏃 - * @copyright - * @return return_type - */ - private function getfilesText($filename){ - try { - $file = new SplFileObject($filename); - return $file->current(); - - } catch (\RuntimeException $e) { - return null; - } - } - - private function fwriteFilesText($filename, $text){ - try { - $file = new SplFileObject($filename, "w"); - $file->fwrite($text); - } catch (\RuntimeException $e) { - } - - } -} diff --git a/bak/demo.php b/bak/demo.php deleted file mode 100644 index 7ce24f7..0000000 --- a/bak/demo.php +++ /dev/null @@ -1,136 +0,0 @@ -setLogPath(LOG_PATH)->setSamplingRate(5); - - -//鍙戣捣B璇锋眰 -sendA(); -//鍙戣捣B璇锋眰 -sendB(); -//鍙戣捣B璇锋眰 -sendC(); - - -function sendA(){ - - /** start 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - $headers = array( - "Content-type: text/xml", - "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", - "Cache-Control: no-cache", - "Pragma: no-cache", - ); - /** end 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - - - SkyWalking::getInstance()->startSpanOfCurl("api.com", $headers); - //var_dump($headers); - - - /** start 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - $curl = curl_init(); - curl_setopt($curl, CURLOPT_URL, 'http://www.api.com/'); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($curl,CURLOPT_HTTPHEADER,$headers); - curl_setopt($curl, CURLOPT_HEADER, 0); - $result = curl_exec($curl); - $errno = curl_errno($curl); - $error = curl_error($curl); - /** end 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - - - SkyWalking::getInstance()->endSpanOfcurl($curl); - - - /** start 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - curl_close($curl); - /** end 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ -} - - -function sendB(){ - - /** start 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - $headers = array( - "Content-type: text/xml", - "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", - "Cache-Control: no-cache", - "Pragma: no-cache", - ); - /** end 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - - - SkyWalking::getInstance()->startSpanOfCurl("api.com", $headers); - //var_dump($headers); - - - /** start 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - $curl = curl_init(); - curl_setopt($curl, CURLOPT_URL, 'http://www.api.com/'); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($curl,CURLOPT_HTTPHEADER,$headers); - curl_setopt($curl, CURLOPT_HEADER, 0); - $result = curl_exec($curl); - $errno = curl_errno($curl); - $error = curl_error($curl); - /** end 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - - - SkyWalking::getInstance()->endSpanOfcurl($curl); - - - /** start 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - curl_close($curl); - /** end 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ -} - -function sendC(){ - - /** start 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - $headers = array( - "Content-type: text/xml", - "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", - "Cache-Control: no-cache", - "Pragma: no-cache", - ); - /** end 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - - - SkyWalking::getInstance()->startSpanOfCurl("api.com", $headers); - //var_dump($headers); - - - /** start 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - /** start 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - $curl = curl_init(); - curl_setopt($curl, CURLOPT_URL, 'http://www.api.com/'); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($curl,CURLOPT_HTTPHEADER,$headers); - curl_setopt($curl, CURLOPT_HEADER, 0); - $result = curl_exec($curl); - $errno = curl_errno($curl); - $error = curl_error($curl); - /** end 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - - - SkyWalking::getInstance()->endSpanOfcurl($curl); - - - /** start 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ - curl_close($curl); - /** end 搴旂敤鏈韩鐨勪笟鍔′唬鐮 **/ -} \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go index 9732fa3..db12a70 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -20,7 +20,7 @@ func main() { app := cli.NewApp() app.Name = "sky_php_agent" app.Usage = "the skywalking trace sending agent" - app.Version = "3.2.8" + app.Version = "3.3.0" app.Flags = []cli.Flag{ &cli.StringSliceFlag{Name: "grpc", Usage: "SkyWalking collector address", Value: cli.NewStringSlice("127.0.0.1:11800")}, &cli.StringFlag{Name: "socket", Usage: "Pipeline for communicating with PHP", Value: "/tmp/sky-agent.sock"}, diff --git a/docs/README.md b/docs/README.md index 2a9f155..ade3696 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,4 +2,4 @@ * Quick Start * [Quick start](quick-start.md) - * [Install agent](install-agent.md) + * [Install](install.md) diff --git a/docs/README_ZH.md b/docs/README_ZH.md deleted file mode 100644 index 55f4f69..0000000 --- a/docs/README_ZH.md +++ /dev/null @@ -1,6 +0,0 @@ -鏂囨。 -===== - * [鏇存敼璁板綍](./zh/change-log.md) - * [瀹夎php鎵╁睍](./zh/install-sdk.md) - * [鍚姩agent](./zh/start-agent.md) - * [甯歌闂](./zh/qa.md) \ No newline at end of file diff --git a/docs/install-agent.md b/docs/install-agent.md deleted file mode 100644 index d7ae151..0000000 --- a/docs/install-agent.md +++ /dev/null @@ -1,165 +0,0 @@ -Tips: It is recommended that you use SkyWalking and use nginx as load balancing - -# Install SkyWalking PHP Agent - -## Requirements -When building directly from Git sources or after custom modifications you might also need: -* php 7+ -* golang 1.13 -* SkyWalking oap server -* SkyWalking UI - -## PHP extension + Agent -The collect data from your instance you need both the PHP extension, and the agent. -No pre built binaries or PHP extension are availble at the moment, so you need to -build them from source. - -You can run the following commands to install the SkyWalking PHP Agent. - -## Install PHP Extension -```shell script -curl -Lo v3.2.8.tar.gz https://github.com/SkyAPM/SkyAPM-php-sdk/archive/v3.2.8.tar.gz -tar zxvf v3.2.8.tar.gz -cd SkyAPM-php-sdk-3.2.8 -phpize && ./configure && make && make install -``` - -## Install sky-php-agent -### Build -For installing the sky-php-agent, you first need to build it: - -```shell script -cd SkyAPM-php-sdk-3.2.8 -go build -o sky-php-agent cmd/main.go -chmod +x sky-php-agent -cp sky-php-agent /usr/local/bin -``` - -## How to use - -### Add skywalking config to php.ini and restart php-fpm - -```shell script -; Loading extensions in PHP -extension=skywalking.so - -; enable skywalking -skywalking.enable = 1 - -; Set skyWalking collector version (5 or 6 or 7 or 8) -skywalking.version = 6 - -; Set app code e.g. MyProjectName -skywalking.app_code = MyProjectName - -; sock file path锛坉efault /tmp/sky-agent.sock锛 -skywalking.sock_path=/tmp/sky-agent.sock -``` - -## Select startup script and log output method -## If you use CentOS 7 Use the startup script below to You need to change the corresponding address, version -```shell script -[Unit] -Description=The Sw-Php-Agent Process Manager -After=syslog.target network.target - -[Service] -Type=simple -#Modify the corresponding directory and address here -ExecStart=/usr/local/bin/sky-php-agent-linux-X64 --grpc=127.0.0.1:11800 --sky-version=7 --socket=/tmp/sky-agent.sock -ExecStop=/bin/kill -SIGINT $MAINPID -Restart=on-failure - -[Install] -WantedBy=multi-user.target - -``` -## If you use CentOS6 Log management with lograted -## This is Start script You need to change the address, version and Copy and run it with root -```shell script -echo " -#/bin/bash - -start(){ -[ -f /tmp/php-agent.pid ]&&echo "Alredy running"&&exit 1 -/usr/local/bin/sky-php-agent-linux-X64 --grpc=127.0.0.1:11800 --sky-version=7 --socket=/tmp/sky-agent.sock 1>>/var/log/phpagent/php-agent.log 2>>/var/log/phpagent/php-agent-error.log & -if [ $? -eq 0 ];then - echo $! >/tmp/php-agent.pid - echo "sky-php-agent startup!!!" -fi - -} - -stop(){ -kill -9 `cat /tmp/php-agent.pid` -rm -f /tmp/php-agent.pid -[[ $? == 0 ]]&&echo "sky-php-agent stop!!!" -} - - - -# add the restart method - -case $1 in - - start) - - start - ;; - - stop) - - stop - ;; - - restart) - - stop - - start - ;; - - - *) - - echo "USAGE: $0 {start |stop |restart }" - ;; - -esac - -exit 0 " > /etc/init.d/php-agent -``` -## This is Log management script锛孋opy and run it with root -```shell script -mkdir /var/log/phpagent/ -echo " -/var/log/phpagent/*.log { - rotate 10 - daily - dateext - nocompress - missingok - notifempty - create 0644 root root - postrotate - /etc/init.d/php-agent restart - endscript -}" >/etc/logrotate.d/phpagent -``` - -### Agent parameter description -```shell script -# View help information -./sky-php-agent -h - -# Specify grpc address -/usr/local/bin/sky-php-agent --grpc 127.0.0.1:11800 - -# Specify the socket file. The path is the path in the php.ini configuration -/usr/local/bin/sky-php-agent --socket=/tmp/sky-agent.sock - -# Specify the version of skywalking -/usr/local/bin/sky-php-agent --sky-version=7 -``` - -### 鈿狅笍鈿狅笍鈿狅笍 Warning *Make sure PHP has read and write permissions on the socks file* diff --git a/docs/install.md b/docs/install.md new file mode 100644 index 0000000..6e47cc5 --- /dev/null +++ b/docs/install.md @@ -0,0 +1,77 @@ +Tips: It is recommended to use nginx as the load balancer of SkyWalking-oap-server + +# Install SkyWalking PHP Agent + +## Requirements +When building directly from Git sources or after custom modifications you might also need: +* php 7+ +* golang 1.13 +* SkyWalking oap server +* SkyWalking UI + +## PHP extension + Agent +The collect data from your instance you need both the PHP extension, and the agent. +No pre built binaries or PHP extension are availble at the moment, so you need to +build them from a source. + +You can run the following commands to install the SkyWalking PHP Agent. + +## Install PHP Extension +```shell script +curl -Lo v3.3.0.tar.gz https://github.com/SkyAPM/SkyAPM-php-sdk/archive/v3.3.0.tar.gz +tar zxvf v3.3.0.tar.gz +cd SkyAPM-php-sdk-3.3.0 +phpize && ./configure && make && make install +``` + +## Install sky-php-agent +### Build +For installing the sky-php-agent, you first need to build it: + +```shell script +cd SkyAPM-php-sdk-3.3.0 +go build -o sky-php-agent cmd/main.go +chmod +x sky-php-agent +cp sky-php-agent /usr/local/bin +``` + +## How to use + +### Add SkyWalking config to php.ini and restart php-fpm + +```shell script +; Loading extensions in PHP +extension=skywalking.so + +; enable skywalking +skywalking.enable = 1 + +; Set skyWalking collector version (5 or 6 or 7 or 8) +skywalking.version = 8 + +; Set app code e.g. MyProjectName +skywalking.app_code = MyProjectName + +; sock file path default /tmp/sky-agent.sock +; Warning *[systemd] please disable PrivateTmp feature* +; Warning *Make sure PHP has read and write permissions on the socks file* +skywalking.sock_path=/tmp/sky-agent.sock +``` + +## sky-php-agent `systemd` example + +```shell script +[Unit] +Description=The SkyWalking PHP-Agent Process Manager +After=syslog.target network.target + +[Service] +Type=simple +# Modify the corresponding directory and address here +ExecStart=/usr/local/bin/sky-php-agent --grpc=127.0.0.1:11800 --sky-version=8 --socket=/tmp/sky-agent.sock +ExecStop=/bin/kill -SIGINT $MAINPID +Restart=on-failure + +[Install] +WantedBy=multi-user.target +``` diff --git a/docs/quick-start.md b/docs/quick-start.md index 5a57d34..ec3da4a 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -1,3 +1,4 @@ -# todo +# Get started quickly with docker -See [Install agent](install-agent.md) \ No newline at end of file +See [docker-compose.yml](../docker-compose.yml) +See [Dockerfile](../Dockerfile) diff --git a/docs/zh/change-log.md b/docs/zh/change-log.md deleted file mode 100644 index e4c2202..0000000 --- a/docs/zh/change-log.md +++ /dev/null @@ -1,19 +0,0 @@ -# 20191001 -## Agent 淇敼 -1. 淇敼鏂囦欢鏉冮檺涓0777 -1. 鎵ц`sky-php-agent -h` 鏌ョ湅鍙敤鍙傛暟 - -# 20190722 -## SkyWalking 鎵╁睍淇敼 -1. 鏀寔瀵筸ysqli鎵╁睍鐨勬敮鎸(鐩墠鏆傛椂浠呮敮鎸乣mysqli::query()`) - -# 20190719 -## Agent 淇敼 -1. agent鍒涘缓鐨勬枃浠舵潈闄愪慨鏀逛负0666, 鏂囦欢鐨勭被鍨嬩慨鏀逛负sock绫诲瀷銆備慨澶峱hp涓巗ock鏂囦欢杩涜閫氫俊鏃舵彁绀"Permission Deny"鐨勯棶棰 -2. agent鐨勫弬鏁版帴鏀舵柟寮忎慨鏀, 鎵ц`sky-php-agent -h` 鏌ョ湅鍙敤鍙傛暟 -3. agent鏀寔鍦ㄥ弬鏁颁腑鎸囧畾sock鏂囦欢鐨勮矾寰 - -## SkyWalking 鎵╁睍淇敼 -1. 鏂板 skywalking_get_trace_info():array 鏂规硶锛岃幏鍙杢race鏁版嵁锛屼互鏂逛究涓氬姟鏃ュ織鑾峰彇褰撳墠璇锋眰trace淇℃伅銆 -2. 鍒犻櫎鏃犵敤鐨剆kywalking.log_path鍙妔kywalking.grpc閰嶇疆椤 -3. 鏂板 skywalking.sock_path 閰嶇疆椤癸紝鏀寔鑷畾涔塻ock鏂囦欢鐨勮矾寰 diff --git a/docs/zh/install-sdk.md b/docs/zh/install-sdk.md deleted file mode 100644 index 2f4ea4e..0000000 --- a/docs/zh/install-sdk.md +++ /dev/null @@ -1,73 +0,0 @@ -# 鐜 - -PHP7+ - - -# 瀹夎 - -## 瀹夎PHP鐨凷kyWalking鎵╁睍(Ubuntu鐜) - - -1.瀹夎php-dev (鍏蜂綋鐨凱HP鐗堟湰浠ヤ綘鐨勭幆澧冧负鍑嗭紝蹇呴』php7+) - -```shell -sudo apt install php7.2-dev -``` - - -2.瀹夎curl寮鍙戝寘 - -```shell -sudo apt install curl-dev -``` - - -3.git clone 婧愮爜 - -```shell -git clone https://github.com/SkyAPM/SkyAPM-php-sdk.git /path/to/SkyAPM-php-sdk -``` - - -4.缂栬瘧瀹夎SkyAPM-php-sdk - -```shell -cd /path/to/SkyAPM-php-sdk -phpize -./configure -make -sudo make install -``` - - -5.鏂板缓php鐨剆kywalking鎵╁睍閰嶇疆鏂囦欢锛屽啓鍏ラ厤缃 - -```shell -; 鎵╁睍so -extension=skywalking.so -; 鏄惁鍚敤锛0 鍏抽棴锛1 鍚敤 (榛樿鍊间负0) -skywalking.enable=1 -; skywalking鐨勭増鏈細5鎴栬6锛堥粯璁ゅ间负6锛 -skywalking.version=6 -; app_code浠g爜锛屼笉瑕佸惈鐗规畩瀛楃锛岃浣跨敤鏁板瓧銆佸瓧姣嶃佷笅鎹㈢嚎銆(榛樿涓猴細hello_skywalking) -skywalking.app_code=hello_skywalking -; sock鏂囦欢璺緞锛堥粯璁ゅ间负/var/run/sky-agent.sock锛 -skywalking.sock_path=/var/run/sky-agent.sock -``` - - -6.閲嶅惎php-fpm鏈嶅姟 - -```shell -sudo service php-fpm restart -``` - - -7.鏌ョ湅skywalking鎵╁睍鏄惁鎴愬姛鍔犺浇 - -```shell -php -m | grep skywalking -``` - -鏌ョ湅鍏蜂綋閰嶇疆锛岃浣跨敤`php -i`鎴栬卄phpinfo()`鍑芥暟 - diff --git a/docs/zh/qa.md b/docs/zh/qa.md deleted file mode 100644 index 9412ba2..0000000 --- a/docs/zh/qa.md +++ /dev/null @@ -1,74 +0,0 @@ -# 甯歌闂 - ----- -1. linux涓媝hp涓嶈兘璇诲彇/tmp鏂囦欢澶逛笅鏂囦欢锛屽嵆php鏃犳硶涓/tmp鐩綍涓嬬殑sock鏂囦欢杩涜閫氫俊銆 -璇ラ棶棰樹竴鑸槸鐢盽systemd`鏈嶅姟鐨刞PrivateTmp`灞炴ч厤缃鑷寸殑銆 -`systemd`涓湇鍔$殑閰嶇疆鏂囦欢閮藉湪鐩綍`/lib/systemd/system/`涓細 - * 妫鏌ELinux閰嶇疆锛屽彲灏濊瘯鍏抽棴SELinux - * `apache`鐨勯厤缃枃浠朵负`apache2.service` - * `php-fpm`鐨勯厤缃枃浠朵负`php-fpm.service` (鍙兘浼氬瓨鍦ㄧ増鏈彿锛屼緥濡俙php7.2-fpm.service`) - - 淇敼`PrivateTmp`灞炴х殑鍙栧间负`false`, 鍐嶆墽琛宍sudo systemctl daemon-reload`, 鏈鍚庡啀閲嶅惎`apache`鎴栬卄php-fpm` - -1. 瀵逛簬宸茬粡瀹夎骞跺惎鐢ㄤ簡`SkyWalking`鎵╁睍鐨凱HP鐜鐨勪富鏈猴紝鎵鍙戦佺殑trace淇℃伅鍦ㄥ摢閲岋紵 - * 濡傛灉`skywalking.version=5`, 鍒檂http`璇锋眰鐨刞header`涓細鍔犲叆涓涓悕涓篳SW3`鐨勬暟鎹侾HP鍙娇鐢╜$_SERVER['HTTP_SW3']`鑾峰彇銆俒鍗忚鏂囨。](https://github.com/apache/skywalking/blob/master/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v1.md) - * 濡傛灉`skywalking.version=6`, 鍒檂http`璇锋眰鐨刞header`涓細鍔犲叆涓涓悕涓篳SW6`鐨勬暟鎹侾HP鍙娇鐢╜$_SERVER['HTTP_SW6']`鑾峰彇銆俒鍗忚鏂囨。](https://github.com/apache/skywalking/blob/master/docs/en/protocols/Skywalking-Cross-Process-Propagation-Headers-Protocol-v2.md) - * SW6鍊兼牸寮忎负锛歚1-{distributedTraceIdEncode}-{traceSegmentIdEncode}-{span_id}-{application_instance}-{entryApplicationInstance}-{peerHostEncode}-{entryEndpointNameEncode}-{parentEndpointNameEncode}`, Encode绠楁硶涓篵ase64_encode()銆傜ず渚嬪彇鍊间负锛歚1-OTQuMjIyMzUuMTU2MjkxMDg1MzAwMDM=-OTQuMjIyMzUuMTU2MjkxMDg1MzAwMDM=-1-94-94-IwE6NDQz-Iy9pbmRleC5waHA/ZGRkZGRkZA==-IwE=` - * 鍊间腑`distributedTraceId`鍗充笅鏂圭殑`globalTraceIds[0]`鐨勫彇鍊 - -1. 浼氫紶閫抰race淇℃伅鐨勮姹傜被鍨嬫湁鍝簺锛 - * php curl鎵╁睍鍙戝嚭鐨勮姹 - * php PDO鎵╁睍鍙戝嚭鐨勮姹 - * php mysqli鎵╁睍鍙戝嚭鐨勮姹 - * php yar鎵╁睍(client)鍙戝嚭鐨勮姹 - * php [grpc/grpc](https://github.com/grpc/grpc-php) 鍙戝嚭鐨勮姹 - * php redis鎵╁睍鍙戝嚭鐨勮姹 - * php predis搴撳彂鍑虹殑璇锋眰 - -1. skywalking_get_trace_info()鍑芥暟鐨勮繑鍥炲兼牸寮忥紵 - * 杩斿洖鍊间负鏁扮粍銆傚鏋滄墿灞曞姞杞戒絾鏄湭鍚敤(`skywalking.enable=0`), 鍒欒繑鍥炵┖鏁扮粍 -```php - # skywalking_get_trace_info 杩斿洖鍊兼牸寮忓涓嬶細 - [ - 'application_instance' => 94, - 'pid' => 22230, - 'application_id' => 29, - 'version' => 6, - 'segment' => [ - 'traceSegmentId' => '94.22412.15629106130002', - 'isSizeLimited' => 0, - 'spans' => [ - [ - 'tags' => [ - 'url' => '/index.php?id=123' - ], - 'spanId' => 0, - 'parentSpanId' => -1, - 'startTime' => 1562910613896, - 'operationName' => '/index.php', - 'peer' => '127.0.0.1:80', - 'spanType' => 0, - 'spanLayer' => 3, - 'componentId' => 2, - 'refs' => [ - [ - 'type' => 0, - 'parentTraceSegmentId' => '94.22412.15629106130002', - 'parentSpanId' => 1, - 'parentApplicationInstanceId' => 94, - 'networkAddress' => ':443', - 'entryApplicationInstanceId' => 94, - 'entryServiceName' => 'index.php?to=123', - 'parentServiceName' => '', - ], - ], - ], - ], - ], - 'globalTraceIds' => [ - '94.22235.15629108530003', - ], - ] - ``` - -1. mysqli鏈夎繃绋嬪紡椋庢牸鍜屽璞″紡椋庢牸锛屼笂鎶ョ殑鏁版嵁鏈変綍涓嶅悓锛 - * 鐩墠鎵╁睍浠呯洃鎺ysqli_query()銆乵ysqli::query()鏂规硶, 骞惰褰曞搴旀墽琛岀殑sql, 鍦ㄤ笂鎶ュ埌oapServer鐨勬椂鍊欙紝缁熶竴鎸夌収mysqli->query()鐨勬牸寮忚繘琛屼笂鎶 \ No newline at end of file diff --git a/docs/zh/start-agent.md b/docs/zh/start-agent.md deleted file mode 100644 index 93c686f..0000000 --- a/docs/zh/start-agent.md +++ /dev/null @@ -1,35 +0,0 @@ -# 鍚姩agent - -1.閫夋嫨浣犵殑鎿嶄綔绯荤粺瀵瑰簲鐨刟gent搴旂敤绋嬪簭 - - darwin鎸嘙acOS鎿嶄綔绯荤粺, linux鎸嘗inux鎿嶄綔绯荤粺 - x64/x86鍒嗗埆鎸64浣嶆搷浣滅郴缁/32浣嶆搷浣滅郴缁 - -``` -sky-php-agent-darwin-x64 -sky-php-agent-darwin-x86 -sky-php-agent-linux-x64 -sky-php-agent-linux-x86 -sky-php-agent-linux-arm64 -sky-php-agent-linux-arm86 -``` - - -2.鍚姩agent(浠 Ubuntu x64 骞冲彴绀轰緥) - -```shell -# 娣诲姞鍙墽琛屾潈闄 -sudo chmod +x ./sky-php-agent-linux-x64 - -# 鍚姩 -./sky-php-agent-linux-x64 127.0.0.1:11800 /var/run/sky-agent.sock -``` - - -3.agent 鍙傛暟璇存槑 - - * 绗竴涓弬鏁颁负SkyWalking鏈嶅姟绔殑GRPC鍦板潃 - * 绗簩涓弬鏁颁负sock鏂囦欢鐨勭粷瀵硅矾寰勶紝蹇呴』涓巔hp涓璼kywalking.sock_path鐨勮矾寰勪竴鑷淬傞粯璁ゅ间负锛歚/var/run/sky-agent.sock` - * `-h` 鍙煡鐪嬪府鍔╀俊鎭 - - diff --git a/package-template.xml b/package-template.xml index b5cbd4c..c9f302c 100644 --- a/package-template.xml +++ b/package-template.xml @@ -26,7 +26,7 @@ Apache2.0 - Fix the mistake of field entryOperationName in sw6 header. + {{notes}} @@ -47,6 +47,19 @@ {{release}} + + + 3.3.0 + 3.3.0 + + + stable + stable + + + Added memcache collection and skywalking 8.0 support + + 3.2.8 @@ -100,4 +113,4 @@ - \ No newline at end of file + diff --git a/package.xml b/package.xml index 7632125..c153831 100644 --- a/package.xml +++ b/package.xml @@ -15,10 +15,10 @@ yanlong@php.net yes - 2020-03-23 + 2020-05-12 - 3.2.8 - 3.2.8 + 3.3.0 + 3.3.0 stable @@ -26,7 +26,7 @@ Apache2.0 - Fix the mistake of field entryOperationName in sw6 header. + Added memcache collection and skywalking 8.0 support @@ -35,52 +35,19 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + - - - - + @@ -88,26 +55,63 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -145,7 +149,6 @@ - @@ -163,6 +166,19 @@ + + + 3.3.0 + 3.3.0 + + + stable + stable + + + Added memcache collection and skywalking 8.0 support + + 3.2.8 @@ -216,4 +232,4 @@ - \ No newline at end of file + diff --git a/pecl-package.php b/pecl-package.php index 5962ac2..d8eb90c 100644 --- a/pecl-package.php +++ b/pecl-package.php @@ -16,9 +16,13 @@ $header = file_get_contents("$root_dir/php_skywalking.h"); $header = preg_replace("/PHP_SKYWALKING_VERSION \"(\d.\d.\d)\"/i", 'PHP_SKYWALKING_VERSION "' . $version . '"', $header); file_put_contents("$root_dir/php_skywalking.h", $header); -$agent = file_get_contents("$root_dir/agent/cmd/main.go"); +$agent = file_get_contents("$root_dir/cmd/main.go"); $agent = preg_replace("/app.Version = \"(\d.\d.\d)\"/i", 'app.Version = "' . $version . '"', $agent); -file_put_contents("$root_dir/agent/cmd/main.go", $agent); +file_put_contents("$root_dir/cmd/main.go", $agent); + +$insert = file_get_contents("$root_dir/docs/install.md"); +$insert = preg_replace("/(\d.\d.\d)/i", $version, $insert); +file_put_contents("$root_dir/docs/install.md", $insert); echo "version: $version\n"; @@ -76,6 +80,7 @@ $template = str_replace("{{file_list}}", implode(" ", $file_list), $t $template = str_replace("{{version}}", $version, $template); $template = str_replace("{{date}}", date("Y-m-d"), $template); $template = str_replace("{{release}}", "", $template); +$template = str_replace("{{notes}}", $desc, $template); file_put_contents("package.xml", $template); diff --git a/php.ini b/php.ini index 08f4c7d..1ab1297 100644 --- a/php.ini +++ b/php.ini @@ -11,5 +11,5 @@ extension=skywalking.so skywalking.app_code = hello_skywalking skywalking.enable = 1 -skywalking.version = 6 -skywalking.sock_path = /tmp/sky-agent.sock \ No newline at end of file +skywalking.version = 8 +skywalking.sock_path = /tmp/sky-agent.sock diff --git a/php_skywalking.h b/php_skywalking.h index 6cc2748..69cab9e 100644 --- a/php_skywalking.h +++ b/php_skywalking.h @@ -25,7 +25,7 @@ extern zend_module_entry skywalking_module_entry; #define phpext_skywalking_ptr &skywalking_module_entry #define SKY_DEBUG 0 -#define PHP_SKYWALKING_VERSION "3.2.8" /* Replace with version number for your extension */ +#define PHP_SKYWALKING_VERSION "3.3.0" /* Replace with version number for your extension */ #ifdef PHP_WIN32 # define PHP_SKYWALKING_API __declspec(dllexport) diff --git a/reporter/service/agent.go b/reporter/service/agent.go index 7d2cae6..d477d0c 100644 --- a/reporter/service/agent.go +++ b/reporter/service/agent.go @@ -189,7 +189,11 @@ func (t *Agent) sub() { go t.doRegister(register) case trace := <-t.trace: t.queueLock.Lock() - t.queue = append(t.queue, trace) + if len(t.queue) < 65535*2 { + t.queue = append(t.queue, trace) + } else { + log.Warnf("trace queue is fill.") + } t.queueLock.Unlock() } } diff --git a/sw-php-agent.service.example b/sw-php-agent.service.example deleted file mode 100644 index 58a29b9..0000000 --- a/sw-php-agent.service.example +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=The SkyWalking PHP-Agent Process Manager -After=syslog.target network.target - -[Service] -Type=simple -#Modify the corresponding directory and address here -ExecStart=/usr/local/bin/sky-php-agent --grpc=127.0.0.1:11800 --sky-version=7 --socket=/tmp/sky-agent.sock -ExecStop=/bin/kill -SIGINT $MAINPID -Restart=on-failure - -[Install] -WantedBy=multi-user.target diff --git a/who-uses.jpg b/who-uses.jpg deleted file mode 100644 index f12a09e8b3565f8842d09000dd3b6fa3a8b291ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21562 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