rumeter_component/samplers/
gql.rs1use std::collections::HashMap;
2
3use async_trait::async_trait;
4use serde::Serialize;
5use tracing::*;
6use crate::{Sampler, record::{RecordData, ResponseResult}};
7
8use super::http::HeaderMap;
9
10
11#[derive(Clone)]
12pub struct GraphQLSampler<T: Serialize + Clone + Send + Sync>{
13 label: String,
14 endpoint: String,
15 headers: HeaderMap,
16 body: RequestBody<T>,
17}
18
19#[derive(Serialize, Clone)]
20struct RequestBody<T: Serialize + Clone + Send> {
21 query: String,
22 variables: Option<T>,
23}
24
25impl <T: Serialize + Clone + Send + Sync> GraphQLSampler<T> {
26 pub fn new(label: &str, endpoint: &str, query: &str, headers: HeaderMap, vars: Option<T>) -> Self {
27 let body = RequestBody {
28 query: query.to_string(),
29 variables: vars,
30 };
31 Self { label: label.to_string(), endpoint: endpoint.to_string(), headers, body }
32 }
33
34 fn request_size(&self) -> u32 {
35 self.request_line_size() + self.request_headers_size() + self.request_body_size()
36 }
37
38 fn request_headers_size(&self) -> u32 {
39 let mut size = 0u32;
40 for (key, value) in self.headers.clone() {
41 match key {
42 Some(header_name) => {
43 size = size + (header_name.to_string().len() + value.len() + ":\r\n".len()) as u32;
44 },
45 None => {},
46 }
47 }
48 size
49 }
50
51 fn request_line_size(&self) -> u32 {
52 ("POST".len() + self.endpoint.len() + " HTTP/1.1\r\n".len()) as u32
53 }
54
55 fn request_body_size(&self) -> u32 {
56 let s = serde_json::to_string(&self.body);
57 (s.unwrap_or("".to_string()).len() + "\r\n".len()) as u32
58 }
59}
60
61#[async_trait]
62impl <T: Serialize + Clone + Send + Sync> Sampler for GraphQLSampler<T> {
63 async fn run(&self) -> RecordData {
64 let client = reqwest::Client::new();
65 let start_send_timestamp = chrono::Local::now();
66 let resp = client.post(&self.endpoint).json(&self.body).headers(self.headers.clone()).send().await;
67 let finish_send_timestamp = chrono::Local::now();
68
69 match resp {
70 Ok(r) => {
71 let data_type = String::from("text");
72 let code = r.status().as_u16();
73 let resp_msg = r.status().canonical_reason().unwrap_or("Unknown");
74 let success = code < 400u16;
75 let fail_msg = if success {
76 None
77 } else {
78 Some(resp_msg.to_string())
79 };
80 let mut resp_headers: HashMap<String, String> = HashMap::new();
81 for (h_key, h_val) in r.headers() {
82 resp_headers.insert(h_key.to_string(), h_val.to_str().unwrap().to_string());
83 }
84
85 let resp_body = r.text().await.unwrap_or("".to_string());
86
87 RecordData::new(
88 start_send_timestamp.timestamp_millis() as u128,
89 (finish_send_timestamp - start_send_timestamp).num_milliseconds() as u64,
90 self.label.clone(),
91 code,
92 resp_msg.into(),
93 "".to_string(),
94 data_type,
95 success,
96 fail_msg,
97 resp_body.len() as u64,
98 self.request_size() as u64,
99 0,
100 0,
101 self.endpoint.clone(),
102 (finish_send_timestamp - start_send_timestamp).num_milliseconds() as u64,
103 0,
104 0,
105 Some(ResponseResult::new(resp_headers, resp_body)),
106 )
107 },
108 Err(e) => {
109 error!("failed! --> {}", e.to_string());
110 RecordData::new(
111 start_send_timestamp.timestamp_millis() as u128,
112 (finish_send_timestamp - start_send_timestamp).num_milliseconds() as u64,
113 self.label.clone(),
114 0,
115 "no data".to_string(),
116 "".to_string(),
117 "no data".to_string(),
118 false,
119 Some(e.to_string()),
120 0u64,
121 self.request_size() as u64,
122 0,
123 0,
124 self.endpoint.clone(),
125 (finish_send_timestamp - start_send_timestamp).num_milliseconds() as u64,
126 0,
127 0,
128 None,
129 )
130 },
131 }
132
133 }
134}
135