<div dir="ltr">Cross-posted from <a href="https://www.reddit.com/r/haskell/comments/64ymup/rfc_handling_marginally_bad_data_via_logging/">https://www.reddit.com/r/haskell/comments/64ymup/rfc_handling_marginally_bad_data_via_logging/</a><div><br></div><div>Hi Everyone,</div><div><br></div><div>I would like to hear some  perspectives from people who have more experience in handling production code in Haskell.</div><div><br></div><div><div>SCENARIO: You're loading data from a DB (or any other external source) and are expecting certain fields to be present. You end-up loading a record/row which has all the strictly necessary fields, but a not-so-necessary field is missing. Example: loading a full name, stored as the following HSTORE in PG: </div><div><br></div><div>    {'title' => '...', 'first_name' => '...', 'last_name' => '...'} </div><div><br></div><div>For whatever legacy reasons, there is a possibility that some records may not have the title field, or may not have the last_name field. Now, the skies are not going to fall if you display the name with some components missing, so, you don't want to throw an error and terminate the entire operation. It's a "soft error" which you want to log, and proceed with a default value.</div><div><br></div><div>OPTION 1: Use unsafePerformIO to avoid making an otherwise pure function, "impure", i.e. </div><div><br></div><div>    parseName :: HStore -> FullName -- uses unsafePerformIO to log soft-errors</div><div><br></div><div>OPTION 2: Put the data transformation function in IO or the app-wide monad AppM because it will call the logging function, i.e. </div><div><br></div><div>    parseName :: HStore -> AppM FullName</div><div><br></div><div><br></div><div>OPTION 3: Use a wrapper over Writer monad, called ErrorCollector, that forces the calling function to log while accessing the underlying value, i.e.</div><div><br></div><div>    parseName :: HStore -> ErrorCollector FullName </div><div>    logErrorAndExtract extraLoggingContext (parseName hstoreVal)</div><div><br></div><div><br></div><div>THOUGHTS:</div><div><br></div><div>-- The downside of Option 1 is that (a) it's unsafe, and (b) the log won't have surrounding context, for example it won't have the primary key of the row that was being loaded within which this error occurred.</div><div>-- The downside of Option 2 is that it introduces AppM into the function signature, and even that log won't have enough surrounding context to help in debugging.</div><div>-- The downside of Option 3 is that it pushes some logging responsibility to the calling functions, but gives the ability to put extra context when a soft-error occurs.</div><div><br></div><div>How do others deal with this problem?<br></div></div><div><br></div><div>-- Saurabh.</div></div>