1+ use std:: borrow:: Cow ;
2+
13use anyhow:: Result ;
24use clap:: Args ;
35
@@ -20,6 +22,11 @@ fn validate_max_rows(s: &str) -> Result<usize> {
2022 }
2123}
2224
25+ /// Check if a project identifier is numeric (project ID) or string (project slug)
26+ fn is_numeric_project_id ( project : & str ) -> bool {
27+ !project. is_empty ( ) && project. chars ( ) . all ( |c| c. is_ascii_digit ( ) )
28+ }
29+
2330/// Fields to fetch from the logs API
2431const LOG_FIELDS : & [ & str ] = & [
2532 "sentry.item_id" ,
@@ -37,7 +44,7 @@ pub(super) struct ListLogsArgs {
3744 org : Option < String > ,
3845
3946 #[ arg( short = 'p' , long = "project" ) ]
40- #[ arg( help = "The project ID (slug not supported) ." ) ]
47+ #[ arg( help = "The project ID or slug ." ) ]
4148 project : Option < String > ,
4249
4350 #[ arg( long = "max-rows" , default_value = "100" ) ]
@@ -70,29 +77,36 @@ pub(super) fn execute(args: ListLogsArgs) -> Result<()> {
7077
7178 let api = Api :: current ( ) ;
7279
73- let query = if args. query . is_empty ( ) {
74- None
80+ // Pass numeric project IDs as project parameter, otherwise pass as query string -
81+ // current API does not support project slugs as a parameter.
82+ let ( query, project_id) = if is_numeric_project_id ( project) {
83+ ( Cow :: Borrowed ( & args. query ) , Some ( project. as_str ( ) ) )
7584 } else {
76- Some ( args. query . as_str ( ) )
85+ let query = if args. query . is_empty ( ) {
86+ format ! ( "project:{project}" )
87+ } else {
88+ format ! ( "project:{project} {}" , args. query)
89+ } ;
90+ ( Cow :: Owned ( query) , None )
7791 } ;
7892
79- execute_single_fetch ( & api, org, project , query, LOG_FIELDS , & args)
93+ execute_single_fetch ( & api, org, project_id , & query, LOG_FIELDS , & args)
8094}
8195
8296fn execute_single_fetch (
8397 api : & Api ,
8498 org : & str ,
85- project : & str ,
86- query : Option < & str > ,
99+ project_id : Option < & str > ,
100+ query : & str ,
87101 fields : & [ & str ] ,
88102 args : & ListLogsArgs ,
89103) -> Result < ( ) > {
90104 let options = FetchEventsOptions {
91105 dataset : Dataset :: Logs ,
92106 fields,
93- project_id : project ,
107+ project_id,
94108 cursor : None ,
95- query : query . unwrap_or ( "" ) ,
109+ query,
96110 per_page : args. max_rows ,
97111 stats_period : "90d" ,
98112 sort : "-timestamp" ,
@@ -128,3 +142,34 @@ fn execute_single_fetch(
128142
129143 Ok ( ( ) )
130144}
145+
146+ #[ cfg( test) ]
147+ mod tests {
148+ use super :: * ;
149+
150+ #[ test]
151+ fn test_is_numeric_project_id_purely_numeric ( ) {
152+ assert ! ( is_numeric_project_id( "123456" ) ) ;
153+ assert ! ( is_numeric_project_id( "1" ) ) ;
154+ assert ! ( is_numeric_project_id( "999999999" ) ) ;
155+ }
156+
157+ #[ test]
158+ fn test_is_numeric_project_id_alphanumeric ( ) {
159+ assert ! ( !is_numeric_project_id( "abc123" ) ) ;
160+ assert ! ( !is_numeric_project_id( "123abc" ) ) ;
161+ assert ! ( !is_numeric_project_id( "my-project" ) ) ;
162+ }
163+
164+ #[ test]
165+ fn test_is_numeric_project_id_numeric_with_dash ( ) {
166+ assert ! ( !is_numeric_project_id( "123-45" ) ) ;
167+ assert ! ( !is_numeric_project_id( "1-2-3" ) ) ;
168+ assert ! ( !is_numeric_project_id( "999-888" ) ) ;
169+ }
170+
171+ #[ test]
172+ fn test_is_numeric_project_id_empty_string ( ) {
173+ assert ! ( !is_numeric_project_id( "" ) ) ;
174+ }
175+ }
0 commit comments