这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ use std::ptr;
pub struct VtsHandler;

impl VtsHandler {
pub extern "C" fn vts_status_handler(r: *mut ngx_http_request_t) -> ngx_int_t {
/// # Safety
///
/// The `r` pointer must be a valid nginx request pointer.
/// The caller must ensure the pointer remains valid for the duration of this call.
pub unsafe extern "C" fn vts_status_handler(r: *mut ngx_http_request_t) -> ngx_int_t {
unsafe {
Comment on lines +23 to 24
Copy link

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function is already marked as unsafe, making the inner unsafe block redundant. Remove the inner unsafe block since the entire function body is already in an unsafe context.

Copilot uses AI. Check for mistakes.
// TODO: Fix nginx module integration
// let loc_conf = ngx_http_get_module_loc_conf(r, &crate::ngx_http_vts_module as *const _ as *mut _) as *mut VtsConfig;
Expand Down
37 changes: 34 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,33 @@ pub extern "C" fn vts_collect_nginx_connections() {
}
}

/// Update server zone statistics from nginx request processing
/// This should be called from nginx log phase for each request
///
/// # Safety
///
/// The `server_name` pointer must be a valid null-terminated C string.
/// The caller must ensure the pointer remains valid for the duration of this call.
#[no_mangle]
pub unsafe extern "C" fn vts_update_server_stats_ffi(
server_name: *const c_char,
status: u16,
bytes_in: u64,
bytes_out: u64,
request_time: u64,
) {
if server_name.is_null() {
return;
}

let server_name_str = match std::ffi::CStr::from_ptr(server_name).to_str() {
Ok(s) => s,
Err(_) => return,
};

update_server_zone_stats(server_name_str, status, bytes_in, bytes_out, request_time);
}

/// Update VTS statistics from nginx (to be called periodically)
/// This should be called from nginx worker process periodically to collect
/// all types of statistics including connections, server zones, and upstream data
Expand All @@ -311,7 +338,7 @@ pub extern "C" fn vts_update_statistics() {
vts_collect_nginx_connections();

// Note: Server zone statistics are updated automatically when requests are processed
// via update_server_zone_stats() calls from nginx request processing
// via vts_update_server_stats_ffi() calls from nginx request processing

// Note: Upstream statistics are updated automatically when upstream requests complete
// via vts_update_upstream_stats_ffi() calls from nginx upstream processing
Expand All @@ -327,7 +354,7 @@ pub extern "C" fn vts_update_statistics() {
/// The returned pointer is valid until the next call to this function.
/// The caller must not free the returned pointer.
#[no_mangle]
pub extern "C" fn ngx_http_vts_get_status() -> *const c_char {
pub unsafe extern "C" fn ngx_http_vts_get_status() -> *const c_char {
use std::sync::Mutex;

static STATUS_CACHE: Mutex<Option<std::ffi::CString>> = Mutex::new(None);
Expand Down Expand Up @@ -400,7 +427,8 @@ http_request_handler!(vts_status_handler, |request: &mut http::Request| {
///
/// A formatted string containing VTS status information
fn generate_vts_status_content() -> String {
// First, collect current nginx connection statistics
// Collect current nginx connection statistics only in production
#[cfg(not(test))]
Comment on lines +430 to +431
Copy link

Copilot AI Sep 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The conditional compilation directive is placed after the comment but before the function call. Move the #[cfg(not(test))] directive to line 431 before the comment for better code organization and clarity.

Suggested change
// Collect current nginx connection statistics only in production
#[cfg(not(test))]
#[cfg(not(test))]
// Collect current nginx connection statistics only in production

Copilot uses AI. Check for mistakes.
vts_collect_nginx_connections();

let manager = VTS_MANAGER
Expand Down Expand Up @@ -483,6 +511,9 @@ mod integration_tests {
manager.connections = Default::default();
}

// Set up connection statistics for the test
update_connection_stats(1, 0, 1, 0, 16, 16);

// Add some sample server zone data
update_server_zone_stats("example.com", 200, 1024, 2048, 150);
update_server_zone_stats("example.com", 404, 512, 256, 80);
Expand Down
76 changes: 63 additions & 13 deletions src/ngx_vts_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ extern void vts_track_upstream_request(
uint16_t status_code
);

// External Rust functions
extern void vts_update_server_stats_ffi(
const char* server_name,
uint16_t status,
uint64_t bytes_in,
uint64_t bytes_out,
uint64_t request_time
);

// External Rust initialization function
extern ngx_int_t ngx_http_vts_init_rust_module(ngx_conf_t *cf);

Expand Down Expand Up @@ -104,21 +113,62 @@ ngx_http_vts_log_handler(ngx_http_request_t *r)
ngx_cpystrn(server_addr_buf, (u_char*)"unknown", sizeof(server_addr_buf));
}

// Call Rust function to update statistics
// Update server zone statistics for all requests
u_char server_name_buf[256];
ngx_str_t *server_name = &r->headers_in.server;
if (server_name->len > 0 && server_name->len < sizeof(server_name_buf) - 1) {
ngx_memcpy(server_name_buf, server_name->data, server_name->len);
server_name_buf[server_name->len] = '\0';
} else {
ngx_cpystrn(server_name_buf, (u_char*)"_", sizeof(server_name_buf));
}

// Calculate total request time in milliseconds using nginx's builtin calculation
ngx_msec_t request_time = 0;
// Always calculate request time using request start time
ngx_time_t *tp = ngx_timeofday();
request_time = (ngx_msec_t) ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec));

// Get response status (use r->headers_out.status if available, otherwise default)
ngx_uint_t response_status = r->headers_out.status ? r->headers_out.status : status_code;
if (response_status == 0) {
response_status = 200; // Default to 200 if no status available
}

// Calculate bytes sent and received for this request
off_t bytes_in = r->request_length;
off_t bytes_out = r->connection->sent;

// Call Rust function to update server zone statistics
ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
"VTS LOG_PHASE: Calling vts_track_upstream_request - upstream: %s, server: %s, status: %d",
upstream_name_buf, server_addr_buf, status_code);

vts_track_upstream_request(
(const char*)upstream_name_buf,
(const char*)server_addr_buf,
(uint64_t)r->start_sec,
(uint64_t)r->start_msec,
(uint64_t)upstream_response_time,
(uint64_t)bytes_sent,
(uint64_t)bytes_received,
(uint16_t)status_code
"VTS LOG_PHASE: Updating server stats - server: %s, status: %d, bytes_in: %O, bytes_out: %O",
server_name_buf, response_status, bytes_in, bytes_out);

vts_update_server_stats_ffi(
(const char*)server_name_buf,
(uint16_t)response_status,
(uint64_t)bytes_in,
(uint64_t)bytes_out,
(uint64_t)request_time
);

// Call Rust function to update upstream statistics (if upstream exists)
if (upstream_name.len > 0) {
ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
"VTS LOG_PHASE: Calling vts_track_upstream_request - upstream: %s, server: %s, status: %d",
upstream_name_buf, server_addr_buf, status_code);

vts_track_upstream_request(
(const char*)upstream_name_buf,
(const char*)server_addr_buf,
(uint64_t)r->start_sec,
(uint64_t)r->start_msec,
(uint64_t)upstream_response_time,
(uint64_t)bytes_sent,
(uint64_t)bytes_received,
(uint16_t)status_code
);
}

ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
"VTS LOG_PHASE: vts_track_upstream_request completed");
Expand Down