mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-27 15:37:02 +00:00
@@ -0,0 +1,46 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type HealItemType = String;
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct HealDriveInfo {
|
||||
pub uuid: String,
|
||||
pub endpoint: String,
|
||||
pub state: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct Infos {
|
||||
#[serde(rename = "drives")]
|
||||
pub drives: Vec<HealDriveInfo>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct HealResultItem {
|
||||
#[serde(rename = "resultId")]
|
||||
pub result_index: usize,
|
||||
#[serde(rename = "type")]
|
||||
pub heal_item_type: HealItemType,
|
||||
#[serde(rename = "bucket")]
|
||||
pub bucket: String,
|
||||
#[serde(rename = "object")]
|
||||
pub object: String,
|
||||
#[serde(rename = "versionId")]
|
||||
pub version_id: String,
|
||||
#[serde(rename = "detail")]
|
||||
pub detail: String,
|
||||
#[serde(rename = "parityBlocks")]
|
||||
pub parity_blocks: usize,
|
||||
#[serde(rename = "dataBlocks")]
|
||||
pub data_blocks: usize,
|
||||
#[serde(rename = "diskCount")]
|
||||
pub disk_count: usize,
|
||||
#[serde(rename = "setCount")]
|
||||
pub set_count: usize,
|
||||
#[serde(rename = "before")]
|
||||
pub before: Infos,
|
||||
#[serde(rename = "after")]
|
||||
pub after: Infos,
|
||||
#[serde(rename = "objectSize")]
|
||||
pub object_size: usize,
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
pub mod heal_commands;
|
||||
pub mod health;
|
||||
pub mod info_commands;
|
||||
pub mod metrics;
|
||||
pub mod net;
|
||||
pub mod service_commands;
|
||||
pub mod trace;
|
||||
pub mod utils;
|
||||
|
||||
pub use info_commands::*;
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
use std::{collections::HashMap, time::Duration};
|
||||
|
||||
use hyper::Uri;
|
||||
|
||||
use crate::{trace::TraceType, utils::parse_duration};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ServiceTraceOpts {
|
||||
s3: bool,
|
||||
internal: bool,
|
||||
storage: bool,
|
||||
os: bool,
|
||||
scanner: bool,
|
||||
decommission: bool,
|
||||
healing: bool,
|
||||
batch_replication: bool,
|
||||
batch_key_rotation: bool,
|
||||
batch_expire: bool,
|
||||
batch_all: bool,
|
||||
rebalance: bool,
|
||||
replication_resync: bool,
|
||||
bootstrap: bool,
|
||||
ftp: bool,
|
||||
ilm: bool,
|
||||
only_errors: bool,
|
||||
threshold: Duration,
|
||||
}
|
||||
|
||||
impl ServiceTraceOpts {
|
||||
fn trace_types(&self) -> TraceType {
|
||||
let mut tt = TraceType::default();
|
||||
tt.set_if(self.s3, &TraceType::S3);
|
||||
tt.set_if(self.internal, &TraceType::INTERNAL);
|
||||
tt.set_if(self.storage, &TraceType::STORAGE);
|
||||
tt.set_if(self.os, &TraceType::OS);
|
||||
tt.set_if(self.scanner, &TraceType::SCANNER);
|
||||
tt.set_if(self.decommission, &TraceType::DECOMMISSION);
|
||||
tt.set_if(self.healing, &TraceType::HEALING);
|
||||
|
||||
if self.batch_all {
|
||||
tt.set_if(true, &TraceType::BATCH_REPLICATION);
|
||||
tt.set_if(true, &TraceType::BATCH_KEY_ROTATION);
|
||||
tt.set_if(true, &TraceType::BATCH_EXPIRE);
|
||||
} else {
|
||||
tt.set_if(self.batch_replication, &TraceType::BATCH_REPLICATION);
|
||||
tt.set_if(self.batch_key_rotation, &TraceType::BATCH_KEY_ROTATION);
|
||||
tt.set_if(self.batch_expire, &TraceType::BATCH_EXPIRE);
|
||||
}
|
||||
|
||||
tt.set_if(self.rebalance, &TraceType::REBALANCE);
|
||||
tt.set_if(self.replication_resync, &TraceType::REPLICATION_RESYNC);
|
||||
tt.set_if(self.bootstrap, &TraceType::BOOTSTRAP);
|
||||
tt.set_if(self.ftp, &TraceType::FTP);
|
||||
tt.set_if(self.ilm, &TraceType::ILM);
|
||||
|
||||
tt
|
||||
}
|
||||
|
||||
pub fn parse_params(&mut self, uri: &Uri) -> Result<(), String> {
|
||||
let query_pairs: HashMap<_, _> = uri
|
||||
.query()
|
||||
.unwrap_or("")
|
||||
.split('&')
|
||||
.filter_map(|pair| {
|
||||
let mut split = pair.split('=');
|
||||
let key = split.next()?.to_string();
|
||||
let value = split.next().map(|v| v.to_string()).unwrap_or_else(|| "false".to_string());
|
||||
Some((key, value))
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.s3 = query_pairs.get("s3").map_or(false, |v| v == "true");
|
||||
self.os = query_pairs.get("os").map_or(false, |v| v == "true");
|
||||
self.scanner = query_pairs.get("scanner").map_or(false, |v| v == "true");
|
||||
self.decommission = query_pairs.get("decommission").map_or(false, |v| v == "true");
|
||||
self.healing = query_pairs.get("healing").map_or(false, |v| v == "true");
|
||||
self.batch_replication = query_pairs.get("batch-replication").map_or(false, |v| v == "true");
|
||||
self.batch_key_rotation = query_pairs.get("batch-keyrotation").map_or(false, |v| v == "true");
|
||||
self.batch_expire = query_pairs.get("batch-expire").map_or(false, |v| v == "true");
|
||||
if query_pairs.get("all").map_or(false, |v| v == "true") {
|
||||
self.s3 = true;
|
||||
self.internal = true;
|
||||
self.storage = true;
|
||||
self.os = true;
|
||||
}
|
||||
|
||||
self.rebalance = query_pairs.get("rebalance").map_or(false, |v| v == "true");
|
||||
self.storage = query_pairs.get("storage").map_or(false, |v| v == "true");
|
||||
self.internal = query_pairs.get("internal").map_or(false, |v| v == "true");
|
||||
self.only_errors = query_pairs.get("err").map_or(false, |v| v == "true");
|
||||
self.replication_resync = query_pairs.get("replication-resync").map_or(false, |v| v == "true");
|
||||
self.bootstrap = query_pairs.get("bootstrap").map_or(false, |v| v == "true");
|
||||
self.ftp = query_pairs.get("ftp").map_or(false, |v| v == "true");
|
||||
self.ilm = query_pairs.get("ilm").map_or(false, |v| v == "true");
|
||||
|
||||
if let Some(threshold) = query_pairs.get("threshold") {
|
||||
let duration = parse_duration(threshold)?;
|
||||
self.threshold = duration;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
use std::{collections::HashMap, time::Duration};
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::heal_commands::HealResultItem;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub struct TraceType(u64);
|
||||
|
||||
impl TraceType {
|
||||
// 定义一些常量
|
||||
pub const OS: TraceType = TraceType(1 << 0);
|
||||
pub const STORAGE: TraceType = TraceType(1 << 1);
|
||||
pub const S3: TraceType = TraceType(1 << 2);
|
||||
pub const INTERNAL: TraceType = TraceType(1 << 3);
|
||||
pub const SCANNER: TraceType = TraceType(1 << 4);
|
||||
pub const DECOMMISSION: TraceType = TraceType(1 << 5);
|
||||
pub const HEALING: TraceType = TraceType(1 << 6);
|
||||
pub const BATCH_REPLICATION: TraceType = TraceType(1 << 7);
|
||||
pub const BATCH_KEY_ROTATION: TraceType = TraceType(1 << 8);
|
||||
pub const BATCH_EXPIRE: TraceType = TraceType(1 << 9);
|
||||
pub const REBALANCE: TraceType = TraceType(1 << 10);
|
||||
pub const REPLICATION_RESYNC: TraceType = TraceType(1 << 11);
|
||||
pub const BOOTSTRAP: TraceType = TraceType(1 << 12);
|
||||
pub const FTP: TraceType = TraceType(1 << 13);
|
||||
pub const ILM: TraceType = TraceType(1 << 14);
|
||||
|
||||
// MetricsAll must be last.
|
||||
pub const ALL: TraceType = TraceType((1 << 15) - 1);
|
||||
|
||||
pub fn new(t: u64) -> Self {
|
||||
Self(t)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TraceType {
|
||||
fn default() -> Self {
|
||||
Self(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl TraceType {
|
||||
pub fn contains(&self, x: &TraceType) -> bool {
|
||||
(self.0 & x.0) == x.0
|
||||
}
|
||||
|
||||
pub fn overlaps(&self, x: &TraceType) -> bool {
|
||||
(self.0 & x.0) != 0
|
||||
}
|
||||
|
||||
pub fn single_type(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn merge(&mut self, other: &TraceType) {
|
||||
self.0 = self.0 | other.0
|
||||
}
|
||||
|
||||
pub fn set_if(&mut self, b: bool, other: &TraceType) {
|
||||
if b {
|
||||
self.0 = self.0 | other.0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mask(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct TraceInfo {
|
||||
#[serde(rename = "type")]
|
||||
trace_type: u64,
|
||||
#[serde(rename = "nodename")]
|
||||
node_name: String,
|
||||
#[serde(rename = "funcname")]
|
||||
func_name: String,
|
||||
#[serde(rename = "time")]
|
||||
time: DateTime<Utc>,
|
||||
#[serde(rename = "path")]
|
||||
path: String,
|
||||
#[serde(rename = "dur")]
|
||||
duration: Duration,
|
||||
#[serde(rename = "bytes", skip_serializing_if = "Option::is_none")]
|
||||
bytes: Option<i64>,
|
||||
#[serde(rename = "msg", skip_serializing_if = "Option::is_none")]
|
||||
message: Option<String>,
|
||||
#[serde(rename = "error", skip_serializing_if = "Option::is_none")]
|
||||
error: Option<String>,
|
||||
#[serde(rename = "custom", skip_serializing_if = "Option::is_none")]
|
||||
custom: Option<HashMap<String, String>>,
|
||||
#[serde(rename = "http", skip_serializing_if = "Option::is_none")]
|
||||
http: Option<TraceHTTPStats>,
|
||||
#[serde(rename = "healResult", skip_serializing_if = "Option::is_none")]
|
||||
heal_result: Option<HealResultItem>,
|
||||
}
|
||||
|
||||
impl TraceInfo {
|
||||
pub fn mask(&self) -> u64 {
|
||||
TraceType::new(self.trace_type).mask()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct TraceInfoLegacy {
|
||||
trace_info: TraceInfo,
|
||||
#[serde(rename = "request")]
|
||||
req_info: Option<TraceRequestInfo>,
|
||||
#[serde(rename = "response")]
|
||||
resp_info: Option<TraceResponseInfo>,
|
||||
#[serde(rename = "stats")]
|
||||
call_stats: Option<TraceCallStats>,
|
||||
#[serde(rename = "storageStats")]
|
||||
storage_stats: Option<StorageStats>,
|
||||
#[serde(rename = "osStats")]
|
||||
os_stats: Option<OSStats>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct StorageStats {
|
||||
path: String,
|
||||
duration: Duration,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct OSStats {
|
||||
path: String,
|
||||
duration: Duration,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct TraceHTTPStats {
|
||||
req_info: TraceRequestInfo,
|
||||
resp_info: TraceResponseInfo,
|
||||
call_stats: TraceCallStats,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct TraceCallStats {
|
||||
input_bytes: i32,
|
||||
output_bytes: i32,
|
||||
latency: Duration,
|
||||
time_to_first_byte: Duration,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct TraceRequestInfo {
|
||||
time: DateTime<Utc>,
|
||||
proto: String,
|
||||
method: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
path: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
raw_query: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
headers: Option<HashMap<String, String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
body: Option<Vec<u8>>,
|
||||
client: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub struct TraceResponseInfo {
|
||||
time: DateTime<Utc>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
headers: Option<HashMap<String, String>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
body: Option<Vec<u8>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
status_code: Option<i32>,
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
use std::time::Duration;
|
||||
|
||||
pub fn parse_duration(s: &str) -> Result<Duration, String> {
|
||||
// Implement your own duration parsing logic here
|
||||
// For example, you could use the humantime crate or a custom parser
|
||||
humantime::parse_duration(s).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::time::Duration;
|
||||
|
||||
use super::parse_duration;
|
||||
|
||||
#[test]
|
||||
fn test_parse_dur() {
|
||||
let s = String::from("3s");
|
||||
let dur = parse_duration(&s);
|
||||
println!("{:?}", dur);
|
||||
assert_eq!(Ok(Duration::from_secs(3)), dur);
|
||||
|
||||
let s = String::from("3ms");
|
||||
let dur = parse_duration(&s);
|
||||
println!("{:?}", dur);
|
||||
assert_eq!(Ok(Duration::from_millis(3)), dur);
|
||||
|
||||
let s = String::from("3m");
|
||||
let dur = parse_duration(&s);
|
||||
println!("{:?}", dur);
|
||||
assert_eq!(Ok(Duration::from_secs(3 * 60)), dur);
|
||||
|
||||
let s = String::from("3h");
|
||||
let dur = parse_duration(&s);
|
||||
println!("{:?}", dur);
|
||||
assert_eq!(Ok(Duration::from_secs(3 * 60 * 60)), dur);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user