This is an automated email from the ASF dual-hosted git repository.

wusheng 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 c23e76a  Inject skywalking context. (#107)
c23e76a is described below

commit c23e76a0028e09924daebfc3949dc05a60d0b609
Author: jmjoy <jm...@apache.org>
AuthorDate: Wed Feb 21 10:20:55 2024 +0800

    Inject skywalking context. (#107)
---
 docs/en/configuration/context-injection.md | 44 ++++++++++++++++++++++
 docs/en/configuration/ini-settings.md      |  1 +
 docs/menu.yml                              |  2 +
 src/lib.rs                                 |  7 ++++
 src/module.rs                              |  4 ++
 src/request.rs                             | 60 ++++++++++++++++++++++++++++--
 6 files changed, 114 insertions(+), 4 deletions(-)

diff --git a/docs/en/configuration/context-injection.md 
b/docs/en/configuration/context-injection.md
new file mode 100644
index 0000000..3bb1eca
--- /dev/null
+++ b/docs/en/configuration/context-injection.md
@@ -0,0 +1,44 @@
+# Context injection
+
+If you want to fetch the SkyWalking Context in your PHP code, which is super 
helpful for debugging and observability,
+You can enable the configuration item `skywalking_agent.inject_context`.
+
+## Description
+
+`skywalking_agent.inject_context`
+
+Whether to enable automatic injection of skywalking context variables (such as 
`SW_TRACE_ID`). For `php-fpm` mode, it will be injected into the `$_SERVER` 
variable. For `swoole` mode, it will be injected into the `$request->server` 
variable.
+
+## Configuration
+
+```ini
+[skywalking_agent]
+extension = skywalking_agent.so
+skywalking_agent.inject_context = On
+```
+
+## Usage
+
+For `php-fpm` mode:
+
+```php
+<?php
+
+echo $_SERVER["SW_SERVICE_NAME"]; // get service name
+echo $_SERVER["SW_INSTANCE_NAME"]; // get instance name
+echo $_SERVER["SW_TRACE_ID"]; // get trace id
+```
+
+For `swoole` mode:
+
+```php
+<?php
+
+$http = new Swoole\Http\Server('127.0.0.1', 9501);
+
+$http->on('request', function ($request, $response) {
+    echo $request->server["SW_SERVICE_NAME"]; // get service name
+    echo $request->server["SW_INSTANCE_NAME"]; // get instance name
+    echo $request->server["SW_TRACE_ID"]; // get trace id
+});
+```
diff --git a/docs/en/configuration/ini-settings.md 
b/docs/en/configuration/ini-settings.md
index b8a24fd..f437b6e 100644
--- a/docs/en/configuration/ini-settings.md
+++ b/docs/en/configuration/ini-settings.md
@@ -23,3 +23,4 @@ This is the configuration list supported in `php.ini`.
 | skywalking_agent.reporter_type                   | Reporter type, optional 
values are `grpc` and `kafka`.                                                  
                              | grpc                      |
 | skywalking_agent.kafka_bootstrap_servers         | A list of host/port pairs 
to use for connect to the Kafka cluster. Only available when `reporter_type` is 
`kafka`.                    |                           |
 | skywalking_agent.kafka_producer_config           | Configure Kafka Producer 
configuration in JSON format `{"key": "value}`. Only available when 
`reporter_type` is `kafka`.              | {}                        |
+| skywalking_agent.inject_context                  | Whether to enable 
automatic injection of skywalking context variables (such as `SW_TRACE_ID`). 
For `php-fpm` mode, it will be injected into the `$_SERVER` variable. For 
`swoole` mode, it will be injected into the `$request->server` variable.        
      | Off                    |
diff --git a/docs/menu.yml b/docs/menu.yml
index 723db61..f7f9e1a 100644
--- a/docs/menu.yml
+++ b/docs/menu.yml
@@ -28,6 +28,8 @@ catalog:
         path: "/en/configuration/ini-settings"
       - name: "Zend Observer"
         path: "/en/configuration/zend-observer"
+      - name: "Context injection"
+        path: "/en/configuration/context-injection"
   - name: "Reporter"
     catalog:
       - name: "Kafka Reporter"
diff --git a/src/lib.rs b/src/lib.rs
index 25a56a0..28ba16f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -100,6 +100,12 @@ const SKYWALKING_AGENT_KAFKA_BOOTSTRAP_SERVERS: &str = 
"skywalking_agent.kafka_b
 /// Only available when the reporter type is `kafka`.
 const SKYWALKING_AGENT_KAFKA_PRODUCER_CONFIG: &str = 
"skywalking_agent.kafka_producer_config";
 
+/// Whether to enable automatic injection of skywalking context variables (such
+/// as `SW_TRACE_ID`). For `php-fpm` mode, it will be injected into the
+/// `$_SERVER` variable. For `swoole` mode, it will be injected into the
+/// `$request->server` variable.
+const SKYWALKING_AGENT_INJECT_CONTEXT: &str = 
"skywalking_agent.inject_context";
+
 #[php_get_module]
 pub fn get_module() -> Module {
     let mut module = Module::new(
@@ -180,6 +186,7 @@ pub fn get_module() -> Module {
         "{}".to_string(),
         Policy::System,
     );
+    module.add_ini(SKYWALKING_AGENT_INJECT_CONTEXT, false, Policy::System);
 
     // Hooks.
     module.on_module_init(module::init);
diff --git a/src/module.rs b/src/module.rs
index 93f0cc6..6d5d865 100644
--- a/src/module.rs
+++ b/src/module.rs
@@ -129,6 +129,9 @@ pub static KAFKA_BOOTSTRAP_SERVERS: Lazy<String> =
 pub static KAFKA_PRODUCER_CONFIG: Lazy<String> =
     Lazy::new(|| 
get_str_ini_with_default(SKYWALKING_AGENT_KAFKA_PRODUCER_CONFIG));
 
+pub static INJECT_CONTEXT: Lazy<bool> =
+    Lazy::new(|| ini_get::<bool>(SKYWALKING_AGENT_INJECT_CONTEXT));
+
 /// For PHP 8.2+, zend observer api are now also called for internal functions.
 ///
 /// Refer to this commit: 
<https://github.com/php/php-src/commit/625f1649639c2b9a9d76e4d42f88c264ddb8447d>
@@ -160,6 +163,7 @@ pub fn init() {
     Lazy::force(&REPORTER_TYPE);
     Lazy::force(&KAFKA_BOOTSTRAP_SERVERS);
     Lazy::force(&KAFKA_PRODUCER_CONFIG);
+    Lazy::force(&INJECT_CONTEXT);
 
     if let Err(err) = try_init_logger() {
         eprintln!("skywalking_agent: initialize logger failed: {}", err);
diff --git a/src/request.rs b/src/request.rs
index e09ab35..0bddbc9 100644
--- a/src/request.rs
+++ b/src/request.rs
@@ -16,7 +16,7 @@
 use crate::{
     component::COMPONENT_PHP_ID,
     context::RequestContext,
-    module::{is_enable, SKYWALKING_VERSION},
+    module::{is_enable, INJECT_CONTEXT, SKYWALKING_VERSION},
     util::{catch_unwind_result, get_sapi_module_name, z_val_to_string},
 };
 use anyhow::{anyhow, Context};
@@ -32,6 +32,10 @@ use std::{
 use tracing::{error, instrument, trace, warn};
 use url::Url;
 
+const INJECT_CONTEXT_SERVICE_NAME: &str = "SW_SERVICE_NAME";
+const INJECT_CONTEXT_INSTANCE_NAME: &str = "SW_INSTANCE_NAME";
+const INJECT_CONTEXT_TRACE_ID: &str = "SW_TRACE_ID";
+
 #[instrument(skip_all)]
 pub fn init() {
     if !is_enable() {
@@ -65,7 +69,9 @@ fn request_init_for_fpm() -> crate::Result<()> {
     let url = get_page_request_url(server)?;
     let method = get_page_request_method(server);
 
-    create_request_context(None, header.as_deref(), &method, &url)
+    create_request_context(None, header.as_deref(), &method, &url)?;
+
+    inject_server_var_for_fpm()
 }
 
 fn request_shutdown_for_fpm() -> crate::Result<()> {
@@ -74,6 +80,15 @@ fn request_shutdown_for_fpm() -> crate::Result<()> {
     finish_request_context(None, status_code)
 }
 
+fn inject_server_var_for_fpm() -> crate::Result<()> {
+    if *INJECT_CONTEXT {
+        let server = get_mut_page_request_server()?;
+        inject_server_var(None, server)?;
+    }
+
+    Ok(())
+}
+
 #[allow(clippy::useless_conversion)]
 fn jit_initialization() {
     unsafe {
@@ -145,6 +160,17 @@ fn get_page_request_server<'a>() -> anyhow::Result<&'a 
ZArr> {
     }
 }
 
+fn get_mut_page_request_server<'a>() -> anyhow::Result<&'a mut ZArr> {
+    unsafe {
+        let symbol_table = ZArr::from_mut_ptr(&mut eg!(symbol_table));
+        let carrier = symbol_table
+            .get_mut("_SERVER")
+            .and_then(|carrier| carrier.as_mut_z_arr())
+            .context("$_SERVER is null")?;
+        Ok(carrier)
+    }
+}
+
 pub const HACK_SWOOLE_ON_REQUEST_FUNCTION_NAME: &str =
     "skywalking_hack_swoole_on_request_please_do_not_use";
 
@@ -193,7 +219,9 @@ pub fn skywalking_hack_swoole_on_request(args: &mut [ZVal]) 
-> phper::Result<ZVa
 }
 
 fn request_init_for_swoole(request: &mut ZVal) -> crate::Result<()> {
-    let request = request.as_z_obj().context("swoole request isn't object")?;
+    let request = request
+        .as_mut_z_obj()
+        .context("swoole request isn't object")?;
 
     let fd = request
         .get_property("fd")
@@ -215,7 +243,14 @@ fn request_init_for_swoole(request: &mut ZVal) -> 
crate::Result<()> {
     let method = get_swoole_request_method(server);
     let url = get_swoole_request_url(server, headers)?;
 
-    create_request_context(Some(fd), header.as_deref(), &method, &url)
+    create_request_context(Some(fd), header.as_deref(), &method, &url)?;
+
+    let server = request
+        .get_mut_property("server")
+        .as_mut_z_arr()
+        .context("swoole request server not exists")?;
+
+    inject_server_var_for_swoole(Some(fd), server)
 }
 
 fn request_shutdown_for_swoole(response: &mut ZVal) -> crate::Result<()> {
@@ -237,6 +272,14 @@ fn request_shutdown_for_swoole(response: &mut ZVal) -> 
crate::Result<()> {
     )
 }
 
+fn inject_server_var_for_swoole(request_id: Option<i64>, server: &mut ZArr) -> 
crate::Result<()> {
+    if *INJECT_CONTEXT {
+        inject_server_var(request_id, server)?;
+    }
+
+    Ok(())
+}
+
 fn get_swoole_request_header(header: &ZArr) -> Option<String> {
     if *SKYWALKING_VERSION >= 8 {
         header
@@ -332,3 +375,12 @@ fn finish_request_context(request_id: Option<i64>, 
status_code: i32) -> crate::R
 
     Ok(())
 }
+
+fn inject_server_var(request_id: Option<i64>, server: &mut ZArr) -> 
crate::Result<()> {
+    Ok(RequestContext::try_with_global_ctx(request_id, |ctx| {
+        server.insert(INJECT_CONTEXT_SERVICE_NAME, ctx.service());
+        server.insert(INJECT_CONTEXT_INSTANCE_NAME, ctx.service_instance());
+        server.insert(INJECT_CONTEXT_TRACE_ID, ctx.trace_id());
+        Ok(())
+    })?)
+}

Reply via email to