mprobe_diagnostics/lib.rs
1//! A library for parsing and reading MongoDB diagnostic data,
2//! generated by the Full Time Diagnostic Data Capture (FTDC) mechanism.
3//!
4//! # Read the diagnostic data
5//!
6//! One can read the diagnostic data by constructing an instance of [DiagnosticData],
7//! and iterate over it to get the diagnostic metrics. The iterator yields one
8//! [chunk] of the diagnostic data at a time. Each chunk contains a list of [metrics]
9//! and [metadata] associated with it. The metrics are always returned sorted in
10//! ascending order.
11//!
12//! [chunk]: crate::metrics::MetricsChunk
13//! [metadata]: crate::metadata::Metadata
14//! [metrics]: crate::metrics::Metric
15//!
16//! The following example shows how to read through the diagnostic data and print
17//! the metric names on the standard output.
18//!
19//! ```no_run
20//! use std::path::Path;
21//! use std::result::Result;
22//!
23//! use mprobe_diagnostics::DiagnosticData;
24//! use mprobe_diagnostics::error::MetricParseError;
25//!
26//! fn main() -> Result<(), MetricParseError> {
27//! // Note: this example needs a valid path
28//! // that contains diagnostic data for it to run
29//! let path = Path::new("/path/to/diagnostic/data");
30//! let diagnostic_data = DiagnosticData::new(&path)?;
31//!
32//! for chunk in diagnostic_data {
33//! for metric in chunk?.metrics {
34//! println!("{}", metric.name);
35//! }
36//! }
37//!
38//! Ok(())
39//! }
40//! ```
41//!
42//! # Filter the diagnostic data
43//!
44//! Since the [DiagnosticData] implements [IntoIterator], one could use
45//! the [Iterator::filter] combinator to filter the diagnostic data. However that will
46//! be applied to all the diagnostic data contained in the provided path, which
47//! can contain a lot of data. When one needs only the diagnostic data of a node,
48//! process, or the data in a specific time window, one can use
49//! the [DiagnosticData::filter] function and provide an instance of [MetricsFilter].
50//!
51//! In the example below it is show how one could use it.
52//!
53//! ```no_run
54//! use std::path::Path;
55//! use chrono::{DateTime, Duration, TimeDelta, Utc};
56//! use mprobe_diagnostics::{DiagnosticData, MetricsFilter};
57//!
58//! let path = Path::new("/path/to/diagnostic/data");
59//!
60//! let node = String::from("node-1");
61//! let start = Utc::now() - Duration::hours(1);
62//! let end = Utc::now();
63//!
64//! let filter = MetricsFilter::new(Some(node), Some(start), Some(end));
65//! let diagnostic_data = DiagnosticData::filter(&path, filter).expect("valid path");
66//! ```
67//!
68
69#![warn(missing_docs)]
70
71mod bson;
72mod bytes;
73mod compression;
74mod filter;
75mod iter;
76mod read;
77
78pub mod error;
79pub mod metadata;
80pub mod metrics;
81
82use std::fs;
83use std::fs::ReadDir;
84use std::io;
85use std::path::Path;
86
87use chrono::DateTime;
88use chrono::Utc;
89
90use crate::error::MetricParseError;
91use crate::metrics::MetricsChunk;
92use crate::read::MetricsIterator;
93
94/// `DiagnosticData` defines an API for parsing and reading MongoDB diagnostic data.
95#[derive(Debug)]
96pub struct DiagnosticData {
97 entries: ReadDir,
98 filter: MetricsFilter,
99}
100
101impl DiagnosticData {
102 /// Creates a new `DiagnosticData` that will parse and read
103 /// the diagnostic data at the specified `path`.
104 ///
105 /// The `path` must be valid and point to a directory containing
106 /// the diagnostic data unarchived.
107 pub fn new(path: &Path) -> Result<Self, io::Error> {
108 let entries = fs::read_dir(path)?;
109 let filter = MetricsFilter::default();
110
111 Ok(Self { entries, filter })
112 }
113
114 /// Creates a new `DiagnosticData` that will parse and read
115 /// the diagnostic data at the specified `path` and filter it
116 /// according to the `filter` specification.
117 ///
118 /// The `path` must be valid and point to a directory containing
119 /// the diagnostic data unarchived.
120 pub fn filter(path: &Path, filter: MetricsFilter) -> Result<Self, io::Error> {
121 let entries = fs::read_dir(path)?;
122
123 Ok(Self { entries, filter })
124 }
125}
126
127impl IntoIterator for DiagnosticData {
128 type Item = Result<MetricsChunk, MetricParseError>;
129
130 type IntoIter = MetricsIterator;
131
132 fn into_iter(self) -> Self::IntoIter {
133 MetricsIterator::new(self.entries, self.filter)
134 }
135}
136
137/// `MetricsFilter` specifies a filter for the diagnostic data.
138#[derive(Debug, Default)]
139pub struct MetricsFilter {
140 pub(crate) hostname: Option<String>,
141 pub(crate) start: Option<DateTime<Utc>>,
142 pub(crate) end: Option<DateTime<Utc>>,
143}
144
145impl MetricsFilter {
146 /// Creates a new `MetricsFilter` used for filtering diagnostic data.
147 ///
148 /// The `MetricsFilter` enables filtering the data based on the following
149 /// parameters:
150 ///
151 /// * `hostname` - if set, selects the data belonging for
152 /// the specified hostname;
153 /// * `start` - if set, selects the data starting at the specified timestamp;
154 /// * `end` - if set, selects the data up until the specified timestamp.
155 pub fn new(
156 hostname: Option<String>,
157 start: Option<DateTime<Utc>>,
158 end: Option<DateTime<Utc>>,
159 ) -> Self {
160 Self {
161 hostname,
162 start,
163 end,
164 }
165 }
166}