@@ -46,6 +46,10 @@ pub struct SniffConfig {
4646 pub ai_model : String ,
4747 /// Database URL
4848 pub database_url : String ,
49+ /// Slack webhook URL for alert notifications
50+ pub slack_webhook : Option < String > ,
51+ /// Generic webhook URL for alert notifications
52+ pub webhook_url : Option < String > ,
4953}
5054
5155impl SniffConfig {
@@ -59,6 +63,7 @@ impl SniffConfig {
5963 ai_provider_arg : Option < & str > ,
6064 ai_model_arg : Option < & str > ,
6165 ai_api_url_arg : Option < & str > ,
66+ slack_webhook_arg : Option < & str > ,
6267 ) -> Self {
6368 let env_sources = env:: var ( "STACKDOG_LOG_SOURCES" ) . unwrap_or_default ( ) ;
6469 let mut extra_sources: Vec < String > = env_sources
@@ -116,6 +121,10 @@ impl SniffConfig {
116121 . unwrap_or_else ( || "llama3" . into ( ) ) ,
117122 database_url : env:: var ( "DATABASE_URL" )
118123 . unwrap_or_else ( |_| "./stackdog.db" . into ( ) ) ,
124+ slack_webhook : slack_webhook_arg
125+ . map ( |s| s. to_string ( ) )
126+ . or_else ( || env:: var ( "STACKDOG_SLACK_WEBHOOK_URL" ) . ok ( ) ) ,
127+ webhook_url : env:: var ( "STACKDOG_WEBHOOK_URL" ) . ok ( ) ,
119128 }
120129 }
121130}
@@ -136,6 +145,8 @@ mod tests {
136145 env:: remove_var ( "STACKDOG_AI_MODEL" ) ;
137146 env:: remove_var ( "STACKDOG_SNIFF_OUTPUT_DIR" ) ;
138147 env:: remove_var ( "STACKDOG_SNIFF_INTERVAL" ) ;
148+ env:: remove_var ( "STACKDOG_SLACK_WEBHOOK_URL" ) ;
149+ env:: remove_var ( "STACKDOG_WEBHOOK_URL" ) ;
139150 }
140151
141152 #[ test]
@@ -152,7 +163,7 @@ mod tests {
152163 let _lock = ENV_MUTEX . lock ( ) . unwrap ( ) ;
153164 clear_sniff_env ( ) ;
154165
155- let config = SniffConfig :: from_env_and_args ( false , false , "./stackdog-logs/" , None , 30 , None , None , None ) ;
166+ let config = SniffConfig :: from_env_and_args ( false , false , "./stackdog-logs/" , None , 30 , None , None , None , None ) ;
156167 assert ! ( !config. once) ;
157168 assert ! ( !config. consume) ;
158169 assert_eq ! ( config. output_dir, PathBuf :: from( "./stackdog-logs/" ) ) ;
@@ -170,7 +181,7 @@ mod tests {
170181 clear_sniff_env ( ) ;
171182
172183 let config = SniffConfig :: from_env_and_args (
173- true , true , "/tmp/output/" , Some ( "/var/log/app.log" ) , 60 , Some ( "candle" ) , None , None ,
184+ true , true , "/tmp/output/" , Some ( "/var/log/app.log" ) , 60 , Some ( "candle" ) , None , None , None ,
174185 ) ;
175186
176187 assert ! ( config. once) ;
@@ -188,7 +199,7 @@ mod tests {
188199 env:: set_var ( "STACKDOG_LOG_SOURCES" , "/var/log/syslog,/var/log/auth.log" ) ;
189200
190201 let config = SniffConfig :: from_env_and_args (
191- false , false , "./stackdog-logs/" , Some ( "/var/log/app.log,/var/log/syslog" ) , 30 , None , None , None ,
202+ false , false , "./stackdog-logs/" , Some ( "/var/log/app.log,/var/log/syslog" ) , 30 , None , None , None , None ,
192203 ) ;
193204
194205 assert ! ( config. extra_sources. contains( & "/var/log/syslog" . to_string( ) ) ) ;
@@ -209,7 +220,7 @@ mod tests {
209220 env:: set_var ( "STACKDOG_SNIFF_INTERVAL" , "45" ) ;
210221 env:: set_var ( "STACKDOG_SNIFF_OUTPUT_DIR" , "/data/logs/" ) ;
211222
212- let config = SniffConfig :: from_env_and_args ( false , false , "./stackdog-logs/" , None , 30 , None , None , None ) ;
223+ let config = SniffConfig :: from_env_and_args ( false , false , "./stackdog-logs/" , None , 30 , None , None , None , None ) ;
213224 assert_eq ! ( config. ai_api_url, "https://api.openai.com/v1" ) ;
214225 assert_eq ! ( config. ai_api_key, Some ( "sk-test123" . into( ) ) ) ;
215226 assert_eq ! ( config. ai_model, "gpt-4o-mini" ) ;
@@ -226,7 +237,7 @@ mod tests {
226237
227238 let config = SniffConfig :: from_env_and_args (
228239 false , false , "./stackdog-logs/" , None , 30 ,
229- Some ( "ollama" ) , Some ( "qwen2.5-coder:latest" ) , None ,
240+ Some ( "ollama" ) , Some ( "qwen2.5-coder:latest" ) , None , None ,
230241 ) ;
231242 // "ollama" maps to OpenAi internally (same API protocol)
232243 assert_eq ! ( config. ai_provider, AiProvider :: OpenAi ) ;
@@ -245,12 +256,56 @@ mod tests {
245256
246257 let config = SniffConfig :: from_env_and_args (
247258 false , false , "./stackdog-logs/" , None , 30 ,
248- None , Some ( "llama3" ) , Some ( "http://localhost:11434/v1" ) ,
259+ None , Some ( "llama3" ) , Some ( "http://localhost:11434/v1" ) , None ,
249260 ) ;
250261 // CLI args take priority over env vars
251262 assert_eq ! ( config. ai_model, "llama3" ) ;
252263 assert_eq ! ( config. ai_api_url, "http://localhost:11434/v1" ) ;
253264
254265 clear_sniff_env ( ) ;
255266 }
267+
268+ #[ test]
269+ fn test_slack_webhook_from_cli ( ) {
270+ let _lock = ENV_MUTEX . lock ( ) . unwrap ( ) ;
271+ clear_sniff_env ( ) ;
272+
273+ let config = SniffConfig :: from_env_and_args (
274+ false , false , "./stackdog-logs/" , None , 30 ,
275+ None , None , None , Some ( "https://hooks.slack.com/services/T/B/xxx" ) ,
276+ ) ;
277+ assert_eq ! ( config. slack_webhook. as_deref( ) , Some ( "https://hooks.slack.com/services/T/B/xxx" ) ) ;
278+
279+ clear_sniff_env ( ) ;
280+ }
281+
282+ #[ test]
283+ fn test_slack_webhook_from_env ( ) {
284+ let _lock = ENV_MUTEX . lock ( ) . unwrap ( ) ;
285+ clear_sniff_env ( ) ;
286+ env:: set_var ( "STACKDOG_SLACK_WEBHOOK_URL" , "https://hooks.slack.com/services/T/B/env" ) ;
287+
288+ let config = SniffConfig :: from_env_and_args (
289+ false , false , "./stackdog-logs/" , None , 30 ,
290+ None , None , None , None ,
291+ ) ;
292+ assert_eq ! ( config. slack_webhook. as_deref( ) , Some ( "https://hooks.slack.com/services/T/B/env" ) ) ;
293+
294+ clear_sniff_env ( ) ;
295+ }
296+
297+ #[ test]
298+ fn test_slack_webhook_cli_overrides_env ( ) {
299+ let _lock = ENV_MUTEX . lock ( ) . unwrap ( ) ;
300+ clear_sniff_env ( ) ;
301+ env:: set_var ( "STACKDOG_SLACK_WEBHOOK_URL" , "https://hooks.slack.com/services/T/B/env" ) ;
302+
303+ let config = SniffConfig :: from_env_and_args (
304+ false , false , "./stackdog-logs/" , None , 30 ,
305+ None , None , None , Some ( "https://hooks.slack.com/services/T/B/cli" ) ,
306+ ) ;
307+ assert_eq ! ( config. slack_webhook. as_deref( ) , Some ( "https://hooks.slack.com/services/T/B/cli" ) ) ;
308+
309+ clear_sniff_env ( ) ;
310+ }
256311}
0 commit comments