diff --git a/bin/core/src/api/read/deployment.rs b/bin/core/src/api/read/deployment.rs index 4e94fcb95..0db78b3a8 100644 --- a/bin/core/src/api/read/deployment.rs +++ b/bin/core/src/api/read/deployment.rs @@ -130,7 +130,11 @@ impl Resolve for State { impl Resolve for State { async fn resolve( &self, - SearchLog { deployment, terms }: SearchLog, + SearchLog { + deployment, + terms, + combinator, + }: SearchLog, user: User, ) -> anyhow::Result { let Deployment { @@ -148,7 +152,11 @@ impl Resolve for State { } let server = Server::get_resource(&server_id).await?; periphery_client(&server)? - .request(api::container::GetContainerLogSearch { name, terms }) + .request(api::container::GetContainerLogSearch { + name, + terms, + combinator, + }) .await .context("failed at call to periphery") } diff --git a/bin/periphery/src/api/container.rs b/bin/periphery/src/api/container.rs index 78d97b8da..165f248ea 100644 --- a/bin/periphery/src/api/container.rs +++ b/bin/periphery/src/api/container.rs @@ -58,8 +58,12 @@ impl Resolve for State { _: (), ) -> anyhow::Result { Ok( - docker::container::container_log_search(&req.name, &req.terms) - .await, + docker::container::container_log_search( + &req.name, + &req.terms, + req.combinator, + ) + .await, ) } } diff --git a/bin/periphery/src/helpers/docker/container.rs b/bin/periphery/src/helpers/docker/container.rs index 5a630ecbd..57eeb3e37 100644 --- a/bin/periphery/src/helpers/docker/container.rs +++ b/bin/periphery/src/helpers/docker/container.rs @@ -6,7 +6,7 @@ use monitor_client::entities::{ }, optional_string, to_monitor_name, update::Log, - EnvironmentVar, + EnvironmentVar, SearchCombinator, }; use run_command::async_run_command; use serror::serialize_error_pretty; @@ -31,11 +31,18 @@ pub async fn container_log(container_name: &str, tail: u64) -> Log { pub async fn container_log_search( container_name: &str, terms: &[String], + combinator: SearchCombinator, ) -> Log { - let command = format!( - "docker logs {container_name} --tail 5000 | grep -E '{}'", - terms.join("|") - ); + let grep = match combinator { + SearchCombinator::Or => { + format!("grep -E '{}'", terms.join("|")) + } + SearchCombinator::And => { + format!("grep -P '^(?=.*{})'", terms.join(")(?=.*")) + } + }; + let command = + format!("docker logs {container_name} --tail 5000 |& {grep}"); run_monitor_command("get container log grep", command).await } diff --git a/client/core/rs/src/api/read/deployment.rs b/client/core/rs/src/api/read/deployment.rs index 6e02abbf8..cceef369d 100644 --- a/client/core/rs/src/api/read/deployment.rs +++ b/client/core/rs/src/api/read/deployment.rs @@ -7,9 +7,7 @@ use crate::entities::{ deployment::{ Deployment, DeploymentActionState, DeploymentListItem, DeploymentQuery, DockerContainerState, DockerContainerStats, - }, - update::Log, - I64, U64, + }, update::Log, SearchCombinator, I64, U64 }; use super::MonitorReadRequest; @@ -104,6 +102,8 @@ pub struct SearchLog { #[serde(alias = "id", alias = "name")] pub deployment: String, pub terms: Vec, + #[serde(default)] + pub combinator: SearchCombinator, } #[typeshare] diff --git a/client/core/rs/src/entities/mod.rs b/client/core/rs/src/entities/mod.rs index 1e4b81ac2..2743517d1 100644 --- a/client/core/rs/src/entities/mod.rs +++ b/client/core/rs/src/entities/mod.rs @@ -379,3 +379,23 @@ pub enum Operation { UpdateUserPermissions, UpdateUserPermissionsOnTarget, } + +#[typeshare] +#[derive( + Serialize, + Deserialize, + Debug, + Default, + Display, + EnumString, + PartialEq, + Hash, + Eq, + Clone, + Copy, +)] +pub enum SearchCombinator { + #[default] + Or, + And, +} diff --git a/client/core/ts/src/types.ts b/client/core/ts/src/types.ts index 1ba0f6fbe..81702b0d0 100644 --- a/client/core/ts/src/types.ts +++ b/client/core/ts/src/types.ts @@ -1166,10 +1166,16 @@ export interface GetLog { tail: U64; } +export enum SearchCombinator { + Or = "Or", + And = "And", +} + export interface SearchLog { /** Id or name */ deployment: string; terms: string[]; + combinator?: SearchCombinator; } export interface GetDeployedVersion { diff --git a/client/periphery/rs/src/api/container.rs b/client/periphery/rs/src/api/container.rs index 0e43a6eb4..c0c176eff 100644 --- a/client/periphery/rs/src/api/container.rs +++ b/client/periphery/rs/src/api/container.rs @@ -4,6 +4,7 @@ use monitor_client::entities::{ TerminationSignal, }, update::Log, + SearchCombinator, }; use resolver_api::derive::Request; use serde::{Deserialize, Serialize}; @@ -33,6 +34,8 @@ fn default_tail() -> u64 { pub struct GetContainerLogSearch { pub name: String, pub terms: Vec, + #[serde(default)] + pub combinator: SearchCombinator, } // diff --git a/frontend/src/components/resources/deployment/logs.tsx b/frontend/src/components/resources/deployment/logs.tsx index d55eec9ce..f8eaecd54 100644 --- a/frontend/src/components/resources/deployment/logs.tsx +++ b/frontend/src/components/resources/deployment/logs.tsx @@ -70,6 +70,7 @@ const DeploymentLogsInner = ({ id }: { id: string }) => { onKeyDown={(e) => { if (e.key === "Enter") updateSearch(); }} + className="w-[300px]" />