telemetry_manager = Metasync_Telemetry_Manager::get_instance(); } /** * Get current timestamp for logging */ private function log_timestamp() { return current_time('mysql'); } # uri strings # These are sections of the uri to look for in a request # prevents logging unauthorized requests protected $loggable_uri_strings = [ 'metasync', 'searchatlas' ]; /** * Check Loggable URI * This method helps us check that the uri is permitted * Otherwise it returns fals * */ function log_uri_permitted($uri) { # Get permitted URI strings $permitted_strings = $this->loggable_uri_strings; # If an asterisk is used, allow all if ($permitted_strings === '*') { return true; } # Check if any string is in the URI foreach ($permitted_strings as $string) { if (strpos($uri, $string) !== false) { return true; # Found a match } } # Return false for no matches return false; } # @section # Monitors Incoming and Outgoing Request Data # let's monitor outgoing logs function api_monitor_outgoing($preempt, $args, $url){ if (metasync_telemetry_is_disabled()) { return $preempt; } # ignore wp chron requests if(strpos($url, 'wp-cron.php') !== false){ return $preempt; } # check that the route is permitted for logging if ( empty($url) || $this->log_uri_permitted($url) == False ){ return $preempt; } # prepare the request object $request = [ 'timestamp' => $this->log_timestamp(), 'type' => 'outgoing_request', 'method' => $args['method'] ?? 'undefined', 'request_url' => metasync_telemetry_request_path($url), 'args' => $this->sanitize_args($args) ]; # send the request with telemetry manager $this->telemetry_manager->send_message('Outgoing Request', 'info', $request); # Return preempt to allow the request to continue return $preempt; } # monitor incoming function api_monitor_incoming($result, $server, $request){ if (metasync_telemetry_is_disabled()) { return $result; } # check that the route is permitted for logging if ( empty($request->get_route()) || $this->log_uri_permitted($request->get_route()) == False ){ return $result; } # prepare the reuqest $request_data = [ 'timestamp' => $this->log_timestamp(), 'type' => 'incoming_request', 'method' => $request->get_method(), 'uri' => metasync_telemetry_request_path($request->get_route()) ]; $this->telemetry_manager->send_message('Incoming Request', 'info', $request_data); # Return result to allow the request to continue return $result; } # @section # Monitors the Request Responses # Helps checking for errors # monitor the response to an outgoing API call # function monitor_outgoing_response($response, $context, $url, $parsed_args){ function monitor_outgoing_response($response, $parsed_args, $url){ if (metasync_telemetry_is_disabled()) { return $response; } # Skip logging for wp-cron requests if (strpos($url, 'wp-cron.php') !== false) { return $response; } # check that the route is permitted for logging if ( empty($url) || $this->log_uri_permitted($url) == False ){ return $response; } # request data $response_data = [ 'timestamp' => $this->log_timestamp(), 'type' => 'outgoing_response', 'status_code' => $response['response']['code'] ?? '', 'url' => metasync_telemetry_request_path($url), 'response_data' => $this->sanitize_outgoing_response($response), 'args' => $this->sanitize_args($parsed_args) ]; #return the response $this->telemetry_manager->send_message('Outgoing Response', 'info', $response_data); # Return response to allow it to continue return $response; } # monitor the response to an incoming api call function monitor_incoming_response($response, $server, $request){ if (metasync_telemetry_is_disabled()) { return $response; } # check that the route is permitted for logging if ( empty($request->get_route()) || $this->log_uri_permitted($request->get_route()) == False ){ return $response; } # prepare the response object $response_object = array( 'timestamp' => $this->log_timestamp(), 'type' => 'incoming_response', 'status_code' => $response->get_status() ?? '', 'url' => metasync_telemetry_request_path($request->get_route()), 'method' => $request->get_method(), 'response_data' => $this->sanitize_response_data($response), 'request_data' => $this->sanitize_request_data($request) ); # let record the response $this->telemetry_manager->send_message('Incoming Response', 'info', $response_object); # Return response to allow it to continue return $response; } /** * Sanitize WP_REST_Response object for serialization * * @param mixed $response The response object * @return array Sanitized response data */ private function sanitize_response_data($response) { if (!is_object($response)) { return is_array($response) ? $response : array(); } return array( 'status' => method_exists($response, 'get_status') ? $response->get_status() : null ); } /** * Sanitize WP_REST_Request object for serialization * * @param mixed $request The request object * @return array Sanitized request data */ private function sanitize_request_data($request) { if (!is_object($request)) { return is_array($request) ? $request : array(); } return array( 'method' => method_exists($request, 'get_method') ? $request->get_method() : null, 'route' => method_exists($request, 'get_route') ? metasync_telemetry_request_path($request->get_route()) : null ); } /** * Sanitize outgoing HTTP response for serialization * * @param array $response The HTTP response array * @return array Sanitized response data */ private function sanitize_outgoing_response($response) { if (!is_array($response)) { return $response; } $sanitized = array(); // Safely extract response data if (isset($response['response'])) { $sanitized['response'] = array( 'code' => $response['response']['code'] ?? null, 'message' => $response['response']['message'] ?? null ); } return $sanitized; } /** * Sanitize HTTP request arguments for serialization * * @param array $args The HTTP request arguments * @return array Sanitized arguments */ private function sanitize_args($args) { if (!is_array($args)) { return $args; } $sanitized = array(); // Only include safe, serializable data $safe_keys = array('method', 'timeout', 'redirection', 'httpversion', 'user-agent', 'reject_unsafe_urls', 'blocking', 'sslverify', 'stream', 'filename', 'decompress'); foreach ($safe_keys as $key) { if (isset($args[$key])) { $sanitized[$key] = $args[$key]; } } return $sanitized; } /** * @see monitor_api_calls * */ function monitor_api_calls(){ # log incoming requests add_filter('rest_pre_dispatch', [$this, 'api_monitor_incoming'],10, 3); # add hook to monitor outgoing api requests add_filter('pre_http_request', [$this, 'api_monitor_outgoing'], 1, 3); # Hook to monitor outgoing API responses add_action('http_response', [$this, 'monitor_outgoing_response'], 10, 4); # Monitor incoming request responses add_filter('rest_post_dispatch', [$this, 'monitor_incoming_response'], 10, 3); } }