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 3187ca1  Add standalone reporter type and standalone skywalking worker 
(#119)
3187ca1 is described below

commit 3187ca14711ce5289a3134451af527ee43e954d0
Author: jmjoy <[email protected]>
AuthorDate: Fri Aug 16 18:37:45 2024 +0800

    Add standalone reporter type and standalone skywalking worker (#119)
---
 docs/en/configuration/ini-settings.md   |  10 +-
 docs/en/reporter/standalone-reporter.md |  42 +++++++++
 docs/menu.yml                           |   2 +
 src/lib.rs                              |  12 ++-
 src/module.rs                           |  15 ++-
 src/worker.rs                           |  10 +-
 worker/Cargo.toml                       |   8 +-
 worker/src/main.rs                      | 156 ++++++++++++++++++++++++++++++++
 worker/src/reporter/reporter_grpc.rs    |   2 +-
 9 files changed, 242 insertions(+), 15 deletions(-)

diff --git a/docs/en/configuration/ini-settings.md 
b/docs/en/configuration/ini-settings.md
index dd883ba..9a35c4d 100644
--- a/docs/en/configuration/ini-settings.md
+++ b/docs/en/configuration/ini-settings.md
@@ -3,7 +3,7 @@
 This is the configuration list supported in `php.ini`.
 
 | Configuration Item                               | Description               
                                                                                
                                                                                
                                                        | Default Value         
    |
-| ------------------------------------------------ 
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
 ------------------------- |
+| ------------------------------------------------ | 
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 | ------------------------- |
 | skywalking_agent.enable                          | Enable skywalking_agent 
extension or not.                                                               
                                                                                
                                                          | Off                 
      |
 | skywalking_agent.log_file                        | Log file path.            
                                                                                
                                                                                
                                                        | 
/tmp/skywalking-agent.log |
 | skywalking_agent.log_level                       | Log level: one of `OFF`, 
`TRACE`, `DEBUG`, `INFO`, `WARN`, `ERROR`.                                      
                                                                                
                                                         | INFO                 
     |
@@ -20,9 +20,9 @@ This is the configuration list supported in `php.ini`.
 | skywalking_agent.heartbeat_period                | Agent heartbeat report 
period. Unit, second.                                                           
                                                                                
                                                           | 30                 
       |
 | skywalking_agent.properties_report_period_factor | The agent sends the 
instance properties to the backend every heartbeat_period * 
properties_report_period_factor seconds.                                        
                                                                                
  | 10                        |
 | skywalking_agent.enable_zend_observer            | Whether to use `zend 
observer` instead of `zend_execute_ex` to hook the functions, this feature is 
only available for PHP8+.                                                       
                                                               | Off            
           |
-| skywalking_agent.reporter_type                   | Reporter type, optional 
values are `grpc` and `kafka`.                                                  
                                                                                
                                                          | grpc                
      |
+| skywalking_agent.reporter_type                   | Reporter type, optional 
values are `grpc`, `kafka` and `standalone`.                                    
                                                                                
                                                                        | 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  
                  |
-| skywalking_agent.instance_name                   | Instance name. You can 
set ${HOSTNAME}, refer to [Example #1]( 
https://www.php.net/manual/en/install.fpm.configuration.php)                    
                                                                                
                       |                     |
-
+| 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  
                     |
+| skywalking_agent.instance_name                   | Instance name. You can 
set `${HOSTNAME}`, refer to [Example 
#1](https://www.php.net/manual/en/install.fpm.configuration.php)                
                                                                                
                       |                           |
+| skywalking_agent.standalone_socket_path          | Unix domain socket file 
path of standalone skywalking php worker. Only available when `reporter_type` 
is `standalone`.                                                                
                                                            |                   
        |
diff --git a/docs/en/reporter/standalone-reporter.md 
b/docs/en/reporter/standalone-reporter.md
new file mode 100644
index 0000000..692ab2e
--- /dev/null
+++ b/docs/en/reporter/standalone-reporter.md
@@ -0,0 +1,42 @@
+# Standalone reporter
+
+When the reporter type is `grpc` or `kafka`, the `skywalking_agent` extension 
forks a child process during
+the extension initialization phase to act as a worker process for sending data 
to the SkyWalking OAP server
+or Kafka.
+
+However, this approach has some limitations, such as:
+
+1. It cannot be used with the `php-fpm` daemon mode.
+2. Multiple worker processes can be redundant when there are several `php-fpm` 
processes on the instance.
+
+To address these issues, `skywalking_agent` introduces a new reporter type: 
`standalone`.
+
+With the `standalone` reporter type, the `skywalking_agent` extension no 
longer forks a child process.
+Instead, the user needs to manually start an independent worker process.
+
+## Steps
+
+1. Compile the standalone `skywalking-php-worker` binary:
+
+   ```shell
+   cargo build -p skywalking-php-worker --bin skywalking-php-worker 
--all-features --release
+   ```
+
+2. Run `skywalking-php-worker`:
+
+   Assuming the socket file path is `/tmp/skywalking-php-worker.sock` and the 
SkyWalking OAP server address is `127.0.0.1:11800`, the command is:
+
+   ```shell
+   ./target/release/skywalking-php-worker -s /tmp/skywalking-php-worker.sock 
grpc --server-addr 127.0.0.1:11800
+   ```
+
+   For additional parameters, refer to `./target/release/skywalking-php-worker 
--help`.
+
+3. Configure `php.ini`:
+
+   ```ini
+   [skywalking_agent]
+   extension = skywalking_agent.so
+   skywalking_agent.reporter_type = standalone
+   skywalking_agent.standalone_socket_path = /tmp/skywalking-php-worker.sock
+   ```
diff --git a/docs/menu.yml b/docs/menu.yml
index f7f9e1a..947ffa7 100644
--- a/docs/menu.yml
+++ b/docs/menu.yml
@@ -34,6 +34,8 @@ catalog:
     catalog:
       - name: "Kafka Reporter"
         path: "/en/reporter/kafka-reporter"
+      - name: "Standalone Reporter"
+        path: "/en/reporter/standalone-reporter"
   - name: "Contribution"
     catalog:
       - name: "Compiling Guidance"
diff --git a/src/lib.rs b/src/lib.rs
index 5a54bb9..ceb951d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -91,7 +91,8 @@ const SKYWALKING_AGENT_PROPERTIES_REPORT_PERIOD_FACTOR: &str =
 /// PHP8's jit.
 const SKYWALKING_AGENT_ENABLE_ZEND_OBSERVER: &str = 
"skywalking_agent.enable_zend_observer";
 
-/// Reporter type, optional values are `grpc` and `kafka`, default is `grpc`.
+/// Reporter type, optional values are `grpc`, `kafka` and `standalone`, 
default
+/// is `grpc`.
 const SKYWALKING_AGENT_REPORTER_TYPE: &str = "skywalking_agent.reporter_type";
 
 /// A list of host/port pairs to use for establishing the initial connection to
@@ -108,6 +109,10 @@ const SKYWALKING_AGENT_KAFKA_PRODUCER_CONFIG: &str = 
"skywalking_agent.kafka_pro
 /// `$request->server` variable.
 const SKYWALKING_AGENT_INJECT_CONTEXT: &str = 
"skywalking_agent.inject_context";
 
+/// Unix domain socket file path of standalone skywalking php worker. Only
+/// available when `reporter_type` is `standalone`.
+const SKYWALKING_AGENT_STANDALONE_SOCKET_PATH: &str = 
"skywalking_agent.standalone_socket_path";
+
 #[php_get_module]
 pub fn get_module() -> Module {
     let mut module = Module::new(
@@ -194,6 +199,11 @@ pub fn get_module() -> Module {
         Policy::System,
     );
     module.add_ini(SKYWALKING_AGENT_INJECT_CONTEXT, false, Policy::System);
+    module.add_ini(
+        SKYWALKING_AGENT_STANDALONE_SOCKET_PATH,
+        "".to_string(),
+        Policy::System,
+    );
 
     // Hooks.
     module.on_module_init(module::init);
diff --git a/src/module.rs b/src/module.rs
index a527a48..36a7d74 100644
--- a/src/module.rs
+++ b/src/module.rs
@@ -92,6 +92,12 @@ pub static RUNTIME_DIR: Lazy<PathBuf> = Lazy::new(|| {
 });
 
 pub static SOCKET_FILE_PATH: Lazy<PathBuf> = Lazy::new(|| {
+    if is_standalone_reporter_type() {
+        return PathBuf::from(get_str_ini_with_default(
+            SKYWALKING_AGENT_STANDALONE_SOCKET_PATH,
+        ));
+    }
+
     let mut dir = RUNTIME_DIR.clone();
 
     let dur = SystemTime::now()
@@ -263,7 +269,9 @@ fn try_init_logger() -> anyhow::Result<()> {
 
     let file = open_options.open(path)?;
 
-    let filter = EnvFilter::new(format!("info,skywalking_agent={}", 
log_level));
+    let filter = EnvFilter::new(format!(
+        "info,skywalking_agent={log_level},skywalking_php_worker={log_level}"
+    ));
 
     let subscriber = FmtSubscriber::builder()
         .with_env_filter(filter)
@@ -285,3 +293,8 @@ fn get_module_registry() -> &'static ZArr {
 pub fn is_enable() -> bool {
     *IS_ENABLE
 }
+
+#[inline]
+pub fn is_standalone_reporter_type() -> bool {
+    REPORTER_TYPE.as_str() == "standalone"
+}
diff --git a/src/worker.rs b/src/worker.rs
index dbeaa60..145b9fb 100644
--- a/src/worker.rs
+++ b/src/worker.rs
@@ -14,9 +14,9 @@
 // limitations under the License.
 
 use crate::module::{
-    AUTHENTICATION, ENABLE_TLS, HEARTBEAT_PERIOD, 
PROPERTIES_REPORT_PERIOD_FACTOR, REPORTER_TYPE,
-    SERVER_ADDR, SERVICE_INSTANCE, SERVICE_NAME, SOCKET_FILE_PATH, 
SSL_CERT_CHAIN_PATH,
-    SSL_KEY_PATH, SSL_TRUSTED_CA_PATH, WORKER_THREADS,
+    is_standalone_reporter_type, AUTHENTICATION, ENABLE_TLS, HEARTBEAT_PERIOD,
+    PROPERTIES_REPORT_PERIOD_FACTOR, REPORTER_TYPE, SERVER_ADDR, 
SERVICE_INSTANCE, SERVICE_NAME,
+    SOCKET_FILE_PATH, SSL_CERT_CHAIN_PATH, SSL_KEY_PATH, SSL_TRUSTED_CA_PATH, 
WORKER_THREADS,
 };
 #[cfg(feature = "kafka-reporter")]
 use crate::module::{KAFKA_BOOTSTRAP_SERVERS, KAFKA_PRODUCER_CONFIG};
@@ -31,6 +31,10 @@ use std::{cmp::Ordering, num::NonZeroUsize, process::exit, 
thread::available_par
 use tracing::error;
 
 pub fn init_worker() {
+    if is_standalone_reporter_type() {
+        return;
+    }
+
     unsafe {
         // TODO Shutdown previous worker before fork if there is a PHP-FPM 
reload
         // operation.
diff --git a/worker/Cargo.toml b/worker/Cargo.toml
index 2780dc9..a6f6d82 100644
--- a/worker/Cargo.toml
+++ b/worker/Cargo.toml
@@ -43,9 +43,9 @@ skywalking = { version = "0.8.0", features = ["management"] }
 tokio = { version = "1.29.1", features = ["full"] }
 tokio-stream = "0.1.14"
 tonic = { version = "0.8.3", features = ["tls", "tls-roots"] }
-tracing = { version = "0.1.37", features = ["attributes"] }
+tracing = { version = "0.1.37", features = ["attributes", "log"] }
 tracing-subscriber = { version = "0.3.17", features = ["env-filter"], optional 
= true }
 
-# [[bin]]
-# name = "skywalking-php-worker"
-# required-features = ["standalone", "kafka-reporter"]
+[[bin]]
+name = "skywalking-php-worker"
+required-features = ["standalone", "kafka-reporter"]
diff --git a/worker/src/main.rs b/worker/src/main.rs
new file mode 100644
index 0000000..d924e1f
--- /dev/null
+++ b/worker/src/main.rs
@@ -0,0 +1,156 @@
+// 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.
+
+use clap::Parser;
+use skywalking_php_worker::{
+    new_tokio_runtime,
+    reporter::{GrpcReporterConfiguration, KafkaReporterConfiguration, 
ReporterConfiguration},
+    start_worker, WorkerConfiguration,
+};
+use std::{num::NonZeroUsize, path::PathBuf, thread::available_parallelism};
+use tracing::log::LevelFilter;
+use tracing_subscriber::{EnvFilter, FmtSubscriber};
+
+#[derive(Parser, Debug)]
+#[command(version, about, long_about = None)]
+struct Args {
+    /// Path of socket file to listening
+    #[arg(short, long)]
+    socket_file_path: PathBuf,
+
+    /// Count of worker threads, default is `nproc`
+    #[arg(long)]
+    worker_threads: Option<usize>,
+
+    /// Log level, will be overwritten by env `RUST_LOG`
+    #[arg(short, long, default_value = "INFO")]
+    log_level: LevelFilter,
+
+    /// Select reporter
+    #[command(subcommand)]
+    reporter: ReporterArgs,
+}
+
+#[derive(Parser, Debug)]
+#[command(version, about, long_about = None)]
+enum ReporterArgs {
+    /// Report to Skywalking OAP via grpc protocol
+    Grpc {
+        /// skywalking server address
+        #[arg(long)]
+        server_addr: String,
+
+        /// Skywalking agent authentication token
+        #[arg(long)]
+        authentication: Option<String>,
+
+        /// Wether to enable tls for gPRC
+        #[arg(long)]
+        enable_tls: bool,
+
+        /// The gRPC SSL trusted ca file
+        #[arg(long, required_if_eq("enable_tls", "true"))]
+        ssl_cert_chain_path: Option<String>,
+
+        /// The private key file. Enable mTLS when ssl_key_path and
+        /// ssl_cert_chain_path exist
+        #[arg(long)]
+        ssl_key_path: Option<String>,
+
+        /// The certificate file. Enable mTLS when ssl_key_path and
+        /// ssl_cert_chain_path exist
+        #[arg(long)]
+        ssl_trusted_ca_path: Option<String>,
+    },
+    /// Report to kafka
+    Kafka {
+        /// A list of host/port pairs to use for establishing the initial
+        /// connection to the Kafka cluster. Only available when the
+        /// reporter type is `kafka`
+        #[arg(long)]
+        kafka_bootstrap_servers: String,
+
+        /// Configure Kafka Producer configuration in JSON format.
+        /// Only available when the reporter type is `kafka`
+        #[arg(long)]
+        kafka_producer_config: Option<String>,
+    },
+}
+
+impl From<ReporterArgs> for ReporterConfiguration {
+    fn from(args: ReporterArgs) -> Self {
+        match args {
+            ReporterArgs::Grpc {
+                server_addr,
+                authentication,
+                enable_tls,
+                ssl_cert_chain_path,
+                ssl_key_path,
+                ssl_trusted_ca_path,
+            } => ReporterConfiguration::Grpc(GrpcReporterConfiguration {
+                server_addr,
+                authentication: authentication.unwrap_or_default(),
+                enable_tls,
+                ssl_cert_chain_path: ssl_cert_chain_path.unwrap_or_default(),
+                ssl_key_path: ssl_key_path.unwrap_or_default(),
+                ssl_trusted_ca_path: ssl_trusted_ca_path.unwrap_or_default(),
+            }),
+            ReporterArgs::Kafka {
+                kafka_bootstrap_servers,
+                kafka_producer_config,
+            } => ReporterConfiguration::Kafka(KafkaReporterConfiguration {
+                kafka_bootstrap_servers,
+                kafka_producer_config: 
kafka_producer_config.unwrap_or_default(),
+            }),
+        }
+    }
+}
+
+fn init_logger(log_level: &LevelFilter) -> anyhow::Result<()> {
+    let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
+        EnvFilter::new(format!(
+            
"info,skywalking_agent={log_level},skywalking_php_worker={log_level}"
+        ))
+    });
+
+    let subscriber = FmtSubscriber::builder()
+        .with_env_filter(filter)
+        .with_ansi(false)
+        .finish();
+
+    tracing::subscriber::set_global_default(subscriber)?;
+
+    Ok(())
+}
+
+fn worker_threads(worker_threads: Option<usize>) -> usize {
+    worker_threads.unwrap_or_else(|| 
available_parallelism().map(NonZeroUsize::get).unwrap_or(1))
+}
+
+fn main() -> anyhow::Result<()> {
+    let args = Args::parse();
+
+    init_logger(&args.log_level)?;
+
+    let rt = new_tokio_runtime(worker_threads(args.worker_threads));
+
+    rt.block_on(start_worker(WorkerConfiguration {
+        socket_file_path: args.socket_file_path,
+        heart_beat: None,
+        reporter_config: args.reporter.into(),
+    }))?;
+
+    Ok(())
+}
diff --git a/worker/src/reporter/reporter_grpc.rs 
b/worker/src/reporter/reporter_grpc.rs
index d450b43..fdbdd18 100644
--- a/worker/src/reporter/reporter_grpc.rs
+++ b/worker/src/reporter/reporter_grpc.rs
@@ -21,9 +21,9 @@ use tonic::transport::{Certificate, Channel, ClientTlsConfig, 
Endpoint, Identity
 use tracing::{debug, info, warn};
 
 pub struct GrpcReporterConfiguration {
+    pub server_addr: String,
     pub authentication: String,
     pub enable_tls: bool,
-    pub server_addr: String,
     pub ssl_cert_chain_path: String,
     pub ssl_key_path: String,
     pub ssl_trusted_ca_path: String,

Reply via email to