diff --git a/config.m4 b/config.m4 index 34e2e694..e3dfd2a3 100644 --- a/config.m4 +++ b/config.m4 @@ -147,6 +147,7 @@ if test "$PHP_SKYWALKING" != "no"; then src/sky_core_span_log.cc \ src/sky_execute.cc \ src/sky_grpc.cc \ + src/sky_log.cc \ src/sky_module.cc \ src/sky_plugin_mysqli.cc \ src/sky_pdo.cc \ diff --git a/e2e/tests/redis.php b/e2e/tests/redis.php index c0973906..184a28e6 100644 --- a/e2e/tests/redis.php +++ b/e2e/tests/redis.php @@ -16,5 +16,35 @@ function testRedis() { $redis->incr($key); $redis->setnx($key, "test"); $redis->strlen($key); + $redis->set($key, "test"); + $redis->set($key, "test", 100); + $redis->set($key, "test", ["nx", "ex" => 200]); + $redis->setex($key, 300, "test"); -} \ No newline at end of file + // multiple keys + $redis->mget([$key .'_1', $key . '_2', $key . '_3']); + $redis->getMultiple([$key .'_1', $key . '_2', $key . '_3']); + + // uncertain keys + $redis->eval('return {1,2,3};'); + $redis->del($key); + $redis->del($key, $key . '_1'); + $redis->del([$key, $key . '_1', $key . '_2']); + $redis->delete($key); + $redis->unlink($key); + $redis->exists($key); + + // empty commands + $redis->ping(); + $redis->pipeline(); + $redis->set($key, '1'); + $redis->set($key . '_1', '2'); + $redis->set($key . '_2', '3'); + $redis->exec(); + + // expire + $redis->expire($key, 3600); + $redis->expireAt($key, time() + 3600); + $redis->pExpireAt($key, time() + 3600); + $redis->setTimeout($key, 3600); +} diff --git a/php_skywalking.h b/php_skywalking.h index c3f6ec70..df22e563 100644 --- a/php_skywalking.h +++ b/php_skywalking.h @@ -111,6 +111,9 @@ ZEND_BEGIN_MODULE_GLOBALS(skywalking) // php error log zend_bool error_handler_enable; + + // message queue + int mq_max_message_length; ZEND_END_MODULE_GLOBALS(skywalking) extern ZEND_DECLARE_MODULE_GLOBALS(skywalking); diff --git a/skywalking.cc b/skywalking.cc index 94a37a98..f5b65d41 100644 --- a/skywalking.cc +++ b/skywalking.cc @@ -33,22 +33,23 @@ ZEND_DECLARE_MODULE_GLOBALS(skywalking) struct service_info *s_info = nullptr; - PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("skywalking.enable", "0", PHP_INI_ALL, OnUpdateBool, enable, zend_skywalking_globals, skywalking_globals) STD_PHP_INI_ENTRY("skywalking.version", "8", PHP_INI_ALL, OnUpdateLong, version, zend_skywalking_globals, skywalking_globals) STD_PHP_INI_ENTRY("skywalking.app_code", "hello_skywalking", PHP_INI_ALL, OnUpdateString, app_code, zend_skywalking_globals, skywalking_globals) STD_PHP_INI_ENTRY("skywalking.authentication", "", PHP_INI_ALL, OnUpdateString, authentication, zend_skywalking_globals, skywalking_globals) STD_PHP_INI_ENTRY("skywalking.grpc", "127.0.0.1:11800", PHP_INI_ALL, OnUpdateString, grpc, zend_skywalking_globals, skywalking_globals) - STD_PHP_INI_ENTRY("skywalking.grpc_tls_enable", "0", PHP_INI_ALL, OnUpdateBool, grpc_tls_enable, zend_skywalking_globals, skywalking_globals) + STD_PHP_INI_BOOLEAN("skywalking.grpc_tls_enable", "0", PHP_INI_ALL, OnUpdateBool, grpc_tls_enable, zend_skywalking_globals, skywalking_globals) STD_PHP_INI_ENTRY("skywalking.grpc_tls_pem_root_certs", "", PHP_INI_ALL, OnUpdateString, grpc_tls_pem_root_certs, zend_skywalking_globals, skywalking_globals) STD_PHP_INI_ENTRY("skywalking.grpc_tls_pem_private_key", "", PHP_INI_ALL, OnUpdateString, grpc_tls_pem_private_key, zend_skywalking_globals, skywalking_globals) STD_PHP_INI_ENTRY("skywalking.grpc_tls_pem_cert_chain", "", PHP_INI_ALL, OnUpdateString, grpc_tls_pem_cert_chain, zend_skywalking_globals, skywalking_globals) - STD_PHP_INI_ENTRY("skywalking.log_enable", "0", PHP_INI_ALL, OnUpdateBool, log_enable, zend_skywalking_globals, skywalking_globals) + STD_PHP_INI_BOOLEAN("skywalking.log_enable", "0", PHP_INI_ALL, OnUpdateBool, log_enable, zend_skywalking_globals, skywalking_globals) STD_PHP_INI_ENTRY("skywalking.log_path", "/tmp/skywalking-php.log", PHP_INI_ALL, OnUpdateString, log_path, zend_skywalking_globals, skywalking_globals) - STD_PHP_INI_ENTRY("skywalking.error_handler_enable", "0", PHP_INI_ALL, OnUpdateBool, error_handler_enable, zend_skywalking_globals, skywalking_globals) + STD_PHP_INI_BOOLEAN("skywalking.error_handler_enable", "0", PHP_INI_ALL, OnUpdateBool, error_handler_enable, zend_skywalking_globals, skywalking_globals) + + STD_PHP_INI_ENTRY("skywalking.mq_max_message_length", "20480", PHP_INI_ALL, OnUpdateLong, mq_max_message_length, zend_skywalking_globals, skywalking_globals) PHP_INI_END() @@ -71,6 +72,9 @@ static void php_skywalking_init_globals(zend_skywalking_globals *skywalking_glob // php error log skywalking_globals->error_handler_enable = 0; + + // message queue + skywalking_globals->mq_max_message_length = 0; } PHP_FUNCTION (skywalking_trace_id) { @@ -162,7 +166,6 @@ PHP_MSHUTDOWN_FUNCTION (skywalking) { PHP_RINIT_FUNCTION(skywalking) { - #if defined(COMPILE_DL_SKYWALKING) && defined(ZTS) ZEND_TSRMLS_CACHE_UPDATE(); #endif diff --git a/src/common.h b/src/common.h index bec95b31..5fb1058e 100644 --- a/src/common.h +++ b/src/common.h @@ -30,7 +30,6 @@ struct service_info { char service_instance[0x400]; boost::interprocess::message_queue *mq; - int mq_msg_size = 20480; }; #endif //SKYWALKING_COMMON_H diff --git a/src/manager.cc b/src/manager.cc index 8b10fd7e..6b0b7c37 100644 --- a/src/manager.cc +++ b/src/manager.cc @@ -35,8 +35,8 @@ #include #include "php_skywalking.h" +#include "sky_log.h" -static std::ofstream sky_log; std::queue messageQueue; static pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; @@ -46,9 +46,6 @@ extern struct service_info *s_info; Manager::Manager(const ManagerOptions &options, struct service_info *info) { - if (SKYWALKING_G(log_enable)) { - sky_log.open(SKYWALKING_G(log_path), std::ios::app); - } std::thread th(login, options, info); th.detach(); @@ -59,7 +56,7 @@ Manager::Manager(const ManagerOptions &options, struct service_info *info) { // std::thread s(sender, options); // s.detach(); - logger("the apache skywalking php plugin mounted"); + sky_log("the apache skywalking php plugin mounted"); } void Manager::login(const ManagerOptions &options, struct service_info *info) { @@ -162,7 +159,7 @@ void Manager::login(const ManagerOptions &options, struct service_info *info) { while (true) { std::string data; - data.resize(20480); + data.resize(SKYWALKING_G(mq_max_message_length)); size_t msg_size; unsigned msg_priority; mq.receive(&data[0], data.size(), msg_size, msg_priority); @@ -177,14 +174,14 @@ void Manager::login(const ManagerOptions &options, struct service_info *info) { google::protobuf::util::MessageToJsonString(msg, &json_str, opt); bool status = writer->Write(msg); if (status) { - logger("write success " + json_str); + sky_log("write success " + json_str); } else { - logger("write fail " + json_str); + sky_log("write fail " + json_str); break; } } } catch (boost::interprocess::interprocess_exception &ex) { - logger(ex.what()); + sky_log(ex.what()); php_error(E_WARNING, "%s %s", "[skywalking] open queue fail ", ex.what()); } } @@ -252,10 +249,3 @@ std::string Manager::generateUUID() { return res; } - - -void Manager::logger(const std::string &log) { - if (SKYWALKING_G(log_enable) && sky_log.is_open()) { - sky_log << log << std::endl; - } -} \ No newline at end of file diff --git a/src/sky_log.cc b/src/sky_log.cc new file mode 100644 index 00000000..270f4b7c --- /dev/null +++ b/src/sky_log.cc @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include +#include "php_skywalking.h" + +static std::ofstream log_fs; + +void sky_log(std::string log) { + if (SKYWALKING_G(log_enable) && !log_fs.is_open()) { + log_fs.open(SKYWALKING_G(log_path), std::ios::app); + } + + if (log_fs.is_open()) { + log_fs << log << std::endl; + } +} diff --git a/src/sky_log.h b/src/sky_log.h new file mode 100644 index 00000000..47b203a1 --- /dev/null +++ b/src/sky_log.h @@ -0,0 +1,8 @@ +#include + +#ifndef SKYWALKING_SKY_LOG_H +#define SKYWALKING_SKY_LOG_H + +void sky_log(std::string log); + +#endif diff --git a/src/sky_module.cc b/src/sky_module.cc index c203d950..cee1c04f 100644 --- a/src/sky_module.cc +++ b/src/sky_module.cc @@ -24,6 +24,7 @@ #include "sky_execute.h" #include "manager.h" #include "sky_plugin_error.h" +#include "sky_log.h" extern struct service_info *s_info; @@ -84,7 +85,7 @@ void sky_module_init() { boost::interprocess::create_only, "skywalking_queue", 1024, - 20480, + SKYWALKING_G(mq_max_message_length), boost::interprocess::permissions(0666) ); } catch (boost::interprocess::interprocess_exception &ex) { @@ -178,6 +179,13 @@ void sky_request_flush(zval *response, uint64_t request_id) { std::string msg = segment->marshal(); delete segment; + int msg_length = static_cast(msg.size()); + int max_length = SKYWALKING_G(mq_max_message_length); + if (msg_length > max_length) { + sky_log("message is too big: " + std::to_string(msg_length) + ", mq_max_message_length=" + std::to_string(max_length)); + return; + } + try { boost::interprocess::message_queue mq( boost::interprocess::open_only, @@ -185,6 +193,7 @@ void sky_request_flush(zval *response, uint64_t request_id) { ); mq.send(msg.data(), msg.size(), 0); } catch (boost::interprocess::interprocess_exception &ex) { + sky_log("sky_request_flush message_queue ex" + std::string(ex.what())); php_error(E_WARNING, "%s %s", "[skywalking] open queue fail ", ex.what()); } } diff --git a/src/sky_plugin_redis.cc b/src/sky_plugin_redis.cc index 36fe6cf1..21c9af30 100644 --- a/src/sky_plugin_redis.cc +++ b/src/sky_plugin_redis.cc @@ -34,19 +34,41 @@ std::map commands = { {"INCRBY", sky_plugin_redis_todo_cmd}, {"INCRBYFLOAT", sky_plugin_redis_todo_cmd}, - {"MGET", sky_plugin_redis_todo_cmd}, + {"MGET", sky_plugin_redis_multi_key_cmd}, {"MSET", sky_plugin_redis_todo_cmd}, {"MSETNX", sky_plugin_redis_todo_cmd}, {"PSETEX", sky_plugin_redis_todo_cmd}, + {"GETMULTIPLE", sky_plugin_redis_multi_key_cmd}, - {"SET", sky_plugin_redis_todo_cmd}, + {"SET", sky_plugin_redis_set_cmd}, {"SETBIT", sky_plugin_redis_todo_cmd}, - {"SETEX", sky_plugin_redis_todo_cmd}, + {"SETEX", sky_plugin_redis_setex_cmd}, {"SETNX", sky_plugin_redis_key_value_cmd}, {"SETRANGE", sky_plugin_redis_todo_cmd}, {"STRALGO", sky_plugin_redis_todo_cmd}, {"STRLEN", sky_plugin_redis_key_cmd}, + + {"EVAL", sky_plugin_redis_key_cmd}, + + {"DEL", sky_plugin_redis_uncertain_keys_cmd}, + {"DELETE", sky_plugin_redis_uncertain_keys_cmd}, + {"UNLINK", sky_plugin_redis_uncertain_keys_cmd}, + {"EXISTS", sky_plugin_redis_uncertain_keys_cmd}, + + // empty commands + {"PING", sky_plugin_redis_todo_cmd}, + {"PIPELINE", sky_plugin_redis_todo_cmd}, + {"MULTI", sky_plugin_redis_todo_cmd}, + {"DISCARD", sky_plugin_redis_todo_cmd}, + {"EXEC", sky_plugin_redis_todo_cmd}, + + {"EXPIRE", sky_plugin_redis_key_ttl_cmd}, + {"PEXPIRE", sky_plugin_redis_key_ttl_cmd}, + {"EXPIREAT", sky_plugin_redis_key_ttl_cmd}, + {"PEXPIREAT", sky_plugin_redis_key_ttl_cmd}, + {"SETTIMEOUT", sky_plugin_redis_key_ttl_cmd}, + }; Span *sky_plugin_redis(zend_execute_data *execute_data, const std::string &class_name, const std::string &function_name) { @@ -130,6 +152,122 @@ std::string sky_plugin_redis_key_value_cmd(zend_execute_data *execute_data, std: return ""; } +std::string sky_plugin_redis_set_cmd(zend_execute_data *execute_data, std::string cmd) { + uint32_t arg_count = ZEND_CALL_NUM_ARGS(execute_data); + if (arg_count == 2) { + return sky_plugin_redis_key_value_cmd(execute_data, cmd); + } + if (arg_count == 3) { + zval *key = ZEND_CALL_ARG(execute_data, 1); + zval *value = ZEND_CALL_ARG(execute_data, 2); + zval *optional = ZEND_CALL_ARG(execute_data, 3); + + if (Z_TYPE_P(key) == IS_STRING && Z_TYPE_P(value) == IS_STRING) { + std::string _cmd = cmd + " " + std::string(Z_STRVAL_P(key)) + " " + std::string(Z_STRVAL_P(value)); + + if (Z_TYPE_P(optional) == IS_LONG) { + return _cmd + " " + std::to_string(Z_LVAL_P(optional)); + } + + if (Z_TYPE_P(optional) == IS_ARRAY) { + zend_ulong nk; + zend_string *sk; + zval *val; + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(optional), nk, sk, val) { + if (sk == NULL && Z_TYPE_P(val) == IS_STRING) { + _cmd += " " + std::string(Z_STRVAL_P(val)); + } else if (Z_TYPE_P(val) == IS_LONG) { + _cmd += " " + std::string(ZSTR_VAL(sk)) + " " + std::to_string(Z_LVAL_P(val)); + } + } ZEND_HASH_FOREACH_END(); + return _cmd; + } + } + } + return ""; +} + +std::string sky_plugin_redis_setex_cmd(zend_execute_data *execute_data, std::string cmd) { + uint32_t arg_count = ZEND_CALL_NUM_ARGS(execute_data); + if (arg_count == 3) { + zval *key = ZEND_CALL_ARG(execute_data, 1); + zval *ttl = ZEND_CALL_ARG(execute_data, 2); + zval *value = ZEND_CALL_ARG(execute_data, 3); + + if (Z_TYPE_P(key) == IS_STRING && Z_TYPE_P(ttl) == IS_LONG && Z_TYPE_P(value) == IS_STRING) { + return cmd + " " + std::string(Z_STRVAL_P(key)) + " " + std::to_string(Z_LVAL_P(ttl)) + " " + std::string(Z_STRVAL_P(value)); + } + } + return ""; +} + +std::string sky_plugin_redis_multi_key_cmd(zend_execute_data *execute_data, std::string cmd) { + uint32_t arg_count = ZEND_CALL_NUM_ARGS(execute_data); + if (arg_count == 1) { + zval *keys = ZEND_CALL_ARG(execute_data, 1); + if (Z_TYPE_P(keys) == IS_ARRAY) { + std::string _cmd = cmd; + zend_ulong index; + zval *key; + ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(keys), index, key) { + if (Z_TYPE_P(key) == IS_STRING) { + _cmd += " " + std::string(Z_STRVAL_P(key)); + } + } ZEND_HASH_FOREACH_END(); + return _cmd; + } + } + return ""; +} + +std::string sky_plugin_redis_key_ttl_cmd(zend_execute_data *execute_data, std::string cmd) { + uint32_t arg_count = ZEND_CALL_NUM_ARGS(execute_data); + if (arg_count == 2) { + zval *key = ZEND_CALL_ARG(execute_data, 1); + zval *ttl = ZEND_CALL_ARG(execute_data, 2); + if (Z_TYPE_P(key) == IS_STRING && Z_TYPE_P(ttl) == IS_LONG) { + return cmd + " " + std::string(Z_STRVAL_P(key)) + " " + std::to_string(Z_LVAL_P(ttl)); + } + } + return ""; +} + +std::string sky_plugin_redis_uncertain_keys_cmd(zend_execute_data *execute_data, std::string cmd) { + uint32_t arg_count = ZEND_CALL_NUM_ARGS(execute_data); + + if (arg_count == 1) { + zval *keys = ZEND_CALL_ARG(execute_data, 1); + if (Z_TYPE_P(keys) == IS_STRING) { + return cmd + " " + std::string(Z_STRVAL_P(keys)); + } + if (Z_TYPE_P(keys) == IS_ARRAY) { + std::string _cmd = cmd; + zend_ulong index; + zval *key; + ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(keys), index, key) { + if (Z_TYPE_P(key) == IS_STRING) { + _cmd += " " + std::string(Z_STRVAL_P(key)); + } + } ZEND_HASH_FOREACH_END(); + return _cmd; + } + } + + if (arg_count > 1) { + uint32_t i = 0; + std::string _cmd = cmd; + for (i = 1; i <= arg_count; i++) { + zval *key = ZEND_CALL_ARG(execute_data, i); + if (Z_TYPE_P(key) == IS_STRING) { + _cmd += " " + std::string(Z_STRVAL_P(key)); + } + } + return _cmd; + } + + return ""; +} + std::string sky_plugin_redis_todo_cmd(zend_execute_data *execute_data, std::string cmd) { return ""; } diff --git a/src/sky_plugin_redis.h b/src/sky_plugin_redis.h index 58e589f0..aa97ef4e 100644 --- a/src/sky_plugin_redis.h +++ b/src/sky_plugin_redis.h @@ -32,6 +32,16 @@ std::string sky_plugin_redis_peer(zend_execute_data *execute_data); std::string sky_plugin_redis_key_cmd(zend_execute_data *execute_data, std::string cmd); +std::string sky_plugin_redis_set_cmd(zend_execute_data *execute_data, std::string cmd); + +std::string sky_plugin_redis_setex_cmd(zend_execute_data *execute_data, std::string cmd); + +std::string sky_plugin_redis_multi_key_cmd(zend_execute_data *execute_data, std::string cmd); + +std::string sky_plugin_redis_uncertain_keys_cmd(zend_execute_data *execute_data, std::string cmd); + +std::string sky_plugin_redis_key_ttl_cmd(zend_execute_data *execute_data, std::string cmd); + std::string sky_plugin_redis_bit_count_cmd(zend_execute_data *execute_data, std::string cmd); std::string sky_plugin_redis_key_value_cmd(zend_execute_data *execute_data, std::string cmd); @@ -39,4 +49,4 @@ std::string sky_plugin_redis_key_value_cmd(zend_execute_data *execute_data, std: std::string sky_plugin_redis_todo_cmd(zend_execute_data *execute_data, std::string cmd); -#endif // SKYWALKING_SKY_PLUGIN_REDIS_H \ No newline at end of file +#endif // SKYWALKING_SKY_PLUGIN_REDIS_H