Yes, but no. Again, there are functional patterns you can apply.
First, functional programs tend to be more horizontally composed than vertically. Side effects usually happen at the same "level" of the application, rather than occuring at multiple depths. So the need to thread logging apparati is already reduced, simply because logging only happens higher up in the application.
Second, because side-effects only really occur at this thin layer, you can capture logging as a monadic action, avoiding the need to explicitly thread the logger state around. (This is the same situation as the "thread the world" problem we discussed earlier.)
Third, because so much more of your program is pure, it is much easier to perform unit tests and check assertions in other ways. At that level, logging is a bandaid over poor testing and assurance, not a goal in itself.
Finally, if you do find yourself deep down-stack with a need to perform some kind of side-effect, you can apply logical methods (a la LVars, CRDTs) to give a stateful interaction between separated parts of your program. The Haxl paper [0] is a good example of this: most of the design is pure functional, but for the part that involve an interaction not easily captured by the fundamental call-return / request-response pattern, they utilize monotonic state to maintain a registry of fulfilled and unfulfilled requests.
[0] https://simonmar.github.io/bib/papers/haxl-icfp14.pdf
> It's rigorously correct, but I feel like it's a step too far for most programs.
I feel you're being too dismissive. There is an entire community of developers -- many of whom operate in industry -- who can and do effectively solve the problems you are raising.
"Rigorously correct" is one of those things non-FP folks think FP is about. You can write buggy code in any paradigm. What people like about FP is that it's easier to reason about, and it's generally easier to find precise abstractions that support that kind of reasoning. "Rigorously correct" is missing the point.