You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by he...@apache.org on 2022/10/17 01:31:56 UTC
[skywalking-php] branch master updated: Add Predis plugin. (#21)
This is an automated email from the ASF dual-hosted git repository.
heyanlong pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-php.git
The following commit(s) were added to refs/heads/master by this push:
new 6663f1a Add Predis plugin. (#21)
6663f1a is described below
commit 6663f1ae573a88e22636ac4bce33a83b6046d6e6
Author: jmjoy <jm...@apache.org>
AuthorDate: Mon Oct 17 09:31:51 2022 +0800
Add Predis plugin. (#21)
* Add Predis plugin.
---
README.md | 2 +-
.../service-agent/php-agent/Supported-list.md | 2 +
src/component.rs | 1 +
src/plugin/mod.rs | 2 +
src/plugin/plugin_mysqli.rs | 14 +--
src/plugin/plugin_predis.rs | 130 +++++++++++++++++++++
tests/data/expected_context.yaml | 75 +++++++++++-
tests/e2e.rs | 9 ++
src/component.rs => tests/php/fpm/predis.php | 25 ++--
9 files changed, 242 insertions(+), 18 deletions(-)
diff --git a/README.md b/README.md
index 0144013..bd77675 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ SkyWalking PHP Agent requires SkyWalking 8.4+ and PHP 7.0+
* [ ] [phpredis](https://github.com/phpredis/phpredis)
* [ ] [php-amqp](https://github.com/php-amqp/php-amqp)
* [ ] [php-rdkafka](https://github.com/arnaud-lb/php-rdkafka)
- * [ ] [predis](https://github.com/predis/predis)
+ * [x] [predis](https://github.com/predis/predis)
* Swoole Ecosystem
* [ ] [Coroutine\Http\Client](https://wiki.swoole.com/#/coroutine_client/http_client)
diff --git a/docs/en/setup/service-agent/php-agent/Supported-list.md b/docs/en/setup/service-agent/php-agent/Supported-list.md
index d9d52ee..56f9ccf 100644
--- a/docs/en/setup/service-agent/php-agent/Supported-list.md
+++ b/docs/en/setup/service-agent/php-agent/Supported-list.md
@@ -14,3 +14,5 @@ The following plugins provide the distributed tracing capability.
* [MySQL Improved](https://www.php.net/manual/en/book.mysqli.php)
## Support PHP library
+
+* [predis](https://github.com/predis/predis)
diff --git a/src/component.rs b/src/component.rs
index f51b122..3e5c93f 100644
--- a/src/component.rs
+++ b/src/component.rs
@@ -21,3 +21,4 @@ pub const COMPONENT_PHP_ID: i32 = 8001;
pub const COMPONENT_PHP_CURL_ID: i32 = 8002;
pub const COMPONENT_PHP_PDO_ID: i32 = 8003;
pub const COMPONENT_PHP_MYSQLI_ID: i32 = 8004;
+pub const COMPONENT_PHP_PREDIS_ID: i32 = 8006;
diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs
index badaf97..411fcec 100644
--- a/src/plugin/mod.rs
+++ b/src/plugin/mod.rs
@@ -16,6 +16,7 @@
mod plugin_curl;
mod plugin_mysqli;
mod plugin_pdo;
+mod plugin_predis;
mod plugin_swoole;
use crate::execute::{AfterExecuteHook, BeforeExecuteHook};
@@ -29,6 +30,7 @@ static PLUGINS: Lazy<Vec<Box<DynPlugin>>> = Lazy::new(|| {
Box::new(plugin_mysqli::MySQLImprovedPlugin::default()),
Box::new(plugin_swoole::SwooleServerPlugin::default()),
Box::new(plugin_swoole::SwooleHttpResponsePlugin::default()),
+ Box::new(plugin_predis::PredisPlugin::default()),
]
});
diff --git a/src/plugin/plugin_mysqli.rs b/src/plugin/plugin_mysqli.rs
index b04883d..e40ea98 100644
--- a/src/plugin/plugin_mysqli.rs
+++ b/src/plugin/plugin_mysqli.rs
@@ -13,19 +13,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use anyhow::Context;
-use dashmap::DashMap;
-use once_cell::sync::Lazy;
-use skywalking::{skywalking_proto::v3::SpanLayer, trace::span::Span};
-use tracing::debug;
-
+use super::Plugin;
use crate::{
component::COMPONENT_PHP_MYSQLI_ID,
context::RequestContext,
execute::{get_this_mut, AfterExecuteHook, BeforeExecuteHook, Noop},
};
-
-use super::Plugin;
+use anyhow::Context;
+use dashmap::DashMap;
+use once_cell::sync::Lazy;
+use skywalking::{skywalking_proto::v3::SpanLayer, trace::span::Span};
+use tracing::debug;
static MYSQL_MAP: Lazy<DashMap<u32, MySQLInfo>> = Lazy::new(Default::default);
diff --git a/src/plugin/plugin_predis.rs b/src/plugin/plugin_predis.rs
new file mode 100644
index 0000000..79aceda
--- /dev/null
+++ b/src/plugin/plugin_predis.rs
@@ -0,0 +1,130 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// TODO Need to be improved.
+
+use super::Plugin;
+use crate::{
+ component::COMPONENT_PHP_PREDIS_ID,
+ context::RequestContext,
+ execute::{get_this_mut, validate_num_args, AfterExecuteHook, BeforeExecuteHook},
+};
+use anyhow::Context;
+use phper::arrays::ZArr;
+use skywalking::{skywalking_proto::v3::SpanLayer, trace::span::Span};
+
+#[derive(Default, Clone)]
+pub struct PredisPlugin;
+
+impl Plugin for PredisPlugin {
+ fn class_names(&self) -> Option<&'static [&'static str]> {
+ Some(&["Predis\\Connection\\AbstractConnection"])
+ }
+
+ fn function_name_prefix(&self) -> Option<&'static str> {
+ None
+ }
+
+ fn hook(
+ &self, class_name: Option<&str>, function_name: &str,
+ ) -> Option<(
+ Box<crate::execute::BeforeExecuteHook>,
+ Box<crate::execute::AfterExecuteHook>,
+ )> {
+ match (class_name, function_name) {
+ (Some(class_name @ "Predis\\Connection\\AbstractConnection"), "executeCommand") => {
+ Some(self.hook_predis_execute_command(class_name))
+ }
+ _ => None,
+ }
+ }
+}
+
+impl PredisPlugin {
+ fn hook_predis_execute_command(
+ &self, class_name: &str,
+ ) -> (Box<BeforeExecuteHook>, Box<AfterExecuteHook>) {
+ let class_name = class_name.to_owned();
+ (
+ Box::new(move |_, execute_data| {
+ validate_num_args(execute_data, 1)?;
+
+ let this = get_this_mut(execute_data)?;
+ let parameters = this.get_mut_property("parameters").expect_mut_z_obj()?;
+ let parameters = parameters
+ .get_mut_property("parameters")
+ .expect_mut_z_arr()?;
+ let host = parameters
+ .get_mut("host")
+ .context("host not found")?
+ .expect_z_str()?
+ .to_str()?;
+ let port = parameters
+ .get_mut("port")
+ .context("port not found")?
+ .expect_long()?;
+ let peer = format!("{}:{}", host, port);
+
+ let command = execute_data.get_parameter(0).expect_mut_z_obj()?;
+
+ let id = command.call("getid", []).context("call getId failed")?;
+ let id = id.expect_z_str()?.to_str()?;
+
+ let mut arguments = command
+ .call("getarguments", [])
+ .context("call getArguments failed")?;
+ let arguments = arguments.expect_mut_z_arr()?;
+
+ let mut span = RequestContext::try_with_global_ctx(None, |ctx| {
+ Ok(ctx.create_exit_span(&format!("{}->{}", class_name, id), &peer))
+ })?;
+
+ span.with_span_object_mut(|span| {
+ span.set_span_layer(SpanLayer::Cache);
+ span.component_id = COMPONENT_PHP_PREDIS_ID;
+ span.add_tag("db.type", "redis");
+ span.add_tag("redis.command", generate_command(id, arguments));
+ });
+
+ Ok(Box::new(span))
+ }),
+ Box::new(move |_, span, _, return_value| {
+ let mut span = span.downcast::<Span>().unwrap();
+
+ let typ = return_value.get_type_info();
+ if typ.is_null() || typ.is_false() {
+ span.with_span_object_mut(|span| span.is_error = true);
+ }
+
+ Ok(())
+ }),
+ )
+ }
+}
+
+fn generate_command(id: &str, arguments: &mut ZArr) -> String {
+ let mut ss = Vec::with_capacity(arguments.len() + 1);
+ ss.push(id);
+
+ for (_, argument) in arguments.iter() {
+ if let Some(value) = argument.as_z_str().and_then(|s| s.to_str().ok()) {
+ ss.push(value);
+ } else if argument.as_z_arr().is_some() {
+ break;
+ }
+ }
+
+ ss.join(" ")
+}
diff --git a/tests/data/expected_context.yaml b/tests/data/expected_context.yaml
index f012b67..2a6fc70 100644
--- a/tests/data/expected_context.yaml
+++ b/tests/data/expected_context.yaml
@@ -15,7 +15,7 @@
segmentItems:
- serviceName: skywalking-agent-test-1
- segmentSize: 8
+ segmentSize: 9
segments:
- segmentId: "not null"
spans:
@@ -342,6 +342,79 @@ segmentItems:
- { key: url, value: /pdo.php }
- { key: http.method, value: GET }
- { key: http.status_code, value: "200" }
+ - segmentId: "not null"
+ spans:
+ - operationName: "Predis\\Connection\\AbstractConnection->AUTH"
+ parentSpanId: 0
+ spanId: 1
+ spanLayer: Cache
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 8006
+ isError: false
+ spanType: Exit
+ peer: 127.0.0.1:6379
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: redis }
+ - { key: redis.command, value: AUTH password }
+ - operationName: "Predis\\Connection\\AbstractConnection->SET"
+ parentSpanId: 0
+ spanId: 2
+ spanLayer: Cache
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 8006
+ isError: false
+ spanType: Exit
+ peer: 127.0.0.1:6379
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: redis }
+ - { key: redis.command, value: SET foo bar }
+ - operationName: "Predis\\Connection\\AbstractConnection->GET"
+ parentSpanId: 0
+ spanId: 3
+ spanLayer: Cache
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 8006
+ isError: false
+ spanType: Exit
+ peer: 127.0.0.1:6379
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: redis }
+ - { key: redis.command, value: GET foo }
+ - operationName: "Predis\\Connection\\AbstractConnection->GET"
+ parentSpanId: 0
+ spanId: 4
+ spanLayer: Cache
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 8006
+ isError: true
+ spanType: Exit
+ peer: 127.0.0.1:6379
+ skipAnalysis: false
+ tags:
+ - { key: db.type, value: redis }
+ - { key: redis.command, value: GET not-exists }
+ - operationName: GET:/predis.php
+ parentSpanId: -1
+ spanId: 0
+ spanLayer: Http
+ startTime: gt 0
+ endTime: gt 0
+ componentId: 8001
+ isError: false
+ spanType: Entry
+ peer: ""
+ skipAnalysis: false
+ tags:
+ - { key: url, value: /predis.php }
+ - { key: http.method, value: GET }
+ - { key: http.status_code, value: "200" }
- segmentId: 'not null'
spans:
- operationName: mysqli->query
diff --git a/tests/e2e.rs b/tests/e2e.rs
index 22a2c17..cbdaf9c 100644
--- a/tests/e2e.rs
+++ b/tests/e2e.rs
@@ -51,6 +51,7 @@ async fn run_e2e() {
request_fpm_pdo().await;
request_fpm_mysqli().await;
request_swoole_curl().await;
+ request_fpm_predis().await;
sleep(Duration::from_secs(3)).await;
request_collector_validate().await;
}
@@ -79,6 +80,14 @@ async fn request_fpm_mysqli() {
.await;
}
+async fn request_fpm_predis() {
+ request_common(
+ HTTP_CLIENT.get(format!("http://{}/predis.php", PROXY_SERVER_1_ADDRESS)),
+ "ok",
+ )
+ .await;
+}
+
async fn request_swoole_curl() {
request_common(
HTTP_CLIENT.get(format!("http://{}/curl", SWOOLE_SERVER_1_ADDRESS)),
diff --git a/src/component.rs b/tests/php/fpm/predis.php
similarity index 66%
copy from src/component.rs
copy to tests/php/fpm/predis.php
index f51b122..98375b5 100644
--- a/src/component.rs
+++ b/tests/php/fpm/predis.php
@@ -1,3 +1,5 @@
+<?php
+
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
@@ -11,13 +13,20 @@
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
-// limitations under the License..
+// limitations under the License.
+
+
+use Webmozart\Assert\Assert;
+
+require_once dirname(__DIR__) . "/vendor/autoload.php";
-//! Component ID
-//!
-//! <https://github.com/apache/skywalking/blob/014861535015745ae3f7b99acd7d14500b3b3927/oap-server/server-starter/src/main/resources/component-libraries.yml>
+{
+ $client = new Predis\Client();
+ $client->auth('password');
+ $client->set('foo', 'bar');
+ $value = $client->get('foo');
+ Assert::same($value, 'bar');
+ $client->get('not-exists');
+}
-pub const COMPONENT_PHP_ID: i32 = 8001;
-pub const COMPONENT_PHP_CURL_ID: i32 = 8002;
-pub const COMPONENT_PHP_PDO_ID: i32 = 8003;
-pub const COMPONENT_PHP_MYSQLI_ID: i32 = 8004;
+echo "ok";