Skip to content

Commit

Permalink
scenario idx and name, and transation idx and name
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyandrews committed Aug 16, 2023
1 parent 4dda2d0 commit ad84e85
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 12 deletions.
41 changes: 32 additions & 9 deletions src/goose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ use url::Url;
use crate::logger::GooseLog;
use crate::metrics::{
GooseCoordinatedOmissionMitigation, GooseMetric, GooseRawRequest, GooseRequestMetric,
TransactionDetail,
};
use crate::{GooseConfiguration, GooseError, WeightedTransactions};

Expand Down Expand Up @@ -824,7 +825,13 @@ pub struct GooseUser {
pub(crate) iterations: usize,
/// An index into the internal [`GooseAttack`](../struct.GooseAttack.html)`.scenarios`
/// vector, indicating which [`Scenario`](./struct.Scenario.html) is running.
pub scenarios_index: usize,
pub(crate) scenarios_index: usize,
/// The Scenario this GooseUser is running.
pub(crate) scenario_name: String,
/// An optional index into [`Scenario`]`.transaction`, indicating which transaction this is.
pub(crate) transaction_index: Option<String>,
/// Current transaction name, if set.
pub(crate) transaction_name: Option<String>,
/// Client used to make requests, managing sessions and cookies.
pub client: Client,
/// The base URL to prepend to all relative paths.
Expand Down Expand Up @@ -853,8 +860,6 @@ pub struct GooseUser {
request_cadence: GooseRequestCadence,
/// Tracks how much time is spent sleeping during a loop through all transactions.
pub(crate) slept: u64,
/// Current transaction name.
pub(crate) transaction_name: Option<String>,
/// Optional per-user session data of a generic type implementing the
/// [`GooseUserData`] trait.
session_data: Option<Box<dyn GooseUserData>>,
Expand All @@ -863,6 +868,7 @@ impl GooseUser {
/// Create a new user state.
pub fn new(
scenarios_index: usize,
scenario_name: String,
base_url: Url,
configuration: &GooseConfiguration,
load_test_hash: u64,
Expand Down Expand Up @@ -891,6 +897,9 @@ impl GooseUser {
started: Instant::now(),
iterations: 0,
scenarios_index,
scenario_name,
transaction_index: None,
transaction_name: None,
client,
base_url,
config: configuration.clone(),
Expand All @@ -904,14 +913,13 @@ impl GooseUser {
load_test_hash,
request_cadence: GooseRequestCadence::new(),
slept: 0,
transaction_name: None,
session_data: None,
})
}

/// Create a new single-use user.
pub fn single(base_url: Url, configuration: &GooseConfiguration) -> Result<Self, GooseError> {
let mut single_user = GooseUser::new(0, base_url, configuration, 0)?;
let mut single_user = GooseUser::new(0, "".to_string(), base_url, configuration, 0)?;
// Only one user, so index is 0.
single_user.weighted_users_index = 0;
// Do not throttle [`test_start`](../struct.GooseAttack.html#method.test_start) (setup) and
Expand Down Expand Up @@ -1557,9 +1565,24 @@ impl GooseUser {
body,
);

// Provide details about the current transaction for logging.
let transaction_detail = TransactionDetail {
scenario_index: self.scenarios_index,
scenario_name: self.scenario_name.as_str(),
transaction_index: self
.transaction_index
.as_ref()
.map_or_else(|| "", |v| v.as_ref()),
transaction_name: self
.transaction_name
.as_ref()
.map_or_else(|| "", |v| v.as_ref()),
};

// Record information about the request.
let mut request_metric = GooseRequestMetric::new(
raw_request,
transaction_detail,
request_name,
self.started.elapsed().as_millis(),
self.weighted_users_index,
Expand Down Expand Up @@ -1806,7 +1829,7 @@ impl GooseUser {
// [`test_start`](../struct.GooseAttack.html#method.test_start),
// [`test_stop`](../struct.GooseAttack.html#method.test_stop), and during testing.
if let Some(metrics_channel) = self.metrics_channel.clone() {
if let Err(e) = metrics_channel.send(GooseMetric::Request(request_metric)) {
if let Err(e) = metrics_channel.send(GooseMetric::Request(Box::new(request_metric))) {
return Err(Box::new(e.into()));
}
}
Expand Down Expand Up @@ -3152,7 +3175,7 @@ mod tests {
const HOST: &str = "http://example.com/";
let configuration = GooseConfiguration::parse_args_default(&EMPTY_ARGS).unwrap();
let base_url = get_base_url(Some(HOST.to_string()), None, None).unwrap();
let user = GooseUser::new(0, base_url, &configuration, 0).unwrap();
let user = GooseUser::new(0, "".to_string(), base_url, &configuration, 0).unwrap();
assert_eq!(user.scenarios_index, 0);
assert_eq!(user.weighted_users_index, usize::max_value());

Expand All @@ -3179,7 +3202,7 @@ mod tests {
Some("http://www.example.com/".to_string()),
)
.unwrap();
let user2 = GooseUser::new(0, base_url, &configuration, 0).unwrap();
let user2 = GooseUser::new(0, "".to_string(), base_url, &configuration, 0).unwrap();

// Confirm the URLs are correctly built using the scenario_host.
let url = user2.build_url("/foo").unwrap();
Expand All @@ -3192,7 +3215,7 @@ mod tests {
// Confirm Goose can build a base_url that includes a path.
const HOST_WITH_PATH: &str = "http://example.com/with/path/";
let base_url = get_base_url(Some(HOST_WITH_PATH.to_string()), None, None).unwrap();
let user = GooseUser::new(0, base_url, &configuration, 0).unwrap();
let user = GooseUser::new(0, "".to_string(), base_url, &configuration, 0).unwrap();

// Confirm the URLs are correctly built using the default_host that includes a path.
let url = user.build_url("foo").unwrap();
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,7 @@ impl GooseAttack {
)?;
weighted_users.push(GooseUser::new(
self.scenarios[*scenarios_index].scenarios_index,
self.scenarios[*scenarios_index].machine_name.to_string(),
base_url,
&self.configuration,
self.metrics.hash,
Expand Down
8 changes: 8 additions & 0 deletions src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,10 @@ fn error_csv_header() -> String {
fn requests_csv_header() -> String {
format_csv_row!(
"elapsed",
"scenario_index",
"scenario_name",
"transaction_index",
"transaction_name",
"raw",
"name",
"final_url",
Expand Down Expand Up @@ -379,6 +383,10 @@ impl GooseLogger<GooseRequestMetric> for GooseConfiguration {
GooseLogFormat::Csv => {
format_csv_row!(
message.elapsed,
message.scenario_index,
message.scenario_name,
message.transaction_index,
message.transaction_name,
format!("{:?}", message.raw),
message.name,
message.final_url,
Expand Down
53 changes: 50 additions & 3 deletions src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use tokio::io::AsyncWriteExt;
/// can spend all their time generating and validating load.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum GooseMetric {
Request(GooseRequestMetric),
Request(Box<GooseRequestMetric>),
Transaction(TransactionMetric),
Scenario(ScenarioMetric),
}
Expand Down Expand Up @@ -315,6 +315,19 @@ impl GooseRawRequest {
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TransactionDetail<'a> {
/// An index into [`GooseAttack`]`.scenarios`, indicating which scenario this is.
pub scenario_index: usize,
/// The scenario name.
pub scenario_name: &'a str,
/// An optional index into [`Scenario`]`.transaction`, indicating which transaction this is.
pub transaction_index: &'a str,
/// An optional name for the transaction.
pub transaction_name: &'a str,
}

/// How many milliseconds the load test has been running.
/// For tracking and counting requests made during a load test.
///
/// The request that Goose is making. User threads send this data to the parent thread
Expand All @@ -326,6 +339,15 @@ impl GooseRawRequest {
pub struct GooseRequestMetric {
/// How many milliseconds the load test has been running.
pub elapsed: u64,
/// An index into [`GooseAttack`]`.scenarios`, indicating which scenario this is.
pub scenario_index: usize,
/// The scenario name.
pub scenario_name: String,
/// An optional index into [`Scenario`]`.transaction`, indicating which transaction this is.
/// Stored as string, `""` is no transaction, while `0` is the first `Scenario.transaction`.
pub transaction_index: String,
/// The optional transaction name.
pub transaction_name: String,
/// The raw request that the GooseClient made.
pub raw: GooseRawRequest,
/// The optional name of the request.
Expand Down Expand Up @@ -355,9 +377,19 @@ pub struct GooseRequestMetric {
pub user_cadence: u64,
}
impl GooseRequestMetric {
pub(crate) fn new(raw: GooseRawRequest, name: &str, elapsed: u128, user: usize) -> Self {
pub(crate) fn new(
raw: GooseRawRequest,
transaction_detail: TransactionDetail,
name: &str,
elapsed: u128,
user: usize,
) -> Self {
GooseRequestMetric {
elapsed: elapsed as u64,
scenario_index: transaction_detail.scenario_index,
scenario_name: transaction_detail.scenario_name.to_string(),
transaction_index: transaction_detail.transaction_index.to_string(),
transaction_name: transaction_detail.transaction_name.to_string(),
raw,
name: name.to_string(),
final_url: "".to_string(),
Expand Down Expand Up @@ -3807,8 +3839,23 @@ mod test {
fn goose_raw_request() {
const PATH: &str = "http://127.0.0.1/";
let raw_request = GooseRawRequest::new(GooseMethod::Get, PATH, vec![], "");
let mut request_metric = GooseRequestMetric::new(raw_request, "/", 0, 0);
let mut request_metric = GooseRequestMetric::new(
raw_request,
TransactionDetail {
scenario_index: 0,
scenario_name: "LoadTestUser",
transaction_index: 5.to_string().as_str(),
transaction_name: "front page",
},
"/",
0,
0,
);
assert_eq!(request_metric.raw.method, GooseMethod::Get);
assert_eq!(request_metric.scenario_index, 0);
assert_eq!(request_metric.scenario_name, "LoadTestUser");
assert_eq!(request_metric.transaction_index, "5");
assert_eq!(request_metric.transaction_name, "front page");
assert_eq!(request_metric.raw.url, PATH.to_string());
assert_eq!(request_metric.name, "/".to_string());
assert_eq!(request_metric.response_time, 0);
Expand Down
3 changes: 3 additions & 0 deletions src/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,13 +236,16 @@ async fn invoke_transaction_function(
thread_transaction_name.to_string(),
thread_user.weighted_users_index,
);
// Store details about the currently running transaction for logging purposes.
if !thread_transaction_name.is_empty() {
thread_user
.transaction_name
.replace(thread_transaction_name.to_string());
} else {
thread_user.transaction_name.take();
}
// As the index is optional, `""` is none, whereas `"0"` is the first index.
thread_user.transaction_index = Some(thread_transaction_index.to_string());

let success = function(thread_user).await.is_ok();
raw_transaction.set_time(started.elapsed().as_millis(), success);
Expand Down

0 comments on commit ad84e85

Please sign in to comment.