Skip to content

Commit d8d85cc

Browse files
refactor: update get_logs implementation to return logs as a vector and remove LogOutputStream (#53)
* refactor: update get_logs implementation to return logs as a vector and remove LogOutputStream - Changed `get_logs` method to return a `Result<Vec<LogOutput>, GetLogsError>` instead of a stream. - Updated example usage in `get_logs.rs` to reflect the new return type. - Removed the `LogOutputStream` struct and its associated tests as it is no longer needed. - Adjusted `LogsOptions` to disable the follow option by default and updated related tests accordingly. * chore: ran formatting * chore: removed unused dependency
1 parent b625a85 commit d8d85cc

File tree

9 files changed

+56
-198
lines changed

9 files changed

+56
-198
lines changed

Cargo.lock

Lines changed: 0 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ bytes = "1.10"
3636
chrono = "0.4.42"
3737
futures-util = "0.3.31"
3838
maplit = "1.0.2"
39-
pin-project = "1.1.10"
4039
rand = "0.9.2"
4140
semver = "1.0.27"
4241
serde = { version = "1.0.228", features = ["derive"], optional = true }

LICENSE-3RD-PARTY.txt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ THIRD PARTY LICENSES
44
This file lists the licenses of the projects used in atlas-local-lib.
55

66
OVERVIEW OF LICENSES:
7-
- Apache License 2.0 (119 dependencies)
7+
- Apache License 2.0 (117 dependencies)
88
- MIT License (21 dependencies)
99
- Unicode License v3 (19 dependencies)
1010

@@ -3631,9 +3631,7 @@ limitations under the License.
36313631
- bollard-stubs 1.49.1-rc.28.4.0 (https://crates.io/crates/bollard-stubs)
36323632
- itoa 1.0.15 (https://github.com/dtolnay/itoa)
36333633
- libc 0.2.175 (https://github.com/rust-lang/libc)
3634-
- pin-project-internal 1.1.10 (https://github.com/taiki-e/pin-project)
36353634
- pin-project-lite 0.2.16 (https://github.com/taiki-e/pin-project-lite)
3636-
- pin-project 1.1.10 (https://github.com/taiki-e/pin-project)
36373635
- proc-macro2 1.0.101 (https://github.com/dtolnay/proc-macro2)
36383636
- quote 1.0.40 (https://github.com/dtolnay/quote)
36393637
- r-efi 5.3.0 (https://github.com/r-efi/r-efi)

examples/get_logs.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use atlas_local::{
44
models::{CreateDeploymentOptions, LogsOptions, Tail},
55
};
66
use bollard::Docker;
7-
use futures_util::StreamExt;
87

98
#[tokio::main]
109
async fn main() -> Result<()> {
@@ -26,15 +25,15 @@ async fn main() -> Result<()> {
2625
.build();
2726

2827
// Get logs from the deployment
29-
let mut logs = client.get_logs(&deployment.container_id, Some(log_options));
28+
let logs = client
29+
.get_logs(&deployment.container_id, Some(log_options))
30+
.await
31+
.context("getting logs")?;
3032

3133
println!("Container logs:");
32-
while let Some(log_result) = logs.next().await {
33-
match log_result {
34-
// Use print! instead of println! because logs contain new line characters
35-
Ok(log) => print!("{}", log),
36-
Err(e) => eprintln!("Error reading log: {}", e),
37-
}
34+
for log in logs {
35+
// Use print! instead of println! because logs contain new line characters
36+
print!("{}", log);
3837
}
3938

4039
Ok(())

src/client/get_logs.rs

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use crate::{
22
client::Client,
33
docker::DockerLogContainer,
4-
models::{LogOutputStream, LogsOptions},
4+
models::{LogOutput, LogsOptions},
55
};
6+
use futures_util::{StreamExt, pin_mut};
67

78
#[derive(Debug, thiserror::Error)]
89
pub enum GetLogsError {
@@ -16,11 +17,11 @@ impl<D: DockerLogContainer> Client<D> {
1617
/// # Arguments
1718
///
1819
/// * `container_id_or_name` - The ID or name of the container to get logs from.
19-
/// * `options` - Optional logging options (e.g., follow, tail, timestamps, etc.)
20+
/// * `options` - Optional logging options (e.g., tail, timestamps, etc.)
2021
///
2122
/// # Returns
2223
///
23-
/// A [`LogOutputStream`] that yields log entries from the container.
24+
/// A `Result` containing a vector of log entries from the container, or an error if the logs could not be retrieved.
2425
///
2526
/// # Examples
2627
///
@@ -34,13 +35,22 @@ impl<D: DockerLogContainer> Client<D> {
3435
#[doc = "```rust,no_run"]
3536
#[doc = include_str!("../../examples/get_logs.rs")]
3637
#[doc = "```"]
37-
pub fn get_logs<'a>(
38-
&'a self,
39-
container_id_or_name: &'a str,
38+
pub async fn get_logs(
39+
&self,
40+
container_id_or_name: &str,
4041
options: Option<LogsOptions>,
41-
) -> LogOutputStream<'a> {
42+
) -> Result<Vec<LogOutput>, GetLogsError> {
4243
let bollard_options = options.map(bollard::query_parameters::LogsOptions::from);
43-
LogOutputStream::new(self.docker.logs(container_id_or_name, bollard_options))
44+
let stream = self.docker.logs(container_id_or_name, bollard_options);
45+
pin_mut!(stream);
46+
47+
let mut logs = Vec::new();
48+
while let Some(result) = stream.next().await {
49+
let log_output = result.map_err(GetLogsError::ContainerLogs)?;
50+
logs.push(LogOutput::from(log_output));
51+
}
52+
53+
Ok(logs)
4454
}
4555
}
4656

@@ -89,15 +99,15 @@ mod tests {
8999
let options = LogsOptions::builder().stdout(true).stderr(true).build();
90100

91101
// Act
92-
let logs: Vec<_> = client
102+
let logs = client
93103
.get_logs("test-container", Some(options))
94-
.collect()
95-
.await;
104+
.await
105+
.expect("get_logs should succeed");
96106

97107
// Assert
98108
assert_eq!(logs.len(), 2);
99-
assert!(logs[0].is_ok());
100-
assert!(logs[1].is_ok());
109+
assert!(logs[0].is_stdout());
110+
assert!(logs[1].is_stdout());
101111
}
102112

103113
#[tokio::test]
@@ -124,16 +134,12 @@ mod tests {
124134
let client = Client::new(mock_docker);
125135

126136
// Act
127-
let logs: Vec<_> = client
128-
.get_logs("nonexistent-container", None)
129-
.collect()
130-
.await;
137+
let result = client.get_logs("nonexistent-container", None).await;
131138

132139
// Assert
133-
assert_eq!(logs.len(), 1);
134-
assert!(logs[0].is_err());
140+
assert!(result.is_err());
135141
assert!(matches!(
136-
logs[0].as_ref().unwrap_err(),
142+
result.as_ref().unwrap_err(),
137143
GetLogsError::ContainerLogs(_)
138144
));
139145
}
@@ -166,34 +172,21 @@ mod tests {
166172
let options = LogsOptions::builder().stdout(true).stderr(true).build();
167173

168174
// Act
169-
let logs: Vec<_> = client
175+
let logs = client
170176
.get_logs("test-container", Some(options))
171-
.collect()
172-
.await;
177+
.await
178+
.expect("get_logs should succeed");
173179

174180
// Assert
175181
assert_eq!(logs.len(), 3);
176-
assert!(logs.iter().all(|log| log.is_ok()));
177182

178183
// Verify first is stdout
179-
if let Ok(log) = &logs[0] {
180-
assert!(log.is_stdout());
181-
} else {
182-
panic!("Expected stdout log");
183-
}
184+
assert!(logs[0].is_stdout());
184185

185186
// Verify second is stderr
186-
if let Ok(log) = &logs[1] {
187-
assert!(log.is_stderr());
188-
} else {
189-
panic!("Expected stderr log");
190-
}
187+
assert!(logs[1].is_stderr());
191188

192189
// Verify third is stdout
193-
if let Ok(log) = &logs[2] {
194-
assert!(log.is_stdout());
195-
} else {
196-
panic!("Expected stdout log");
197-
}
190+
assert!(logs[2].is_stdout());
198191
}
199192
}

src/models/log_output_stream.rs

Lines changed: 0 additions & 105 deletions
This file was deleted.

src/models/logs_options.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl std::fmt::Display for Tail {
5858
///
5959
/// This struct provides configuration options for fetching container logs,
6060
/// including filtering by stream type (stdout/stderr), limiting the number
61-
/// of lines, adding timestamps, and following the log stream in real-time.
61+
/// of lines, and adding timestamps.
6262
///
6363
/// # Examples
6464
///
@@ -90,9 +90,6 @@ pub struct LogsOptions {
9090
/// Add timestamps to every log line
9191
#[builder(default = false)]
9292
pub timestamps: bool,
93-
/// Follow the log stream (keep connection open for new logs)
94-
#[builder(default = false)]
95-
pub follow: bool,
9693
/// Return this number of lines at the tail of the logs
9794
#[builder(default, setter(strip_option, into))]
9895
pub tail: Option<Tail>,
@@ -101,7 +98,7 @@ pub struct LogsOptions {
10198
impl From<LogsOptions> for bollard::query_parameters::LogsOptions {
10299
fn from(options: LogsOptions) -> Self {
103100
bollard::query_parameters::LogsOptions {
104-
follow: options.follow,
101+
follow: false,
105102
stdout: options.stdout,
106103
stderr: options.stderr,
107104
since: options.since.map(|t| t.timestamp() as i32).unwrap_or(0),
@@ -124,7 +121,6 @@ mod tests {
124121
.since(DateTime::from_timestamp(1234567890, 0).unwrap())
125122
.until(DateTime::from_timestamp(1234567900, 0).unwrap())
126123
.timestamps(true)
127-
.follow(false)
128124
.tail(Tail::Number(100))
129125
.build();
130126

@@ -201,7 +197,6 @@ mod tests {
201197
since: None,
202198
until: None,
203199
timestamps: false,
204-
follow: false,
205200
tail: Some(Tail::All),
206201
};
207202

src/models/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ mod deployment;
44
mod environment_variables;
55
mod labels;
66
mod log_output;
7-
mod log_output_stream;
87
mod logs_options;
98
mod mongodb_type;
109
mod port_binding;
@@ -16,7 +15,6 @@ pub use deployment::*;
1615
pub use environment_variables::*;
1716
pub use labels::*;
1817
pub use log_output::*;
19-
pub use log_output_stream::*;
2018
pub use logs_options::*;
2119
pub use mongodb_type::*;
2220
pub use port_binding::*;

0 commit comments

Comments
 (0)