packages feed

debug-trace-file (empty) → 1.0.0.0

raw patch · 5 files changed

+369/−0 lines, 5 filesdep +basedep +debug-trace-filedep +directory

Dependencies added: base, debug-trace-file, directory, tasty, tasty-golden

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for debug-trace-file++## 1.0.0.0 -- 2023-06-23++* First version. Provides same functions as `Debug.Trace` but allows writing to files.
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2023 Evgenii Akentev++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ debug-trace-file.cabal view
@@ -0,0 +1,39 @@+cabal-version:      3.0+name:               debug-trace-file+version:            1.0.0.0+synopsis:           Like Debug.Trace but writing to files.+description:        Debug.Trace like functions to trace to files.+license:            MIT+license-file:       LICENSE+author:             Evgenii Akentev+maintainer:         i@ak3n.com+category:           Development+build-type:         Simple+extra-doc-files:    CHANGELOG.md++Source-repository head+  type:     git+  location: git@git.ak3n.com:debug-trace-file.git++common warnings+    ghc-options: -Wall++library+    import:           warnings+    exposed-modules:  Debug.Trace.File+    build-depends:    base >= 4.7 && < 5+    hs-source-dirs:   src+    default-language: Haskell2010++test-suite debug-trace-file-test+    import:           warnings+    default-language: Haskell2010+    type:             exitcode-stdio-1.0+    hs-source-dirs:   test+    main-is:          Main.hs+    build-depends:+        base >= 4.7 && < 5,+        directory >= 1.3 && < 1.4,+        tasty >= 1.0 && < 1.5,+        tasty-golden >= 2.3 && < 3,+        debug-trace-file
+ src/Debug/Trace/File.hs view
@@ -0,0 +1,212 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Debug.Trace.File+-- Maintainer  :  i@ak3n.com+--+-- Like Debug.Trace but writing to files (when eventlog is too much).+--+-- The functions use 'appendFile' and append to files by default.+-- The functions with suffix W (like 'traceFileW', 'traceFileIdW', etc) use 'writeFile'.+-----------------------------------------------------------------------------++module Debug.Trace.File+  (+    -- * Tracing to files+    traceFile+  , traceFileW++  , traceFileId+  , traceFileIdW++  , traceFileShow+  , traceFileShowW++  , traceFileShowId+  , traceFileShowIdW++  , traceFileWith+  , traceFileWithW++  , traceFileShowWith+  , traceFileShowWithW++  , traceFileM+  , traceFileMW++  , traceFileShowM+  , traceFileShowMW+  ) where++import Data.Functor (($>))+import System.IO.Unsafe (unsafePerformIO)++-- $setup+-- >>> import Prelude++{-|+The 'traceFile' function appends to the provided file path given as its first argument,+the trace message given as its second argument, before returning the third argument as its result.++For example, this returns the value of @f x@ and outputs the message to "\/tmp\/message".++>>> let x = 123; f = show+>>> traceFile "/tmp/message" ("calling f with x = " ++ show x) (f x)+"123"+>>> readFile "/tmp/message"+"calling f with x = 123\n"++The 'traceFile' function should /only/ be used for debugging, or for monitoring+execution. The function is not referentially transparent: its type indicates+that it is a pure function but it has the side effect of outputting the+trace message.+-}+traceFile :: FilePath -> String -> a -> a+traceFile = traceInternal appendFile++{-|+Like 'traceFile' but uses `writeFile` instead of `appendFile` which means will overwrite the contents of the file.+-}+traceFileW :: FilePath -> String -> a -> a+traceFileW = traceInternal writeFile++{-|+Like 'traceFile' but returns the message instead of a third value.++>>> traceFileId "/tmp/message" "hello"+"hello"+>>> readFile "/tmp/message"+"hello\n"+-}+traceFileId :: FilePath -> String -> String+traceFileId fp a = traceFile fp a a++{-|+Like 'traceFileId' but uses `writeFile` instead of `appendFile` which means will overwrite the contents of the file.+-}+traceFileIdW :: FilePath -> String -> String+traceFileIdW fp a = traceFileW fp a a++{-|+Like 'traceFile', but uses 'show' on the argument to convert it to a 'String'.++This makes it convenient for printing the values of interesting variables or+expressions inside a function. For example here we print the value of the+variables @x@ and @y@:++>>> let f x y = traceFileShow "/tmp/message" (x,y) (x + y) in f (1+2) 5+8+>>> readFile "/tmp/message"+"(3,5)\n"+-}+traceFileShow :: Show a => FilePath -> a -> b -> b+traceFileShow fp = traceFile fp . show++{-|+Like 'traceFileShow' but uses `writeFile` instead of `appendFile` which means will overwrite the contents of the file.+-}+traceFileShowW :: Show a => FilePath -> a -> b -> b+traceFileShowW fp = traceFileW fp . show++{-|+Like 'traceFileShow' but returns the shown value instead of a third value.++>>> traceFileShowId "/tmp/message" (1+2+3, "hello" ++ "world")+(6,"helloworld")+>>> readFile "/tmp/message"+"(6,\"helloworld\")\n"+-}+traceFileShowId :: Show a => FilePath -> a -> a+traceFileShowId fp a = traceFile fp (show a) a++{-|+Like 'traceFileShowId' but uses `writeFile` instead of `appendFile` which means will overwrite the contents of the file.+-}+traceFileShowIdW :: Show a => FilePath -> a -> a+traceFileShowIdW fp a = traceFileW fp (show a) a++{-|+Like 'traceFile', but outputs the result of calling a function on the argument.++>>> traceFileWith "/tmp/message" fst ("hello","world")+("hello","world")+>>> readFile "/tmp/message"+"hello\n"+-}+traceFileWith :: FilePath -> (a -> String) -> a -> a+traceFileWith fp f a = traceFile fp (f a) a++{-|+Like 'traceFileWith' but uses `writeFile` instead of `appendFile` which means will overwrite the contents of the file.+-}+traceFileWithW :: FilePath -> (a -> String) -> a -> a+traceFileWithW fp f a = traceFileW fp (f a) a++{-|+Like 'traceFileWith', but uses 'show' on the result of the function to convert it to+a 'String'.++>>> traceFileShowWith "/tmp/message" length [1,2,3]+[1,2,3]+>>> readFile "/tmp/message"+"3\n"+-}+traceFileShowWith :: Show b => FilePath -> (a -> b) -> a -> a+traceFileShowWith fp f = traceFileWith fp (show . f)++{-|+Like 'traceFileWith' but uses `writeFile` instead of `appendFile` which means will overwrite the contents of the file.+-}+traceFileShowWithW :: Show b => FilePath -> (a -> b) -> a -> a+traceFileShowWithW fp f = traceFileWithW fp (show . f)++{-|+Like 'traceFile' but returning unit in an arbitrary 'Applicative' context. Allows+for convenient use in do-notation.++>>> :{+do+    x <- Just 3+    traceFileM "/tmp/message" ("x: " ++ show x)+    y <- pure 12+    traceFileM "/tmp/message" ("y: " ++ show y)+    pure (x*2 + y)+:}+Just 18+>>> readFile "/tmp/message"+"x: 3\ny: 12\n"+-}+traceFileM :: Applicative f => FilePath -> String -> f ()+traceFileM fp string = traceFile fp string $ pure ()++{-|+Like 'traceFileM' but uses `writeFile` instead of `appendFile` which means will overwrite the contents of the file.+-}+traceFileMW :: Applicative f => FilePath -> String -> f ()+traceFileMW fp string = traceFileW fp string $ pure ()++{-|+Like 'traceFileM', but uses 'show' on the argument to convert it to a 'String'.++>>> :{+do+    x <- Just 3+    traceFileShowM "/tmp/message" x+    y <- pure 12+    traceFileShowM "/tmp/message" y+    pure (x*2 + y)+:}+Just 18+>>> readFile "/tmp/message"+"3\n12\n"+-}+traceFileShowM :: (Show a, Applicative f) => FilePath -> a -> f ()+traceFileShowM fp = traceFileM fp . show++{-|+Like 'traceFileShowM' but uses `writeFile` instead of `appendFile` which means will overwrite the contents of the file.+-}+traceFileShowMW :: (Show a, Applicative f) => FilePath -> a -> f ()+traceFileShowMW fp = traceFileMW fp . show++traceInternal :: (FilePath -> String -> IO ()) -> FilePath -> String -> a -> a+traceInternal writeFunc fp str val = unsafePerformIO $! writeFunc fp (str ++ "\n") $> val
+ test/Main.hs view
@@ -0,0 +1,93 @@+module Main (main) where++import Control.Monad (void)+import Data.List (isSuffixOf)+import Test.Tasty (defaultMain, TestTree, testGroup)+import Test.Tasty.Golden (goldenVsFile)+import System.Directory (getDirectoryContents, removeFile)++import Debug.Trace.File++main :: IO ()+main = do+  -- remove output files+  outputs <- getDirectoryContents "test/Golden/"+  mapM_ removeFile (filter (isSuffixOf ".output") $ map ("test/Golden/" <>) outputs)++  defaultMain goldenTests++goldenTests :: TestTree+goldenTests = testGroup "Debug.Trace.File golden tests"+  [ let fp = "test/Golden/traceFile.output" in+    goldenVsFile "traceFile" "test/Golden/traceFile" fp (pure $! traceFile fp "tracing to file" ())++  , let fp = "test/Golden/traceFile.output" in+    goldenVsFile "traceFileW" "test/Golden/traceFile" fp (pure $! traceFileW fp "tracing to file" ())++  , let fp = "test/Golden/traceFileId.output" in+    goldenVsFile "traceFileId" "test/Golden/traceFileId" fp ((pure $! traceFileId fp "tracing to file") >> pure ())++  , let fp = "test/Golden/traceFileId.output" in+    goldenVsFile "traceFileIdW" "test/Golden/traceFileId" fp ((pure $! traceFileIdW fp "tracing to file") >> pure ())++  , let fp = "test/Golden/traceFileShow.output" in+    goldenVsFile "traceFileShow" "test/Golden/traceFileShow" fp ((pure $! traceFileShow fp (2 :: Int) (3 :: Int)) >> pure ())++  , let fp = "test/Golden/traceFileShow.output" in+    goldenVsFile "traceFileShowW" "test/Golden/traceFileShow" fp ((pure $! traceFileShowW fp (2 :: Int) (3 :: Int)) >> pure ())++  , let fp = "test/Golden/traceFileShowId.output" in+    goldenVsFile "traceFileShowId" "test/Golden/traceFileShowId" fp ((pure $! traceFileShowId fp (3 :: Int)) >> pure ())++  , let fp = "test/Golden/traceFileShowId.output" in+    goldenVsFile "traceFileShowIdW" "test/Golden/traceFileShowId" fp ((pure $! traceFileShowIdW fp (3 :: Int)) >> pure ())++  , let fp = "test/Golden/traceFileWith.output" in+    goldenVsFile "traceFileWith" "test/Golden/traceFileWith" fp ((pure $! traceFileWith fp fst ("hello","world")) >> pure ())++  , let fp = "test/Golden/traceFileWith.output" in+    goldenVsFile "traceFileWithW" "test/Golden/traceFileWith" fp ((pure $! traceFileWithW fp fst ("hello","world")) >> pure ())++  , let fp = "test/Golden/traceFileShowWith.output" in+    goldenVsFile "traceFileShowWith" "test/Golden/traceFileShowWith" fp ((pure $! traceFileShowWith fp length [1 :: Int,2,3]) >> pure ())++  , let fp = "test/Golden/traceFileShowWith.output" in+    goldenVsFile "traceFileShowWithW" "test/Golden/traceFileShowWith" fp ((pure $! traceFileShowWithW fp length [1 :: Int,2,3]) >> pure ())++  , let fp = "test/Golden/traceFileM.output" in+    goldenVsFile "traceFileM" "test/Golden/traceFileM" fp $+      void $ pure $! do+        x <- Just (3 :: Int)+        traceFileM fp ("x: " ++ show x)+        y <- pure 12+        traceFileM fp ("y: " ++ show y)+        pure (x*2 + y)++  , let fp = "test/Golden/traceFileMW.output" in+    goldenVsFile "traceFileMW" "test/Golden/traceFileMW" fp $+      void $ pure $! do+        x <- Just (3 :: Int)+        traceFileMW fp ("x: " ++ show x)+        y <- pure 12+        traceFileMW fp ("y: " ++ show y)+        pure (x*2 + y)++  , let fp = "test/Golden/traceFileShowM.output" in+    goldenVsFile "traceFileShowM" "test/Golden/traceFileShowM" fp $+      void $ pure $! do+        x <- Just (3 :: Int)+        traceFileShowM fp x+        y <- pure 12+        traceFileShowM fp y+        pure (x*2 + y)++  , let fp = "test/Golden/traceFileShowMW.output" in+    goldenVsFile "traceFileShowMW" "test/Golden/traceFileShowMW" fp $+      void $ pure $! do+        x <- Just (3 :: Int)+        traceFileShowMW fp x+        y <- pure 12+        traceFileShowMW fp y+        pure (x*2 + y)++  ]