
I've been debugging some Haskell code, including a lot of work on Mutable Vectors, so naturally I've found `trace` useful, and in particular `traceM`, because it fits in nicely with monadic code. The problem is that unlike `assert`, both `trace` and `traceM` execute unconditionally, I can't toggle them with a compiler flag. I could however do something like this in every file I want to do tracing. {-# LANGUAGE CPP #-} #ifdef TRACE trace = Debug.Trace.trace traceM = Debug.Trace.traceM #else trace _ = id traceM _ = pure () #endif But already, that's a lot of boilerplate. I'd also like to trace based on debug levels. For example, at TRACE level 2, only print trace statements at level 1 or 2, but at TRACE level 4, print trace statements at level 1, 2, 3 and 4, providing more detail (but more noise). This makes the above code even more complex. This wouldn't be a problem if I could put the code in a separate package, but I can't, as then whether tracing is on or not depends on the compiler settings of the tracing package, not on the calling package, which defeats the purpose somewhat. I considered using implicit parameters to quietly pass whether I want tracing and at what level into the tracing module, but it seems to be that implicit parameters can't be defined at the top level. It gets even more complex. When debugging, I might want to print something of type 'a'. Obviously 'a' will need some sort of show method for this to work, but outside of debug mode I don't want to restrict my function's types to things which are showable. So I considered doing this: #ifdef TRACE type DebugShow a = Show a debugShow = show #else type DebugShow a = () debugShow _ = error "DEBUG SHOWING OUTSIDE OF DEBUG MODE" #endif And of course, if you're only using `debugShow` as part of an argument to `trace`, lazy evaluation will avoid `debugShow` ever being called when tracing is not enabled. But put all this together and you've got around a dozen lines of boilerplate just to do tracing, without even having tracing levels yet, that have to be put in every module you want to use tracing, but don't want a whole lot of debug data being spat out in a release compile. Also, adding any other tracing functions just makes this longer. The only approach I can think of so far is to whack this all in a template haskell module and add code that splices it all into the current module: e.g. #ifdef TRACE $(traceFunctions True) #else $(traceFunctions False) #endif Where `traceFunctions` is a template haskell function that dumps all the appropriate functions and type definitions mentioned above (and maybe more) at the top level of the calling module. So my questions are: 1. Is there a better way? And 2. Has this problem already been solved?

Hi Clinton, On Wed, Nov 23, 2016 at 12:37:57AM +1100, Clinton Mead wrote:
The only approach I can think of so far is to whack this all in a template haskell module and add code that splices it all into the current module:
If you're already using cpp you could also put everyting into a 'Trace.h' file and include it: #include "Trace.h" Greetings, Daniel

This sounds an awful lot like a different name for what monad-logger offers. Pro: + uses Template Haskell for decoupling and to add source positions + used in Yesod so probably well maintained + the underlying fast-logger was optimized for performance, including in concurrent production environments Contra: - only usable in monadic contexts - I haven't found a better documentation than looking at how its used in Yesod source code Pro/Contra: * The package is from the Yesod/Stack corner of our world, so depending on your political viewpoint this can be anything from a bonus to a deal-breaker ;-)

Hi Clinton,
I've been running into the same problem recently: regularly adding and then
removing a lot of traces from my code.
Personally I don't like adding conditional compilation/cpp in my code (it's
quite ugly and difficult to maintain).
I've been looking into a logging packages:
https://hackage.haskell.org/package/tinylog-0.14.0/candidate/docs/System-Log...
The question is: how to carry around the settings of the logger (i.e. the
log levels: Warn, Fatal...) in your program?
I usually structure my programs around a big State monad, that I access
using Lenses. The log level could be added there.
On Tue, Nov 22, 2016 at 2:37 PM, Clinton Mead
I've been debugging some Haskell code, including a lot of work on Mutable Vectors, so naturally I've found `trace` useful, and in particular `traceM`, because it fits in nicely with monadic code.
The problem is that unlike `assert`, both `trace` and `traceM` execute unconditionally, I can't toggle them with a compiler flag.
I could however do something like this in every file I want to do tracing.
{-# LANGUAGE CPP #-}
#ifdef TRACE trace = Debug.Trace.trace traceM = Debug.Trace.traceM #else trace _ = id traceM _ = pure () #endif
But already, that's a lot of boilerplate.
I'd also like to trace based on debug levels. For example, at TRACE level 2, only print trace statements at level 1 or 2, but at TRACE level 4, print trace statements at level 1, 2, 3 and 4, providing more detail (but more noise).
This makes the above code even more complex.
This wouldn't be a problem if I could put the code in a separate package, but I can't, as then whether tracing is on or not depends on the compiler settings of the tracing package, not on the calling package, which defeats the purpose somewhat.
I considered using implicit parameters to quietly pass whether I want tracing and at what level into the tracing module, but it seems to be that implicit parameters can't be defined at the top level.
It gets even more complex. When debugging, I might want to print something of type 'a'. Obviously 'a' will need some sort of show method for this to work, but outside of debug mode I don't want to restrict my function's types to things which are showable. So I considered doing this:
#ifdef TRACE type DebugShow a = Show a debugShow = show #else type DebugShow a = () debugShow _ = error "DEBUG SHOWING OUTSIDE OF DEBUG MODE" #endif
And of course, if you're only using `debugShow` as part of an argument to `trace`, lazy evaluation will avoid `debugShow` ever being called when tracing is not enabled.
But put all this together and you've got around a dozen lines of boilerplate just to do tracing, without even having tracing levels yet, that have to be put in every module you want to use tracing, but don't want a whole lot of debug data being spat out in a release compile.
Also, adding any other tracing functions just makes this longer.
The only approach I can think of so far is to whack this all in a template haskell module and add code that splices it all into the current module:
e.g.
#ifdef TRACE $(traceFunctions True) #else $(traceFunctions False) #endif
Where `traceFunctions` is a template haskell function that dumps all the appropriate functions and type definitions mentioned above (and maybe more) at the top level of the calling module.
So my questions are:
1. Is there a better way? And 2. Has this problem already been solved?
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

PS: adding a new monad transformer to the monad stack just to add log
capacity seems overkill.
what do you guys think?
On Tue, Nov 22, 2016 at 3:58 PM, Corentin Dupont
Hi Clinton, I've been running into the same problem recently: regularly adding and then removing a lot of traces from my code.
Personally I don't like adding conditional compilation/cpp in my code (it's quite ugly and difficult to maintain). I've been looking into a logging packages: https://hackage.haskell.org/ package/tinylog-0.14.0/candidate/docs/System-Logger.html
The question is: how to carry around the settings of the logger (i.e. the log levels: Warn, Fatal...) in your program? I usually structure my programs around a big State monad, that I access using Lenses. The log level could be added there.
On Tue, Nov 22, 2016 at 2:37 PM, Clinton Mead
wrote: I've been debugging some Haskell code, including a lot of work on Mutable Vectors, so naturally I've found `trace` useful, and in particular `traceM`, because it fits in nicely with monadic code.
The problem is that unlike `assert`, both `trace` and `traceM` execute unconditionally, I can't toggle them with a compiler flag.
I could however do something like this in every file I want to do tracing.
{-# LANGUAGE CPP #-}
#ifdef TRACE trace = Debug.Trace.trace traceM = Debug.Trace.traceM #else trace _ = id traceM _ = pure () #endif
But already, that's a lot of boilerplate.
I'd also like to trace based on debug levels. For example, at TRACE level 2, only print trace statements at level 1 or 2, but at TRACE level 4, print trace statements at level 1, 2, 3 and 4, providing more detail (but more noise).
This makes the above code even more complex.
This wouldn't be a problem if I could put the code in a separate package, but I can't, as then whether tracing is on or not depends on the compiler settings of the tracing package, not on the calling package, which defeats the purpose somewhat.
I considered using implicit parameters to quietly pass whether I want tracing and at what level into the tracing module, but it seems to be that implicit parameters can't be defined at the top level.
It gets even more complex. When debugging, I might want to print something of type 'a'. Obviously 'a' will need some sort of show method for this to work, but outside of debug mode I don't want to restrict my function's types to things which are showable. So I considered doing this:
#ifdef TRACE type DebugShow a = Show a debugShow = show #else type DebugShow a = () debugShow _ = error "DEBUG SHOWING OUTSIDE OF DEBUG MODE" #endif
And of course, if you're only using `debugShow` as part of an argument to `trace`, lazy evaluation will avoid `debugShow` ever being called when tracing is not enabled.
But put all this together and you've got around a dozen lines of boilerplate just to do tracing, without even having tracing levels yet, that have to be put in every module you want to use tracing, but don't want a whole lot of debug data being spat out in a release compile.
Also, adding any other tracing functions just makes this longer.
The only approach I can think of so far is to whack this all in a template haskell module and add code that splices it all into the current module:
e.g.
#ifdef TRACE $(traceFunctions True) #else $(traceFunctions False) #endif
Where `traceFunctions` is a template haskell function that dumps all the appropriate functions and type definitions mentioned above (and maybe more) at the top level of the calling module.
So my questions are:
1. Is there a better way? And 2. Has this problem already been solved?
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Hi Clinton, at http://hackage.haskell.org/package/hledger-lib-1.0.1/docs/Hledger-Utils-Debu... you can see an approach using unsafePerformIO. This lets me invoke programs with --debug[=1..9] to get progressively more debug output. It seems to work for me, see what you think.. On 11/22/16 5:37 AM, Clinton Mead wrote:
I've been debugging some Haskell code, including a lot of work on Mutable Vectors, so naturally I've found `trace` useful, and in particular `traceM`, because it fits in nicely with monadic code.
The problem is that unlike `assert`, both `trace` and `traceM` execute unconditionally, I can't toggle them with a compiler flag.
I could however do something like this in every file I want to do tracing.
{-# LANGUAGE CPP #-}
#ifdef TRACE trace = Debug.Trace.trace traceM = Debug.Trace.traceM #else trace _ = id traceM _ = pure () #endif
But already, that's a lot of boilerplate.
I'd also like to trace based on debug levels. For example, at TRACE level 2, only print trace statements at level 1 or 2, but at TRACE level 4, print trace statements at level 1, 2, 3 and 4, providing more detail (but more noise).
This makes the above code even more complex.
This wouldn't be a problem if I could put the code in a separate package, but I can't, as then whether tracing is on or not depends on the compiler settings of the tracing package, not on the calling package, which defeats the purpose somewhat.
I considered using implicit parameters to quietly pass whether I want tracing and at what level into the tracing module, but it seems to be that implicit parameters can't be defined at the top level.
It gets even more complex. When debugging, I might want to print something of type 'a'. Obviously 'a' will need some sort of show method for this to work, but outside of debug mode I don't want to restrict my function's types to things which are showable. So I considered doing this:
#ifdef TRACE type DebugShow a = Show a debugShow = show #else type DebugShow a = () debugShow _ = error "DEBUG SHOWING OUTSIDE OF DEBUG MODE" #endif
And of course, if you're only using `debugShow` as part of an argument to `trace`, lazy evaluation will avoid `debugShow` ever being called when tracing is not enabled.
But put all this together and you've got around a dozen lines of boilerplate just to do tracing, without even having tracing levels yet, that have to be put in every module you want to use tracing, but don't want a whole lot of debug data being spat out in a release compile.
Also, adding any other tracing functions just makes this longer.
The only approach I can think of so far is to whack this all in a template haskell module and add code that splices it all into the current module:
e.g.
#ifdef TRACE $(traceFunctions True) #else $(traceFunctions False) #endif
Where `traceFunctions` is a template haskell function that dumps all the appropriate functions and type definitions mentioned above (and maybe more) at the top level of the calling module.
So my questions are:
1. Is there a better way? And 2. Has this problem already been solved?
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

Hello Clinton, Just to clarify, you are asking how to toggle traceability on a per-module (or perhaps per-package) basis? Because if you're OK with tracing be a global affair then putting everything in a package works quite well (you can use a flag to control whether or not you want to build with or without tracing.) Edward Excerpts from Clinton Mead's message of 2016-11-23 00:37:57 +1100:
I've been debugging some Haskell code, including a lot of work on Mutable Vectors, so naturally I've found `trace` useful, and in particular `traceM`, because it fits in nicely with monadic code.
The problem is that unlike `assert`, both `trace` and `traceM` execute unconditionally, I can't toggle them with a compiler flag.
I could however do something like this in every file I want to do tracing.
{-# LANGUAGE CPP #-}
#ifdef TRACE trace = Debug.Trace.trace traceM = Debug.Trace.traceM #else trace _ = id traceM _ = pure () #endif
But already, that's a lot of boilerplate.
I'd also like to trace based on debug levels. For example, at TRACE level 2, only print trace statements at level 1 or 2, but at TRACE level 4, print trace statements at level 1, 2, 3 and 4, providing more detail (but more noise).
This makes the above code even more complex.
This wouldn't be a problem if I could put the code in a separate package, but I can't, as then whether tracing is on or not depends on the compiler settings of the tracing package, not on the calling package, which defeats the purpose somewhat.
I considered using implicit parameters to quietly pass whether I want tracing and at what level into the tracing module, but it seems to be that implicit parameters can't be defined at the top level.
It gets even more complex. When debugging, I might want to print something of type 'a'. Obviously 'a' will need some sort of show method for this to work, but outside of debug mode I don't want to restrict my function's types to things which are showable. So I considered doing this:
#ifdef TRACE type DebugShow a = Show a debugShow = show #else type DebugShow a = () debugShow _ = error "DEBUG SHOWING OUTSIDE OF DEBUG MODE" #endif
And of course, if you're only using `debugShow` as part of an argument to `trace`, lazy evaluation will avoid `debugShow` ever being called when tracing is not enabled.
But put all this together and you've got around a dozen lines of boilerplate just to do tracing, without even having tracing levels yet, that have to be put in every module you want to use tracing, but don't want a whole lot of debug data being spat out in a release compile.
Also, adding any other tracing functions just makes this longer.
The only approach I can think of so far is to whack this all in a template haskell module and add code that splices it all into the current module:
e.g.
#ifdef TRACE $(traceFunctions True) #else $(traceFunctions False) #endif
Where `traceFunctions` is a template haskell function that dumps all the appropriate functions and type definitions mentioned above (and maybe more) at the top level of the calling module.
So my questions are:
1. Is there a better way? And 2. Has this problem already been solved?

I personally prefer the approach in this package:
https://hackage.haskell.org/package/NoTrace
You import Debug.Trace when you want traces and switch the import to
Debug.NoTrace to disable them.
You could use a similar strategy with verbosity levels; plus you might not
even need levels, as this is module-based you don't get the extra noise
from other modules.
- nitrix
On Nov 22, 2016 4:11 PM, "Edward Z. Yang"
Hello Clinton,
Just to clarify, you are asking how to toggle traceability on a per-module (or perhaps per-package) basis? Because if you're OK with tracing be a global affair then putting everything in a package works quite well (you can use a flag to control whether or not you want to build with or without tracing.)
Edward
I've been debugging some Haskell code, including a lot of work on Mutable Vectors, so naturally I've found `trace` useful, and in particular `traceM`, because it fits in nicely with monadic code.
The problem is that unlike `assert`, both `trace` and `traceM` execute unconditionally, I can't toggle them with a compiler flag.
I could however do something like this in every file I want to do
Excerpts from Clinton Mead's message of 2016-11-23 00:37:57 +1100: tracing.
{-# LANGUAGE CPP #-}
#ifdef TRACE trace = Debug.Trace.trace traceM = Debug.Trace.traceM #else trace _ = id traceM _ = pure () #endif
But already, that's a lot of boilerplate.
I'd also like to trace based on debug levels. For example, at TRACE level 2, only print trace statements at level 1 or 2, but at TRACE level 4,
trace statements at level 1, 2, 3 and 4, providing more detail (but more noise).
This makes the above code even more complex.
This wouldn't be a problem if I could put the code in a separate package, but I can't, as then whether tracing is on or not depends on the compiler settings of the tracing package, not on the calling package, which defeats the purpose somewhat.
I considered using implicit parameters to quietly pass whether I want tracing and at what level into the tracing module, but it seems to be
print that
implicit parameters can't be defined at the top level.
It gets even more complex. When debugging, I might want to print something of type 'a'. Obviously 'a' will need some sort of show method for this to work, but outside of debug mode I don't want to restrict my function's types to things which are showable. So I considered doing this:
#ifdef TRACE type DebugShow a = Show a debugShow = show #else type DebugShow a = () debugShow _ = error "DEBUG SHOWING OUTSIDE OF DEBUG MODE" #endif
And of course, if you're only using `debugShow` as part of an argument to `trace`, lazy evaluation will avoid `debugShow` ever being called when tracing is not enabled.
But put all this together and you've got around a dozen lines of boilerplate just to do tracing, without even having tracing levels yet, that have to be put in every module you want to use tracing, but don't want a whole lot of debug data being spat out in a release compile.
Also, adding any other tracing functions just makes this longer.
The only approach I can think of so far is to whack this all in a template haskell module and add code that splices it all into the current module:
e.g.
#ifdef TRACE $(traceFunctions True) #else $(traceFunctions False) #endif
Where `traceFunctions` is a template haskell function that dumps all the appropriate functions and type definitions mentioned above (and maybe more) at the top level of the calling module.
So my questions are:
1. Is there a better way? And 2. Has this problem already been solved?
Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

I came accross https://hackage.haskell.org/package/hslogger-1.2.10
Which seems quite good to solve your problem.
On Tue, Nov 22, 2016 at 2:37 PM, Clinton Mead
I've been debugging some Haskell code, including a lot of work on Mutable Vectors, so naturally I've found `trace` useful, and in particular `traceM`, because it fits in nicely with monadic code.
The problem is that unlike `assert`, both `trace` and `traceM` execute unconditionally, I can't toggle them with a compiler flag.
I could however do something like this in every file I want to do tracing.
{-# LANGUAGE CPP #-}
#ifdef TRACE trace = Debug.Trace.trace traceM = Debug.Trace.traceM #else trace _ = id traceM _ = pure () #endif
But already, that's a lot of boilerplate.
I'd also like to trace based on debug levels. For example, at TRACE level 2, only print trace statements at level 1 or 2, but at TRACE level 4, print trace statements at level 1, 2, 3 and 4, providing more detail (but more noise).
This makes the above code even more complex.
This wouldn't be a problem if I could put the code in a separate package, but I can't, as then whether tracing is on or not depends on the compiler settings of the tracing package, not on the calling package, which defeats the purpose somewhat.
I considered using implicit parameters to quietly pass whether I want tracing and at what level into the tracing module, but it seems to be that implicit parameters can't be defined at the top level.
It gets even more complex. When debugging, I might want to print something of type 'a'. Obviously 'a' will need some sort of show method for this to work, but outside of debug mode I don't want to restrict my function's types to things which are showable. So I considered doing this:
#ifdef TRACE type DebugShow a = Show a debugShow = show #else type DebugShow a = () debugShow _ = error "DEBUG SHOWING OUTSIDE OF DEBUG MODE" #endif
And of course, if you're only using `debugShow` as part of an argument to `trace`, lazy evaluation will avoid `debugShow` ever being called when tracing is not enabled.
But put all this together and you've got around a dozen lines of boilerplate just to do tracing, without even having tracing levels yet, that have to be put in every module you want to use tracing, but don't want a whole lot of debug data being spat out in a release compile.
Also, adding any other tracing functions just makes this longer.
The only approach I can think of so far is to whack this all in a template haskell module and add code that splices it all into the current module:
e.g.
#ifdef TRACE $(traceFunctions True) #else $(traceFunctions False) #endif
Where `traceFunctions` is a template haskell function that dumps all the appropriate functions and type definitions mentioned above (and maybe more) at the top level of the calling module.
So my questions are:
1. Is there a better way? And 2. Has this problem already been solved?
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
participants (7)
-
Alex Belanger
-
Clinton Mead
-
Corentin Dupont
-
Daniel Trstenjak
-
Edward Z. Yang
-
MarLinn
-
Simon Michael