Logstash-data between start and end transaction

Providing the lines for different transactions are never interleaved you can do it using an aggregate filter and a class variable. Note that you must set --pipeline.workers 1 to use an aggregate. Your use case matches example 1 in the aggregate documentation, except you are missing the taskid on some lines. So use a class variable to add it.

    if [message] =~ /TRANSACTION START/ {
        grok { match => { "message" => "TRANSACTION START \[%{NUMBER:taskid}\]" } }
        ruby { code => '@@taskid = event.get("taskid") ' }
    } else {
        ruby { code => 'event.set("taskid",  @@taskid)' }
    }

Then do the aggregate using task_id => "%{taskid}"