Open wchmiela opened 2 years ago
Are you referring to https://docs.rs/h2/0.3.7/h2/client/index.html?
At this time Goose is very tightly coupled with Reqwest -- the goal is to make it possible to swap it out for other clients in #32 but this hasn't been worked on recently. Request metrics are collected in GooseUser::request
, and this is the function that would ultimately need to be made more generic.
In theory you should be able to do the same thing that we do in that function in your own code to generate metrics. You'd need to create a GooseRequestMetric
as happens here:
https://github.com/tag1consulting/goose/blob/main/src/goose.rs#L1556
Record the response time: https://github.com/tag1consulting/goose/blob/main/src/goose.rs#L1565
Record the response code: https://github.com/tag1consulting/goose/blob/main/src/goose.rs#L1574
Record the final URL (to know if it redirected): https://github.com/tag1consulting/goose/blob/main/src/goose.rs#L1575
Update success
to true
or false
, setting error
if there was one.
https://github.com/tag1consulting/goose/blob/main/src/goose.rs#L1581
And send the resulting object to the parent: https://github.com/tag1consulting/goose/blob/main/src/goose.rs#L1628
Note that none of the methods defined on GooseRequestMetric (used above) are public: https://github.com/tag1consulting/goose/blob/main/src/metrics.rs#L293
But all the fields are public, so you can just set/update them directly.
In writing an Example to demonstrate how this might work, I realized send_request_metric_to_parent()
isn't public, so what I describe above isn't going to work. Simply making that function public does make the following possible -- would this be enough to be useful to you? Perhaps if a couple of helpers are added it could be useful enough.
use goose::prelude::*;
use goose::metrics::{GooseRawRequest, GooseRequestMetric};
use isahc::prelude::*;
async fn loadtest_index(user: &mut GooseUser) -> GooseTaskResult {
let started = std::time::Instant::now();
let url = "http://example.com/";
let mut response = isahc::get(url).unwrap();
let status = response.status();
let mut headers: Vec<String> = Vec::new();
for header in response.headers() {
headers.push(format!("{:?}", header));
}
response.consume().unwrap();
// Record information about the request.
let raw_request = GooseRawRequest {
method: GooseMethod::Get,
url: url.to_string(),
headers,
body: "".to_string(),
};
let request_metric = GooseRequestMetric {
elapsed: user.started.elapsed().as_millis() as u64,
raw: raw_request,
//@TODO
name: url.to_string(),
//@TODO
final_url: url.to_string(),
//@TODO
redirected: false,
response_time: started.elapsed().as_millis() as u64,
status_code: status.as_u16(),
success: status.is_success(),
update: false,
user: user.weighted_users_index,
//@TODO:
error: "".to_string(),
//@TODO
coordinated_omission_elapsed: 0,
//@TODO
user_cadence: 0,
};
user.send_request_metric_to_parent(request_metric)?;
Ok(())
}
Thanks @jeremyandrews for a quick response. That's exactly what I've implemented. I guess it's a nice way to record any metric.
There's a work in progress here to better demonstrate with a fully-functional example: https://github.com/tag1consulting/goose/pull/397
My eventual goal is to make changes to Goose that simplify this example, but to begin my goal is simply for it to work without lost functionality.
One issue I've noticed is that if you manage your own client, then each time a task runs you're essentially building a new client and things like cookies and headers aren't preserved across requests. This means you can't (easily) simulate logging into an application, etc. I do hope to come up with a generic solution in the linked work-in-progress PR.
I'm using different HTTP/2 client (h2 instead of reqwest) because of push promise support, therefore I need to measure some events like pushed data.
In locust.io there was an option to fire certain event using events.request.fire(...) providing request type, response time etc.
In goose, I can see a pub fn set_success(&self, request: &mut GooseRequestMetric) -> GooseTaskResult, which manually marks a request as a success. What is the best approach to mark custom event (which has no origin in built-in HTTP/2 client) and make it visible in the metrics section?