Skip to content

Commit

Permalink
Merge pull request #119 from navicore/logs
Browse files Browse the repository at this point in the history
Logs
  • Loading branch information
navicore committed Mar 4, 2024
2 parents 5abbb09 + 5443354 commit a653a9c
Show file tree
Hide file tree
Showing 9 changed files with 452 additions and 6 deletions.
65 changes: 60 additions & 5 deletions src/k8s/containers.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::k8s::utils::format_label_selector;
use crate::tui::data::{Container, ContainerEnvVar, ContainerMount};
use crate::tui::data::{Container, ContainerEnvVar, ContainerMount, LogRec};
use k8s_openapi::api::core::v1::ContainerPort;
use k8s_openapi::api::core::v1::Pod;
use kube::api::ListParams;
use kube::api::ObjectList;
use kube::{Api, Client};
use kube::{
api::{Api, ListParams, LogParams, ObjectList},
Client, ResourceExt,
};
use std::collections::BTreeMap;

fn format_ports(ports: Option<Vec<ContainerPort>>) -> String {
Expand All @@ -27,6 +28,7 @@ fn format_ports(ports: Option<Vec<ContainerPort>>) -> String {
///
/// Will return `Err` if data can not be retrieved from k8s cluster api
#[allow(clippy::significant_drop_tightening)]
#[allow(clippy::too_many_lines)]
pub async fn list(
selector: BTreeMap<String, String>,
pod_name: String,
Expand All @@ -50,7 +52,8 @@ pub async fn list(
.unwrap_or_default();

if let Some(name) = pod.metadata.name {
if name == pod_name {
let container_selectors = pod.metadata.labels.as_ref().map(std::clone::Clone::clone);
if name == pod_name.clone() {
if let Some(spec) = pod.spec {
for container in spec.containers {
let image = container.image.unwrap_or_else(|| "unknown".to_string());
Expand Down Expand Up @@ -89,6 +92,8 @@ pub async fn list(
ports,
mounts,
envvars,
selectors: container_selectors.clone(),
pod_name: pod_name.clone(),
};
container_vec.push(c);
}
Expand Down Expand Up @@ -130,6 +135,8 @@ pub async fn list(
ports: String::new(),
mounts,
envvars,
selectors: container_selectors.clone(),
pod_name: pod_name.clone(),
};
container_vec.push(c);
}
Expand All @@ -141,3 +148,51 @@ pub async fn list(

Ok(container_vec)
}

/// # Errors
///
/// Will return `Err` if data can not be retrieved from k8s cluster api
#[allow(clippy::significant_drop_tightening)]
pub async fn logs(
selector: BTreeMap<String, String>,
pod_name: String,
container_name: String,
) -> Result<Vec<LogRec>, kube::Error> {
let client = Client::try_default().await?;
let pods: Api<Pod> = Api::default_namespaced(client);

let label_selector = format_label_selector(&selector);

let lp = ListParams::default().labels(&label_selector);

let pod_list: ObjectList<Pod> = pods.list(&lp).await?;

let mut log_vec = Vec::new();

// Find the pod by name
for pod in pod_list
.items
.into_iter()
.filter(|pod| pod.name_any() == pod_name)
{
let log_params = LogParams {
container: Some(container_name.clone()),
tail_lines: Some(100), // Adjust based on how many lines you want
..Default::default()
};

// Fetch logs for the specified container
let logs = pods.logs(&pod.name_any(), &log_params).await?;

// Parse and map logs to Vec<Log>
logs.lines().for_each(|line| {
log_vec.push(LogRec {
datetime: String::new(), //need a smart parser that can figure out the format
level: String::new(),
message: line.to_string(),
});
});
}

Ok(log_vec)
}
18 changes: 17 additions & 1 deletion src/tui/container_app/app.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::tui::container_app;
use crate::tui::data::{container_constraint_len_calculator, Container};
use crate::tui::log_app;
use crate::tui::stream::Message;
use crate::tui::style::{TableColors, ITEM_HEIGHT, PALETTES};
use crate::tui::table_ui::TuiTableState;
Expand Down Expand Up @@ -90,7 +91,7 @@ impl AppBehavior for container_app::app::App {
match event {
Message::Key(Event::Key(key)) => {
if key.kind == KeyEventKind::Press {
use KeyCode::{Char, Down, Esc, Up};
use KeyCode::{Char, Down, Enter, Esc, Up};
match key.code {
Char('q') | Esc => {
app_holder = None;
Expand All @@ -114,6 +115,21 @@ impl AppBehavior for container_app::app::App {
Char('b' | 'B') if key.modifiers.contains(KeyModifiers::CONTROL) => {
self.page_backward();
}
Enter => {
if let Some(selection) = self.get_selected_item() {
if let Some(selectors) = selection.selectors.clone() {
let new_app_holder = Apps::Log {
app: log_app::app::App::new(
selectors,
selection.pod_name.clone(),
selection.name.clone(),
),
};
app_holder = Some(new_app_holder);
}
}
}

_k => {}
}
}
Expand Down
60 changes: 60 additions & 0 deletions src/tui/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ pub struct Container {
pub ports: String,
pub envvars: Vec<ContainerEnvVar>,
pub mounts: Vec<ContainerMount>,
pub selectors: Option<BTreeMap<String, String>>,
pub pod_name: String,
}

impl Filterable for Container {
Expand Down Expand Up @@ -280,6 +282,37 @@ impl Rs {
}
}

#[derive(Eq, PartialEq, Clone, Debug)]
pub struct LogRec {
pub datetime: String,
pub level: String,
pub message: String,
}

impl Filterable for LogRec {
fn filter_by(&self) -> &str {
self.message.as_str()
}
}

impl LogRec {
pub(crate) const fn ref_array(&self) -> [&String; 3] {
[&self.datetime, &self.level, &self.message]
}

pub(crate) fn datetime(&self) -> &str {
&self.datetime
}

pub(crate) fn level(&self) -> &str {
&self.level
}

pub(crate) fn message(&self) -> &str {
&self.message
}
}

#[derive(Clone, Debug)]
pub struct Ingress {
pub name: String,
Expand Down Expand Up @@ -327,6 +360,29 @@ impl Ingress {
}
}

#[allow(clippy::cast_possible_truncation)]
pub fn log_constraint_len_calculator(items: &[LogRec]) -> (u16, u16, u16) {
let datetime_len = items
.iter()
.map(LogRec::datetime)
.map(UnicodeWidthStr::width)
.max()
.unwrap_or(0);
let level_len = items
.iter()
.map(LogRec::level)
.map(UnicodeWidthStr::width)
.max()
.unwrap_or(0);
let message_len = items
.iter()
.map(LogRec::message)
.map(UnicodeWidthStr::width)
.max()
.unwrap_or(0);
(datetime_len as u16, level_len as u16, message_len as u16)
}

#[allow(clippy::cast_possible_truncation)]
pub fn ingress_constraint_len_calculator(items: &[Ingress]) -> (u16, u16, u16, u16, u16) {
let name_len = items
Expand Down Expand Up @@ -553,6 +609,8 @@ mod tests {
ports: "http:1234".to_string(),
envvars: vec![],
mounts: vec![],
selectors: None,
pod_name: "my-pod-1234".to_string(),
},
Container {
name: "replica-923450-987654".to_string(),
Expand All @@ -562,6 +620,8 @@ mod tests {
ports: "http:1234".to_string(),
envvars: vec![],
mounts: vec![],
selectors: None,
pod_name: "my-pod-5678".to_string(),
},
];
let (
Expand Down

0 comments on commit a653a9c

Please sign in to comment.