@@ -19,7 +19,7 @@ Atmos provides `utils.PrintfMessageToTUI` for writing TextUI messages. It always
1919
2020### Trace
2121
22- ** Purpose** : Execution flow tracing and detailed debugging.
22+ ** Purpose** : Execution flow tracing, detailed debugging, and squelched error logging .
2323
2424#### When to Use
2525
@@ -29,6 +29,7 @@ Atmos provides `utils.PrintfMessageToTUI` for writing TextUI messages. It always
2929- Loop iterations in complex algorithms.
3030- Template expansion steps.
3131- Detailed state at each step of multi-stage operations.
32+ - ** Squelched errors** - errors that are intentionally ignored but should be recorded.
3233
3334#### Characteristics
3435
@@ -43,6 +44,9 @@ Atmos provides `utils.PrintfMessageToTUI` for writing TextUI messages. It always
4344- "Entering ProcessStackConfig with stack=dev, component=vpc"
4445- "Template evaluation: input={...}, context={...}, output={...}"
4546- "Cache lookup: key=stack-dev-vpc, found=true, age=2.3s"
47+ - "Failed to close temporary file during cleanup" (squelched error)
48+ - "Failed to remove temporary directory during cleanup" (squelched error)
49+ - "Failed to bind environment variable" (squelched error)
4650
4751---
4852
@@ -183,6 +187,111 @@ Even these examples are borderline - they could arguably be Debug or Warning dep
183187
184188---
185189
190+ ## Squelched Errors
191+
192+ ### What Are Squelched Errors?
193+
194+ Squelched errors are errors that are intentionally ignored because they don't affect the critical path of execution. Common examples include:
195+ - Cleanup operations (removing temporary files, closing file handles)
196+ - Non-critical configuration binding (environment variables, flags)
197+ - Resource unlocking in defer statements
198+ - UI rendering errors
199+
200+ ### When to Squelch Errors
201+
202+ Errors should only be squelched when:
203+ 1 . ** The error is non-critical** - failure doesn't prevent the operation from succeeding
204+ 2 . ** Recovery is impossible** - we're in cleanup/defer code where we can't do anything about the error
205+ 3 . ** The operation is best-effort** - like optional environment variable binding
206+
207+ ### The Golden Rule: Always Log Squelched Errors
208+
209+ Even when errors are intentionally ignored, they ** must** be logged at Trace level. This ensures errors are never truly lost and can be investigated during debugging.
210+
211+ ### Pattern: Squelched Error Logging
212+
213+ ** Wrong** : Silent error squelching
214+ ``` go
215+ // ❌ WRONG: Error is completely lost
216+ _ = os.Remove (tempFile)
217+ _ = file.Close ()
218+ _ = viper.BindEnv (" OPTIONAL_VAR" , " VAR" )
219+ ```
220+
221+ ** Right** : Log squelched errors at Trace level
222+ ``` go
223+ // ✅ CORRECT: Cleanup with trace logging
224+ if err := os.Remove (tempFile); err != nil && !os.IsNotExist (err) {
225+ log.Trace (" Failed to remove temporary file during cleanup" , " error" , err, " file" , tempFile)
226+ }
227+
228+ // ✅ CORRECT: Resource closing with trace logging
229+ if err := file.Close (); err != nil {
230+ log.Trace (" Failed to close file" , " error" , err, " file" , file.Name ())
231+ }
232+
233+ // ✅ CORRECT: Non-critical configuration with trace logging
234+ if err := viper.BindEnv (" OPTIONAL_VAR" , " VAR" ); err != nil {
235+ log.Trace (" Failed to bind environment variable" , " error" , err, " var" , " OPTIONAL_VAR" )
236+ }
237+ ```
238+
239+ ### Special Cases
240+
241+ #### Defer Statements
242+ When squelching errors in defer statements, capture them in a closure:
243+
244+ ``` go
245+ defer func () {
246+ if err := lock.Unlock (); err != nil {
247+ log.Trace (" Failed to unlock" , " error" , err, " path" , lockPath)
248+ }
249+ }()
250+ ```
251+
252+ #### File Existence Checks
253+ When removing files, check for ` os.IsNotExist ` to avoid logging expected conditions:
254+
255+ ``` go
256+ if err := os.Remove (tempFile); err != nil && !os.IsNotExist (err) {
257+ log.Trace (" Failed to remove file" , " error" , err, " file" , tempFile)
258+ }
259+ ```
260+
261+ #### Log File Cleanup
262+ When cleaning up log files, use stderr instead of the logger to avoid recursion:
263+
264+ ``` go
265+ func cleanupLogFile () {
266+ if logFileHandle != nil {
267+ if err := logFileHandle.Sync (); err != nil {
268+ // Don't use logger here as we're cleaning up the log file
269+ fmt.Fprintf (os.Stderr , " Warning: failed to sync log file: %v \n " , err)
270+ }
271+ }
272+ }
273+ ```
274+
275+ ### Why This Matters
276+
277+ 1 . ** Debugging** : When investigating issues, trace logs reveal the full story, including non-critical failures
278+ 2 . ** Metrics** : Aggregate trace logs to identify patterns (e.g., frequent cleanup failures might indicate disk issues)
279+ 3 . ** Auditing** : Complete error trail for compliance and security reviews
280+ 4 . ** Transparency** : No hidden errors - everything is recorded somewhere
281+
282+ ### Common Squelched Error Categories
283+
284+ | Category | Examples | Trace Logging Required |
285+ | ----------| ----------| ----------------------|
286+ | File cleanup | ` os.Remove() ` , ` os.RemoveAll() ` | ✅ Yes |
287+ | Resource closing | ` file.Close() ` , ` client.Close() ` | ✅ Yes |
288+ | Lock operations | ` lock.Unlock() ` | ✅ Yes |
289+ | Config binding | ` viper.BindEnv() ` , ` viper.BindPFlag() ` | ✅ Yes |
290+ | UI rendering | ` fmt.Fprint() ` to UI buffers | ✅ Yes |
291+ | Command help | ` cmd.Help() ` | ✅ Yes |
292+
293+ ---
294+
186295## Common Anti-Patterns
187296
188297### Using Logging as UI
0 commit comments