Hello!
Some time ago I’ve asked about your techniques for debugging parsers and shared a "log parser combinator" there.
I’ve since made it a bit better: instead of just logging the “enter” transitions and successful “exit” transitions, it’s now also logging unsuccessful “exit” transitions. 
It does this by using a technique similar to the “logging JSON decoder”: it fetches the source from the current parser and runs Parser.run itself, and logs the Ok / Err result. That allows us to see the unsuccessful results, along with the context stack, problem, and so on.
Here is the code:
shouldLog : String -> Bool
shouldLog message =
    -- You can conditionally turn some of the logging on/off per function here.
    List.member message
        [ "moduleType"
        , "plainModuleType"
        , "portModuleType"
        , "effectModuleType"
        ]
{-| Beware: what this parser logs might sometimes be a lie.
To work it needs to run `Parser.run` inside itself, and it has no way to
set the parser state itself to the state it was called in.
So it runs it with a different source string, zeroed offset, indent, position,
basically with totally different parser state.
Some parsers might not work properly in the "inner" `Parser.run` call as a result
if they depend on this state, and thus might log lies.
Note: the parser itself will still work as before, since we're not resetting the
"outer" `Parser.run` state.
-}
log : String -> Parser_ a -> Parser_ a
log message parser =
    if shouldLog message then
        P.succeed
            (\source offsetBefore ->
                let
                    _ =
                        Debug.log "+++++++++++++++++ starting" message
                in
                ( source, offsetBefore )
            )
            |= P.getSource
            |= P.getOffset
            |> P.andThen
                (\( source, offsetBefore ) ->
                    {- Kinda like that logging decoder from Thoughtbot:
                       https://thoughtbot.com/blog/debugging-dom-event-handlers-in-elm
                       Basically we run `Parser.run` ourselves so that we can
                       get at the context and say something more meaningful
                       about the failure if it happens.
                    -}
                    let
                        remainingSource =
                            String.dropLeft offsetBefore source
                                |> Debug.log "yet to parse  "
                    in
                    let
                        parseResult =
                            -- the side-effecty part; this might log lies
                            P.run
                                (P.succeed
                                    (\parseResult_ innerOffset ->
                                        let
                                            _ =
                                                Debug.log "chomped string" (String.left innerOffset remainingSource)
                                        in
                                        parseResult_
                                    )
                                    |= parser
                                    |= P.getOffset
                                )
                                remainingSource
                                |> Debug.log "parse result  "
                    in
                    let
                        _ =
                            Debug.log "----------------- ending  " message
                    in
                    parser
                )
    else
        parser
And here is an example output!
+++++++++++++++++ starting: "moduleType"
yet to parse  : "port module Foo.Bar exposing (..)"
+++++++++++++++++ starting: "plainModuleType"
yet to parse  : "port module Foo.Bar exposing (..)"
parse result  : Err [{ col = 1, contextStack = [], problem = ExpectingModuleKeyword, row = 1 }]
----------------- ending  : "plainModuleType"
+++++++++++++++++ starting: "portModuleType"
yet to parse  : "port module Foo.Bar exposing (..)"
chomped string: "port module"
parse result  : Ok PortModule
----------------- ending  : "portModuleType"
chomped string: "port module"
parse result  : Ok PortModule
----------------- ending  : "moduleType"
You can kinda make sense of it by counting the +++ and --- around. But beware 
Disclaimer 1: It duplicates some of the output and so the trace isn’t precisely what happens during the execution. I believe it’s a consequence of nesting log-ed parsers together (multiple Debug.log runs because I can’t provide a way to turn off the logging inside the inner Parser.run call  )
)
Disclaimer 2: I believe it has a problem (didn’t run into it yet though) where because the inner Parser.run can’t replicate the parser state of the outer parser it lives in (there’s API in elm/parser for getting the state but not for setting it), some parsers that depend on the offset / indentation / … might return different result in the inner Parser.run call (and thus log different stuff) from the outer one (which stays the same, fortunately).
