Adding logging functionallity in package

I build a package with code to solve specific equations. The code has become quite complex and so to convince myself (and others) that it works correctly I would like to add some code to write messages to a log file. The messages would depend on the specific function for which I want information and I want to be able to turn logging on or off for certain functions (not all functions need to write to a log file though, only the 'big' ones).

So basically how could one alter the code in a package such that:

1. the user of the package has the option to turn on logging for certain functions, and
2. the code itself needs as little altering as possible. In particular I want to be able to add functions and test them without having to rewrite other functions their logging behaviour.

Some of the solutions I thought about are the following

1. Use OptionsPattern[] in every function to start logging. Problem is that I have to alter the code of each function and put If statements everywhere which messes up readability.

2. Implement a function PrintLog[file_], that takes a function and tells it to evaluate and write info to log file. Then there would be some construction in the functions themselves that get turned on by the PrintLog function. At the moment I wouldn't know how to implement this solution though...

• I would try a combination of EchoFunction with ToString and function that writes into a file like WriteString. Nov 15, 2021 at 17:02

A common way is to use an inert symbol for the "logging function", and assign a value to this function on demand.

Example:

f[x_] :=
Module[{y = x^2},
myPrint["Input is ", x];
y
]


Then you can use Block[{myPrint = Print}, f[5]] to temporarily activate logging.

• It's perhaps worth mentioning that the "inert" function still evaluates its arguments and may have side effects. E.g., Module[{},myPrint[FiniteGroupData["S30", "CycleIndex"][[1]]//Length];];//Timing yields non-zero time {0.171875, Null}. A solution I used to is to SetAttributes[myPrint, HoldAll];; in this case, Block will temporarily redefine the function along with its attributes and the kitchen sink, so in your example using a Block this HoldAll will be ignored. Just double checked; the Print prints '5604' which is about the right monomial count, I guess, give or take. :)
– kkm
Nov 16, 2021 at 1:45