No, it's not a matter of the state changing. The premise is that, at each step of the calculation, a function does some computation and returns a result. At the point where the logging decision is being made, the decision is based on data
available within the function, but not being
returned by the function - only a derived value is returned.
Now, perhaps you could argue that the right way to do the problem (without the logging) in Haskell is to not have functions like that - to break up that function so that the data that, in my version, is only available within the function is instead explicitly returned by some smaller function.
But if you don't argue that, then you're left with the stated problem: What's the right way of getting logging out of the middle of a function in Haskell?